{"file_path":"src/UsdnProtocol/UsdnProtocolImpl.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { UUPSUpgradeable } from \"solady/src/utils/UUPSUpgradeable.sol\";\n\nimport { IBaseLiquidationRewardsManager } from\n    \"../interfaces/LiquidationRewardsManager/IBaseLiquidationRewardsManager.sol\";\nimport { IBaseOracleMiddleware } from \"../interfaces/OracleMiddleware/IBaseOracleMiddleware.sol\";\nimport { IUsdn } from \"../interfaces/Usdn/IUsdn.sol\";\nimport { IUsdnProtocolErrors } from \"../interfaces/UsdnProtocol/IUsdnProtocolErrors.sol\";\nimport { IUsdnProtocolFallback } from \"../interfaces/UsdnProtocol/IUsdnProtocolFallback.sol\";\nimport { IUsdnProtocolImpl } from \"../interfaces/UsdnProtocol/IUsdnProtocolImpl.sol\";\nimport { UsdnProtocolActions } from \"./UsdnProtocolActions.sol\";\nimport { UsdnProtocolCore } from \"./UsdnProtocolCore.sol\";\nimport { UsdnProtocolLong } from \"./UsdnProtocolLong.sol\";\nimport { UsdnProtocolVault } from \"./UsdnProtocolVault.sol\";\nimport { UsdnProtocolConstantsLibrary as Constants } from \"./libraries/UsdnProtocolConstantsLibrary.sol\";\nimport { UsdnProtocolUtilsLibrary as Utils } from \"./libraries/UsdnProtocolUtilsLibrary.sol\";\n\ncontract UsdnProtocolImpl is\n    IUsdnProtocolErrors,\n    IUsdnProtocolImpl,\n    UsdnProtocolActions,\n    UsdnProtocolCore,\n    UsdnProtocolVault,\n    UsdnProtocolLong,\n    UUPSUpgradeable\n{\n    /// @custom:oz-upgrades-unsafe-allow constructor\n    constructor() {\n        _disableInitializers();\n    }\n\n    /// @inheritdoc IUsdnProtocolImpl\n    function initializeStorage(\n        IUsdn usdn,\n        IERC20Metadata sdex,\n        IERC20Metadata asset,\n        IBaseOracleMiddleware oracleMiddleware,\n        IBaseLiquidationRewardsManager liquidationRewardsManager,\n        int24 tickSpacing,\n        address feeCollector,\n        IUsdnProtocolFallback protocolFallback\n    ) public initializer {\n        Storage storage s = Utils._getMainStorage();\n\n        __AccessControlDefaultAdminRules_init(0, msg.sender);\n        __initializeReentrancyGuard_init();\n        __Pausable_init();\n        __EIP712_init(\"UsdnProtocol\", \"1\");\n\n        _setRoleAdmin(Constants.SET_EXTERNAL_ROLE, Constants.ADMIN_SET_EXTERNAL_ROLE);\n        _setRoleAdmin(Constants.CRITICAL_FUNCTIONS_ROLE, Constants.ADMIN_CRITICAL_FUNCTIONS_ROLE);\n        _setRoleAdmin(Constants.SET_PROTOCOL_PARAMS_ROLE, Constants.ADMIN_SET_PROTOCOL_PARAMS_ROLE);\n        _setRoleAdmin(Constants.SET_USDN_PARAMS_ROLE, Constants.ADMIN_SET_USDN_PARAMS_ROLE);\n        _setRoleAdmin(Constants.SET_OPTIONS_ROLE, Constants.ADMIN_SET_OPTIONS_ROLE);\n        _setRoleAdmin(Constants.PROXY_UPGRADE_ROLE, Constants.ADMIN_PROXY_UPGRADE_ROLE);\n        _setRoleAdmin(Constants.PAUSER_ROLE, Constants.ADMIN_PAUSER_ROLE);\n        _setRoleAdmin(Constants.UNPAUSER_ROLE, Constants.ADMIN_UNPAUSER_ROLE);\n\n        s._minLeverage = 10 ** Constants.LEVERAGE_DECIMALS + 10 ** (Constants.LEVERAGE_DECIMALS - 1); // x1.1\n        s._maxLeverage = 10 * 10 ** Constants.LEVERAGE_DECIMALS; // x10\n        s._lowLatencyValidatorDeadline = 15 minutes;\n        s._onChainValidatorDeadline = 65 minutes; // slightly more than chainlink's heartbeat\n        s._safetyMarginBps = 200; // 2%\n        s._liquidationIteration = 1;\n        s._protocolFeeBps = 800; // 8%\n        s._rebalancerBonusBps = 8000; // 80%\n        s._liquidationPenalty = 200; // 200 ticks -> ~2.02%\n        s._EMAPeriod = 5 days;\n        s._fundingSF = 12 * 10 ** (Constants.FUNDING_SF_DECIMALS - 2); // 0.12\n        s._feeThreshold = 1 ether;\n        s._openExpoImbalanceLimitBps = 500; // 5%\n        s._withdrawalExpoImbalanceLimitBps = 600; // 6%\n        s._depositExpoImbalanceLimitBps = 500; // 5%\n        s._closeExpoImbalanceLimitBps = 600; // 6%\n        s._rebalancerCloseExpoImbalanceLimitBps = 350; // 3.5%\n        s._longImbalanceTargetBps = 400; // 4%\n        s._positionFeeBps = 4; // 0.04%\n        s._vaultFeeBps = 4; // 0.04%\n        s._sdexRewardsRatioBps = 100; // 1%\n        s._sdexBurnOnDepositRatio = 5e6; // 5%\n        s._securityDepositValue = 0.5 ether;\n        s._EMA = int256(3 * 10 ** (Constants.FUNDING_RATE_DECIMALS - 4));\n\n        // since all USDN must be minted by the protocol, we check that the total supply is 0\n        if (usdn.totalSupply() != 0) {\n            revert UsdnProtocolInvalidUsdn(address(usdn));\n        }\n        if (feeCollector == address(0)) {\n            revert UsdnProtocolInvalidFeeCollector();\n        }\n\n        s._usdn = usdn;\n        s._sdex = sdex;\n        // make sure the USDN and SDEX tokens have the same number of decimals\n        if (usdn.decimals() != Constants.TOKENS_DECIMALS || sdex.decimals() != Constants.TOKENS_DECIMALS) {\n            revert UsdnProtocolInvalidTokenDecimals();\n        }\n\n        s._usdnMinDivisor = usdn.MIN_DIVISOR();\n        s._asset = asset;\n        uint8 assetDecimals = asset.decimals();\n        s._assetDecimals = assetDecimals;\n        if (assetDecimals < Constants.FUNDING_SF_DECIMALS) {\n            revert UsdnProtocolInvalidAssetDecimals(assetDecimals);\n        }\n        s._oracleMiddleware = oracleMiddleware;\n        uint8 priceFeedDecimals = oracleMiddleware.getDecimals();\n        s._priceFeedDecimals = priceFeedDecimals;\n        s._liquidationRewardsManager = liquidationRewardsManager;\n        s._tickSpacing = tickSpacing;\n        s._feeCollector = feeCollector;\n\n        s._targetUsdnPrice = uint128(10_087 * 10 ** (priceFeedDecimals - 4)); // $1.0087\n        s._usdnRebaseThreshold = uint128(1009 * 10 ** (priceFeedDecimals - 3)); // $1.009\n        s._minLongPosition = 2 * 10 ** assetDecimals; // 2 tokens\n        s._protocolFallbackAddr = address(protocolFallback);\n    }\n\n    /**\n     * @inheritdoc UUPSUpgradeable\n     * @notice Verifies that the caller is allowed to upgrade the protocol.\n     * @param implementation The address of the new implementation contract.\n     */\n    function _authorizeUpgrade(address implementation) internal override onlyRole(Constants.PROXY_UPGRADE_ROLE) { }\n\n    /**\n     * @notice Delegates the call to the fallback contract.\n     * @param protocolFallbackAddr The address of the fallback contract.\n     */\n    function _delegate(address protocolFallbackAddr) internal {\n        assembly {\n            calldatacopy(0, 0, calldatasize())\n            let result := delegatecall(gas(), protocolFallbackAddr, 0, calldatasize(), 0, 0)\n            returndatacopy(0, 0, returndatasize())\n            switch result\n            case 0 { revert(0, returndatasize()) }\n            default { return(0, returndatasize()) }\n        }\n    }\n\n    /**\n     * @notice Delegates the call to the fallback contract if the function signature contained in the transaction data\n     * does not match any function in the implementation contract.\n     */\n    fallback() external {\n        _delegate(Utils._getMainStorage()._protocolFallbackAddr);\n    }\n}\n","deployed_bytecode":"0x60806040526004361061031d575f3560e01c806384ef8ffc116101a4578063ab493b1e116100eb578063ba08c8eb11610094578063cf6eefb71161006e578063cf6eefb714610a49578063d547741f14610ac0578063d602b9fd14610adf578063dded0c4e14610af35761031d565b8063ba08c8eb14610a0e578063cc8463c814610a21578063cefc142914610a355761031d565b8063b27ddda7116100c5578063b27ddda7146109bd578063b3042999146109dc578063b8ef222a146109ef5761031d565b8063ab493b1e146108cf578063acea51be146108ee578063ae1043441461099e5761031d565b806393dc7ca01161014d578063a1eda53c11610127578063a1eda53c1461086a578063a217fddf1461089d578063a63563cf146108b05761031d565b806393dc7ca01461081157806397366618146108445780639d3960db146108575761031d565b80638da5cb5b1161017e5780638da5cb5b1461076c57806391d148541461078057806392d2e41f146107f05761031d565b806384ef8ffc146106c4578063874cf8e61461072e578063895e22761461074d5761031d565b80634f1ef28611610268578063649a5ec7116102115780637aeabd99116101eb5780637aeabd991461065d578063806b48731461067c57806384b0196e1461069d5761031d565b8063649a5ec71461061657806372fcfbf81461063557806378e890ba146106495761031d565b80635c975abb116102425780635c975abb14610587578063612008f4146105bd578063634e93da146105f75761031d565b80634f1ef2861461054d57806352d1902d1461056057806358dd74b3146105745761031d565b8063248a9ca3116102ca578063422f289f116102a4578063422f289f146104f557806342ff0e59146105085780634c1877651461051b5761031d565b8063248a9ca31461045c5780632f2ff15d146104b757806336568abe146104d65761031d565b806308256b29116102fb57806308256b29146103e85780630aa6220b146104285780631721539b1461043c5761031d565b806301ffc9a71461036c578063022d63fb146103a05780630239040b146103c8575b348015610328575f80fd5b507fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc972c5461036a9073ffffffffffffffffffffffffffffffffffffffff16610b12565b005b348015610377575f80fd5b5061038b6103863660046144fa565b610b35565b60405190151581526020015b60405180910390f35b3480156103ab575f80fd5b50620697805b60405165ffffffffffff9091168152602001610397565b6103db6103d63660046145c5565b610b90565b604051610397919061467a565b3480156103f3575f80fd5b506104076104023660046147e3565b610c71565b6040516fffffffffffffffffffffffffffffffff9091168152602001610397565b348015610433575f80fd5b5061036a610d4e565b61044f61044a36600461484e565b610d63565b604051610397919061488d565b348015610467575f80fd5b506104a9610476366004614923565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b604051908152602001610397565b3480156104c2575f80fd5b5061036a6104d136600461493a565b610e59565b3480156104e1575f80fd5b5061036a6104f036600461493a565b610e9e565b6103db610503366004614978565b611005565b61038b6105163660046145c5565b6111b8565b348015610526575f80fd5b5061053a610535366004614a6c565b611266565b60405160029190910b8152602001610397565b61036a61055b366004614a87565b611304565b34801561056b575f80fd5b506104a96113e4565b61038b610582366004614ad8565b611441565b348015610592575f80fd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1661038b565b3480156105c8575f80fd5b506105dc6105d7366004614a6c565b611522565b60408051938452602084019290925290820152606001610397565b348015610602575f80fd5b5061036a610611366004614b9d565b6115d1565b348015610621575f80fd5b5061036a610630366004614bb8565b6115e4565b348015610640575f80fd5b5061053a6115f7565b348015610654575f80fd5b506104a9611668565b348015610668575f80fd5b506104a9610677366004614a6c565b611671565b61068f61068a3660046145c5565b61170f565b604051610397929190614bdd565b3480156106a8575f80fd5b506106b161180d565b6040516103979796959493929190614c5b565b3480156106cf575f80fd5b507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610397565b348015610739575f80fd5b506104a9610748366004614d1a565b611907565b348015610758575f80fd5b5061036a610767366004614d46565b6119b4565b348015610777575f80fd5b50610709611a67565b34801561078b575f80fd5b5061038b61079a36600461493a565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6108036107fe366004614da6565b611aa6565b604051610397929190614e76565b34801561081c575f80fd5b5061083061082b366004614ea3565b611c67565b60405162ffffff9091168152602001610397565b61036a610852366004614ebe565b611cf7565b61038b610865366004614f35565b611dc2565b348015610875575f80fd5b5061087e611e39565b6040805165ffffffffffff938416815292909116602083015201610397565b3480156108a8575f80fd5b506104a95f81565b3480156108bb575f80fd5b506104a96108ca366004614d1a565b611ef6565b3480156108da575f80fd5b506104a96108e9366004614f7e565b611fa4565b3480156108f9575f80fd5b5061090d610908366004614fc5565b612039565b6040516103979291905f60c08201905083511515825264ffffffffff602085015116602083015273ffffffffffffffffffffffffffffffffffffffff60408501511660408301526fffffffffffffffffffffffffffffffff60608501511660608301526fffffffffffffffffffffffffffffffff608085015116608083015262ffffff831660a08301529392505050565b3480156109a9575f80fd5b5061036a6109b8366004615009565b6120fd565b3480156109c8575f80fd5b506104a96109d7366004614d1a565b612e6b565b6104a96109ea3660046150ad565b612ed7565b3480156109fa575f80fd5b506104a9610a09366004614d1a565b612f81565b61038b610a1c3660046145c5565b612fed565b348015610a2c575f80fd5b506103b161305c565b348015610a40575f80fd5b5061036a61313c565b348015610a54575f80fd5b507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400546040805173ffffffffffffffffffffffffffffffffffffffff831681527401000000000000000000000000000000000000000090920465ffffffffffff16602083015201610397565b348015610acb575f80fd5b5061036a610ada36600461493a565b6131b7565b348015610aea575f80fd5b5061036a6131f8565b348015610afe575f80fd5b5061053a610b0d3660046150ef565b61320a565b365f80375f80365f845af43d5f803e808015610b2c573d5ff35b3d5ffd5b505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f31498786000000000000000000000000000000000000000000000000000000001480610b8a5750610b8a826132db565b92915050565b5f610b99613371565b610ba16133cf565b610ba9613428565b6040517fd37c8d8000000000000000000000000000000000000000000000000000000000815273ffc37455f53cbc0360ef3f3cccb6a967e1ae2a459063d37c8d8090610bff908890889088908890600401615346565b602060405180830381865af4158015610c1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c3e91906153a0565b9050610c6960017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b949350505050565b6040517f16f7fcff0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8716600482015260248101869052604481018590528351606482015260208401516084820152600283900b60a482015262ffffff821660c48201525f9073932a7755749879426925e7d977afa6baa64a3455906316f7fcff9060e4016040805180830381865af4158015610d1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d4291906153b9565b98975050505050505050565b5f610d58816134a9565b610d606134b3565b50565b6060610d6d613371565b610d756133cf565b610d7d613428565b6040517f1721539b00000000000000000000000000000000000000000000000000000000815273af13fa20fa5128b1ea37559d407285962a2b7ffe90631721539b90610dcf90869086906004016153e6565b5f60405180830381865af4158015610de9573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610e2e91908101906153f9565b9050610b8a60017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b81610e90576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e9a82826134bd565b5050565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840082158015610f0657507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff8381169116145b15610ffb577feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900465ffffffffffff1681151580610f79575065ffffffffffff8116155b80610f8c57504265ffffffffffff821610155b15610fd2576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff821660048201526024015b60405180910390fd5b505080547fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff1681555b610b308383613500565b5f61100e613371565b6110166133cf565b61101e613428565b5f7fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc970090505f6040518061010001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018f80360381019061109e9190614fc5565b81526fffffffffffffffffffffffffffffffff8f166020820152604081018e9052601684015467ffffffffffffffff1660608201526080016110de613559565b90526040517f52bbc6fd00000000000000000000000000000000000000000000000000000000815290915073ffc37455f53cbc0360ef3f3cccb6a967e1ae2a45906352bbc6fd9061113d9084908c908c908c908c908c906004016154f1565b602060405180830381865af4158015611158573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061117c91906153a0565b925050506111a960017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b9b9a5050505050505050505050565b5f6111c1613371565b6111c96133cf565b6111d1613428565b6040517f1a5c8297000000000000000000000000000000000000000000000000000000008152735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90631a5c829790611227908890889088908890600401615346565b602060405180830381865af4158015611242573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c3e919061560b565b6040517f4c1877650000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff821660048201525f9073932a7755749879426925e7d977afa6baa64a345590634c18776590602401602060405180830381865af41580156112e0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8a9190615624565b7f000000000000000000000000271df5517a4daacb7cab988aa64d23debda4c49830810361133957639f03a0265f526004601cfd5b61134284613562565b8360601b60601c93506352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80602060016004601d895afa5114611394576355299b496001526004601dfd5b847fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f38a284905581156113de57604051828482375f388483885af46113dc573d5f823e3d81fd5b505b50505050565b5f7f000000000000000000000000271df5517a4daacb7cab988aa64d23debda4c49830811461141a57639f03a0265f526004601cfd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91505090565b5f61144a613371565b6114526133cf565b61145a613428565b6040517f8aaebb6b000000000000000000000000000000000000000000000000000000008152735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90638aaebb6b906114b8908c908c908c908c908c908c908c908c9060040161563f565b602060405180830381865af41580156114d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114f7919061560b565b9050610d4260017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b6040517f612008f40000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff821660048201525f9081908190730de8af2200c88a51b1a53d640729ed459acfba389063612008f490602401606060405180830381865af41580156115a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c491906156c3565b9250925092509193909250565b5f6115db816134a9565b610e9a8261358c565b5f6115ee816134a9565b610e9a8261360b565b5f73932a7755749879426925e7d977afa6baa64a34556372fcfbf86040518163ffffffff1660e01b8152600401602060405180830381865af415801561163f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116639190615624565b905090565b5f611663613559565b6040517f7aeabd990000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff821660048201525f90735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90637aeabd9990602401602060405180830381865af41580156116eb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8a91906156ee565b604080516060810182525f80825260208201819052918101829052611732613371565b61173a6133cf565b611742613428565b6040517fb99599b400000000000000000000000000000000000000000000000000000000815273ffc37455f53cbc0360ef3f3cccb6a967e1ae2a459063b99599b490611798908990899089908990600401615346565b608060405180830381865af41580156117b3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117d79190615748565b9150915061180460017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b94509492505050565b5f60608082808083817fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100805490915015801561184b57506001810154155b6118b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4549503731323a20556e696e697469616c697a656400000000000000000000006044820152606401610fc9565b6118b961367a565b6118c161374d565b604080515f808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009c939b5091995046985030975095509350915050565b6040517f874cf8e60000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8084166004830152821660248201525f90730de8af2200c88a51b1a53d640729ed459acfba389063874cf8e6906044016040805180830381865af4158015611988573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ac919061577a565b509392505050565b6119bc613371565b6119c46133cf565b6119cc613428565b73af13fa20fa5128b1ea37559d407285962a2b7ffe639d9f041b858585856119f2613559565b6040518663ffffffff1660e01b8152600401611a129594939291906157c1565b5f6040518083038186803b158015611a28575f80fd5b505af4158015611a3a573d5f803e3d5ffd5b505050506113de60017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b5f6116637feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff1690565b604080516060810182525f80825260208201819052918101829052611ac9613371565b611ad16133cf565b611ad9613428565b604080516101208101825233815273ffffffffffffffffffffffffffffffffffffffff8a811660208301528916818301526fffffffffffffffffffffffffffffffff808f1660608301528d811660808301528c1660a082015260c081018b905260e081018890527fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc97165467ffffffffffffffff1661010082015290517f49bc293a0000000000000000000000000000000000000000000000000000000081527fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc9700919073ffc37455f53cbc0360ef3f3cccb6a967e1ae2a45906349bc293a90611bea9084908b908b908b9060040161580f565b608060405180830381865af4158015611c05573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c29919061593b565b935093505050611c5860017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b9a509a98505050505050505050565b6040517f93dc7ca0000000000000000000000000000000000000000000000000000000008152600282900b60048201525f9073932a7755749879426925e7d977afa6baa64a3455906393dc7ca090602401602060405180830381865af4158015611cd3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8a9190615960565b611cff61379e565b5f611d09816134a9565b6040517f97366618000000000000000000000000000000000000000000000000000000008152730de8af2200c88a51b1a53d640729ed459acfba3890639736661890611d61908990899089908990899060040161597b565b5f6040518083038186803b158015611d77575f80fd5b505af4158015611d89573d5f803e3d5ffd5b50505050505f611db67f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60090565b60019055505050505050565b5f611dcb613371565b611dd36133cf565b611ddb613428565b6040517f5a5c2353000000000000000000000000000000000000000000000000000000008152735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90635a5c2353906114b8908c908c908c908c908c908c908c908c906004016159d6565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff167feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984008115801590611ebb57504265ffffffffffff831610155b611ec6575f80611eed565b600181015474010000000000000000000000000000000000000000900465ffffffffffff16825b92509250509091565b6040517fa63563cf0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8084166004830152821660248201525f90735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb9063a63563cf906044015b602060405180830381865af4158015611f79573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f9d91906156ee565b9392505050565b6040517fac61d46c0000000000000000000000000000000000000000000000000000000081525f9073932a7755749879426925e7d977afa6baa64a34559063ac61d46c90611ffa90879087908790600401615a45565b602060405180830381865af4158015612015573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c6991906156ee565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091526040517f750233330000000000000000000000000000000000000000000000000000000081525f9073af13fa20fa5128b1ea37559d407285962a2b7ffe906375023333906120b5908690600401615a8b565b60c060405180830381865af41580156120d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120f49190615aaf565b91509150915091565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f811580156121475750825b90505f8267ffffffffffffffff1660011480156121635750303b155b905081158015612171575080155b156121a8576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156122095784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b7fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc97006122345f336137f8565b61225c5f7f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b61226461380a565b6122d86040518060400160405280600c81526020017f5573646e50726f746f636f6c00000000000000000000000000000000000000008152506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525061381a565b6123227f112a81abbbc0a642a71c01ee707237745fdf9150a36cd6c341a77a82b042fcfe7fe066b764dbc472e706cbc2f8733ab0fcee541dd01136dc6512dca8f6dc61b69261382c565b61236c7f02f5b57e73f7374270c293a6c0f8f21b963fcb794517ca371178f1ebf3e0ea7d7fe7b4cf829186f8c4eae56184e8b39efd89f053da9890202c466f766239b5c06d61382c565b6123b67fa33d215b27d5ec861579769ea5343a0a14da1a34a49b09fa343facf13bf852ba7f668144e07fd661d09cc13a56f823a5cecc9ddd81fac15e0f66a794e2048f7eeb61382c565b6124007f2332b7708e4d211430c3d07e50a5483bc31f86f1a3c7c79e159a5bab63060e827f750ec48621e602bf6e87efd3f05aacefc0afaaf02ef76bf2316cd7d61322e13661382c565b61244a7f5fdbe07c81484705bc90cbf005feb2ecc66822288a5ac5d3cf89e384fa6fdd477f98de2855152060acaf991c6c67bcd523513322d493b38e46544cf92e3fee833461382c565b6124947f233d5d22cfc2df30a1764cac21e2207537a3711647f2c29fe3702201f65c14447f5afc0553d94a015add162f99e64d9f1e7954cb5168d8eb6c93ee26a783968d8a61382c565b6124de7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a7f365fccb66c62533ad1447fec73f7b764cf03ac69d512070f7c0aa889025cec1961382c565b6125287f427da25fe773164f88948d3e215c94b6554e2ed5e5f203a821c9f2f6131cf75a7fe7747964bba14b1d51bb4f84f826a6ba3ef37d424902280c5a01c99b837c970d61382c565b61253460016015615b72565b61253f90600a615cac565b61254b6015600a615cac565b6125559190615cba565b60088201556125666015600a615cac565b61257190600a615ccd565b6009820155710f3c00000000000000000000000000000384600a82015560c8600b820155600c810180547fffffffffffffff00000000000000000000000000000000000000000000000000166b0697800000c81f40032000011790556125d960026003615b72565b6125e490600a615cac565b6125ef90600c615ccd565b600d820155670de0b6b3a7640000600e8201556101f4600f820181905561025860108301819055601183019190915560128083019190915561015e60138301556101906014830155601582018054684c4b400064000400047fffffffffffffffffffffffffffffffffffffffffffff000000000000000000009091161790556016820180547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166706f05b59d3b200001790556126ae90600490615b72565b6126b990600a615cac565b6126c4906003615ccd565b81602101819055508d73ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612715573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061273991906156ee565b15612788576040517ff701733000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8f166004820152602401610fc9565b73ffffffffffffffffffffffffffffffffffffffff88166127d5576040517fbddceb9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8d816001015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508c816002015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550601260ff168e73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128cb9190615ce4565b60ff1614158061294e5750601260ff168d73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612924573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129489190615ce4565b60ff1614155b15612985576040517f1d6ebfbf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8d73ffffffffffffffffffffffffffffffffffffffff1663a79ebd606040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129ce573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129f291906156ee565b600382015580547fffffffffffffffffff0000000000000000000000000000000000000000ffffff16630100000073ffffffffffffffffffffffffffffffffffffffff8e16908102919091178255604080517f313ce56700000000000000000000000000000000000000000000000000000000815290515f929163313ce5679160048083019260209291908290030181865afa158015612a94573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ab89190615ce4565b82547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000060ff831690810291909117845590915060031115612b44576040517f1158dc9500000000000000000000000000000000000000000000000000000000815260ff82166004820152602401610fc9565b600482810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8f16908117909155604080517ff0141d8400000000000000000000000000000000000000000000000000000000815290515f9363f0141d84928082019260209290918290030181865afa158015612bdb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bff9190615ce4565b905080835f0160186101000a81548160ff021916908360ff1602179055508b836005015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508a835f015f6101000a81548162ffffff021916908360020b62ffffff1602179055508983601501600a6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600481612cd19190615b72565b612cdc90600a615cac565b612ce890612767615ccd565b6016840180546fffffffffffffffffffffffffffffffff9290921668010000000000000000027fffffffffffffffff00000000000000000000000000000000ffffffffffffffff909216919091179055612d43600382615b72565b612d4e90600a615cac565b612d5a906103f1615ccd565b6017840180547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff92909216919091179055612da882600a615cac565b612db3906002615ccd565b60188401555050602c0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88161790558315612e5c5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050505050565b6040517fb27ddda70000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8084166004830152821660248201525f90735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb9063b27ddda790604401611f5e565b5f612ee0613371565b612ee86133cf565b612ef0613428565b6040517f32080b1d00000000000000000000000000000000000000000000000000000000815273af13fa20fa5128b1ea37559d407285962a2b7ffe906332080b1d90612f429086908690600401615d04565b602060405180830381865af4158015612f5d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e2e91906156ee565b6040517fb8ef222a0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8084166004830152821660248201525f90730de8af2200c88a51b1a53d640729ed459acfba389063b8ef222a90604401611f5e565b5f612ff6613371565b612ffe6133cf565b613006613428565b6040517f07337984000000000000000000000000000000000000000000000000000000008152735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90630733798490611227908890889088908890600401615346565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401545f907feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400907a010000000000000000000000000000000000000000000000000000900465ffffffffffff1680158015906130de57504265ffffffffffff8216105b61310f5781547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16613135565b600182015474010000000000000000000000000000000000000000900465ffffffffffff165b9250505090565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005473ffffffffffffffffffffffffffffffffffffffff163381146131af576040517fc22c8022000000000000000000000000000000000000000000000000000000008152336004820152602401610fc9565b610d6061386d565b816131ee576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e9a828261399c565b5f613202816134a9565b610d606139df565b6040517f85aeba290000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8616600482015260248101859052604481018490528251606482015260208301516084820152600282900b60a48201525f9073932a7755749879426925e7d977afa6baa64a3455906385aeba299060c401602060405180830381865af41580156132ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132d19190615624565b9695505050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610b8a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610b8a565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16156133cd576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b7f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea6008054610d60576040517ff65383af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016134a3576040517fdb2b9f0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b610d6081336139e9565b6133cd5f80613a8f565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260409020600101546134f6816134a9565b6113de8383613c27565b73ffffffffffffffffffffffffffffffffffffffff8116331461354f576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b308282613d27565b5f611663613dca565b7f233d5d22cfc2df30a1764cac21e2207537a3711647f2c29fe3702201f65c1444610e9a816134a9565b5f61359561305c565b61359e42613e3d565b6135a89190615d25565b90506135b48282613e8c565b60405165ffffffffffff8216815273ffffffffffffffffffffffffffffffffffffffff8316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed69060200160405180910390a25050565b5f61361582613f46565b61361e42613e3d565b6136289190615d25565b90506136348282613a8f565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b910160405180910390a15050565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060917fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100916136cb90615d43565b80601f01602080910402602001604051908101604052809291908181526020018280546136f790615d43565b80156137425780601f1061371957610100808354040283529160200191613742565b820191905f5260205f20905b81548152906001019060200180831161372557829003601f168201915b505050505091505090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10380546060917fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100916136cb90615d43565b7f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea600805415610d60576040517f40553a1c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613800613f8d565b610e9a8282613ff4565b613812613f8d565b6133cd6140bd565b613822613f8d565b610e9a828261410e565b81613863576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e9a8282614180565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400805473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900465ffffffffffff168015806138dd57504265ffffffffffff821610155b1561391e576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff82166004820152602401610fc9565b6139655f6139607feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff1690565b613d27565b506139705f83613c27565b505081547fffffffffffff00000000000000000000000000000000000000000000000000001690915550565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260409020600101546139d5816134a9565b6113de8383613d27565b6133cd5f80613e8c565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610e9a576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610fc9565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401547feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400907a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015613ba1574265ffffffffffff82161015613b78576001820154825479ffffffffffffffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000090910465ffffffffffff167a01000000000000000000000000000000000000000000000000000002178255613ba1565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b50600101805473ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000065ffffffffffff9485160279ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009290931691909102919091179055565b5f7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840083613d1d575f613c8d7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614613cda576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85161790555b610c698484614221565b5f7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840083158015613d9057507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff8481169116145b15613dc0576001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b610c69848461433f565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f613df461441b565b613dfc614496565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b5f65ffffffffffff821115613e88576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526030600482015260248101839052604401610fc9565b5090565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840080547401000000000000000000000000000000000000000065ffffffffffff84811682027fffffffffffff0000000000000000000000000000000000000000000000000000841673ffffffffffffffffffffffffffffffffffffffff88161717845591041680156113de576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a150505050565b5f80613f5061305c565b90508065ffffffffffff168365ffffffffffff1611613f7857613f738382615d8e565b611f9d565b611f9d65ffffffffffff8416620697806144eb565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff166133cd576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613ffc613f8d565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840073ffffffffffffffffffffffffffffffffffffffff821661406c576040517fc22c80220000000000000000000000000000000000000000000000000000000081525f6004820152602401610fc9565b805479ffffffffffffffffffffffffffffffffffffffffffffffffffff167a01000000000000000000000000000000000000000000000000000065ffffffffffff8516021781556113de5f83613c27565b6140c5613f8d565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b614116613f8d565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1026141628482615df0565b50600381016141718382615df0565b505f8082556001909101555050565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268005f6141d9845f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b5f85815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff16614336575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556142d23390565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610b8a565b5f915050610b8a565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff1615614336575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610b8a565b5f7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1008161444661367a565b80519091501561445e57805160209091012092915050565b8154801561446d579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b5f7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100816144c161374d565b8051909150156144d957805160209091012092915050565b6001820154801561446d579392505050565b5f828218828410028218611f9d565b5f6020828403121561450a575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611f9d575f80fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610d60575f80fd5b803561456581614539565b919050565b5f8083601f84011261457a575f80fd5b50813567ffffffffffffffff811115614591575f80fd5b6020830191508360208285010111156145a8575f80fd5b9250929050565b5f604082840312156145bf575f80fd5b50919050565b5f805f80606085870312156145d8575f80fd5b84356145e381614539565b9350602085013567ffffffffffffffff8111156145fe575f80fd5b61460a8782880161456a565b909450925050604085013567ffffffffffffffff811115614629575f80fd5b614635878288016145af565b91505092959194509250565b60038110614676577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610b8a8284614641565b6fffffffffffffffffffffffffffffffff81168114610d60575f80fd5b803561456581614688565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614700576147006146b0565b60405290565b60405160a0810167ffffffffffffffff81118282101715614700576147006146b0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614770576147706146b0565b604052919050565b5f60408284031215614788575f80fd5b6040805190810167ffffffffffffffff811182821017156147ab576147ab6146b0565b604052823581526020928301359281019290925250919050565b8060020b8114610d60575f80fd5b62ffffff81168114610d60575f80fd5b5f805f805f8060e087890312156147f8575f80fd5b863561480381614688565b955060208701359450604087013593506148208860608901614778565b925060a0870135614830816147c5565b915060c0870135614840816147d3565b809150509295509295509295565b5f806020838503121561485f575f80fd5b823567ffffffffffffffff811115614875575f80fd5b6148818582860161456a565b90969095509350505050565b602080825282518282018190525f918401906040840190835b818110156149185783518051845260208101516020850152604081015160408501526fffffffffffffffffffffffffffffffff60608201511660608501526fffffffffffffffffffffffffffffffff60808201511660808501525060a0830192506020840193506001810190506148a6565b509095945050505050565b5f60208284031215614933575f80fd5b5035919050565b5f806040838503121561494b575f80fd5b82359150602083013561495d81614539565b809150509250929050565b5f606082840312156145bf575f80fd5b5f805f805f805f805f805f6101608c8e031215614993575f80fd5b61499d8d8d614968565b9a506149ab60608d016146a5565b995060808c013598506149c060a08d0161455a565b97506149ce60c08d0161455a565b965060e08c013595506101008c013567ffffffffffffffff8111156149f1575f80fd5b6149fd8e828f0161456a565b9096509450506101208c013567ffffffffffffffff811115614a1d575f80fd5b614a298e828f016145af565b9350506101408c013567ffffffffffffffff811115614a46575f80fd5b614a528e828f0161456a565b915080935050809150509295989b509295989b9093969950565b5f60208284031215614a7c575f80fd5b8135611f9d81614688565b5f805f60408486031215614a99575f80fd5b8335614aa481614539565b9250602084013567ffffffffffffffff811115614abf575f80fd5b614acb8682870161456a565b9497909650939450505050565b5f805f805f805f8060e0898b031215614aef575f80fd5b883572ffffffffffffffffffffffffffffffffffffff81168114614b11575f80fd5b975060208901359650614b2660408a0161455a565b9550614b3460608a0161455a565b94506080890135935060a089013567ffffffffffffffff811115614b56575f80fd5b614b628b828c0161456a565b90945092505060c089013567ffffffffffffffff811115614b81575f80fd5b614b8d8b828c016145af565b9150509295985092959890939650565b5f60208284031215614bad575f80fd5b8135611f9d81614539565b5f60208284031215614bc8575f80fd5b813565ffffffffffff81168114611f9d575f80fd5b60808101614beb8285614641565b611f9d6020830184805160020b825260208082015190830152604090810151910152565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e060208201525f614c9560e0830189614c0f565b8281036040840152614ca78189614c0f565b6060840188905273ffffffffffffffffffffffffffffffffffffffff8716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015614d09578351835260209384019390920191600101614ceb565b50909b9a5050505050505050505050565b5f8060408385031215614d2b575f80fd5b8235614d3681614688565b9150602083013561495d81614688565b5f805f8060a08587031215614d59575f80fd5b614d638686614968565b93506060850135614d7381614539565b9250608085013567ffffffffffffffff811115614d8e575f80fd5b614d9a8782880161456a565b95989497509550505050565b5f805f805f805f805f806101208b8d031215614dc0575f80fd5b8a35614dcb81614688565b9950614dd960208c016146a5565b9850614de760408c016146a5565b975060608b01359650614dfc60808c0161455a565b9550614e0a60a08c0161455a565b945060c08b0135935060e08b013567ffffffffffffffff811115614e2c575f80fd5b614e388d828e0161456a565b9094509250506101008b013567ffffffffffffffff811115614e58575f80fd5b614e648d828e016145af565b9150509295989b9194979a5092959850565b821515815260808101611f9d6020830184805160020b825260208082015190830152604090810151910152565b5f60208284031215614eb3575f80fd5b8135611f9d816147c5565b5f805f805f60808688031215614ed2575f80fd5b8535614edd81614688565b94506020860135614eed81614688565b93506040860135614efd81614688565b9250606086013567ffffffffffffffff811115614f18575f80fd5b614f248882890161456a565b969995985093965092949392505050565b5f805f805f805f8060e0898b031215614f4c575f80fd5b8835614f5781614688565b9750602089013596506040890135614f6e81614539565b95506060890135614b3481614539565b5f805f60a08486031215614f90575f80fd5b614f9a8585614968565b92506060840135614faa81614688565b91506080840135614fba81614688565b809150509250925092565b5f6060828403128015614fd6575f80fd5b50614fdf6146dd565b8235614fea816147c5565b8152602083810135908201526040928301359281019290925250919050565b5f805f805f805f80610100898b031215615021575f80fd5b883561502c81614539565b9750602089013561503c81614539565b9650604089013561504c81614539565b9550606089013561505c81614539565b9450608089013561506c81614539565b935060a089013561507c816147c5565b925060c089013561508c81614539565b915060e089013561509c81614539565b809150509295985092959890939650565b5f80604083850312156150be575f80fd5b823567ffffffffffffffff8111156150d4575f80fd5b6150e0858286016145af565b95602094909401359450505050565b5f805f805f60c08688031215615103575f80fd5b853561510e81614688565b9450602086013593506040860135925061512b8760608801614778565b915060a086013561513b816147c5565b809150509295509295909350565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126151c3575f80fd5b830160208101925035905067ffffffffffffffff8111156151e2575f80fd5b8060051b36038213156145a8575f80fd5b8183526020830192505f815f5b8481101561523a57813561521381614688565b6fffffffffffffffffffffffffffffffff1686526020958601959190910190600101615200565b5093949350505050565b5f604083016152538384615190565b604086528281845260608701905060608260051b8801019350825f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1853603015b84821015615320577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a880301845282358181126152d0575f80fd5b860160208101903567ffffffffffffffff8111156152ec575f80fd5b8036038213156152fa575f80fd5b615305898284615149565b98505050602083019250602084019350600182019150615294565b5050505050506153336020840184615190565b85830360208701526132d18382846151f3565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201525f615375606083018587615149565b82810360408401526153878185615244565b979650505050505050565b805160038110614565575f80fd5b5f602082840312156153b0575f80fd5b611f9d82615392565b5f80604083850312156153ca575f80fd5b82516153d5816147c5565b602084015190925061495d81614688565b602081525f610c69602083018486615149565b5f60208284031215615409575f80fd5b815167ffffffffffffffff81111561541f575f80fd5b8201601f8101841361542f575f80fd5b805167ffffffffffffffff811115615449576154496146b0565b61545860208260051b01614729565b80828252602082019150602060a08402850101925086831115615479575f80fd5b6020840193505b828410156132d15760a08488031215615497575f80fd5b61549f614706565b84518152602080860151908201526040808601519082015260608501516154c581614688565b606082015260808501516154d881614688565b6080820152825260a09390930192602090910190615480565b73ffffffffffffffffffffffffffffffffffffffff875116815273ffffffffffffffffffffffffffffffffffffffff6020880151166020820152604087015160408201525f606088015161555f6060840182805160020b825260208082015190830152604090810151910152565b506fffffffffffffffffffffffffffffffff60808901511660c083015260a088015160e083015260c08801516155a261010084018267ffffffffffffffff169052565b5060e08801516101208301526101a06101408301526155c66101a083018789615149565b8281036101608401526155d98187615244565b90508281036101808401526155ef818587615149565b9998505050505050505050565b80518015158114614565575f80fd5b5f6020828403121561561b575f80fd5b611f9d826155fc565b5f60208284031215615634575f80fd5b8151611f9d816147c5565b72ffffffffffffffffffffffffffffffffffffff8916815287602082015273ffffffffffffffffffffffffffffffffffffffff8716604082015273ffffffffffffffffffffffffffffffffffffffff8616606082015284608082015260e060a08201525f6156b160e083018587615149565b82810360c08401526111a98185615244565b5f805f606084860312156156d5575f80fd5b5050815160208301516040909301519094929350919050565b5f602082840312156156fe575f80fd5b5051919050565b5f60608284031215615715575f80fd5b61571d6146dd565b9050815161572a816147c5565b81526020828101519082015260409182015191810191909152919050565b5f8060808385031215615759575f80fd5b61576283615392565b91506157718460208501615705565b90509250929050565b5f806040838503121561578b575f80fd5b505080516020909101519092909150565b80356157a7816147c5565b60020b825260208181013590830152604090810135910152565b6157cb818761579c565b73ffffffffffffffffffffffffffffffffffffffff8516606082015260c060808201525f6157fd60c083018587615149565b90508260a08301529695505050505050565b73ffffffffffffffffffffffffffffffffffffffff855116815273ffffffffffffffffffffffffffffffffffffffff60208601511660208201525f6040860151615871604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606086015161589560608401826fffffffffffffffffffffffffffffffff169052565b5060808601516158b960808401826fffffffffffffffffffffffffffffffff169052565b5060a08601516158dd60a08401826fffffffffffffffffffffffffffffffff169052565b5060c086015160c083015260e086015160e083015261010086015161590f61010084018267ffffffffffffffff169052565b5061016061012083015261592861016083018587615149565b8281036101408401526153878185615244565b5f806080838503121561594c575f80fd5b615762836155fc565b8051614565816147d3565b5f60208284031215615970575f80fd5b8151611f9d816147d3565b6fffffffffffffffffffffffffffffffff861681526fffffffffffffffffffffffffffffffff851660208201526fffffffffffffffffffffffffffffffff84166040820152608060608201525f615387608083018486615149565b6fffffffffffffffffffffffffffffffff8916815287602082015273ffffffffffffffffffffffffffffffffffffffff8716604082015273ffffffffffffffffffffffffffffffffffffffff8616606082015284608082015260e060a08201525f6156b160e083018587615149565b60a08101615a53828661579c565b6fffffffffffffffffffffffffffffffff841660608301526fffffffffffffffffffffffffffffffff83166080830152949350505050565b815160020b8152602080830151908201526040808301519082015260608101610b8a565b5f8082840360c0811215615ac1575f80fd5b60a0811215615ace575f80fd5b50615ad7614706565b615ae0846155fc565b8152602084015164ffffffffff81168114615af9575f80fd5b60208201526040840151615b0c81614539565b60408201526060840151615b1f81614688565b60608201526080840151615b3281614688565b6080820152915061577160a08401615955565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60ff8281168282160390811115610b8a57610b8a615b45565b6001815b6001841115615bc657808504811115615baa57615baa615b45565b6001841615615bb857908102905b60019390931c928002615b8f565b935093915050565b5f82615bdc57506001610b8a565b81615be857505f610b8a565b8160018114615bfe5760028114615c0857615c24565b6001915050610b8a565b60ff841115615c1957615c19615b45565b50506001821b610b8a565b5060208310610133831016604e8410600b8410161715615c47575081810a610b8a565b615c727fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615b8b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615ca457615ca4615b45565b029392505050565b5f611f9d60ff841683615bce565b80820180821115610b8a57610b8a615b45565b8082028115828204841417610b8a57610b8a615b45565b5f60208284031215615cf4575f80fd5b815160ff81168114611f9d575f80fd5b604081525f615d166040830185615244565b90508260208301529392505050565b65ffffffffffff8181168382160190811115610b8a57610b8a615b45565b600181811c90821680615d5757607f821691505b6020821081036145bf577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b65ffffffffffff8281168282160390811115610b8a57610b8a615b45565b601f821115610b3057805f5260205f20601f840160051c81016020851015615dd15750805b601f840160051c820191505b818110156113dc575f8155600101615ddd565b815167ffffffffffffffff811115615e0a57615e0a6146b0565b615e1e81615e188454615d43565b84615dac565b6020601f821160018114615e6f575f8315615e395750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b1784556113dc565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015615ebc5787850151825560209485019460019092019101615e9c565b5084821015615ef857868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b0190555056fea264697066735822122066500720988b482d6ff3bf7805c917efa07a29fa871bd437fd810a50170bb68364736f6c634300081a0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{"src/UsdnProtocol/libraries/UsdnProtocolActionsLongLibrary.sol:UsdnProtocolActionsLongLibrary":"0xffc37455f53cbc0360ef3f3cccb6a967e1ae2a45","src/UsdnProtocol/libraries/UsdnProtocolActionsUtilsLibrary.sol:UsdnProtocolActionsUtilsLibrary":"0xaf13fa20fa5128b1ea37559d407285962a2b7ffe","src/UsdnProtocol/libraries/UsdnProtocolCoreLibrary.sol:UsdnProtocolCoreLibrary":"0x0de8af2200c88a51b1a53d640729ed459acfba38","src/UsdnProtocol/libraries/UsdnProtocolLongLibrary.sol:UsdnProtocolLongLibrary":"0x932a7755749879426925e7d977afa6baa64a3455","src/UsdnProtocol/libraries/UsdnProtocolVaultLibrary.sol:UsdnProtocolVaultLibrary":"0x5a3b25f3de702ff2209ef4c11e80bd97bb6d53eb"},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":20000},"remappings":[":@chainlink-1.2.0/=dependencies/@chainlink-1.2.0/",":@chainlink/=dependencies/@chainlink-1.2.0/",":@openzeppelin-contracts-5.1.0/=dependencies/@openzeppelin-contracts-5.1.0/",":@openzeppelin-contracts-upgradeable-5.1.0/=dependencies/@openzeppelin-contracts-upgradeable-5.1.0/",":@openzeppelin/contracts-upgradeable/=dependencies/@openzeppelin-contracts-upgradeable-5.1.0/",":@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.1.0/",":@pythnetwork-pyth-sdk-solidity-3.1.0/=dependencies/@pythnetwork-pyth-sdk-solidity-3.1.0/",":@pythnetwork/pyth-sdk-solidity/=dependencies/@pythnetwork-pyth-sdk-solidity-3.1.0/",":@redstone-finance-evm-connector-0.6.2/=dependencies/@redstone-finance-evm-connector-0.6.2/contracts/",":@redstone-finance/evm-connector/=dependencies/@redstone-finance-evm-connector-0.6.2/",":@smardex-solidity-libraries-1.0.1/=dependencies/@smardex-solidity-libraries-1.0.1/src/",":@smardex-solidity-libraries-1/=dependencies/@smardex-solidity-libraries-1.0.1/src/",":@uniswap-permit2-1.0.0/=dependencies/@uniswap-permit2-1.0.0/src/",":@uniswap/permit2/=dependencies/@uniswap-permit2-1.0.0/",":ds-test/=dependencies/openzeppelin-foundry-upgrades-0.3.6/lib/solidity-stringutils/lib/ds-test/src/",":forge-std-1.9.4/=dependencies/forge-std-1.9.4/src/",":forge-std-1/=dependencies/@smardex-solidity-libraries-1.0.1/dependencies/forge-std-1.9.4/src/",":forge-std/=dependencies/forge-std-1.9.4/src/",":openzeppelin-foundry-upgrades-0.3.6/=dependencies/openzeppelin-foundry-upgrades-0.3.6/src/",":openzeppelin-foundry-upgrades/=dependencies/openzeppelin-foundry-upgrades-0.3.6/src/",":solady-0.0.228/=dependencies/solady-0.0.228/src/",":solady/src/=dependencies/solady-0.0.228/src/",":solidity-stringutils/=dependencies/openzeppelin-foundry-upgrades-0.3.6/lib/solidity-stringutils/",":solmate/=dependencies/@uniswap-permit2-1.0.0/lib/solmate/"]},"optimization_runs":20000,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/partial_match/1/0x271df5517a4DaacB7caB988Aa64D23dEbda4c498/","decoded_constructor_args":null,"compiler_version":"0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2025-01-23T20:03:15.867466Z","implementations":[],"proxy_type":null,"external_libraries":[{"name":"src/UsdnProtocol/libraries/UsdnProtocolActionsLongLibrary.sol:UsdnProtocolActionsLongLibrary","address_hash":"0xffc37455f53CBC0360eF3F3ccCB6a967e1AE2a45"},{"name":"src/UsdnProtocol/libraries/UsdnProtocolActionsUtilsLibrary.sol:UsdnProtocolActionsUtilsLibrary","address_hash":"0xAF13Fa20fA5128B1EA37559D407285962A2B7FfE"},{"name":"src/UsdnProtocol/libraries/UsdnProtocolCoreLibrary.sol:UsdnProtocolCoreLibrary","address_hash":"0x0dE8aF2200C88a51B1A53D640729ED459AcFbA38"},{"name":"src/UsdnProtocol/libraries/UsdnProtocolLongLibrary.sol:UsdnProtocolLongLibrary","address_hash":"0x932A7755749879426925E7D977afa6bAA64a3455"},{"name":"src/UsdnProtocol/libraries/UsdnProtocolVaultLibrary.sol:UsdnProtocolVaultLibrary","address_hash":"0x5a3B25F3de702fF2209ef4c11E80bD97bb6D53eB"}],"creation_bytecode":"0x60a060405230608052348015610013575f80fd5b5061001c610021565b6100d3565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100715760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100d05780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051615f3d6100f25f395f818161130601526113e70152615f3d5ff3fe60806040526004361061031d575f3560e01c806384ef8ffc116101a4578063ab493b1e116100eb578063ba08c8eb11610094578063cf6eefb71161006e578063cf6eefb714610a49578063d547741f14610ac0578063d602b9fd14610adf578063dded0c4e14610af35761031d565b8063ba08c8eb14610a0e578063cc8463c814610a21578063cefc142914610a355761031d565b8063b27ddda7116100c5578063b27ddda7146109bd578063b3042999146109dc578063b8ef222a146109ef5761031d565b8063ab493b1e146108cf578063acea51be146108ee578063ae1043441461099e5761031d565b806393dc7ca01161014d578063a1eda53c11610127578063a1eda53c1461086a578063a217fddf1461089d578063a63563cf146108b05761031d565b806393dc7ca01461081157806397366618146108445780639d3960db146108575761031d565b80638da5cb5b1161017e5780638da5cb5b1461076c57806391d148541461078057806392d2e41f146107f05761031d565b806384ef8ffc146106c4578063874cf8e61461072e578063895e22761461074d5761031d565b80634f1ef28611610268578063649a5ec7116102115780637aeabd99116101eb5780637aeabd991461065d578063806b48731461067c57806384b0196e1461069d5761031d565b8063649a5ec71461061657806372fcfbf81461063557806378e890ba146106495761031d565b80635c975abb116102425780635c975abb14610587578063612008f4146105bd578063634e93da146105f75761031d565b80634f1ef2861461054d57806352d1902d1461056057806358dd74b3146105745761031d565b8063248a9ca3116102ca578063422f289f116102a4578063422f289f146104f557806342ff0e59146105085780634c1877651461051b5761031d565b8063248a9ca31461045c5780632f2ff15d146104b757806336568abe146104d65761031d565b806308256b29116102fb57806308256b29146103e85780630aa6220b146104285780631721539b1461043c5761031d565b806301ffc9a71461036c578063022d63fb146103a05780630239040b146103c8575b348015610328575f80fd5b507fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc972c5461036a9073ffffffffffffffffffffffffffffffffffffffff16610b12565b005b348015610377575f80fd5b5061038b6103863660046144fa565b610b35565b60405190151581526020015b60405180910390f35b3480156103ab575f80fd5b50620697805b60405165ffffffffffff9091168152602001610397565b6103db6103d63660046145c5565b610b90565b604051610397919061467a565b3480156103f3575f80fd5b506104076104023660046147e3565b610c71565b6040516fffffffffffffffffffffffffffffffff9091168152602001610397565b348015610433575f80fd5b5061036a610d4e565b61044f61044a36600461484e565b610d63565b604051610397919061488d565b348015610467575f80fd5b506104a9610476366004614923565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b604051908152602001610397565b3480156104c2575f80fd5b5061036a6104d136600461493a565b610e59565b3480156104e1575f80fd5b5061036a6104f036600461493a565b610e9e565b6103db610503366004614978565b611005565b61038b6105163660046145c5565b6111b8565b348015610526575f80fd5b5061053a610535366004614a6c565b611266565b60405160029190910b8152602001610397565b61036a61055b366004614a87565b611304565b34801561056b575f80fd5b506104a96113e4565b61038b610582366004614ad8565b611441565b348015610592575f80fd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1661038b565b3480156105c8575f80fd5b506105dc6105d7366004614a6c565b611522565b60408051938452602084019290925290820152606001610397565b348015610602575f80fd5b5061036a610611366004614b9d565b6115d1565b348015610621575f80fd5b5061036a610630366004614bb8565b6115e4565b348015610640575f80fd5b5061053a6115f7565b348015610654575f80fd5b506104a9611668565b348015610668575f80fd5b506104a9610677366004614a6c565b611671565b61068f61068a3660046145c5565b61170f565b604051610397929190614bdd565b3480156106a8575f80fd5b506106b161180d565b6040516103979796959493929190614c5b565b3480156106cf575f80fd5b507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610397565b348015610739575f80fd5b506104a9610748366004614d1a565b611907565b348015610758575f80fd5b5061036a610767366004614d46565b6119b4565b348015610777575f80fd5b50610709611a67565b34801561078b575f80fd5b5061038b61079a36600461493a565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6108036107fe366004614da6565b611aa6565b604051610397929190614e76565b34801561081c575f80fd5b5061083061082b366004614ea3565b611c67565b60405162ffffff9091168152602001610397565b61036a610852366004614ebe565b611cf7565b61038b610865366004614f35565b611dc2565b348015610875575f80fd5b5061087e611e39565b6040805165ffffffffffff938416815292909116602083015201610397565b3480156108a8575f80fd5b506104a95f81565b3480156108bb575f80fd5b506104a96108ca366004614d1a565b611ef6565b3480156108da575f80fd5b506104a96108e9366004614f7e565b611fa4565b3480156108f9575f80fd5b5061090d610908366004614fc5565b612039565b6040516103979291905f60c08201905083511515825264ffffffffff602085015116602083015273ffffffffffffffffffffffffffffffffffffffff60408501511660408301526fffffffffffffffffffffffffffffffff60608501511660608301526fffffffffffffffffffffffffffffffff608085015116608083015262ffffff831660a08301529392505050565b3480156109a9575f80fd5b5061036a6109b8366004615009565b6120fd565b3480156109c8575f80fd5b506104a96109d7366004614d1a565b612e6b565b6104a96109ea3660046150ad565b612ed7565b3480156109fa575f80fd5b506104a9610a09366004614d1a565b612f81565b61038b610a1c3660046145c5565b612fed565b348015610a2c575f80fd5b506103b161305c565b348015610a40575f80fd5b5061036a61313c565b348015610a54575f80fd5b507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400546040805173ffffffffffffffffffffffffffffffffffffffff831681527401000000000000000000000000000000000000000090920465ffffffffffff16602083015201610397565b348015610acb575f80fd5b5061036a610ada36600461493a565b6131b7565b348015610aea575f80fd5b5061036a6131f8565b348015610afe575f80fd5b5061053a610b0d3660046150ef565b61320a565b365f80375f80365f845af43d5f803e808015610b2c573d5ff35b3d5ffd5b505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f31498786000000000000000000000000000000000000000000000000000000001480610b8a5750610b8a826132db565b92915050565b5f610b99613371565b610ba16133cf565b610ba9613428565b6040517fd37c8d8000000000000000000000000000000000000000000000000000000000815273ffc37455f53cbc0360ef3f3cccb6a967e1ae2a459063d37c8d8090610bff908890889088908890600401615346565b602060405180830381865af4158015610c1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c3e91906153a0565b9050610c6960017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b949350505050565b6040517f16f7fcff0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8716600482015260248101869052604481018590528351606482015260208401516084820152600283900b60a482015262ffffff821660c48201525f9073932a7755749879426925e7d977afa6baa64a3455906316f7fcff9060e4016040805180830381865af4158015610d1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d4291906153b9565b98975050505050505050565b5f610d58816134a9565b610d606134b3565b50565b6060610d6d613371565b610d756133cf565b610d7d613428565b6040517f1721539b00000000000000000000000000000000000000000000000000000000815273af13fa20fa5128b1ea37559d407285962a2b7ffe90631721539b90610dcf90869086906004016153e6565b5f60405180830381865af4158015610de9573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610e2e91908101906153f9565b9050610b8a60017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b81610e90576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e9a82826134bd565b5050565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840082158015610f0657507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff8381169116145b15610ffb577feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900465ffffffffffff1681151580610f79575065ffffffffffff8116155b80610f8c57504265ffffffffffff821610155b15610fd2576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff821660048201526024015b60405180910390fd5b505080547fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff1681555b610b308383613500565b5f61100e613371565b6110166133cf565b61101e613428565b5f7fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc970090505f6040518061010001604052808c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018f80360381019061109e9190614fc5565b81526fffffffffffffffffffffffffffffffff8f166020820152604081018e9052601684015467ffffffffffffffff1660608201526080016110de613559565b90526040517f52bbc6fd00000000000000000000000000000000000000000000000000000000815290915073ffc37455f53cbc0360ef3f3cccb6a967e1ae2a45906352bbc6fd9061113d9084908c908c908c908c908c906004016154f1565b602060405180830381865af4158015611158573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061117c91906153a0565b925050506111a960017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b9b9a5050505050505050505050565b5f6111c1613371565b6111c96133cf565b6111d1613428565b6040517f1a5c8297000000000000000000000000000000000000000000000000000000008152735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90631a5c829790611227908890889088908890600401615346565b602060405180830381865af4158015611242573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c3e919061560b565b6040517f4c1877650000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff821660048201525f9073932a7755749879426925e7d977afa6baa64a345590634c18776590602401602060405180830381865af41580156112e0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8a9190615624565b7f000000000000000000000000000000000000000000000000000000000000000030810361133957639f03a0265f526004601cfd5b61134284613562565b8360601b60601c93506352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80602060016004601d895afa5114611394576355299b496001526004601dfd5b847fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f38a284905581156113de57604051828482375f388483885af46113dc573d5f823e3d81fd5b505b50505050565b5f7f000000000000000000000000000000000000000000000000000000000000000030811461141a57639f03a0265f526004601cfd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91505090565b5f61144a613371565b6114526133cf565b61145a613428565b6040517f8aaebb6b000000000000000000000000000000000000000000000000000000008152735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90638aaebb6b906114b8908c908c908c908c908c908c908c908c9060040161563f565b602060405180830381865af41580156114d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114f7919061560b565b9050610d4260017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b6040517f612008f40000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff821660048201525f9081908190730de8af2200c88a51b1a53d640729ed459acfba389063612008f490602401606060405180830381865af41580156115a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c491906156c3565b9250925092509193909250565b5f6115db816134a9565b610e9a8261358c565b5f6115ee816134a9565b610e9a8261360b565b5f73932a7755749879426925e7d977afa6baa64a34556372fcfbf86040518163ffffffff1660e01b8152600401602060405180830381865af415801561163f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116639190615624565b905090565b5f611663613559565b6040517f7aeabd990000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff821660048201525f90735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90637aeabd9990602401602060405180830381865af41580156116eb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8a91906156ee565b604080516060810182525f80825260208201819052918101829052611732613371565b61173a6133cf565b611742613428565b6040517fb99599b400000000000000000000000000000000000000000000000000000000815273ffc37455f53cbc0360ef3f3cccb6a967e1ae2a459063b99599b490611798908990899089908990600401615346565b608060405180830381865af41580156117b3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117d79190615748565b9150915061180460017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b94509492505050565b5f60608082808083817fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100805490915015801561184b57506001810154155b6118b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4549503731323a20556e696e697469616c697a656400000000000000000000006044820152606401610fc9565b6118b961367a565b6118c161374d565b604080515f808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009c939b5091995046985030975095509350915050565b6040517f874cf8e60000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8084166004830152821660248201525f90730de8af2200c88a51b1a53d640729ed459acfba389063874cf8e6906044016040805180830381865af4158015611988573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ac919061577a565b509392505050565b6119bc613371565b6119c46133cf565b6119cc613428565b73af13fa20fa5128b1ea37559d407285962a2b7ffe639d9f041b858585856119f2613559565b6040518663ffffffff1660e01b8152600401611a129594939291906157c1565b5f6040518083038186803b158015611a28575f80fd5b505af4158015611a3a573d5f803e3d5ffd5b505050506113de60017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b5f6116637feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff1690565b604080516060810182525f80825260208201819052918101829052611ac9613371565b611ad16133cf565b611ad9613428565b604080516101208101825233815273ffffffffffffffffffffffffffffffffffffffff8a811660208301528916818301526fffffffffffffffffffffffffffffffff808f1660608301528d811660808301528c1660a082015260c081018b905260e081018890527fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc97165467ffffffffffffffff1661010082015290517f49bc293a0000000000000000000000000000000000000000000000000000000081527fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc9700919073ffc37455f53cbc0360ef3f3cccb6a967e1ae2a45906349bc293a90611bea9084908b908b908b9060040161580f565b608060405180830381865af4158015611c05573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c29919061593b565b935093505050611c5860017f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b9a509a98505050505050505050565b6040517f93dc7ca0000000000000000000000000000000000000000000000000000000008152600282900b60048201525f9073932a7755749879426925e7d977afa6baa64a3455906393dc7ca090602401602060405180830381865af4158015611cd3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8a9190615960565b611cff61379e565b5f611d09816134a9565b6040517f97366618000000000000000000000000000000000000000000000000000000008152730de8af2200c88a51b1a53d640729ed459acfba3890639736661890611d61908990899089908990899060040161597b565b5f6040518083038186803b158015611d77575f80fd5b505af4158015611d89573d5f803e3d5ffd5b50505050505f611db67f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60090565b60019055505050505050565b5f611dcb613371565b611dd36133cf565b611ddb613428565b6040517f5a5c2353000000000000000000000000000000000000000000000000000000008152735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90635a5c2353906114b8908c908c908c908c908c908c908c908c906004016159d6565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff167feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984008115801590611ebb57504265ffffffffffff831610155b611ec6575f80611eed565b600181015474010000000000000000000000000000000000000000900465ffffffffffff16825b92509250509091565b6040517fa63563cf0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8084166004830152821660248201525f90735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb9063a63563cf906044015b602060405180830381865af4158015611f79573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f9d91906156ee565b9392505050565b6040517fac61d46c0000000000000000000000000000000000000000000000000000000081525f9073932a7755749879426925e7d977afa6baa64a34559063ac61d46c90611ffa90879087908790600401615a45565b602060405180830381865af4158015612015573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c6991906156ee565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091526040517f750233330000000000000000000000000000000000000000000000000000000081525f9073af13fa20fa5128b1ea37559d407285962a2b7ffe906375023333906120b5908690600401615a8b565b60c060405180830381865af41580156120d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120f49190615aaf565b91509150915091565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f811580156121475750825b90505f8267ffffffffffffffff1660011480156121635750303b155b905081158015612171575080155b156121a8576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156122095784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b7fd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc97006122345f336137f8565b61225c5f7f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60055565b61226461380a565b6122d86040518060400160405280600c81526020017f5573646e50726f746f636f6c00000000000000000000000000000000000000008152506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525061381a565b6123227f112a81abbbc0a642a71c01ee707237745fdf9150a36cd6c341a77a82b042fcfe7fe066b764dbc472e706cbc2f8733ab0fcee541dd01136dc6512dca8f6dc61b69261382c565b61236c7f02f5b57e73f7374270c293a6c0f8f21b963fcb794517ca371178f1ebf3e0ea7d7fe7b4cf829186f8c4eae56184e8b39efd89f053da9890202c466f766239b5c06d61382c565b6123b67fa33d215b27d5ec861579769ea5343a0a14da1a34a49b09fa343facf13bf852ba7f668144e07fd661d09cc13a56f823a5cecc9ddd81fac15e0f66a794e2048f7eeb61382c565b6124007f2332b7708e4d211430c3d07e50a5483bc31f86f1a3c7c79e159a5bab63060e827f750ec48621e602bf6e87efd3f05aacefc0afaaf02ef76bf2316cd7d61322e13661382c565b61244a7f5fdbe07c81484705bc90cbf005feb2ecc66822288a5ac5d3cf89e384fa6fdd477f98de2855152060acaf991c6c67bcd523513322d493b38e46544cf92e3fee833461382c565b6124947f233d5d22cfc2df30a1764cac21e2207537a3711647f2c29fe3702201f65c14447f5afc0553d94a015add162f99e64d9f1e7954cb5168d8eb6c93ee26a783968d8a61382c565b6124de7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a7f365fccb66c62533ad1447fec73f7b764cf03ac69d512070f7c0aa889025cec1961382c565b6125287f427da25fe773164f88948d3e215c94b6554e2ed5e5f203a821c9f2f6131cf75a7fe7747964bba14b1d51bb4f84f826a6ba3ef37d424902280c5a01c99b837c970d61382c565b61253460016015615b72565b61253f90600a615cac565b61254b6015600a615cac565b6125559190615cba565b60088201556125666015600a615cac565b61257190600a615ccd565b6009820155710f3c00000000000000000000000000000384600a82015560c8600b820155600c810180547fffffffffffffff00000000000000000000000000000000000000000000000000166b0697800000c81f40032000011790556125d960026003615b72565b6125e490600a615cac565b6125ef90600c615ccd565b600d820155670de0b6b3a7640000600e8201556101f4600f820181905561025860108301819055601183019190915560128083019190915561015e60138301556101906014830155601582018054684c4b400064000400047fffffffffffffffffffffffffffffffffffffffffffff000000000000000000009091161790556016820180547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166706f05b59d3b200001790556126ae90600490615b72565b6126b990600a615cac565b6126c4906003615ccd565b81602101819055508d73ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612715573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061273991906156ee565b15612788576040517ff701733000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8f166004820152602401610fc9565b73ffffffffffffffffffffffffffffffffffffffff88166127d5576040517fbddceb9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8d816001015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508c816002015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550601260ff168e73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128cb9190615ce4565b60ff1614158061294e5750601260ff168d73ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612924573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129489190615ce4565b60ff1614155b15612985576040517f1d6ebfbf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8d73ffffffffffffffffffffffffffffffffffffffff1663a79ebd606040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129ce573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129f291906156ee565b600382015580547fffffffffffffffffff0000000000000000000000000000000000000000ffffff16630100000073ffffffffffffffffffffffffffffffffffffffff8e16908102919091178255604080517f313ce56700000000000000000000000000000000000000000000000000000000815290515f929163313ce5679160048083019260209291908290030181865afa158015612a94573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ab89190615ce4565b82547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000060ff831690810291909117845590915060031115612b44576040517f1158dc9500000000000000000000000000000000000000000000000000000000815260ff82166004820152602401610fc9565b600482810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8f16908117909155604080517ff0141d8400000000000000000000000000000000000000000000000000000000815290515f9363f0141d84928082019260209290918290030181865afa158015612bdb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bff9190615ce4565b905080835f0160186101000a81548160ff021916908360ff1602179055508b836005015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508a835f015f6101000a81548162ffffff021916908360020b62ffffff1602179055508983601501600a6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600481612cd19190615b72565b612cdc90600a615cac565b612ce890612767615ccd565b6016840180546fffffffffffffffffffffffffffffffff9290921668010000000000000000027fffffffffffffffff00000000000000000000000000000000ffffffffffffffff909216919091179055612d43600382615b72565b612d4e90600a615cac565b612d5a906103f1615ccd565b6017840180547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff92909216919091179055612da882600a615cac565b612db3906002615ccd565b60188401555050602c0180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88161790558315612e5c5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050505050565b6040517fb27ddda70000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8084166004830152821660248201525f90735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb9063b27ddda790604401611f5e565b5f612ee0613371565b612ee86133cf565b612ef0613428565b6040517f32080b1d00000000000000000000000000000000000000000000000000000000815273af13fa20fa5128b1ea37559d407285962a2b7ffe906332080b1d90612f429086908690600401615d04565b602060405180830381865af4158015612f5d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e2e91906156ee565b6040517fb8ef222a0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8084166004830152821660248201525f90730de8af2200c88a51b1a53d640729ed459acfba389063b8ef222a90604401611f5e565b5f612ff6613371565b612ffe6133cf565b613006613428565b6040517f07337984000000000000000000000000000000000000000000000000000000008152735a3b25f3de702ff2209ef4c11e80bd97bb6d53eb90630733798490611227908890889088908890600401615346565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401545f907feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400907a010000000000000000000000000000000000000000000000000000900465ffffffffffff1680158015906130de57504265ffffffffffff8216105b61310f5781547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16613135565b600182015474010000000000000000000000000000000000000000900465ffffffffffff165b9250505090565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984005473ffffffffffffffffffffffffffffffffffffffff163381146131af576040517fc22c8022000000000000000000000000000000000000000000000000000000008152336004820152602401610fc9565b610d6061386d565b816131ee576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e9a828261399c565b5f613202816134a9565b610d606139df565b6040517f85aeba290000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff8616600482015260248101859052604481018490528251606482015260208301516084820152600282900b60a48201525f9073932a7755749879426925e7d977afa6baa64a3455906385aeba299060c401602060405180830381865af41580156132ad573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132d19190615624565b9695505050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610b8a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610b8a565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16156133cd576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b7f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea6008054610d60576040517ff65383af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea60080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016134a3576040517fdb2b9f0600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b610d6081336139e9565b6133cd5f80613a8f565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260409020600101546134f6816134a9565b6113de8383613c27565b73ffffffffffffffffffffffffffffffffffffffff8116331461354f576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b308282613d27565b5f611663613dca565b7f233d5d22cfc2df30a1764cac21e2207537a3711647f2c29fe3702201f65c1444610e9a816134a9565b5f61359561305c565b61359e42613e3d565b6135a89190615d25565b90506135b48282613e8c565b60405165ffffffffffff8216815273ffffffffffffffffffffffffffffffffffffffff8316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed69060200160405180910390a25050565b5f61361582613f46565b61361e42613e3d565b6136289190615d25565b90506136348282613a8f565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b910160405180910390a15050565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10280546060917fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100916136cb90615d43565b80601f01602080910402602001604051908101604052809291908181526020018280546136f790615d43565b80156137425780601f1061371957610100808354040283529160200191613742565b820191905f5260205f20905b81548152906001019060200180831161372557829003601f168201915b505050505091505090565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d10380546060917fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100916136cb90615d43565b7f6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea600805415610d60576040517f40553a1c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613800613f8d565b610e9a8282613ff4565b613812613f8d565b6133cd6140bd565b613822613f8d565b610e9a828261410e565b81613863576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e9a8282614180565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400805473ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900465ffffffffffff168015806138dd57504265ffffffffffff821610155b1561391e576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff82166004820152602401610fc9565b6139655f6139607feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff1690565b613d27565b506139705f83613c27565b505081547fffffffffffff00000000000000000000000000000000000000000000000000001690915550565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260409020600101546139d5816134a9565b6113de8383613d27565b6133cd5f80613e8c565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610e9a576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610fc9565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698401547feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400907a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015613ba1574265ffffffffffff82161015613b78576001820154825479ffffffffffffffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000090910465ffffffffffff167a01000000000000000000000000000000000000000000000000000002178255613ba1565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b50600101805473ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000065ffffffffffff9485160279ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009290931691909102919091179055565b5f7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840083613d1d575f613c8d7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614613cda576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85161790555b610c698484614221565b5f7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840083158015613d9057507feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d86984015473ffffffffffffffffffffffffffffffffffffffff8481169116145b15613dc0576001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b610c69848461433f565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f613df461441b565b613dfc614496565b60408051602081019490945283019190915260608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b5f65ffffffffffff821115613e88576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526030600482015260248101839052604401610fc9565b5090565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840080547401000000000000000000000000000000000000000065ffffffffffff84811682027fffffffffffff0000000000000000000000000000000000000000000000000000841673ffffffffffffffffffffffffffffffffffffffff88161717845591041680156113de576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a150505050565b5f80613f5061305c565b90508065ffffffffffff168365ffffffffffff1611613f7857613f738382615d8e565b611f9d565b611f9d65ffffffffffff8416620697806144eb565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff166133cd576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613ffc613f8d565b7feef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d869840073ffffffffffffffffffffffffffffffffffffffff821661406c576040517fc22c80220000000000000000000000000000000000000000000000000000000081525f6004820152602401610fc9565b805479ffffffffffffffffffffffffffffffffffffffffffffffffffff167a01000000000000000000000000000000000000000000000000000065ffffffffffff8516021781556113de5f83613c27565b6140c5613f8d565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b614116613f8d565b7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1007fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1026141628482615df0565b50600381016141718382615df0565b505f8082556001909101555050565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268005f6141d9845f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b5f85815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff16614336575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556142d23390565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610b8a565b5f915050610b8a565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff1615614336575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610b8a565b5f7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d1008161444661367a565b80519091501561445e57805160209091012092915050565b8154801561446d579392505050565b7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470935050505090565b5f7fa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100816144c161374d565b8051909150156144d957805160209091012092915050565b6001820154801561446d579392505050565b5f828218828410028218611f9d565b5f6020828403121561450a575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611f9d575f80fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610d60575f80fd5b803561456581614539565b919050565b5f8083601f84011261457a575f80fd5b50813567ffffffffffffffff811115614591575f80fd5b6020830191508360208285010111156145a8575f80fd5b9250929050565b5f604082840312156145bf575f80fd5b50919050565b5f805f80606085870312156145d8575f80fd5b84356145e381614539565b9350602085013567ffffffffffffffff8111156145fe575f80fd5b61460a8782880161456a565b909450925050604085013567ffffffffffffffff811115614629575f80fd5b614635878288016145af565b91505092959194509250565b60038110614676577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610b8a8284614641565b6fffffffffffffffffffffffffffffffff81168114610d60575f80fd5b803561456581614688565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614700576147006146b0565b60405290565b60405160a0810167ffffffffffffffff81118282101715614700576147006146b0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614770576147706146b0565b604052919050565b5f60408284031215614788575f80fd5b6040805190810167ffffffffffffffff811182821017156147ab576147ab6146b0565b604052823581526020928301359281019290925250919050565b8060020b8114610d60575f80fd5b62ffffff81168114610d60575f80fd5b5f805f805f8060e087890312156147f8575f80fd5b863561480381614688565b955060208701359450604087013593506148208860608901614778565b925060a0870135614830816147c5565b915060c0870135614840816147d3565b809150509295509295509295565b5f806020838503121561485f575f80fd5b823567ffffffffffffffff811115614875575f80fd5b6148818582860161456a565b90969095509350505050565b602080825282518282018190525f918401906040840190835b818110156149185783518051845260208101516020850152604081015160408501526fffffffffffffffffffffffffffffffff60608201511660608501526fffffffffffffffffffffffffffffffff60808201511660808501525060a0830192506020840193506001810190506148a6565b509095945050505050565b5f60208284031215614933575f80fd5b5035919050565b5f806040838503121561494b575f80fd5b82359150602083013561495d81614539565b809150509250929050565b5f606082840312156145bf575f80fd5b5f805f805f805f805f805f6101608c8e031215614993575f80fd5b61499d8d8d614968565b9a506149ab60608d016146a5565b995060808c013598506149c060a08d0161455a565b97506149ce60c08d0161455a565b965060e08c013595506101008c013567ffffffffffffffff8111156149f1575f80fd5b6149fd8e828f0161456a565b9096509450506101208c013567ffffffffffffffff811115614a1d575f80fd5b614a298e828f016145af565b9350506101408c013567ffffffffffffffff811115614a46575f80fd5b614a528e828f0161456a565b915080935050809150509295989b509295989b9093969950565b5f60208284031215614a7c575f80fd5b8135611f9d81614688565b5f805f60408486031215614a99575f80fd5b8335614aa481614539565b9250602084013567ffffffffffffffff811115614abf575f80fd5b614acb8682870161456a565b9497909650939450505050565b5f805f805f805f8060e0898b031215614aef575f80fd5b883572ffffffffffffffffffffffffffffffffffffff81168114614b11575f80fd5b975060208901359650614b2660408a0161455a565b9550614b3460608a0161455a565b94506080890135935060a089013567ffffffffffffffff811115614b56575f80fd5b614b628b828c0161456a565b90945092505060c089013567ffffffffffffffff811115614b81575f80fd5b614b8d8b828c016145af565b9150509295985092959890939650565b5f60208284031215614bad575f80fd5b8135611f9d81614539565b5f60208284031215614bc8575f80fd5b813565ffffffffffff81168114611f9d575f80fd5b60808101614beb8285614641565b611f9d6020830184805160020b825260208082015190830152604090810151910152565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e060208201525f614c9560e0830189614c0f565b8281036040840152614ca78189614c0f565b6060840188905273ffffffffffffffffffffffffffffffffffffffff8716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015614d09578351835260209384019390920191600101614ceb565b50909b9a5050505050505050505050565b5f8060408385031215614d2b575f80fd5b8235614d3681614688565b9150602083013561495d81614688565b5f805f8060a08587031215614d59575f80fd5b614d638686614968565b93506060850135614d7381614539565b9250608085013567ffffffffffffffff811115614d8e575f80fd5b614d9a8782880161456a565b95989497509550505050565b5f805f805f805f805f806101208b8d031215614dc0575f80fd5b8a35614dcb81614688565b9950614dd960208c016146a5565b9850614de760408c016146a5565b975060608b01359650614dfc60808c0161455a565b9550614e0a60a08c0161455a565b945060c08b0135935060e08b013567ffffffffffffffff811115614e2c575f80fd5b614e388d828e0161456a565b9094509250506101008b013567ffffffffffffffff811115614e58575f80fd5b614e648d828e016145af565b9150509295989b9194979a5092959850565b821515815260808101611f9d6020830184805160020b825260208082015190830152604090810151910152565b5f60208284031215614eb3575f80fd5b8135611f9d816147c5565b5f805f805f60808688031215614ed2575f80fd5b8535614edd81614688565b94506020860135614eed81614688565b93506040860135614efd81614688565b9250606086013567ffffffffffffffff811115614f18575f80fd5b614f248882890161456a565b969995985093965092949392505050565b5f805f805f805f8060e0898b031215614f4c575f80fd5b8835614f5781614688565b9750602089013596506040890135614f6e81614539565b95506060890135614b3481614539565b5f805f60a08486031215614f90575f80fd5b614f9a8585614968565b92506060840135614faa81614688565b91506080840135614fba81614688565b809150509250925092565b5f6060828403128015614fd6575f80fd5b50614fdf6146dd565b8235614fea816147c5565b8152602083810135908201526040928301359281019290925250919050565b5f805f805f805f80610100898b031215615021575f80fd5b883561502c81614539565b9750602089013561503c81614539565b9650604089013561504c81614539565b9550606089013561505c81614539565b9450608089013561506c81614539565b935060a089013561507c816147c5565b925060c089013561508c81614539565b915060e089013561509c81614539565b809150509295985092959890939650565b5f80604083850312156150be575f80fd5b823567ffffffffffffffff8111156150d4575f80fd5b6150e0858286016145af565b95602094909401359450505050565b5f805f805f60c08688031215615103575f80fd5b853561510e81614688565b9450602086013593506040860135925061512b8760608801614778565b915060a086013561513b816147c5565b809150509295509295909350565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126151c3575f80fd5b830160208101925035905067ffffffffffffffff8111156151e2575f80fd5b8060051b36038213156145a8575f80fd5b8183526020830192505f815f5b8481101561523a57813561521381614688565b6fffffffffffffffffffffffffffffffff1686526020958601959190910190600101615200565b5093949350505050565b5f604083016152538384615190565b604086528281845260608701905060608260051b8801019350825f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1853603015b84821015615320577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a880301845282358181126152d0575f80fd5b860160208101903567ffffffffffffffff8111156152ec575f80fd5b8036038213156152fa575f80fd5b615305898284615149565b98505050602083019250602084019350600182019150615294565b5050505050506153336020840184615190565b85830360208701526132d18382846151f3565b73ffffffffffffffffffffffffffffffffffffffff85168152606060208201525f615375606083018587615149565b82810360408401526153878185615244565b979650505050505050565b805160038110614565575f80fd5b5f602082840312156153b0575f80fd5b611f9d82615392565b5f80604083850312156153ca575f80fd5b82516153d5816147c5565b602084015190925061495d81614688565b602081525f610c69602083018486615149565b5f60208284031215615409575f80fd5b815167ffffffffffffffff81111561541f575f80fd5b8201601f8101841361542f575f80fd5b805167ffffffffffffffff811115615449576154496146b0565b61545860208260051b01614729565b80828252602082019150602060a08402850101925086831115615479575f80fd5b6020840193505b828410156132d15760a08488031215615497575f80fd5b61549f614706565b84518152602080860151908201526040808601519082015260608501516154c581614688565b606082015260808501516154d881614688565b6080820152825260a09390930192602090910190615480565b73ffffffffffffffffffffffffffffffffffffffff875116815273ffffffffffffffffffffffffffffffffffffffff6020880151166020820152604087015160408201525f606088015161555f6060840182805160020b825260208082015190830152604090810151910152565b506fffffffffffffffffffffffffffffffff60808901511660c083015260a088015160e083015260c08801516155a261010084018267ffffffffffffffff169052565b5060e08801516101208301526101a06101408301526155c66101a083018789615149565b8281036101608401526155d98187615244565b90508281036101808401526155ef818587615149565b9998505050505050505050565b80518015158114614565575f80fd5b5f6020828403121561561b575f80fd5b611f9d826155fc565b5f60208284031215615634575f80fd5b8151611f9d816147c5565b72ffffffffffffffffffffffffffffffffffffff8916815287602082015273ffffffffffffffffffffffffffffffffffffffff8716604082015273ffffffffffffffffffffffffffffffffffffffff8616606082015284608082015260e060a08201525f6156b160e083018587615149565b82810360c08401526111a98185615244565b5f805f606084860312156156d5575f80fd5b5050815160208301516040909301519094929350919050565b5f602082840312156156fe575f80fd5b5051919050565b5f60608284031215615715575f80fd5b61571d6146dd565b9050815161572a816147c5565b81526020828101519082015260409182015191810191909152919050565b5f8060808385031215615759575f80fd5b61576283615392565b91506157718460208501615705565b90509250929050565b5f806040838503121561578b575f80fd5b505080516020909101519092909150565b80356157a7816147c5565b60020b825260208181013590830152604090810135910152565b6157cb818761579c565b73ffffffffffffffffffffffffffffffffffffffff8516606082015260c060808201525f6157fd60c083018587615149565b90508260a08301529695505050505050565b73ffffffffffffffffffffffffffffffffffffffff855116815273ffffffffffffffffffffffffffffffffffffffff60208601511660208201525f6040860151615871604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606086015161589560608401826fffffffffffffffffffffffffffffffff169052565b5060808601516158b960808401826fffffffffffffffffffffffffffffffff169052565b5060a08601516158dd60a08401826fffffffffffffffffffffffffffffffff169052565b5060c086015160c083015260e086015160e083015261010086015161590f61010084018267ffffffffffffffff169052565b5061016061012083015261592861016083018587615149565b8281036101408401526153878185615244565b5f806080838503121561594c575f80fd5b615762836155fc565b8051614565816147d3565b5f60208284031215615970575f80fd5b8151611f9d816147d3565b6fffffffffffffffffffffffffffffffff861681526fffffffffffffffffffffffffffffffff851660208201526fffffffffffffffffffffffffffffffff84166040820152608060608201525f615387608083018486615149565b6fffffffffffffffffffffffffffffffff8916815287602082015273ffffffffffffffffffffffffffffffffffffffff8716604082015273ffffffffffffffffffffffffffffffffffffffff8616606082015284608082015260e060a08201525f6156b160e083018587615149565b60a08101615a53828661579c565b6fffffffffffffffffffffffffffffffff841660608301526fffffffffffffffffffffffffffffffff83166080830152949350505050565b815160020b8152602080830151908201526040808301519082015260608101610b8a565b5f8082840360c0811215615ac1575f80fd5b60a0811215615ace575f80fd5b50615ad7614706565b615ae0846155fc565b8152602084015164ffffffffff81168114615af9575f80fd5b60208201526040840151615b0c81614539565b60408201526060840151615b1f81614688565b60608201526080840151615b3281614688565b6080820152915061577160a08401615955565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60ff8281168282160390811115610b8a57610b8a615b45565b6001815b6001841115615bc657808504811115615baa57615baa615b45565b6001841615615bb857908102905b60019390931c928002615b8f565b935093915050565b5f82615bdc57506001610b8a565b81615be857505f610b8a565b8160018114615bfe5760028114615c0857615c24565b6001915050610b8a565b60ff841115615c1957615c19615b45565b50506001821b610b8a565b5060208310610133831016604e8410600b8410161715615c47575081810a610b8a565b615c727fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615b8b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615ca457615ca4615b45565b029392505050565b5f611f9d60ff841683615bce565b80820180821115610b8a57610b8a615b45565b8082028115828204841417610b8a57610b8a615b45565b5f60208284031215615cf4575f80fd5b815160ff81168114611f9d575f80fd5b604081525f615d166040830185615244565b90508260208301529392505050565b65ffffffffffff8181168382160190811115610b8a57610b8a615b45565b600181811c90821680615d5757607f821691505b6020821081036145bf577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b65ffffffffffff8281168282160390811115610b8a57610b8a615b45565b601f821115610b3057805f5260205f20601f840160051c81016020851015615dd15750805b601f840160051c820191505b818110156113dc575f8155600101615ddd565b815167ffffffffffffffff811115615e0a57615e0a6146b0565b615e1e81615e188454615d43565b84615dac565b6020601f821160018114615e6f575f8315615e395750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b1784556113dc565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015615ebc5787850151825560209485019460019092019101615e9c565b5084821015615ef857868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b0190555056fea264697066735822122066500720988b482d6ff3bf7805c917efa07a29fa871bd437fd810a50170bb68364736f6c634300081a0033","name":"UsdnProtocolImpl","is_blueprint":false,"license_type":"none","is_fully_verified":false,"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":"dependencies/@openzeppelin-contracts-5.1.0/utils/cryptography/ECDSA.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS\n    }\n\n    /**\n     * @dev The signature derives the `address(0)`.\n     */\n    error ECDSAInvalidSignature();\n\n    /**\n     * @dev The signature has an invalid length.\n     */\n    error ECDSAInvalidSignatureLength(uint256 length);\n\n    /**\n     * @dev The signature has an S value that is in the upper half order.\n     */\n    error ECDSAInvalidSignatureS(bytes32 s);\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n     * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n     * and a bytes32 providing additional information about the error.\n     *\n     * If no error is returned, then the address can be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes memory signature\n    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            assembly (\"memory-safe\") {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n        unchecked {\n            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n            // We do not check for an overflow here since the shift operation results in 0 or 1.\n            uint8 v = uint8((uint256(vs) >> 255) + 27);\n            return tryRecover(hash, v, r, s);\n        }\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     */\n    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS, s);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature, bytes32(0));\n        }\n\n        return (signer, RecoverError.NoError, bytes32(0));\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n        _throwError(error, errorArg);\n        return recovered;\n    }\n\n    /**\n     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n     */\n    function _throwError(RecoverError error, bytes32 errorArg) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert ECDSAInvalidSignature();\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert ECDSAInvalidSignatureLength(uint256(errorArg));\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert ECDSAInvalidSignatureS(errorArg);\n        }\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/interfaces/IERC5313.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5313.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface for the Light Contract Ownership Standard.\n *\n * A standardized minimal interface required to identify an account that controls a contract\n */\ninterface IERC5313 {\n    /**\n     * @dev Gets the address of the owner.\n     */\n    function owner() external view returns (address);\n}\n"},{"file_path":"src/libraries/DoubleEndedQueue.sol","source_code":"// SPDX-License-Identifier: MIT\n// based on the OpenZeppelin implementation\npragma solidity ^0.8.20;\n\nimport { IUsdnProtocolTypes as Types } from \"../interfaces/UsdnProtocol/IUsdnProtocolTypes.sol\";\n\n/**\n * @notice A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends\n * of the sequence (called front and back).\n * @dev Storage use is optimized, and all operations are O(1) constant time.\n *\n * The struct is called `Deque` and holds {IUsdnProtocolTypes.PendingAction}'s. This data structure can only be used in\n * storage, and not in memory.\n */\nlibrary DoubleEndedQueue {\n    /// @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty.\n    error QueueEmpty();\n\n    /// @dev A push operation couldn't be completed due to the queue being full.\n    error QueueFull();\n\n    /// @dev An operation (e.g. {atRaw}) couldn't be completed due to an index being out of bounds.\n    error QueueOutOfBounds();\n\n    /**\n     * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access.\n     *\n     * Struct members have an underscore prefix indicating that they are \"private\" and should not be read or written to\n     * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and\n     * lead to unexpected behavior.\n     *\n     * The first item is at `data[begin]` and the last item is at `data[end - 1]`. This range can wrap around.\n     * @param _begin The index of the first item in the queue.\n     * @param _end The index of the item after the last item in the queue.\n     * @param _data The items in the queue.\n     */\n    struct Deque {\n        uint128 _begin;\n        uint128 _end;\n        mapping(uint128 index => Types.PendingAction) _data;\n    }\n\n    /**\n     * @dev Inserts an item at the end of the queue.\n     * Reverts with {QueueFull} if the queue is full.\n     * @param deque The queue.\n     * @param value The item to insert.\n     * @return backIndex_ The raw index of the inserted item.\n     */\n    function pushBack(Deque storage deque, Types.PendingAction memory value) external returns (uint128 backIndex_) {\n        unchecked {\n            backIndex_ = deque._end;\n            if (backIndex_ + 1 == deque._begin) {\n                revert QueueFull();\n            }\n            deque._data[backIndex_] = value;\n            deque._end = backIndex_ + 1;\n        }\n    }\n\n    /**\n     * @dev Removes the item at the end of the queue and returns it.\n     * Reverts with {QueueEmpty} if the queue is empty.\n     * @param deque The queue.\n     * @return value_ The removed item.\n     */\n    function popBack(Deque storage deque) public returns (Types.PendingAction memory value_) {\n        unchecked {\n            uint128 backIndex = deque._end;\n            if (backIndex == deque._begin) {\n                revert QueueEmpty();\n            }\n            --backIndex;\n            value_ = deque._data[backIndex];\n            delete deque._data[backIndex];\n            deque._end = backIndex;\n        }\n    }\n\n    /**\n     * @dev Inserts an item at the beginning of the queue.\n     * Reverts with {QueueFull} if the queue is full.\n     * @param deque The queue.\n     * @param value The item to insert.\n     * @return frontIndex_ The raw index of the inserted item.\n     */\n    function pushFront(Deque storage deque, Types.PendingAction memory value) external returns (uint128 frontIndex_) {\n        unchecked {\n            frontIndex_ = deque._begin - 1;\n            if (frontIndex_ == deque._end) {\n                revert QueueFull();\n            }\n            deque._data[frontIndex_] = value;\n            deque._begin = frontIndex_;\n        }\n    }\n\n    /**\n     * @dev Removes the item at the beginning of the queue and returns it.\n     * Reverts with {QueueEmpty} if the queue is empty.\n     * @param deque The queue.\n     * @return value_ The removed item.\n     */\n    function popFront(Deque storage deque) public returns (Types.PendingAction memory value_) {\n        unchecked {\n            uint128 frontIndex = deque._begin;\n            if (frontIndex == deque._end) {\n                revert QueueEmpty();\n            }\n            value_ = deque._data[frontIndex];\n            delete deque._data[frontIndex];\n            deque._begin = frontIndex + 1;\n        }\n    }\n\n    /**\n     * @dev Returns the item at the beginning of the queue.\n     * Reverts with {QueueEmpty} if the queue is empty.\n     * @param deque The queue.\n     * @return value_ The item at the front of the queue.\n     * @return rawIndex_ The raw index of the returned item.\n     */\n    function front(Deque storage deque) external view returns (Types.PendingAction memory value_, uint128 rawIndex_) {\n        if (empty(deque)) {\n            revert QueueEmpty();\n        }\n        rawIndex_ = deque._begin;\n        value_ = deque._data[rawIndex_];\n    }\n\n    /**\n     * @dev Returns the item at the end of the queue.\n     * Reverts with {QueueEmpty} if the queue is empty.\n     * @param deque The queue.\n     * @return value_ The item at the back of the queue.\n     * @return rawIndex_ The raw index of the returned item.\n     */\n    function back(Deque storage deque) external view returns (Types.PendingAction memory value_, uint128 rawIndex_) {\n        if (empty(deque)) {\n            revert QueueEmpty();\n        }\n        unchecked {\n            rawIndex_ = deque._end - 1;\n            value_ = deque._data[rawIndex_];\n        }\n    }\n\n    /**\n     * @dev Returns the item at a position in the queue given by `index`, with the first item at 0 and the last item at\n     * `length(deque) - 1`.\n     * Reverts with {QueueOutOfBounds} if the index is out of bounds.\n     * @param deque The queue.\n     * @param index The index of the item to return.\n     * @return value_ The item at the given index.\n     * @return rawIndex_ The raw index of the item.\n     */\n    function at(Deque storage deque, uint256 index)\n        external\n        view\n        returns (Types.PendingAction memory value_, uint128 rawIndex_)\n    {\n        if (index >= length(deque)) {\n            revert QueueOutOfBounds();\n        }\n        // by construction, length is a uint128, so the check above ensures that\n        // the index can be safely downcast to a uint128\n        unchecked {\n            rawIndex_ = deque._begin + uint128(index);\n            value_ = deque._data[rawIndex_];\n        }\n    }\n\n    /**\n     * @dev Returns the item at a position in the queue given by `rawIndex`, indexing into the underlying storage array\n     * directly.\n     * Reverts with {QueueOutOfBounds} if the index is out of bounds.\n     * @param deque The queue.\n     * @param rawIndex The index of the item to return.\n     * @return value_ The item at the given index.\n     */\n    function atRaw(Deque storage deque, uint128 rawIndex) external view returns (Types.PendingAction memory value_) {\n        if (!isValid(deque, rawIndex)) {\n            revert QueueOutOfBounds();\n        }\n        value_ = deque._data[rawIndex];\n    }\n\n    /**\n     * @dev Deletes the item at a position in the queue given by `rawIndex`, indexing into the underlying storage array\n     * directly. If clearing the front or back item, then the bounds are updated. Otherwise, the values are simply set\n     * to zero and the queue's begin and end indices are not updated.\n     * @param deque The queue.\n     * @param rawIndex The index of the item to delete.\n     */\n    function clearAt(Deque storage deque, uint128 rawIndex) external {\n        uint128 backIndex = deque._end;\n        unchecked {\n            backIndex--;\n        }\n        if (rawIndex == deque._begin) {\n            popFront(deque); // reverts if empty\n        } else if (rawIndex == backIndex) {\n            popBack(deque); // reverts if empty\n        } else {\n            // we don't care to revert if this is not a valid index, since we're just clearing it\n            delete deque._data[rawIndex];\n        }\n    }\n\n    /**\n     * @dev Checks if the raw index is valid (in bounds).\n     * @param deque The queue.\n     * @param rawIndex The raw index to check.\n     * @return valid_ Whether the raw index is valid.\n     */\n    function isValid(Deque storage deque, uint128 rawIndex) public view returns (bool valid_) {\n        if (deque._begin > deque._end) {\n            // here the values are split at the beginning and end of the range, so invalid indices are in the middle\n            if (rawIndex < deque._begin && rawIndex >= deque._end) {\n                return false;\n            }\n        } else if (rawIndex < deque._begin || rawIndex >= deque._end) {\n            return false;\n        }\n        valid_ = true;\n    }\n\n    /**\n     * @dev Returns the number of items in the queue.\n     * @param deque The queue.\n     * @return length_ The number of items in the queue.\n     */\n    function length(Deque storage deque) public view returns (uint256 length_) {\n        unchecked {\n            length_ = uint256(deque._end - deque._begin);\n        }\n    }\n\n    /**\n     * @dev Returns true if the queue is empty.\n     * @param deque The queue.\n     * @return empty_ True if the queue is empty.\n     */\n    function empty(Deque storage deque) internal view returns (bool empty_) {\n        empty_ = deque._end == deque._begin;\n    }\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolErrors.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/**\n * @title IUsdnProtocolErrors\n * @notice All errors used in the USDN Protocol.\n */\ninterface IUsdnProtocolErrors {\n    /// @dev Insufficient Ether provided to cover the cost of price validation.\n    error UsdnProtocolInsufficientOracleFee();\n\n    /// @dev Ether refund to the sender failed.\n    error UsdnProtocolEtherRefundFailed();\n\n    /**\n     * @dev Validator is not eligible for a security deposit refund.\n     * @param validator The address of the validator.\n     */\n    error UsdnProtocolNotEligibleForRefund(address validator);\n\n    /// @dev The provided amount is zero.\n    error UsdnProtocolZeroAmount();\n\n    /// @dev The provided `to` address is invalid.\n    error UsdnProtocolInvalidAddressTo();\n\n    /// @dev The provided `validator` address is invalid.\n    error UsdnProtocolInvalidAddressValidator();\n\n    /// @dev The initial amount provided during initialization is too small to support opening a long position.\n    error UsdnProtocolMinInitAmount();\n\n    /**\n     * @dev The provided USDN token has a non-zero total supply at deployment.\n     * @param usdnAddress The address of the USDN contract.\n     */\n    error UsdnProtocolInvalidUsdn(address usdnAddress);\n\n    /**\n     * @dev The asset's decimal precision is invalid.\n     * @param assetDecimals The specified asset decimals.\n     */\n    error UsdnProtocolInvalidAssetDecimals(uint8 assetDecimals);\n\n    /// @dev The token's decimals do not match `TOKENS_DECIMALS`.\n    error UsdnProtocolInvalidTokenDecimals();\n\n    /// @dev The caller is not authorized to perform the action.\n    error UsdnProtocolUnauthorized();\n\n    /// @dev A pending action already exists for the user.\n    error UsdnProtocolPendingAction();\n\n    /// @dev The user does not have any pending action.\n    error UsdnProtocolNoPendingAction();\n\n    /// @dev A pending action exists, but its type is not the expected one.\n    error UsdnProtocolInvalidPendingAction();\n\n    /// @dev The provided timestamp predates the last balance update.\n    error UsdnProtocolTimestampTooOld();\n\n    /// @dev The calculated leverage is below the minimum allowed.\n    error UsdnProtocolLeverageTooLow();\n\n    /// @dev The calculated leverage exceeds the maximum allowed.\n    error UsdnProtocolLeverageTooHigh();\n\n    /// @dev The amount of collateral in the long position is too small.\n    error UsdnProtocolLongPositionTooSmall();\n\n    /**\n     * @dev The liquidation price exceeds or equals the starting price.\n     * @param liquidationPrice The specified liquidation price.\n     * @param startPrice The starting price.\n     */\n    error UsdnProtocolInvalidLiquidationPrice(uint128 liquidationPrice, uint128 startPrice);\n\n    /**\n     * @dev The liquidation price exceeds the safety margin.\n     * @param liquidationPrice The specified liquidation price.\n     * @param maxLiquidationPrice The maximum liquidation price.\n     */\n    error UsdnProtocolLiquidationPriceSafetyMargin(uint128 liquidationPrice, uint128 maxLiquidationPrice);\n\n    /**\n     * @dev The provided tick version is outdated due to liquidation.\n     * @param currentVersion The current tick version.\n     * @param providedVersion The provided tick version.\n     */\n    error UsdnProtocolOutdatedTick(uint256 currentVersion, uint256 providedVersion);\n\n    /// @dev The position cannot be closed because it has not been validated yet.\n    error UsdnProtocolPositionNotValidated();\n\n    /// @dev The specified position fee exceeds the allowed maximum.\n    error UsdnProtocolInvalidPositionFee();\n\n    /// @dev The specified vault fee exceeds the allowed maximum.\n    error UsdnProtocolInvalidVaultFee();\n\n    /// @dev The specified SDEX rewards ratio exceeds the allowed maximum.\n    error UsdnProtocolInvalidSdexRewardsRatio();\n\n    /// @dev The specified rebalancer bonus exceeds the allowed maximum.\n    error UsdnProtocolInvalidRebalancerBonus();\n\n    /// @dev The specified ratio exceeds the allowed maximum.\n    error UsdnProtocolInvalidBurnSdexOnDepositRatio();\n\n    /// @dev The specified middleware address is invalid.\n    error UsdnProtocolInvalidMiddlewareAddress();\n\n    /// @dev The specified minimum leverage is invalid.\n    error UsdnProtocolInvalidRebalancerMinLeverage();\n\n    /// @dev The specified `minLeverage` value is invalid.\n    error UsdnProtocolInvalidMinLeverage();\n\n    /// @dev The specified `maxLeverage` value is invalid.\n    error UsdnProtocolInvalidMaxLeverage();\n\n    /// @dev The specified validation deadline is invalid.\n    error UsdnProtocolInvalidValidatorDeadline();\n\n    /// @dev The specified liquidation penalty is invalid.\n    error UsdnProtocolInvalidLiquidationPenalty();\n\n    /// @dev The specified safety margin basis points are invalid.\n    error UsdnProtocolInvalidSafetyMarginBps();\n\n    /// @dev The specified liquidation iteration value is invalid.\n    error UsdnProtocolInvalidLiquidationIteration();\n\n    /// @dev The specified EMA period is invalid.\n    error UsdnProtocolInvalidEMAPeriod();\n\n    /// @dev The specified funding scale factor (SF) is invalid.\n    error UsdnProtocolInvalidFundingSF();\n\n    /// @dev The specified `LiquidationRewardsManager` contract address is invalid.\n    error UsdnProtocolInvalidLiquidationRewardsManagerAddress();\n\n    /// @dev The specified protocol fee basis points are invalid.\n    error UsdnProtocolInvalidProtocolFeeBps();\n\n    /// @dev The specified fee collector address is invalid.\n    error UsdnProtocolInvalidFeeCollector();\n\n    /// @dev The specified security deposit is below the required value.\n    error UsdnProtocolSecurityDepositTooLow();\n\n    /// @dev The contract's ether balance after the action is not as expected.\n    error UsdnProtocolUnexpectedBalance();\n\n    /// @dev The specified trading exposure imbalance limit is invalid.\n    error UsdnProtocolInvalidExpoImbalanceLimit();\n\n    /// @dev The specified imbalance target is invalid.\n    error UsdnProtocolInvalidLongImbalanceTarget();\n\n    /**\n     * @dev The protocol imbalance limit has been reached.\n     * @param imbalanceBps The imbalance value in basis points.\n     */\n    error UsdnProtocolImbalanceLimitReached(int256 imbalanceBps);\n\n    /// @dev The tick of the rebalancer position is invalid.\n    error UsdnProtocolInvalidRebalancerTick();\n\n    /// @dev The long total exposure value is invalid.\n    error UsdnProtocolInvalidLongExpo();\n\n    /// @dev The total exposure value is zero.\n    error UsdnProtocolZeroTotalExpo();\n\n    /// @dev Indicates that the data provided to validate an actionable pending action is invalid.\n    error UsdnProtocolInvalidPendingActionData();\n\n    /// @dev The specified target USDN price is invalid.\n    error UsdnProtocolInvalidTargetUsdnPrice();\n\n    /// @dev The specified USDN rebase threshold is invalid.\n    error UsdnProtocolInvalidUsdnRebaseThreshold();\n\n    /**\n     * @dev The amount to close exceeds the position amount.\n     * @param amountToClose The specified amount to close.\n     * @param positionAmount The total amount in the position.\n     */\n    error UsdnProtocolAmountToCloseHigherThanPositionAmount(uint128 amountToClose, uint128 positionAmount);\n\n    /// @dev The deposit amount is too small to mint USDN.\n    error UsdnProtocolDepositTooSmall();\n\n    /// @dev The long trading exposure is zero, making liquidation tick calculation impossible.\n    error UsdnProtocolZeroLongTradingExpo();\n\n    /// @dev The vault balance is zero, so the calculation cannot proceed.\n    error UsdnProtocolEmptyVault();\n\n    /// @dev The entry price exceeds the maximum specified by the user.\n    error UsdnProtocolSlippageMaxPriceExceeded();\n\n    /// @dev The current price is below the minimum specified by the user.\n    error UsdnProtocolSlippageMinPriceExceeded();\n\n    /// @dev The estimated amount of tokens to be received is less than expected.\n    error UsdnProtocolAmountReceivedTooSmall();\n\n    /// @dev The payment callback execution failed.\n    error UsdnProtocolPaymentCallbackFailed();\n\n    /// @dev The user initiate action's deadline has passed.\n    error UsdnProtocolDeadlineExceeded();\n\n    /// @dev The delegation signature is invalid.\n    error UsdnProtocolInvalidDelegationSignature();\n\n    /// @dev The specified security deposit value exceeds the allowed maximum\n    error UsdnProtocolInvalidSecurityDeposit();\n\n    /// @dev The specified minimum long position value exceeds the allowed maximum.\n    error UsdnProtocolInvalidMinLongPosition();\n\n    /// @dev The low latency delay of the specified oracle middleware contract is below the validator's deadline.\n    error UsdnProtocolInvalidMiddlewareLowLatencyDelay();\n\n    /**\n     * @dev The minimum asset deposit of the specified rebalancer contract is below the protocol's minimum asset\n     * deposit.\n     */\n    error UsdnProtocolInvalidRebalancerMinAssetDeposit();\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/utils/Panic.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n *      using Panic for uint256;\n *\n *      // Use any of the declared internal constants\n *      function foo() { Panic.GENERIC.panic(); }\n *\n *      // Alternatively\n *      function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n    /// @dev generic / unspecified error\n    uint256 internal constant GENERIC = 0x00;\n    /// @dev used by the assert() builtin\n    uint256 internal constant ASSERT = 0x01;\n    /// @dev arithmetic underflow or overflow\n    uint256 internal constant UNDER_OVERFLOW = 0x11;\n    /// @dev division or modulo by zero\n    uint256 internal constant DIVISION_BY_ZERO = 0x12;\n    /// @dev enum conversion error\n    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n    /// @dev invalid encoding in storage\n    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n    /// @dev empty array pop\n    uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n    /// @dev array out of bounds access\n    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n    /// @dev resource error (too large allocation or too large array)\n    uint256 internal constant RESOURCE_ERROR = 0x41;\n    /// @dev calling invalid internal function\n    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n    /// @dev Reverts with a panic code. Recommended to use with\n    /// the internal constants with predefined codes.\n    function panic(uint256 code) internal pure {\n        assembly (\"memory-safe\") {\n            mstore(0x00, 0x4e487b71)\n            mstore(0x20, code)\n            revert(0x1c, 0x24)\n        }\n    }\n}\n"},{"file_path":"src/UsdnProtocol/UsdnProtocolCore.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { AccessControlDefaultAdminRulesUpgradeable } from\n    \"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlDefaultAdminRulesUpgradeable.sol\";\n\nimport { IUsdnProtocolCore } from \"../interfaces/UsdnProtocol/IUsdnProtocolCore.sol\";\nimport { InitializableReentrancyGuard } from \"../utils/InitializableReentrancyGuard.sol\";\nimport { UsdnProtocolCoreLibrary as Core } from \"./libraries/UsdnProtocolCoreLibrary.sol\";\n\nabstract contract UsdnProtocolCore is\n    IUsdnProtocolCore,\n    InitializableReentrancyGuard,\n    AccessControlDefaultAdminRulesUpgradeable\n{\n    /// @inheritdoc IUsdnProtocolCore\n    function initialize(\n        uint128 depositAmount,\n        uint128 longAmount,\n        uint128 desiredLiqPrice,\n        bytes calldata currentPriceData\n    ) external payable protocolInitializer onlyRole(DEFAULT_ADMIN_ROLE) {\n        return Core.initialize(depositAmount, longAmount, desiredLiqPrice, currentPriceData);\n    }\n\n    /// @inheritdoc IUsdnProtocolCore\n    function funding(uint128 timestamp)\n        external\n        view\n        returns (int256 funding_, int256 fundingPerDay_, int256 oldLongExpo_)\n    {\n        return Core.funding(timestamp);\n    }\n}\n"},{"file_path":"dependencies/solady-0.0.228/src/utils/LibBit.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for bit twiddling and boolean operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)\n/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)\nlibrary LibBit {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                  BIT TWIDDLING OPERATIONS                  */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Find last set.\n    /// Returns the index of the most significant bit of `x`,\n    /// counting from the least significant bit position.\n    /// If `x` is zero, returns 256.\n    function fls(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x)))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(r, shl(3, lt(0xff, shr(r, x))))\n            // forgefmt: disable-next-item\n            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),\n                0x0706060506020504060203020504030106050205030304010505030400000000))\n        }\n    }\n\n    /// @dev Count leading zeros.\n    /// Returns the number of zeros preceding the most significant one bit.\n    /// If `x` is zero, returns 256.\n    function clz(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(r, shl(3, lt(0xff, shr(r, x))))\n            // forgefmt: disable-next-item\n            r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),\n                0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))\n        }\n    }\n\n    /// @dev Find first set.\n    /// Returns the index of the least significant bit of `x`,\n    /// counting from the least significant bit position.\n    /// If `x` is zero, returns 256.\n    /// Equivalent to `ctz` (count trailing zeros), which gives\n    /// the number of zeros following the least significant one bit.\n    function ffs(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Isolate the least significant bit.\n            x := and(x, add(not(x), 1))\n            // For the upper 3 bits of the result, use a De Bruijn-like lookup.\n            // Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/\n            // forgefmt: disable-next-item\n            r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,\n                0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),\n                0x8040405543005266443200005020610674053026020000107506200176117077)))\n            // For the lower 5 bits of the result, use a De Bruijn lookup.\n            // forgefmt: disable-next-item\n            r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),\n                0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))\n        }\n    }\n\n    /// @dev Returns the number of set bits in `x`.\n    function popCount(uint256 x) internal pure returns (uint256 c) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let max := not(0)\n            let isMax := eq(x, max)\n            x := sub(x, and(shr(1, x), div(max, 3)))\n            x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))\n            x := and(add(x, shr(4, x)), div(max, 17))\n            c := or(shl(8, isMax), shr(248, mul(x, div(max, 255))))\n        }\n    }\n\n    /// @dev Returns whether `x` is a power of 2.\n    function isPo2(uint256 x) internal pure returns (bool result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to `x && !(x & (x - 1))`.\n            result := iszero(add(and(x, sub(x, 1)), iszero(x)))\n        }\n    }\n\n    /// @dev Returns `x` reversed at the bit level.\n    function reverseBits(uint256 x) internal pure returns (uint256 r) {\n        uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;\n        uint256 m1 = m0 ^ (m0 << 2);\n        uint256 m2 = m1 ^ (m1 << 1);\n        r = reverseBytes(x);\n        r = (m2 & (r >> 1)) | ((m2 & r) << 1);\n        r = (m1 & (r >> 2)) | ((m1 & r) << 2);\n        r = (m0 & (r >> 4)) | ((m0 & r) << 4);\n    }\n\n    /// @dev Returns `x` reversed at the byte level.\n    function reverseBytes(uint256 x) internal pure returns (uint256 r) {\n        unchecked {\n            // Computing masks on-the-fly reduces bytecode size by about 200 bytes.\n            uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == uint256(0)) >> 192);\n            uint256 m1 = m0 ^ (m0 << 32);\n            uint256 m2 = m1 ^ (m1 << 16);\n            uint256 m3 = m2 ^ (m2 << 8);\n            r = (m3 & (x >> 8)) | ((m3 & x) << 8);\n            r = (m2 & (r >> 16)) | ((m2 & r) << 16);\n            r = (m1 & (r >> 32)) | ((m1 & r) << 32);\n            r = (m0 & (r >> 64)) | ((m0 & r) << 64);\n            r = (r >> 128) | (r << 128);\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                     BOOLEAN OPERATIONS                     */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    // A Solidity bool on the stack or memory is represented as a 256-bit word.\n    // Non-zero values are true, zero is false.\n    // A clean bool is either 0 (false) or 1 (true) under the hood.\n    // Usually, if not always, the bool result of a regular Solidity expression,\n    // or the argument of a public/external function will be a clean bool.\n    // You can usually use the raw variants for more performance.\n    // If uncertain, test (best with exact compiler settings).\n    // Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s).\n\n    /// @dev Returns `x & y`. Inputs must be clean.\n    function rawAnd(bool x, bool y) internal pure returns (bool z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := and(x, y)\n        }\n    }\n\n    /// @dev Returns `x & y`.\n    function and(bool x, bool y) internal pure returns (bool z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := and(iszero(iszero(x)), iszero(iszero(y)))\n        }\n    }\n\n    /// @dev Returns `x | y`. Inputs must be clean.\n    function rawOr(bool x, bool y) internal pure returns (bool z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := or(x, y)\n        }\n    }\n\n    /// @dev Returns `x | y`.\n    function or(bool x, bool y) internal pure returns (bool z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := or(iszero(iszero(x)), iszero(iszero(y)))\n        }\n    }\n\n    /// @dev Returns 1 if `b` is true, else 0. Input must be clean.\n    function rawToUint(bool b) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := b\n        }\n    }\n\n    /// @dev Returns 1 if `b` is true, else 0.\n    function toUint(bool b) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := iszero(iszero(b))\n        }\n    }\n}\n"},{"file_path":"dependencies/@smardex-solidity-libraries-1.0.1/src/HugeUint.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/**\n * @notice A library for manipulating uint512 quantities.\n * @dev The 512-bit unsigned integers are represented as two uint256 \"limbs\", a `hi` limb for the most significant bits,\n * and a `lo` limb for the least-significant bits. The resulting uint512 quantity is obtained with `hi * 2^256 + lo`.\n */\nlibrary HugeUint {\n    /// @notice Indicates that the division failed because the divisor is zero or the result overflows a uint256.\n    error HugeUintDivisionFailed();\n\n    /// @notice Indicates that the addition overflowed a uint512.\n    error HugeUintAddOverflow();\n\n    /// @notice Indicates that the subtraction underflowed.\n    error HugeUintSubUnderflow();\n\n    /// @notice Indicates that the multiplication overflowed a uint512.\n    error HugeUintMulOverflow();\n\n    /**\n     * @notice A 512-bit integer represented as two 256-bit limbs.\n     * @dev The integer value can be reconstructed as `hi * 2^256 + lo`.\n     * @param hi The most-significant bits (higher limb) of the integer.\n     * @param lo The least-significant bits (lower limb) of the integer.\n     */\n    struct Uint512 {\n        uint256 hi;\n        uint256 lo;\n    }\n\n    /**\n     * @notice Wraps a uint256 into a {Uint512} integer.\n     * @param x A uint256 integer.\n     * @return The same value as a 512-bit integer.\n     */\n    function wrap(uint256 x) internal pure returns (Uint512 memory) {\n        return Uint512({ hi: 0, lo: x });\n    }\n\n    /**\n     * @notice Calculates the sum `a + b` of two 512-bit unsigned integers.\n     * @dev This function will revert if the result overflows a uint512.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return res_ The sum of `a` and `b`.\n     */\n    function add(Uint512 memory a, Uint512 memory b) internal pure returns (Uint512 memory res_) {\n        (res_.lo, res_.hi) = _add(a.lo, a.hi, b.lo, b.hi);\n        // check for overflow, i.e. if the result is less than b\n        if (res_.hi < b.hi || (res_.hi == b.hi && res_.lo < b.lo)) {\n            revert HugeUintAddOverflow();\n        }\n    }\n\n    /**\n     * @notice Calculates the difference `a - b` of two 512-bit unsigned integers.\n     * @dev This function will revert if `b > a`.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return res_ The difference `a - b`.\n     */\n    function sub(Uint512 memory a, Uint512 memory b) internal pure returns (Uint512 memory res_) {\n        // check for underflow\n        if (a.hi < b.hi || (a.hi == b.hi && a.lo < b.lo)) {\n            revert HugeUintSubUnderflow();\n        }\n        (res_.lo, res_.hi) = _sub(a.lo, a.hi, b.lo, b.hi);\n    }\n\n    /**\n     * @notice Calculates the product `a * b` of two 256-bit unsigned integers using the Chinese remainder theorem.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return res_ The product `a * b` of the operands as an unsigned 512-bit integer.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (Uint512 memory res_) {\n        (res_.lo, res_.hi) = _mul256(a, b);\n    }\n\n    /**\n     * @notice Calculates the product `a * b` of a 512-bit unsigned integer and a 256-bit unsigned integer.\n     * @dev This function reverts if the result overflows a uint512.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return res_ The product `a * b` of the operands as an unsigned 512-bit integer.\n     */\n    function mul(Uint512 memory a, uint256 b) internal pure returns (Uint512 memory res_) {\n        if ((a.hi == 0 && a.lo == 0) || b == 0) {\n            return res_;\n        }\n        (res_.lo, res_.hi) = _mul256(a.lo, b);\n        unchecked {\n            uint256 p = a.hi * b;\n            if (p / b != a.hi) {\n                revert HugeUintMulOverflow();\n            }\n            res_.hi += p;\n            if (res_.hi < p) {\n                revert HugeUintMulOverflow();\n            }\n        }\n    }\n\n    /**\n     * @notice Calculates the division `floor(a / b)` of a 512-bit unsigned integer by an unsigned 256-bit integer.\n     * @dev The call will revert if the result doesn't fit inside a uint256 or if the denominator is zero.\n     * @param a The numerator as a 512-bit unsigned integer.\n     * @param b The denominator as a 256-bit unsigned integer.\n     * @return res_ The division `floor(a / b)` of the operands as an unsigned 256-bit integer.\n     */\n    function div(Uint512 memory a, uint256 b) internal pure returns (uint256 res_) {\n        // make sure the output fits inside a uint256, also prevents b == 0\n        if (b <= a.hi) {\n            revert HugeUintDivisionFailed();\n        }\n        // if the numerator is smaller than the denominator, the result is zero\n        if (a.hi == 0 && a.lo < b) {\n            return 0;\n        }\n        // the first operand fits in 256 bits, we can use the Solidity division operator\n        if (a.hi == 0) {\n            unchecked {\n                return a.lo / b;\n            }\n        }\n        res_ = _div256(a.lo, a.hi, b);\n    }\n\n    /**\n     * @notice Computes the division `floor(a/b)` of two 512-bit integers, knowing the result fits inside a uint256.\n     * @dev Credits chfast (Apache 2.0 License): <https://github.com/chfast/intx>.\n     * This function will revert if the second operand is zero or if the result doesn't fit inside a uint256.\n     * @param a The numerator as a 512-bit integer.\n     * @param b The denominator as a 512-bit integer.\n     * @return res_ The quotient floor(a/b).\n     */\n    function div(Uint512 memory a, Uint512 memory b) internal pure returns (uint256 res_) {\n        res_ = _div(a.lo, a.hi, b.lo, b.hi);\n    }\n\n    /**\n     * @notice Calculates the sum `a + b` of two 512-bit unsigned integers.\n     * @dev Credits Remco Bloemen (MIT license): <https://2π.com/17/512-bit-division>.\n     * The result is not checked for overflow, the caller must ensure that the result fits inside a uint512.\n     * @param a0 The low limb of the first operand.\n     * @param a1 The high limb of the first operand.\n     * @param b0 The low limb of the second operand.\n     * @param b1 The high limb of the second operand.\n     * @return lo_ The low limb of the result of `a + b`.\n     * @return hi_ The high limb of the result of `a + b`.\n     */\n    function _add(uint256 a0, uint256 a1, uint256 b0, uint256 b1) internal pure returns (uint256 lo_, uint256 hi_) {\n        assembly {\n            lo_ := add(a0, b0)\n            hi_ := add(add(a1, b1), lt(lo_, a0))\n        }\n    }\n\n    /**\n     * @notice Calculates the difference `a - b` of two 512-bit unsigned integers.\n     * @dev Credits Remco Bloemen (MIT license): <https://2π.com/17/512-bit-division>.\n     * The result is not checked for underflow, the caller must ensure that the second operand is less than or equal to\n     * the first operand.\n     * @param a0 The low limb of the first operand.\n     * @param a1 The high limb of the first operand.\n     * @param b0 The low limb of the second operand.\n     * @param b1 The high limb of the second operand.\n     * @return lo_ The low limb of the result of `a - b`.\n     * @return hi_ The high limb of the result of `a - b`.\n     */\n    function _sub(uint256 a0, uint256 a1, uint256 b0, uint256 b1) internal pure returns (uint256 lo_, uint256 hi_) {\n        assembly {\n            lo_ := sub(a0, b0)\n            hi_ := sub(sub(a1, b1), lt(a0, b0))\n        }\n    }\n\n    /**\n     * @notice Calculates the product `a * b` of two 256-bit unsigned integers using the Chinese remainder theorem.\n     * @dev Credits Remco Bloemen (MIT license): <https://2π.com/17/chinese-remainder-theorem>\n     * and Solady (MIT license): <https://github.com/Vectorized/solady>.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return lo_ The low limb of the result of `a * b`.\n     * @return hi_ The high limb of the result of `a * b`.\n     */\n    function _mul256(uint256 a, uint256 b) internal pure returns (uint256 lo_, uint256 hi_) {\n        assembly {\n            lo_ := mul(a, b)\n            let mm := mulmod(a, b, not(0)) // (a * b) % uint256.max\n            hi_ := sub(mm, add(lo_, lt(mm, lo_)))\n        }\n    }\n\n    /**\n     * @notice Calculates the division `floor(a / b)` of a 512-bit unsigned integer by an unsigned 256-bit integer.\n     * @dev Credits Solady (MIT license): <https://github.com/Vectorized/solady>.\n     * The caller must ensure that the result fits inside a uint256 and that the division is non-zero.\n     * For performance reasons, the caller should ensure that the numerator high limb (hi) is non-zero.\n     * @param a0 The low limb of the numerator.\n     * @param a1 The high limb of the  numerator.\n     * @param b The denominator as a 256-bit unsigned integer.\n     * @return res_ The division `floor(a / b)` of the operands as an unsigned 256-bit integer.\n     */\n    function _div256(uint256 a0, uint256 a1, uint256 b) internal pure returns (uint256 res_) {\n        uint256 r;\n        assembly {\n            // to make the division exact, we find out the remainder of the division of a by b\n            r := mulmod(a1, not(0), b) // (a1 * uint256.max) % b\n            r := addmod(r, a1, b) // (r + a1) % b\n            r := addmod(r, a0, b) // (r + a0) % b\n\n            // `t` is the least significant bit of `b`\n            // always greater or equal to 1\n            let t := and(b, sub(0, b))\n            // divide `b` by `t`, which is a power of two\n            b := div(b, t)\n            // invert `b mod 2**256`\n            // now that `b` is an odd number, it has an inverse\n            // modulo `2**256` such that `b * inv = 1 mod 2**256`\n            // compute the inverse by starting with a seed that is\n            // correct for four bits. That is, `b * inv = 1 mod 2**4`\n            let inv := xor(2, mul(3, b))\n            // now use Newton-Raphson iteration to improve the precision\n            // thanks to Hensel's lifting lemma, this also works in modular\n            // arithmetic, doubling the correct bits in each step\n            inv := mul(inv, sub(2, mul(b, inv))) // inverse mod 2**8\n            inv := mul(inv, sub(2, mul(b, inv))) // inverse mod 2**16\n            inv := mul(inv, sub(2, mul(b, inv))) // inverse mod 2**32\n            inv := mul(inv, sub(2, mul(b, inv))) // inverse mod 2**64\n            inv := mul(inv, sub(2, mul(b, inv))) // inverse mod 2**128\n            res_ :=\n                mul(\n                    // divide [a1 a0] by the factors of two\n                    // shift in bits from `a1` into `a0`\n                    // for this we need to flip `t` such that it is `2**256 / t`\n                    or(mul(sub(a1, gt(r, a0)), add(div(sub(0, t), t), 1)), div(sub(a0, r), t)),\n                    // inverse mod 2**256\n                    mul(inv, sub(2, mul(b, inv)))\n                )\n        }\n    }\n\n    /**\n     * @notice Computes the division of a 768-bit integer `a` by a 512-bit integer `b`, knowing the reciprocal of `b`.\n     * @dev Credits chfast (Apache 2.0 License): <https://github.com/chfast/intx>.\n     * @param a0 The LSB of the numerator.\n     * @param a1 The middle limb of the numerator.\n     * @param a2 The MSB of the numerator.\n     * @param b0 The low limb of the divisor.\n     * @param b1 The high limb of the divisor.\n     * @param v The reciprocal `v` as defined in `_reciprocal_2`.\n     * @return The quotient floor(a/b).\n     */\n    function _div_2(uint256 a0, uint256 a1, uint256 a2, uint256 b0, uint256 b1, uint256 v)\n        internal\n        pure\n        returns (uint256)\n    {\n        (uint256 q0, uint256 q1) = _mul256(v, a2);\n        (q0, q1) = _add(q0, q1, a1, a2);\n        (uint256 t0, uint256 t1) = _mul256(b0, q1);\n        uint256 r1;\n        assembly {\n            r1 := sub(a1, mul(q1, b1))\n        }\n        uint256 r0;\n        (r0, r1) = _sub(a0, r1, t0, t1);\n        (r0, r1) = _sub(r0, r1, b0, b1);\n        assembly {\n            q1 := add(q1, 1)\n        }\n        if (r1 >= q0) {\n            assembly {\n                q1 := sub(q1, 1)\n            }\n            (r0, r1) = _add(r0, r1, b0, b1);\n        }\n        if (r1 > b1 || (r1 == b1 && r0 >= b0)) {\n            assembly {\n                q1 := add(q1, 1)\n            }\n            // we don't care about the remainder\n            // (r0, r1) = _sub(r0, r1, b0, b1);\n        }\n        return q1;\n    }\n\n    /**\n     * @notice Computes the division floor(a/b) of two 512-bit integers, knowing the result fits inside a uint256.\n     * @dev Credits chfast (Apache 2.0 License): <https://github.com/chfast/intx>.\n     * @param a0 LSB of the numerator.\n     * @param a1 MSB of the numerator.\n     * @param b0 LSB of the divisor.\n     * @param b1 MSB of the divisor.\n     * @return res_ The quotient floor(a/b).\n     */\n    function _div(uint256 a0, uint256 a1, uint256 b0, uint256 b1) internal pure returns (uint256 res_) {\n        if (b1 == 0) {\n            // prevent division by zero\n            if (b0 == 0) {\n                revert HugeUintDivisionFailed();\n            }\n            // if both operands fit inside a uint256, we can use the Solidity division operator\n            if (a1 == 0) {\n                unchecked {\n                    return a0 / b0;\n                }\n            }\n            // if the result fits inside a uint256, we can use the `div(Uint512,uint256)` function\n            if (b0 > a1) {\n                return _div256(a0, a1, b0);\n            }\n            revert HugeUintDivisionFailed();\n        }\n\n        // if the numerator is smaller than the denominator, the result is zero\n        if (a1 < b1 || (a1 == b1 && a0 < b0)) {\n            return 0;\n        }\n\n        // division algo\n        uint256 lsh = _clz(b1);\n        if (lsh == 0) {\n            // numerator is equal or larger than the denominator, and the denominator is at least 0b1000...\n            // the result is necessarily 1\n            return 1;\n        }\n\n        uint256 bn_lo;\n        uint256 bn_hi;\n        uint256 an_lo;\n        uint256 an_hi;\n        uint256 an_ex;\n        assembly {\n            let rsh := sub(256, lsh)\n            bn_lo := shl(lsh, b0)\n            bn_hi := or(shl(lsh, b1), shr(rsh, b0))\n            an_lo := shl(lsh, a0)\n            an_hi := or(shl(lsh, a1), shr(rsh, a0))\n            an_ex := shr(rsh, a1)\n        }\n        uint256 v = _reciprocal_2(bn_lo, bn_hi);\n        res_ = _div_2(an_lo, an_hi, an_ex, bn_lo, bn_hi, v);\n    }\n\n    /**\n     * @notice Computes the reciprocal `v = floor((2^512-1) / d) - 2^256`.\n     * @dev The input must be normalized (d >= 2^255).\n     * @param d The input value.\n     * @return v_ The reciprocal of d.\n     */\n    function _reciprocal(uint256 d) internal pure returns (uint256 v_) {\n        if (d & 0x8000000000000000000000000000000000000000000000000000000000000000 == 0) {\n            revert HugeUintDivisionFailed();\n        }\n        v_ = _div256(type(uint256).max, type(uint256).max - d, d);\n    }\n\n    /**\n     * @notice Computes the reciprocal `v = floor((2^768-1) / d) - 2^256`, where d is a uint512 integer.\n     * @dev Credits chfast (Apache 2.0 License): <https://github.com/chfast/intx>.\n     * @param d0 LSB of the input.\n     * @param d1 MSB of the input.\n     * @return v_ The reciprocal of d.\n     */\n    function _reciprocal_2(uint256 d0, uint256 d1) internal pure returns (uint256 v_) {\n        v_ = _reciprocal(d1);\n        uint256 p;\n        assembly {\n            p := mul(d1, v_)\n            p := add(p, d0)\n            if lt(p, d0) {\n                // carry out\n                v_ := sub(v_, 1)\n                if iszero(lt(p, d1)) {\n                    v_ := sub(v_, 1)\n                    p := sub(p, d1)\n                }\n                p := sub(p, d1)\n            }\n        }\n        (uint256 t0, uint256 t1) = _mul256(v_, d0);\n        assembly {\n            p := add(p, t1)\n            if lt(p, t1) {\n                // carry out\n                v_ := sub(v_, 1)\n                if and(iszero(lt(p, d1)), or(gt(p, d1), iszero(lt(t0, d0)))) {\n                    // if (<p, t0> >= <d1, d0>)\n                    v_ := sub(v_, 1)\n                }\n            }\n        }\n    }\n\n    /**\n     * @notice Counts the number of consecutive zero bits, starting from the left.\n     * @dev Credits Solady (MIT license): <https://github.com/Vectorized/solady>.\n     * @param x An unsigned integer.\n     * @return n_ The number of zeroes starting from the most significant bit.\n     */\n    function _clz(uint256 x) internal pure returns (uint256 n_) {\n        if (x == 0) {\n            return 256;\n        }\n        assembly {\n            n_ := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))\n            n_ := or(n_, shl(6, lt(0xffffffffffffffff, shr(n_, x))))\n            n_ := or(n_, shl(5, lt(0xffffffff, shr(n_, x))))\n            n_ := or(n_, shl(4, lt(0xffff, shr(n_, x))))\n            n_ := or(n_, shl(3, lt(0xff, shr(n_, x))))\n            n_ :=\n                add(\n                    xor(\n                        n_,\n                        byte(\n                            and(0x1f, shr(shr(n_, x), 0x8421084210842108cc6318c6db6d54be)),\n                            0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff\n                        )\n                    ),\n                    iszero(x)\n                )\n        }\n    }\n}\n"},{"file_path":"src/UsdnProtocol/libraries/UsdnProtocolVaultLibrary.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { ERC165Checker } from \"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { FixedPointMathLib } from \"solady/src/utils/FixedPointMathLib.sol\";\nimport { SafeTransferLib } from \"solady/src/utils/SafeTransferLib.sol\";\n\nimport { PriceInfo } from \"../../interfaces/OracleMiddleware/IOracleMiddlewareTypes.sol\";\nimport { IUsdn } from \"../../interfaces/Usdn/IUsdn.sol\";\nimport { IPaymentCallback } from \"../../interfaces/UsdnProtocol/IPaymentCallback.sol\";\nimport { IUsdnProtocolErrors } from \"../../interfaces/UsdnProtocol/IUsdnProtocolErrors.sol\";\nimport { IUsdnProtocolEvents } from \"../../interfaces/UsdnProtocol/IUsdnProtocolEvents.sol\";\nimport { IUsdnProtocolTypes as Types } from \"../../interfaces/UsdnProtocol/IUsdnProtocolTypes.sol\";\nimport { DoubleEndedQueue } from \"../../libraries/DoubleEndedQueue.sol\";\nimport { SignedMath } from \"../../libraries/SignedMath.sol\";\nimport { UsdnProtocolActionsLongLibrary as ActionsLong } from \"./UsdnProtocolActionsLongLibrary.sol\";\nimport { UsdnProtocolActionsUtilsLibrary as ActionsUtils } from \"./UsdnProtocolActionsUtilsLibrary.sol\";\nimport { UsdnProtocolConstantsLibrary as Constants } from \"./UsdnProtocolConstantsLibrary.sol\";\nimport { UsdnProtocolCoreLibrary as Core } from \"./UsdnProtocolCoreLibrary.sol\";\nimport { UsdnProtocolLongLibrary as Long } from \"./UsdnProtocolLongLibrary.sol\";\nimport { UsdnProtocolUtilsLibrary as Utils } from \"./UsdnProtocolUtilsLibrary.sol\";\n\nlibrary UsdnProtocolVaultLibrary {\n    using DoubleEndedQueue for DoubleEndedQueue.Deque;\n    using SafeCast for uint256;\n    using SafeTransferLib for address;\n    using SignedMath for int256;\n\n    /**\n     * @dev Parameters for the internal {_initiateDeposit} function.\n     * The user's input for the minimum amount of shares to receive is not guaranteed due to the price difference\n     * between the initiate and validate actions.\n     * @param user The address of the user initiating the deposit.\n     * @param to The recipient of the USDN tokens.\n     * @param validator The address that is supposed to validate the deposit and receive the security deposit.\n     * @param amount The amount of assets to deposit.\n     * @param sharesOutMin The minimum amount of USDN shares to receive.\n     * @param securityDepositValue The value of the security deposit for the newly created deposit.\n     */\n    struct InitiateDepositParams {\n        address user;\n        address to;\n        address validator;\n        uint128 amount;\n        uint256 sharesOutMin;\n        uint64 securityDepositValue;\n    }\n\n    /**\n     * @dev Structure to hold the transient data during {_initiateDeposit}.\n     * @param lastPrice The last known price of the asset.\n     * @param isLiquidationPending Whether some liquidations still need to be performed.\n     * @param feeBps The vault deposit fee (in basis points).\n     * @param totalExpo The total exposure of the long side.\n     * @param balanceLong The balance of the long side.\n     * @param balanceVault The balance of the vault including the funding.\n     * @param usdnTotalShares Total minted shares of USDN.\n     * @param sdexToBurn The required amount of SDEX to burn for the deposit.\n     */\n    struct InitiateDepositData {\n        uint128 lastPrice;\n        bool isLiquidationPending;\n        uint16 feeBps;\n        uint256 totalExpo;\n        uint256 balanceLong;\n        uint256 balanceVault;\n        uint256 usdnTotalShares;\n        uint256 sdexToBurn;\n    }\n\n    /**\n     * @dev Parameters for the internal {_initiateWithdrawal} function.\n     * @param user The address of the user initiating the withdrawal.\n     * @param to The recipient of the assets.\n     * @param validator The address that is supposed to validate the withdrawal and receive the security deposit.\n     * @param usdnShares The amount of USDN shares to withdraw.\n     * @param amountOutMin The minimum amount of assets to receive.\n     * @param securityDepositValue The value of the security deposit for the newly created withdrawal.\n     */\n    struct WithdrawalParams {\n        address user;\n        address to;\n        address validator;\n        uint152 usdnShares;\n        uint256 amountOutMin;\n        uint64 securityDepositValue;\n    }\n\n    /**\n     * @dev Structure to hold the transient data during {_initiateWithdrawal}.\n     * @param usdnTotalShares The total supply of USDN shares.\n     * @param totalExpo The current total exposure.\n     * @param balanceLong The balance of the long side.\n     * @param balanceVault The balance of the vault including the funding.\n     * @param withdrawalAmountAfterFees The predicted amount of assets that will be withdrawn after fees.\n     * @param lastPrice The last known price of the asset.\n     * @param feeBps The vault deposit fee (in basis points).\n     * @param isLiquidationPending Whether some liquidations still need to be performed.\n     */\n    struct WithdrawalData {\n        uint256 usdnTotalShares;\n        uint256 totalExpo;\n        uint256 balanceLong;\n        uint256 balanceVault;\n        uint256 withdrawalAmountAfterFees;\n        uint128 lastPrice;\n        uint16 feeBps;\n        bool isLiquidationPending;\n    }\n\n    /// @notice See {IUsdnProtocolActions.initiateDeposit}.\n    function initiateDeposit(\n        uint128 amount,\n        uint256 sharesOutMin,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        Types.PreviousActionsData calldata previousActionsData\n    ) external returns (bool success_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (deadline < block.timestamp) {\n            revert IUsdnProtocolErrors.UsdnProtocolDeadlineExceeded();\n        }\n        uint64 securityDepositValue = s._securityDepositValue;\n        if (msg.value < securityDepositValue) {\n            revert IUsdnProtocolErrors.UsdnProtocolSecurityDepositTooLow();\n        }\n        uint256 balanceBefore = address(this).balance;\n\n        uint256 validatorAmount;\n        (validatorAmount, success_) = _initiateDeposit(\n            InitiateDepositParams({\n                user: msg.sender,\n                to: to,\n                validator: validator,\n                amount: amount,\n                sharesOutMin: sharesOutMin,\n                securityDepositValue: securityDepositValue\n            }),\n            currentPriceData\n        );\n\n        uint256 amountToRefund;\n        if (success_) {\n            unchecked {\n                amountToRefund += _executePendingActionOrRevert(previousActionsData);\n            }\n        }\n\n        // refund any securityDeposit from a stale pending action to the validator\n        if (validatorAmount > 0) {\n            if (validator != msg.sender) {\n                balanceBefore -= validatorAmount;\n                Utils._refundEther(validatorAmount, validator);\n            } else {\n                amountToRefund += validatorAmount;\n            }\n        }\n\n        Utils._refundExcessEther(securityDepositValue, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolActions.validateDeposit}.\n    function validateDeposit(\n        address payable validator,\n        bytes calldata depositPriceData,\n        Types.PreviousActionsData calldata previousActionsData\n    ) external returns (bool success_) {\n        uint256 balanceBefore = address(this).balance;\n\n        uint256 amountToRefund;\n        (amountToRefund, success_) = _validateDeposit(validator, depositPriceData);\n        uint256 securityDeposit;\n        if (success_) {\n            securityDeposit = _executePendingActionOrRevert(previousActionsData);\n        }\n        if (msg.sender != validator) {\n            Utils._refundEther(amountToRefund, validator);\n            balanceBefore -= amountToRefund;\n            amountToRefund = securityDeposit;\n        } else {\n            amountToRefund += securityDeposit;\n        }\n        Utils._refundExcessEther(0, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolActions.initiateWithdrawal}.\n    function initiateWithdrawal(\n        uint152 usdnShares,\n        uint256 amountOutMin,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        Types.PreviousActionsData calldata previousActionsData\n    ) external returns (bool success_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (deadline < block.timestamp) {\n            revert IUsdnProtocolErrors.UsdnProtocolDeadlineExceeded();\n        }\n        uint64 securityDepositValue = s._securityDepositValue;\n        if (msg.value < securityDepositValue) {\n            revert IUsdnProtocolErrors.UsdnProtocolSecurityDepositTooLow();\n        }\n\n        uint256 balanceBefore = address(this).balance;\n\n        uint256 validatorAmount;\n        (validatorAmount, success_) = _initiateWithdrawal(\n            WithdrawalParams({\n                user: msg.sender,\n                to: to,\n                validator: validator,\n                usdnShares: usdnShares,\n                amountOutMin: amountOutMin,\n                securityDepositValue: securityDepositValue\n            }),\n            currentPriceData\n        );\n\n        uint256 amountToRefund;\n        if (success_) {\n            unchecked {\n                amountToRefund += _executePendingActionOrRevert(previousActionsData);\n            }\n        }\n\n        // refund any securityDeposit from a stale pending action to the validator\n        if (validatorAmount > 0) {\n            if (validator != msg.sender) {\n                balanceBefore -= validatorAmount;\n                Utils._refundEther(validatorAmount, validator);\n            } else {\n                amountToRefund += validatorAmount;\n            }\n        }\n        Utils._refundExcessEther(securityDepositValue, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolActions.validateWithdrawal}.\n    function validateWithdrawal(\n        address payable validator,\n        bytes calldata withdrawalPriceData,\n        Types.PreviousActionsData calldata previousActionsData\n    ) external returns (bool success_) {\n        uint256 balanceBefore = address(this).balance;\n\n        uint256 amountToRefund;\n        (amountToRefund, success_) = _validateWithdrawal(validator, withdrawalPriceData);\n        uint256 securityDeposit;\n        if (success_) {\n            securityDeposit = _executePendingActionOrRevert(previousActionsData);\n        }\n        if (msg.sender != validator) {\n            Utils._refundEther(amountToRefund, validator);\n            balanceBefore -= amountToRefund;\n            amountToRefund = securityDeposit;\n        } else {\n            amountToRefund += securityDeposit;\n        }\n        Utils._refundExcessEther(0, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolFallback.getActionablePendingActions}.\n    function getActionablePendingActions(address currentUser, uint256 lookAhead, uint256 maxIter)\n        external\n        view\n        returns (Types.PendingAction[] memory actions_, uint128[] memory rawIndices_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 queueLength = s._pendingActionsQueue.length();\n        if (queueLength == 0) {\n            // empty queue, early return\n            return (actions_, rawIndices_);\n        }\n        if (maxIter < Constants.MIN_ACTIONABLE_PENDING_ACTIONS_ITER) {\n            maxIter = Constants.MIN_ACTIONABLE_PENDING_ACTIONS_ITER;\n        }\n        if (queueLength < maxIter) {\n            maxIter = queueLength;\n        }\n        actions_ = new Types.PendingAction[](maxIter);\n        rawIndices_ = new uint128[](maxIter);\n\n        uint256 lowLatencyDeadline = s._lowLatencyValidatorDeadline;\n        // the lookAhead allows to retrieve pending actions which will be actionable some time after block.timestamp. By\n        // subtracting this value to `lowLatencyDeadline`, the range where actions are considered actionable with the\n        // low-latency oracle is increased\n        if (lookAhead > lowLatencyDeadline) {\n            lowLatencyDeadline = 0; // avoid underflow\n        } else {\n            unchecked {\n                lowLatencyDeadline -= lookAhead; // checked above\n            }\n        }\n        uint16 middlewareLowLatencyDelay = s._oracleMiddleware.getLowLatencyDelay();\n        uint256 onChainDeadline = s._onChainValidatorDeadline;\n        // same comment as above, changing this value increases the range where actions are considered actionable\n        // with the on-chain oracle\n        if (lookAhead > onChainDeadline) {\n            onChainDeadline = 0; // avoid underflow\n        } else {\n            unchecked {\n                onChainDeadline -= lookAhead;\n            }\n        }\n        uint256 i;\n        uint256 j;\n        uint256 arrayLen;\n        do {\n            // since `i` cannot be greater or equal to `queueLength`, there is no risk of reverting\n            (Types.PendingAction memory candidate, uint128 rawIndex) = s._pendingActionsQueue.at(i);\n\n            if (candidate.timestamp == 0 || candidate.validator == currentUser) {\n                // if the currentUser is equal to the validator of the pending action, then the pending action is not\n                // actionable by this user (it will get validated automatically by their action)\n                // and so we need to return the next item in the queue so that they can validate a third-party pending\n                // action (if any)\n                if (arrayLen > 0) {\n                    rawIndices_[j] = rawIndex;\n                    unchecked {\n                        j++;\n                    }\n                }\n                // try the next one\n                unchecked {\n                    i++;\n                }\n            } else if (\n                _isActionable(candidate.timestamp, lowLatencyDeadline, middlewareLowLatencyDelay, onChainDeadline)\n            ) {\n                // we found an actionable pending action\n                actions_[j] = candidate;\n                rawIndices_[j] = rawIndex;\n\n                // continue looking\n                unchecked {\n                    i++;\n                    j++;\n                    arrayLen = j;\n                }\n            } else if (block.timestamp > candidate.timestamp + middlewareLowLatencyDelay) {\n                // the pending action is not actionable but some more recent ones might be (with low-latency oracle)\n                // continue looking\n                if (arrayLen > 0) {\n                    rawIndices_[j] = rawIndex;\n                    unchecked {\n                        j++;\n                    }\n                }\n                unchecked {\n                    i++;\n                }\n            } else {\n                // the pending action is not actionable (it is too recent),\n                // following actions can't be actionable either so we return\n                break;\n            }\n        } while (i < maxIter);\n        assembly (\"memory-safe\") {\n            // shrink the size of the arrays\n            mstore(actions_, arrayLen)\n            mstore(rawIndices_, arrayLen)\n        }\n    }\n\n    /// @notice See {IUsdnProtocolVault.usdnPrice(uint128)}.\n    function usdnPrice(uint128 currentPrice) external view returns (uint256 price_) {\n        price_ = usdnPrice(currentPrice, uint128(block.timestamp));\n    }\n\n    /// @notice See {IUsdnProtocolVault.usdnPrice(uint128,uint128)}.\n    function usdnPrice(uint128 currentPrice, uint128 timestamp) public view returns (uint256 price_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        price_ = _calcUsdnPrice(\n            vaultAssetAvailableWithFunding(currentPrice, timestamp),\n            currentPrice,\n            s._usdn.totalSupply(),\n            s._assetDecimals\n        );\n    }\n\n    /// @notice See {IUsdnProtocolVault.vaultAssetAvailableWithFunding}.\n    function vaultAssetAvailableWithFunding(uint128 currentPrice, uint128 timestamp)\n        public\n        view\n        returns (uint256 available_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (timestamp < s._lastUpdateTimestamp) {\n            revert IUsdnProtocolErrors.UsdnProtocolTimestampTooOld();\n        }\n\n        (uint256 longAvailable, int256 fee) = Core.longAssetAvailableWithFunding(currentPrice, timestamp);\n\n        return (s._balanceLong + s._balanceVault - FixedPointMathLib.abs(fee)) - longAvailable;\n    }\n\n    /**\n     * @notice Executes the first actionable pending action.\n     * @dev Will revert if the corresponding price data is invalid.\n     * @param data The price data and corresponding raw indices.\n     * @return securityDepositValue_ The security deposit value of the executed action.\n     */\n    function _executePendingActionOrRevert(Types.PreviousActionsData calldata data)\n        public\n        returns (uint256 securityDepositValue_)\n    {\n        bool success;\n        (success,,, securityDepositValue_) = _executePendingAction(data);\n        if (!success) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingActionData();\n        }\n    }\n\n    /**\n     * @notice Executes the first actionable pending action and reports the outcome.\n     * @param data The price data and corresponding raw indices.\n     * @return success_ Whether the price data is valid.\n     * @return executed_ Whether the pending action was executed (false if the queue has no actionable item).\n     * @return liquidated_ Whether the position corresponding to the pending action was liquidated.\n     * @return securityDepositValue_ The security deposit value of the executed action.\n     */\n    function _executePendingAction(Types.PreviousActionsData calldata data)\n        public\n        returns (bool success_, bool executed_, bool liquidated_, uint256 securityDepositValue_)\n    {\n        (Types.PendingAction memory pending, uint128 rawIndex) = _getActionablePendingAction();\n        if (pending.action == Types.ProtocolAction.None) {\n            // no pending action\n            return (true, false, false, 0);\n        }\n        uint256 length = data.priceData.length;\n        if (data.rawIndices.length != length || length < 1) {\n            return (false, false, false, 0);\n        }\n        uint128 offset;\n        unchecked {\n            // underflow is desired here (wrap-around)\n            offset = rawIndex - data.rawIndices[0];\n        }\n        if (offset >= length || data.rawIndices[offset] != rawIndex) {\n            return (false, false, false, 0);\n        }\n        bytes calldata priceData = data.priceData[offset];\n        // for safety we consider that no pending action was validated by default\n        if (pending.action == Types.ProtocolAction.ValidateDeposit) {\n            executed_ = _validateDepositWithAction(pending, priceData);\n        } else if (pending.action == Types.ProtocolAction.ValidateWithdrawal) {\n            executed_ = _validateWithdrawalWithAction(pending, priceData);\n        } else if (pending.action == Types.ProtocolAction.ValidateOpenPosition) {\n            (executed_, liquidated_,) = ActionsLong._validateOpenPositionWithAction(pending, priceData);\n        } else if (pending.action == Types.ProtocolAction.ValidateClosePosition) {\n            (executed_, liquidated_) = ActionsLong._validateClosePositionWithAction(pending, priceData);\n        }\n\n        success_ = true;\n\n        if (executed_ || liquidated_) {\n            Utils._clearPendingAction(pending.validator, rawIndex);\n            securityDepositValue_ = pending.securityDepositValue;\n            emit IUsdnProtocolEvents.SecurityDepositRefunded(pending.validator, msg.sender, securityDepositValue_);\n        }\n    }\n\n    /**\n     * @notice This is the mutating version of {getActionablePendingActions}, where empty items at the front of the list\n     * are removed.\n     * @return action_ The first actionable pending action if any, otherwise a struct with all fields set to zero and\n     * {IUsdnProtocolTypes.ProtocolAction}'s `None` action.\n     * @return rawIndex_ The raw index in the queue for the returned pending action, or zero if empty.\n     */\n    function _getActionablePendingAction() internal returns (Types.PendingAction memory action_, uint128 rawIndex_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 queueLength = s._pendingActionsQueue.length();\n        if (queueLength == 0) {\n            // empty queue, early return\n            return (action_, rawIndex_);\n        }\n        uint256 maxIter = Constants.MIN_ACTIONABLE_PENDING_ACTIONS_ITER;\n        if (queueLength < maxIter) {\n            maxIter = queueLength;\n        }\n\n        uint128 lowLatencyDeadline = s._lowLatencyValidatorDeadline;\n        uint16 middlewareLowLatencyDelay = s._oracleMiddleware.getLowLatencyDelay();\n        uint128 onChainDeadline = s._onChainValidatorDeadline;\n        uint256 i;\n        uint256 j;\n        do {\n            // since we will never loop more than `queueLength` times, there is no risk of reverting\n            (Types.PendingAction memory candidate, uint128 rawIndex) = s._pendingActionsQueue.at(j);\n            unchecked {\n                i++;\n            }\n            if (candidate.timestamp == 0) {\n                // remove the stale pending action\n                s._pendingActionsQueue.clearAt(rawIndex);\n                // if we were removing another item than the first one, we increment j (otherwise we keep looking at the\n                // first item because it was shifted to the front)\n                if (j > 0) {\n                    unchecked {\n                        j++;\n                    }\n                }\n                // try the next one\n                continue;\n            } else if (\n                _isActionable(candidate.timestamp, lowLatencyDeadline, middlewareLowLatencyDelay, onChainDeadline)\n            ) {\n                // we found an actionable pending action\n                return (candidate, rawIndex);\n            } else if (block.timestamp > candidate.timestamp + middlewareLowLatencyDelay) {\n                // the pending action is not actionable but some more recent ones might be (with low-latency oracle)\n                // continue looking\n                unchecked {\n                    j++;\n                }\n                continue;\n            }\n            // the first pending action is not actionable, none of the following ones will be either\n            return (action_, rawIndex_);\n        } while (i < maxIter);\n    }\n\n    /**\n     * @notice Prepares the data for the {initiateDeposit} function.\n     * @dev Updates the protocol's balances if the price is fresh.\n     * @param validator The address that is supposed to validate the deposit and receive the security deposit.\n     * @param amount The amount of asset to deposit.\n     * @param sharesOutMin The minimum amount of USDN shares to receive.\n     * @param currentPriceData The current price data.\n     * @return data_ The transient data for the `deposit` action.\n     */\n    function _prepareInitiateDepositData(\n        address validator,\n        uint128 amount,\n        uint256 sharesOutMin,\n        bytes calldata currentPriceData\n    ) internal returns (InitiateDepositData memory data_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        PriceInfo memory currentPrice = Utils._getOraclePrice(\n            Types.ProtocolAction.InitiateDeposit,\n            block.timestamp,\n            Utils._calcActionId(validator, uint128(block.timestamp)),\n            currentPriceData\n        );\n\n        (, data_.isLiquidationPending) = Long._applyPnlAndFundingAndLiquidate(\n            currentPrice.neutralPrice,\n            currentPrice.timestamp,\n            s._liquidationIteration,\n            Types.ProtocolAction.InitiateDeposit,\n            currentPriceData\n        );\n\n        if (data_.isLiquidationPending) {\n            return data_;\n        }\n\n        ActionsUtils._checkImbalanceLimitDeposit(amount);\n\n        // apply fees on amount\n        data_.feeBps = s._vaultFeeBps;\n        uint128 fees = FixedPointMathLib.fullMulDiv(amount, data_.feeBps, Constants.BPS_DIVISOR).toUint128();\n        uint128 amountAfterFees = amount - fees;\n\n        data_.totalExpo = s._totalExpo;\n        data_.lastPrice = s._lastPrice;\n        // extrapolate balances to block.timestamp to avoid that the user pays funding prior to initiating the deposit\n        int256 protocolFee;\n        (data_.balanceLong, protocolFee) = Core.longAssetAvailableWithFunding(data_.lastPrice, uint128(block.timestamp));\n        // gas optimization, same formula as `vaultAssetAvailableWithFunding`\n        data_.balanceVault = (s._balanceLong + s._balanceVault - FixedPointMathLib.abs(protocolFee)) - data_.balanceLong;\n        if (data_.balanceVault == 0) {\n            // can't mint USDN if the vault is empty\n            revert IUsdnProtocolErrors.UsdnProtocolEmptyVault();\n        }\n\n        IUsdn usdn = s._usdn;\n        data_.usdnTotalShares = usdn.totalShares();\n\n        // calculate the amount of SDEX tokens to burn\n        uint256 usdnSharesToMintEstimated =\n            Utils._calcMintUsdnShares(amountAfterFees, data_.balanceVault + fees, data_.usdnTotalShares);\n        if (usdnSharesToMintEstimated < sharesOutMin) {\n            revert IUsdnProtocolErrors.UsdnProtocolAmountReceivedTooSmall();\n        }\n        uint256 usdnToMintEstimated = usdn.convertToTokens(usdnSharesToMintEstimated);\n        // we want to at least mint 1 wei of USDN\n        if (usdnToMintEstimated == 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolDepositTooSmall();\n        }\n        uint32 burnRatio = s._sdexBurnOnDepositRatio;\n        data_.sdexToBurn = Utils._calcSdexToBurn(usdnToMintEstimated, burnRatio);\n    }\n\n    /**\n     * @notice Prepares the pending action struct for a deposit and adds it to the queue.\n     * @param to The recipient of the minted USDN.\n     * @param validator The address that is supposed to validate the deposit and receive the security deposit.\n     * @param securityDepositValue The value of the security deposit for the newly created pending action.\n     * @param amount The amount of assets to deposit (before fees).\n     * @param data The deposit action data.\n     * @return amountToRefund_ The security deposit value of a stale pending action.\n     */\n    function _createDepositPendingAction(\n        address to,\n        address validator,\n        uint64 securityDepositValue,\n        uint128 amount,\n        InitiateDepositData memory data\n    ) internal returns (uint256 amountToRefund_) {\n        Types.DepositPendingAction memory pendingAction = Types.DepositPendingAction({\n            action: Types.ProtocolAction.ValidateDeposit,\n            timestamp: uint40(block.timestamp),\n            feeBps: data.feeBps,\n            to: to,\n            validator: validator,\n            securityDepositValue: securityDepositValue,\n            _unused: 0,\n            amount: amount,\n            assetPrice: data.lastPrice,\n            totalExpo: data.totalExpo,\n            balanceVault: data.balanceVault,\n            balanceLong: data.balanceLong,\n            usdnTotalShares: data.usdnTotalShares\n        });\n\n        amountToRefund_ = Core._addPendingAction(validator, Utils._convertDepositPendingAction(pendingAction));\n    }\n\n    /**\n     * @notice Attempts to initiate a deposit of assets into the vault to mint USDN.\n     * @dev Consults the current oracle middleware implementation to know the expected format for the price data, using\n     * the {IUsdnProtocolTypes.ProtocolAction}'s `InitiateDeposit` action. The price validation might require payment\n     * according to the return value of the {IBaseOracleMiddleware.validationCost} function of the middleware.\n     * @param params The parameters for the deposit.\n     * @param currentPriceData The current price data.\n     * @return amountToRefund_ If there are pending liquidations we'll refund the `securityDepositValue`,\n     * else we'll only refund the security deposit value of the stale pending action.\n     * @return isInitiated_ Whether the action is initiated.\n     */\n    function _initiateDeposit(InitiateDepositParams memory params, bytes calldata currentPriceData)\n        internal\n        returns (uint256 amountToRefund_, bool isInitiated_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (params.to == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressTo();\n        }\n        if (params.validator == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressValidator();\n        }\n        if (params.amount == 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolZeroAmount();\n        }\n\n        InitiateDepositData memory data =\n            _prepareInitiateDepositData(params.validator, params.amount, params.sharesOutMin, currentPriceData);\n\n        // early return in case there are still pending liquidations\n        if (data.isLiquidationPending) {\n            return (params.securityDepositValue, false);\n        }\n\n        s._pendingBalanceVault += Utils._toInt256(params.amount);\n\n        amountToRefund_ =\n            _createDepositPendingAction(params.to, params.validator, params.securityDepositValue, params.amount, data);\n\n        if (ERC165Checker.supportsInterface(msg.sender, type(IPaymentCallback).interfaceId)) {\n            if (data.sdexToBurn > 0) {\n                Utils._transferCallback(s._sdex, data.sdexToBurn, address(this));\n            }\n            Utils._transferCallback(s._asset, params.amount, address(this));\n        } else {\n            if (data.sdexToBurn > 0) {\n                // slither-disable-next-line arbitrary-send-erc20\n                address(s._sdex).safeTransferFrom(params.user, address(this), data.sdexToBurn);\n            }\n            // slither-disable-next-line arbitrary-send-erc20\n            address(s._asset).safeTransferFrom(params.user, address(this), params.amount);\n        }\n\n        isInitiated_ = true;\n\n        emit IUsdnProtocolEvents.InitiatedDeposit(\n            params.to, params.validator, params.amount, data.feeBps, block.timestamp, data.sdexToBurn\n        );\n    }\n\n    /**\n     * @notice Attempts to validate the deposit pending action assigned to the given `validator`.\n     * @dev If successful, the pending action will be cleared from the queue.\n     * @param validator The address that is supposed to validate the deposit and receive the security deposit.\n     * @param priceData The price data for the pending action to validate.\n     * @return securityDepositValue_ The value of the security deposit to refund.\n     * @return isValidated_ Whether the action is validated.\n     */\n    function _validateDeposit(address validator, bytes calldata priceData)\n        internal\n        returns (uint256 securityDepositValue_, bool isValidated_)\n    {\n        (Types.PendingAction memory pending, uint128 rawIndex) = Core._getPendingActionOrRevert(validator);\n\n        // check type of action\n        if (pending.action != Types.ProtocolAction.ValidateDeposit) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingAction();\n        }\n        // sanity check\n        if (pending.validator != validator) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingAction();\n        }\n\n        isValidated_ = _validateDepositWithAction(pending, priceData);\n\n        if (isValidated_) {\n            Utils._clearPendingAction(validator, rawIndex);\n            securityDepositValue_ = pending.securityDepositValue;\n        }\n    }\n\n    /**\n     * @notice Attempts to validate the given deposit pending action.\n     * @param pending The pending action to validate.\n     * @param priceData The corresponding price data.\n     * @return isValidated_ Whether the action is validated.\n     */\n    function _validateDepositWithAction(Types.PendingAction memory pending, bytes calldata priceData)\n        internal\n        returns (bool isValidated_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        Types.DepositPendingAction memory deposit = Utils._toDepositPendingAction(pending);\n\n        PriceInfo memory currentPrice = Utils._getOraclePrice(\n            Types.ProtocolAction.ValidateDeposit,\n            deposit.timestamp,\n            Utils._calcActionId(deposit.validator, deposit.timestamp),\n            priceData\n        );\n\n        {\n            // adjust balances\n            (, bool isLiquidationPending) = Long._applyPnlAndFundingAndLiquidate(\n                currentPrice.neutralPrice,\n                currentPrice.timestamp,\n                s._liquidationIteration,\n                Types.ProtocolAction.ValidateDeposit,\n                priceData\n            );\n\n            // early return in case there are still pending liquidations\n            if (isLiquidationPending) {\n                return false;\n            }\n        }\n\n        // we calculate the amount of USDN to mint, either considering the vault balance at the time of the initiate\n        // action, or the current balance with the new price. We will use the higher of the two to mint. Funding between\n        // the initiate and validate actions is ignored. So any balance difference due to funding will be ignored when\n        // calculating the minted USDN\n        uint128 fees = FixedPointMathLib.fullMulDiv(deposit.amount, deposit.feeBps, Constants.BPS_DIVISOR).toUint128();\n        uint128 amountAfterFees = deposit.amount - fees;\n\n        uint256 balanceVault = deposit.balanceVault;\n        if (currentPrice.price < deposit.assetPrice) {\n            // without considering the funding, when the price decreases, the balance of the vault increases\n            int256 available = Utils._vaultAssetAvailable(\n                deposit.totalExpo,\n                deposit.balanceVault,\n                deposit.balanceLong,\n                currentPrice.price.toUint128(),\n                deposit.assetPrice\n            );\n            if (available < 0) {\n                // sanity check, should not happen\n                balanceVault = 0;\n            } else {\n                balanceVault = uint256(available);\n            }\n        }\n\n        s._balanceVault += deposit.amount; // we credit the full deposit amount\n        s._pendingBalanceVault -= Utils._toInt256(deposit.amount);\n\n        uint256 mintedTokens = s._usdn.mintShares(\n            deposit.to, Utils._calcMintUsdnShares(amountAfterFees, balanceVault + fees, deposit.usdnTotalShares)\n        );\n        isValidated_ = true;\n        emit IUsdnProtocolEvents.ValidatedDeposit(\n            deposit.to, deposit.validator, amountAfterFees, mintedTokens, deposit.timestamp\n        );\n    }\n\n    /**\n     * @notice Prepares the data for the {initiateWithdrawal} function.\n     * @dev Updates the protocol's balances if the price is fresh.\n     * @param validator The address that is supposed to validate the withdrawal and receive the security deposit.\n     * @param usdnShares The amount of USDN shares to burn.\n     * @param amountOutMin The estimated minimum amount of assets to receive.\n     * @param currentPriceData The current price data.\n     * @return data_ The transient data for the `withdrawal` action.\n     */\n    function _prepareWithdrawalData(\n        address validator,\n        uint152 usdnShares,\n        uint256 amountOutMin,\n        bytes calldata currentPriceData\n    ) internal returns (WithdrawalData memory data_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        PriceInfo memory currentPrice = Utils._getOraclePrice(\n            Types.ProtocolAction.InitiateWithdrawal,\n            block.timestamp,\n            Utils._calcActionId(validator, uint128(block.timestamp)),\n            currentPriceData\n        );\n\n        (, data_.isLiquidationPending) = Long._applyPnlAndFundingAndLiquidate(\n            currentPrice.neutralPrice,\n            currentPrice.timestamp,\n            s._liquidationIteration,\n            Types.ProtocolAction.InitiateWithdrawal,\n            currentPriceData\n        );\n\n        // early return in case there are still pending liquidations\n        if (data_.isLiquidationPending) {\n            return data_;\n        }\n\n        data_.totalExpo = s._totalExpo;\n        data_.lastPrice = s._lastPrice;\n        // extrapolate balances to block.timestamp to ensure that the user pays funding up to the initiation of the\n        // withdrawal\n        int256 protocolFee;\n        (data_.balanceLong, protocolFee) = Core.longAssetAvailableWithFunding(data_.lastPrice, uint128(block.timestamp));\n        // gas optimization, same formula as `vaultAssetAvailableWithFunding`\n        data_.balanceVault = (s._balanceLong + s._balanceVault - FixedPointMathLib.abs(protocolFee)) - data_.balanceLong;\n        data_.usdnTotalShares = s._usdn.totalShares();\n        data_.feeBps = s._vaultFeeBps;\n        data_.withdrawalAmountAfterFees =\n            Utils._calcAmountToWithdraw(usdnShares, data_.balanceVault, data_.usdnTotalShares, data_.feeBps);\n        if (data_.withdrawalAmountAfterFees < amountOutMin) {\n            revert IUsdnProtocolErrors.UsdnProtocolAmountReceivedTooSmall();\n        }\n        ActionsUtils._checkImbalanceLimitWithdrawal(data_.withdrawalAmountAfterFees, data_.totalExpo);\n    }\n\n    /**\n     * @notice Initiates a withdrawal of assets from the vault by providing USDN tokens.\n     * @dev Consults the current oracle middleware implementation to know the expected format for the price data, using\n     * the {IUsdnProtocolTypes.ProtocolAction}'s `InitiateWithdrawal` action. The price validation might require payment\n     * according to the return value of the {IBaseOracleMiddleware.validationCost} function of the middleware.\n     * @param params The parameters for the withdrawal.\n     * @param currentPriceData The current price data.\n     * @return amountToRefund_ If there are pending liquidations we'll refund the sent security deposit,\n     * else we'll only refund the security deposit value of the stale pending action.\n     * @return isInitiated_ Whether the action is initiated.\n     */\n    function _initiateWithdrawal(WithdrawalParams memory params, bytes calldata currentPriceData)\n        internal\n        returns (uint256 amountToRefund_, bool isInitiated_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (params.to == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressTo();\n        }\n        if (params.validator == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressValidator();\n        }\n        if (params.usdnShares == 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolZeroAmount();\n        }\n\n        WithdrawalData memory data =\n            _prepareWithdrawalData(params.validator, params.usdnShares, params.amountOutMin, currentPriceData);\n\n        if (data.isLiquidationPending) {\n            return (params.securityDepositValue, false);\n        }\n\n        amountToRefund_ = Core._createWithdrawalPendingAction(\n            params.to, params.validator, params.usdnShares, params.securityDepositValue, data\n        );\n\n        // register the pending withdrawal for imbalance checks of future actions\n        s._pendingBalanceVault -= data.withdrawalAmountAfterFees.toInt256();\n\n        IUsdn usdn = s._usdn;\n        if (ERC165Checker.supportsInterface(msg.sender, type(IPaymentCallback).interfaceId)) {\n            // ask the msg.sender to send USDN shares and check the balance\n            Utils._usdnTransferCallback(usdn, params.usdnShares);\n        } else {\n            // retrieve the USDN shares, check that the balance is sufficient\n            usdn.transferSharesFrom(params.user, address(this), params.usdnShares);\n        }\n\n        isInitiated_ = true;\n        emit IUsdnProtocolEvents.InitiatedWithdrawal(\n            params.to, params.validator, usdn.convertToTokens(params.usdnShares), data.feeBps, block.timestamp\n        );\n    }\n\n    /**\n     * @notice Attempts to validate the withdrawal pending action assigned to the given `validator`.\n     * @dev If successful, the pending action will be cleared from the queue.\n     * @param validator The address that is supposed to validate the withdrawal and receive the security deposit.\n     * @param priceData The corresponding price data.\n     * @return securityDepositValue_ The value of the security deposit.\n     * @return isValidated_ Whether the action is validated.\n     */\n    function _validateWithdrawal(address validator, bytes calldata priceData)\n        internal\n        returns (uint256 securityDepositValue_, bool isValidated_)\n    {\n        (Types.PendingAction memory pending, uint128 rawIndex) = Core._getPendingActionOrRevert(validator);\n\n        // check type of action\n        if (pending.action != Types.ProtocolAction.ValidateWithdrawal) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingAction();\n        }\n        // sanity check\n        if (pending.validator != validator) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingAction();\n        }\n\n        isValidated_ = _validateWithdrawalWithAction(pending, priceData);\n\n        if (isValidated_) {\n            Utils._clearPendingAction(validator, rawIndex);\n            securityDepositValue_ = pending.securityDepositValue;\n        }\n    }\n\n    /**\n     * @notice Attempts to validate the given withdrawal pending action.\n     * @param pending The pending action data.\n     * @param priceData The current price data.\n     * @return isValidated_ Whether the action is validated.\n     */\n    function _validateWithdrawalWithAction(Types.PendingAction memory pending, bytes calldata priceData)\n        internal\n        returns (bool isValidated_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        Types.WithdrawalPendingAction memory withdrawal = Utils._toWithdrawalPendingAction(pending);\n\n        PriceInfo memory currentPrice = Utils._getOraclePrice(\n            Types.ProtocolAction.ValidateWithdrawal,\n            withdrawal.timestamp,\n            Utils._calcActionId(withdrawal.validator, withdrawal.timestamp),\n            priceData\n        );\n\n        (, bool isLiquidationPending) = Long._applyPnlAndFundingAndLiquidate(\n            currentPrice.neutralPrice,\n            currentPrice.timestamp,\n            s._liquidationIteration,\n            Types.ProtocolAction.ValidateWithdrawal,\n            priceData\n        );\n\n        // early return in case there are still pending liquidations\n        if (isLiquidationPending) {\n            return false;\n        }\n\n        uint256 available;\n        {\n            // we calculate the available balance of the vault side at the price of the validate action (ignoring any\n            // funding between the initiate and validate)\n            int256 vaultAssetAvailable = Utils._vaultAssetAvailable(\n                withdrawal.totalExpo,\n                withdrawal.balanceVault,\n                withdrawal.balanceLong,\n                currentPrice.price.toUint128(),\n                withdrawal.assetPrice\n            );\n\n            if (vaultAssetAvailable < 0) {\n                vaultAssetAvailable = 0;\n            }\n            available = uint256(vaultAssetAvailable);\n\n            // we compare it to the available balance from the initiate action\n            // we will use the lowest of the two amounts to redeem the underlying asset share\n            // cast is safe because vaultAssetAvailable cannot be negative\n            if (withdrawal.balanceVault <= uint256(vaultAssetAvailable)) {\n                available = withdrawal.balanceVault;\n            }\n        }\n\n        uint256 shares = Utils._mergeWithdrawalAmountParts(withdrawal.sharesLSB, withdrawal.sharesMSB);\n\n        // we can add back the _pendingBalanceVault we subtracted in the initiate action\n        uint256 tempWithdrawalAfterFees =\n            Utils._calcAmountToWithdraw(shares, withdrawal.balanceVault, withdrawal.usdnTotalShares, withdrawal.feeBps);\n        s._pendingBalanceVault += tempWithdrawalAfterFees.toInt256();\n\n        IUsdn usdn = s._usdn;\n        // calculate the amount of asset to transfer with the same fees as recorded during the initiate action\n        uint256 assetToTransferAfterFees =\n            Utils._calcAmountToWithdraw(shares, available, withdrawal.usdnTotalShares, withdrawal.feeBps);\n\n        usdn.burnShares(shares);\n\n        // send the asset to the user\n        if (assetToTransferAfterFees > 0) {\n            uint256 balanceVault = s._balanceVault;\n            // if there aren't enough funds in the vault, send what remains\n            if (assetToTransferAfterFees > balanceVault) {\n                assetToTransferAfterFees = balanceVault;\n            }\n\n            s._balanceVault = balanceVault - assetToTransferAfterFees;\n            address(s._asset).safeTransfer(withdrawal.to, assetToTransferAfterFees);\n        }\n\n        isValidated_ = true;\n\n        emit IUsdnProtocolEvents.ValidatedWithdrawal(\n            withdrawal.to,\n            withdrawal.validator,\n            assetToTransferAfterFees,\n            usdn.convertToTokens(shares),\n            withdrawal.timestamp\n        );\n    }\n\n    /**\n     * @notice Checks whether a pending action is actionable, i.e any user can validate it and retrieve the security\n     * deposit.\n     * @dev Between `initiateTimestamp` and `initiateTimestamp + lowLatencyDeadline`, the validator receives the\n     * security deposit.\n     * Between `initiateTimestamp + lowLatencyDelay` and `initiateTimestamp + lowLatencyDelay + onChainDeadline`,\n     * the validator also receives the security deposit.\n     * Outside of those periods, the security deposit goes to the user validating the pending action.\n     * @param initiateTimestamp The timestamp at which the action was initiated.\n     * @param lowLatencyDeadline The deadline after which the action is actionable with a low latency oracle.\n     * @param lowLatencyDelay The amount of time the action can be validated with a low latency oracle.\n     * @param onChainDeadline The deadline after which the action is actionable with an on-chain oracle.\n     * @return actionable_ Whether the pending action is actionable.\n     */\n    function _isActionable(\n        uint256 initiateTimestamp,\n        uint256 lowLatencyDeadline,\n        uint256 lowLatencyDelay,\n        uint256 onChainDeadline\n    ) internal view returns (bool actionable_) {\n        if (block.timestamp <= initiateTimestamp + lowLatencyDelay) {\n            // the validation must happen with a low-latency oracle\n            actionable_ = block.timestamp > initiateTimestamp + lowLatencyDeadline;\n        } else {\n            // the validation must happen with an on-chain oracle\n            actionable_ = block.timestamp > initiateTimestamp + lowLatencyDelay + onChainDeadline;\n        }\n    }\n\n    /**\n     * @notice Calculates the available balance in the vault if the price moves to `currentPrice`.\n     * @dev The funding is not taken into account.\n     * @param currentPrice The current or predicted price.\n     * @return available_ The available balance in the vault.\n     */\n    function _vaultAssetAvailable(uint128 currentPrice) internal view returns (int256 available_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        available_ =\n            Utils._vaultAssetAvailable(s._totalExpo, s._balanceVault, s._balanceLong, currentPrice, s._lastPrice);\n    }\n\n    /**\n     * @notice Calculates the price of the USDN token as a function of its total supply, the vault balance and the\n     * underlying asset price.\n     * @param vaultBalance The vault balance.\n     * @param assetPrice The price of the asset.\n     * @param usdnTotalSupply The total supply of the USDN token.\n     * @param assetDecimals The number of decimals of the underlying asset.\n     * @return price_ The price of the USDN token.\n     */\n    function _calcUsdnPrice(uint256 vaultBalance, uint128 assetPrice, uint256 usdnTotalSupply, uint8 assetDecimals)\n        internal\n        pure\n        returns (uint256 price_)\n    {\n        price_ = FixedPointMathLib.fullMulDiv(\n            vaultBalance, uint256(assetPrice) * 10 ** Constants.TOKENS_DECIMALS, usdnTotalSupply * 10 ** assetDecimals\n        );\n    }\n\n    /**\n     * @notice Calculates the lower 24 bits of the withdrawal amount (USDN shares).\n     * @param usdnShares The amount of USDN shares.\n     * @return sharesLSB_ The 24 least significant bits of the USDN shares.\n     */\n    function _calcWithdrawalAmountLSB(uint152 usdnShares) internal pure returns (uint24 sharesLSB_) {\n        sharesLSB_ = uint24(usdnShares);\n    }\n\n    /**\n     * @notice Calculates the higher 128 bits of the withdrawal amount (USDN shares).\n     * @param usdnShares The amount of USDN shares.\n     * @return sharesMSB_ The 128 most significant bits of the USDN shares.\n     */\n    function _calcWithdrawalAmountMSB(uint152 usdnShares) internal pure returns (uint128 sharesMSB_) {\n        sharesMSB_ = uint128(usdnShares >> 24);\n    }\n}\n"},{"file_path":"src/UsdnProtocol/UsdnProtocolActions.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { PausableUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol\";\nimport { EIP712Upgradeable } from \"@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol\";\n\nimport { IUsdnProtocolActions } from \"../interfaces/UsdnProtocol/IUsdnProtocolActions.sol\";\nimport { InitializableReentrancyGuard } from \"../utils/InitializableReentrancyGuard.sol\";\nimport { UsdnProtocolActionsLongLibrary as ActionsLong } from \"./libraries/UsdnProtocolActionsLongLibrary.sol\";\nimport { UsdnProtocolActionsUtilsLibrary as ActionsUtils } from \"./libraries/UsdnProtocolActionsUtilsLibrary.sol\";\nimport { UsdnProtocolUtilsLibrary as Utils } from \"./libraries/UsdnProtocolUtilsLibrary.sol\";\nimport { UsdnProtocolVaultLibrary as Vault } from \"./libraries/UsdnProtocolVaultLibrary.sol\";\n\nabstract contract UsdnProtocolActions is\n    IUsdnProtocolActions,\n    InitializableReentrancyGuard,\n    PausableUpgradeable,\n    EIP712Upgradeable\n{\n    /// @inheritdoc IUsdnProtocolActions\n    function initiateOpenPosition(\n        uint128 amount,\n        uint128 desiredLiqPrice,\n        uint128 userMaxPrice,\n        uint256 userMaxLeverage,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable whenNotPaused initializedAndNonReentrant returns (bool isInitiated_, PositionId memory posId_) {\n        Storage storage s = Utils._getMainStorage();\n\n        InitiateOpenPositionParams memory params = InitiateOpenPositionParams({\n            user: msg.sender,\n            to: to,\n            validator: validator,\n            amount: amount,\n            desiredLiqPrice: desiredLiqPrice,\n            userMaxPrice: userMaxPrice,\n            userMaxLeverage: userMaxLeverage,\n            deadline: deadline,\n            securityDepositValue: s._securityDepositValue\n        });\n\n        return ActionsLong.initiateOpenPosition(params, currentPriceData, previousActionsData);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function validateOpenPosition(\n        address payable validator,\n        bytes calldata openPriceData,\n        PreviousActionsData calldata previousActionsData\n    )\n        external\n        payable\n        whenNotPaused\n        initializedAndNonReentrant\n        returns (LongActionOutcome outcome_, PositionId memory posId_)\n    {\n        return ActionsLong.validateOpenPosition(validator, openPriceData, previousActionsData);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function initiateClosePosition(\n        PositionId calldata posId,\n        uint128 amountToClose,\n        uint256 userMinPrice,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        PreviousActionsData calldata previousActionsData,\n        bytes calldata delegationSignature\n    ) external payable whenNotPaused initializedAndNonReentrant returns (LongActionOutcome outcome_) {\n        Storage storage s = Utils._getMainStorage();\n\n        InitiateClosePositionParams memory params = InitiateClosePositionParams({\n            to: to,\n            validator: validator,\n            posId: posId,\n            amountToClose: amountToClose,\n            userMinPrice: userMinPrice,\n            deadline: deadline,\n            securityDepositValue: s._securityDepositValue,\n            domainSeparatorV4: _domainSeparatorV4()\n        });\n\n        return ActionsLong.initiateClosePosition(params, currentPriceData, previousActionsData, delegationSignature);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function validateClosePosition(\n        address payable validator,\n        bytes calldata closePriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable whenNotPaused initializedAndNonReentrant returns (LongActionOutcome outcome_) {\n        return ActionsLong.validateClosePosition(validator, closePriceData, previousActionsData);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function initiateDeposit(\n        uint128 amount,\n        uint256 sharesOutMin,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable whenNotPaused initializedAndNonReentrant returns (bool success_) {\n        return\n            Vault.initiateDeposit(amount, sharesOutMin, to, validator, deadline, currentPriceData, previousActionsData);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function validateDeposit(\n        address payable validator,\n        bytes calldata depositPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable whenNotPaused initializedAndNonReentrant returns (bool success_) {\n        return Vault.validateDeposit(validator, depositPriceData, previousActionsData);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function initiateWithdrawal(\n        uint152 usdnShares,\n        uint256 amountOutMin,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable whenNotPaused initializedAndNonReentrant returns (bool success_) {\n        return Vault.initiateWithdrawal(\n            usdnShares, amountOutMin, to, validator, deadline, currentPriceData, previousActionsData\n        );\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function validateWithdrawal(\n        address payable validator,\n        bytes calldata withdrawalPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable whenNotPaused initializedAndNonReentrant returns (bool success_) {\n        return Vault.validateWithdrawal(validator, withdrawalPriceData, previousActionsData);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function liquidate(bytes calldata currentPriceData)\n        external\n        payable\n        whenNotPaused\n        initializedAndNonReentrant\n        returns (LiqTickInfo[] memory liquidatedTicks_)\n    {\n        return ActionsUtils.liquidate(currentPriceData);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function validateActionablePendingActions(PreviousActionsData calldata previousActionsData, uint256 maxValidations)\n        external\n        payable\n        whenNotPaused\n        initializedAndNonReentrant\n        returns (uint256 validatedActions_)\n    {\n        return ActionsUtils.validateActionablePendingActions(previousActionsData, maxValidations);\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function transferPositionOwnership(PositionId calldata posId, address newOwner, bytes calldata delegationSignature)\n        external\n        whenNotPaused\n        initializedAndNonReentrant\n    {\n        return ActionsUtils.transferPositionOwnership(posId, newOwner, delegationSignature, _domainSeparatorV4());\n    }\n\n    /// @inheritdoc IUsdnProtocolActions\n    function domainSeparatorV4() external view returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n}\n"},{"file_path":"dependencies/solady-0.0.228/src/utils/FixedPointMathLib.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Arithmetic library with operations for fixed-point numbers.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)\nlibrary FixedPointMathLib {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The operation failed, as the output exceeds the maximum value of uint256.\n    error ExpOverflow();\n\n    /// @dev The operation failed, as the output exceeds the maximum value of uint256.\n    error FactorialOverflow();\n\n    /// @dev The operation failed, due to an overflow.\n    error RPowOverflow();\n\n    /// @dev The mantissa is too big to fit.\n    error MantissaOverflow();\n\n    /// @dev The operation failed, due to an multiplication overflow.\n    error MulWadFailed();\n\n    /// @dev The operation failed, due to an multiplication overflow.\n    error SMulWadFailed();\n\n    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.\n    error DivWadFailed();\n\n    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.\n    error SDivWadFailed();\n\n    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.\n    error MulDivFailed();\n\n    /// @dev The division failed, as the denominator is zero.\n    error DivFailed();\n\n    /// @dev The full precision multiply-divide operation failed, either due\n    /// to the result being larger than 256 bits, or a division by a zero.\n    error FullMulDivFailed();\n\n    /// @dev The output is undefined, as the input is less-than-or-equal to zero.\n    error LnWadUndefined();\n\n    /// @dev The input outside the acceptable domain.\n    error OutOfDomain();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         CONSTANTS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The scalar of ETH and most ERC20s.\n    uint256 internal constant WAD = 1e18;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*              SIMPLIFIED FIXED POINT OPERATIONS             */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Equivalent to `(x * y) / WAD` rounded down.\n    function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.\n            if mul(y, gt(x, div(not(0), y))) {\n                mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := div(mul(x, y), WAD)\n        }\n    }\n\n    /// @dev Equivalent to `(x * y) / WAD` rounded down.\n    function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mul(x, y)\n            // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.\n            if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {\n                mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := sdiv(z, WAD)\n        }\n    }\n\n    /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.\n    function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := div(mul(x, y), WAD)\n        }\n    }\n\n    /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.\n    function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := sdiv(mul(x, y), WAD)\n        }\n    }\n\n    /// @dev Equivalent to `(x * y) / WAD` rounded up.\n    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.\n            if mul(y, gt(x, div(not(0), y))) {\n                mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))\n        }\n    }\n\n    /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.\n    function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))\n        }\n    }\n\n    /// @dev Equivalent to `(x * WAD) / y` rounded down.\n    function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.\n            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {\n                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := div(mul(x, WAD), y)\n        }\n    }\n\n    /// @dev Equivalent to `(x * WAD) / y` rounded down.\n    function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mul(x, WAD)\n            // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.\n            if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) {\n                mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := sdiv(mul(x, WAD), y)\n        }\n    }\n\n    /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.\n    function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := div(mul(x, WAD), y)\n        }\n    }\n\n    /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.\n    function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := sdiv(mul(x, WAD), y)\n        }\n    }\n\n    /// @dev Equivalent to `(x * WAD) / y` rounded up.\n    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.\n            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {\n                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))\n        }\n    }\n\n    /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.\n    function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))\n        }\n    }\n\n    /// @dev Equivalent to `x` to the power of `y`.\n    /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.\n    /// Note: This function is an approximation.\n    function powWad(int256 x, int256 y) internal pure returns (int256) {\n        // Using `ln(x)` means `x` must be greater than 0.\n        return expWad((lnWad(x) * y) / int256(WAD));\n    }\n\n    /// @dev Returns `exp(x)`, denominated in `WAD`.\n    /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln\n    /// Note: This function is an approximation. Monotonically increasing.\n    function expWad(int256 x) internal pure returns (int256 r) {\n        unchecked {\n            // When the result is less than 0.5 we return zero.\n            // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.\n            if (x <= -41446531673892822313) return r;\n\n            /// @solidity memory-safe-assembly\n            assembly {\n                // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as\n                // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.\n                if iszero(slt(x, 135305999368893231589)) {\n                    mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.\n                    revert(0x1c, 0x04)\n                }\n            }\n\n            // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`\n            // for more intermediate precision and a binary basis. This base conversion\n            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.\n            x = (x << 78) / 5 ** 18;\n\n            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers\n            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.\n            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).\n            int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;\n            x = x - k * 54916777467707473351141471128;\n\n            // `k` is in the range `[-61, 195]`.\n\n            // Evaluate using a (6, 7)-term rational approximation.\n            // `p` is made monic, we'll multiply by a scale factor later.\n            int256 y = x + 1346386616545796478920950773328;\n            y = ((y * x) >> 96) + 57155421227552351082224309758442;\n            int256 p = y + x - 94201549194550492254356042504812;\n            p = ((p * y) >> 96) + 28719021644029726153956944680412240;\n            p = p * x + (4385272521454847904659076985693276 << 96);\n\n            // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.\n            int256 q = x - 2855989394907223263936484059900;\n            q = ((q * x) >> 96) + 50020603652535783019961831881945;\n            q = ((q * x) >> 96) - 533845033583426703283633433725380;\n            q = ((q * x) >> 96) + 3604857256930695427073651918091429;\n            q = ((q * x) >> 96) - 14423608567350463180887372962807573;\n            q = ((q * x) >> 96) + 26449188498355588339934803723976023;\n\n            /// @solidity memory-safe-assembly\n            assembly {\n                // Div in assembly because solidity adds a zero check despite the unchecked.\n                // The q polynomial won't have zeros in the domain as all its roots are complex.\n                // No scaling is necessary because p is already `2**96` too large.\n                r := sdiv(p, q)\n            }\n\n            // r should be in the range `(0.09, 0.25) * 2**96`.\n\n            // We now need to multiply r by:\n            // - The scale factor `s ≈ 6.031367120`.\n            // - The `2**k` factor from the range reduction.\n            // - The `1e18 / 2**96` factor for base conversion.\n            // We do this all at once, with an intermediate result in `2**213`\n            // basis, so the final right shift is always by a positive amount.\n            r = int256(\n                (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)\n            );\n        }\n    }\n\n    /// @dev Returns `ln(x)`, denominated in `WAD`.\n    /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln\n    /// Note: This function is an approximation. Monotonically increasing.\n    function lnWad(int256 x) internal pure returns (int256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // We want to convert `x` from `10**18` fixed point to `2**96` fixed point.\n            // We do this by multiplying by `2**96 / 10**18`. But since\n            // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here\n            // and add `ln(2**96 / 10**18)` at the end.\n\n            // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.\n            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(r, shl(3, lt(0xff, shr(r, x))))\n            // We place the check here for more optimal stack operations.\n            if iszero(sgt(x, 0)) {\n                mstore(0x00, 0x1615e638) // `LnWadUndefined()`.\n                revert(0x1c, 0x04)\n            }\n            // forgefmt: disable-next-item\n            r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),\n                0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))\n\n            // Reduce range of x to (1, 2) * 2**96\n            // ln(2^k * x) = k * ln(2) + ln(x)\n            x := shr(159, shl(r, x))\n\n            // Evaluate using a (8, 8)-term rational approximation.\n            // `p` is made monic, we will multiply by a scale factor later.\n            // forgefmt: disable-next-item\n            let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.\n                sar(96, mul(add(43456485725739037958740375743393,\n                sar(96, mul(add(24828157081833163892658089445524,\n                sar(96, mul(add(3273285459638523848632254066296,\n                    x), x))), x))), x)), 11111509109440967052023855526967)\n            p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)\n            p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)\n            p := sub(mul(p, x), shl(96, 795164235651350426258249787498))\n            // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.\n\n            // `q` is monic by convention.\n            let q := add(5573035233440673466300451813936, x)\n            q := add(71694874799317883764090561454958, sar(96, mul(x, q)))\n            q := add(283447036172924575727196451306956, sar(96, mul(x, q)))\n            q := add(401686690394027663651624208769553, sar(96, mul(x, q)))\n            q := add(204048457590392012362485061816622, sar(96, mul(x, q)))\n            q := add(31853899698501571402653359427138, sar(96, mul(x, q)))\n            q := add(909429971244387300277376558375, sar(96, mul(x, q)))\n\n            // `p / q` is in the range `(0, 0.125) * 2**96`.\n\n            // Finalization, we need to:\n            // - Multiply by the scale factor `s = 5.549…`.\n            // - Add `ln(2**96 / 10**18)`.\n            // - Add `k * ln(2)`.\n            // - Multiply by `10**18 / 2**96 = 5**18 >> 78`.\n\n            // The q polynomial is known not to have zeros in the domain.\n            // No scaling required because p is already `2**96` too large.\n            p := sdiv(p, q)\n            // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.\n            p := mul(1677202110996718588342820967067443963516166, p)\n            // Add `ln(2) * k * 5**18 * 2**192`.\n            // forgefmt: disable-next-item\n            p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)\n            // Add `ln(2**96 / 10**18) * 5**18 * 2**192`.\n            p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)\n            // Base conversion: mul `2**18 / 2**192`.\n            r := sar(174, p)\n        }\n    }\n\n    /// @dev Returns `W_0(x)`, denominated in `WAD`.\n    /// See: https://en.wikipedia.org/wiki/Lambert_W_function\n    /// a.k.a. Product log function. This is an approximation of the principal branch.\n    /// Note: This function is an approximation. Monotonically increasing.\n    function lambertW0Wad(int256 x) internal pure returns (int256 w) {\n        // forgefmt: disable-next-item\n        unchecked {\n            if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.\n            int256 wad = int256(WAD);\n            int256 p = x;\n            uint256 c; // Whether we need to avoid catastrophic cancellation.\n            uint256 i = 4; // Number of iterations.\n            if (w <= 0x1ffffffffffff) {\n                if (-0x4000000000000 <= w) {\n                    i = 1; // Inputs near zero only take one step to converge.\n                } else if (w <= -0x3ffffffffffffff) {\n                    i = 32; // Inputs near `-1/e` take very long to converge.\n                }\n            } else if (uint256(w >> 63) == uint256(0)) {\n                /// @solidity memory-safe-assembly\n                assembly {\n                    // Inline log2 for more performance, since the range is small.\n                    let v := shr(49, w)\n                    let l := shl(3, lt(0xff, v))\n                    l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),\n                        0x0706060506020504060203020504030106050205030304010505030400000000)), 49)\n                    w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))\n                    c := gt(l, 60)\n                    i := add(2, add(gt(l, 53), c))\n                }\n            } else {\n                int256 ll = lnWad(w = lnWad(w));\n                /// @solidity memory-safe-assembly\n                assembly {\n                    // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.\n                    w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))\n                    i := add(3, iszero(shr(68, x)))\n                    c := iszero(shr(143, x))\n                }\n                if (c == uint256(0)) {\n                    do { // If `x` is big, use Newton's so that intermediate values won't overflow.\n                        int256 e = expWad(w);\n                        /// @solidity memory-safe-assembly\n                        assembly {\n                            let t := mul(w, div(e, wad))\n                            w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))\n                        }\n                        if (p <= w) break;\n                        p = w;\n                    } while (--i != uint256(0));\n                    /// @solidity memory-safe-assembly\n                    assembly {\n                        w := sub(w, sgt(w, 2))\n                    }\n                    return w;\n                }\n            }\n            do { // Otherwise, use Halley's for faster convergence.\n                int256 e = expWad(w);\n                /// @solidity memory-safe-assembly\n                assembly {\n                    let t := add(w, wad)\n                    let s := sub(mul(w, e), mul(x, wad))\n                    w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))\n                }\n                if (p <= w) break;\n                p = w;\n            } while (--i != c);\n            /// @solidity memory-safe-assembly\n            assembly {\n                w := sub(w, sgt(w, 2))\n            }\n            // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of\n            // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.\n            if (c == uint256(0)) return w;\n            int256 t = w | 1;\n            /// @solidity memory-safe-assembly\n            assembly {\n                x := sdiv(mul(x, wad), t)\n            }\n            x = (t * (wad + lnWad(x)));\n            /// @solidity memory-safe-assembly\n            assembly {\n                w := sdiv(x, add(wad, t))\n            }\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                  GENERAL NUMBER UTILITIES                  */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Calculates `floor(x * y / d)` with full precision.\n    /// Throws if result overflows a uint256 or when `d` is zero.\n    /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv\n    function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // 512-bit multiply `[p1 p0] = x * y`.\n            // Compute the product mod `2**256` and mod `2**256 - 1`\n            // then use the Chinese Remainder Theorem to reconstruct\n            // the 512 bit result. The result is stored in two 256\n            // variables such that `product = p1 * 2**256 + p0`.\n\n            // Temporarily use `result` as `p0` to save gas.\n            result := mul(x, y) // Lower 256 bits of `x * y`.\n            for {} 1 {} {\n                // If overflows.\n                if iszero(mul(or(iszero(x), eq(div(result, x), y)), d)) {\n                    let mm := mulmod(x, y, not(0))\n                    let p1 := sub(mm, add(result, lt(mm, result))) // Upper 256 bits of `x * y`.\n\n                    /*------------------- 512 by 256 division --------------------*/\n\n                    // Make division exact by subtracting the remainder from `[p1 p0]`.\n                    let r := mulmod(x, y, d) // Compute remainder using mulmod.\n                    let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`.\n                    // Make sure the result is less than `2**256`. Also prevents `d == 0`.\n                    // Placing the check here seems to give more optimal stack operations.\n                    if iszero(gt(d, p1)) {\n                        mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.\n                        revert(0x1c, 0x04)\n                    }\n                    d := div(d, t) // Divide `d` by `t`, which is a power of two.\n                    // Invert `d mod 2**256`\n                    // Now that `d` is an odd number, it has an inverse\n                    // modulo `2**256` such that `d * inv = 1 mod 2**256`.\n                    // Compute the inverse by starting with a seed that is correct\n                    // correct for four bits. That is, `d * inv = 1 mod 2**4`.\n                    let inv := xor(2, mul(3, d))\n                    // Now use Newton-Raphson iteration to improve the precision.\n                    // Thanks to Hensel's lifting lemma, this also works in modular\n                    // arithmetic, doubling the correct bits in each step.\n                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8\n                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16\n                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32\n                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64\n                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128\n                    result :=\n                        mul(\n                            // Divide [p1 p0] by the factors of two.\n                            // Shift in bits from `p1` into `p0`. For this we need\n                            // to flip `t` such that it is `2**256 / t`.\n                            or(\n                                mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),\n                                div(sub(result, r), t)\n                            ),\n                            mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256\n                        )\n                    break\n                }\n                result := div(result, d)\n                break\n            }\n        }\n    }\n\n    /// @dev Calculates `floor(x * y / d)` with full precision.\n    /// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits.\n    /// Performs the full 512 bit calculation regardless.\n    function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d)\n        internal\n        pure\n        returns (uint256 result)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := mul(x, y)\n            let mm := mulmod(x, y, not(0))\n            let p1 := sub(mm, add(result, lt(mm, result)))\n            let t := and(d, sub(0, d))\n            let r := mulmod(x, y, d)\n            d := div(d, t)\n            let inv := xor(2, mul(3, d))\n            inv := mul(inv, sub(2, mul(d, inv)))\n            inv := mul(inv, sub(2, mul(d, inv)))\n            inv := mul(inv, sub(2, mul(d, inv)))\n            inv := mul(inv, sub(2, mul(d, inv)))\n            inv := mul(inv, sub(2, mul(d, inv)))\n            result :=\n                mul(\n                    or(mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)), div(sub(result, r), t)),\n                    mul(sub(2, mul(d, inv)), inv)\n                )\n        }\n    }\n\n    /// @dev Calculates `floor(x * y / d)` with full precision, rounded up.\n    /// Throws if result overflows a uint256 or when `d` is zero.\n    /// Credit to Uniswap-v3-core under MIT license:\n    /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol\n    function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {\n        result = fullMulDiv(x, y, d);\n        /// @solidity memory-safe-assembly\n        assembly {\n            if mulmod(x, y, d) {\n                result := add(result, 1)\n                if iszero(result) {\n                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.\n                    revert(0x1c, 0x04)\n                }\n            }\n        }\n    }\n\n    /// @dev Returns `floor(x * y / d)`.\n    /// Reverts if `x * y` overflows, or `d` is zero.\n    function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mul(x, y)\n            // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.\n            if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {\n                mstore(0x00, 0xad251c27) // `MulDivFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := div(z, d)\n        }\n    }\n\n    /// @dev Returns `ceil(x * y / d)`.\n    /// Reverts if `x * y` overflows, or `d` is zero.\n    function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mul(x, y)\n            // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.\n            if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {\n                mstore(0x00, 0xad251c27) // `MulDivFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := add(iszero(iszero(mod(z, d))), div(z, d))\n        }\n    }\n\n    /// @dev Returns `ceil(x / d)`.\n    /// Reverts if `d` is zero.\n    function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(d) {\n                mstore(0x00, 0x65244e4e) // `DivFailed()`.\n                revert(0x1c, 0x04)\n            }\n            z := add(iszero(iszero(mod(x, d))), div(x, d))\n        }\n    }\n\n    /// @dev Returns `max(0, x - y)`.\n    function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mul(gt(x, y), sub(x, y))\n        }\n    }\n\n    /// @dev Returns `condition ? x : y`, without branching.\n    function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := xor(x, mul(xor(x, y), iszero(condition)))\n        }\n    }\n\n    /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.\n    /// Reverts if the computation overflows.\n    function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.\n            if x {\n                z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`\n                let half := shr(1, b) // Divide `b` by 2.\n                // Divide `y` by 2 every iteration.\n                for { y := shr(1, y) } y { y := shr(1, y) } {\n                    let xx := mul(x, x) // Store x squared.\n                    let xxRound := add(xx, half) // Round to the nearest number.\n                    // Revert if `xx + half` overflowed, or if `x ** 2` overflows.\n                    if or(lt(xxRound, xx), shr(128, x)) {\n                        mstore(0x00, 0x49f7642b) // `RPowOverflow()`.\n                        revert(0x1c, 0x04)\n                    }\n                    x := div(xxRound, b) // Set `x` to scaled `xxRound`.\n                    // If `y` is odd:\n                    if and(y, 1) {\n                        let zx := mul(z, x) // Compute `z * x`.\n                        let zxRound := add(zx, half) // Round to the nearest number.\n                        // If `z * x` overflowed or `zx + half` overflowed:\n                        if or(xor(div(zx, x), z), lt(zxRound, zx)) {\n                            // Revert if `x` is non-zero.\n                            if x {\n                                mstore(0x00, 0x49f7642b) // `RPowOverflow()`.\n                                revert(0x1c, 0x04)\n                            }\n                        }\n                        z := div(zxRound, b) // Return properly scaled `zxRound`.\n                    }\n                }\n            }\n        }\n    }\n\n    /// @dev Returns the square root of `x`, rounded down.\n    function sqrt(uint256 x) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.\n            z := 181 // The \"correct\" value is 1, but this saves a multiplication later.\n\n            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad\n            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.\n\n            // Let `y = x / 2**r`. We check `y >= 2**(k + 8)`\n            // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.\n            let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))\n            r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffffff, shr(r, x))))\n            z := shl(shr(1, r), z)\n\n            // Goal was to get `z*z*y` within a small factor of `x`. More iterations could\n            // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.\n            // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.\n            // That's not possible if `x < 256` but we can just verify those cases exhaustively.\n\n            // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.\n            // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.\n            // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.\n\n            // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`\n            // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,\n            // with largest error when `s = 1` and when `s = 256` or `1/256`.\n\n            // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.\n            // Then we can estimate `sqrt(y)` using\n            // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.\n\n            // There is no overflow risk here since `y < 2**136` after the first branch above.\n            z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.\n\n            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n            z := shr(1, add(z, div(x, z)))\n\n            // If `x+1` is a perfect square, the Babylonian method cycles between\n            // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.\n            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division\n            z := sub(z, lt(div(x, z), z))\n        }\n    }\n\n    /// @dev Returns the cube root of `x`, rounded down.\n    /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:\n    /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy\n    function cbrt(uint256 x) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(r, shl(3, lt(0xff, shr(r, x))))\n\n            z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))\n\n            z := div(add(add(div(x, mul(z, z)), z), z), 3)\n            z := div(add(add(div(x, mul(z, z)), z), z), 3)\n            z := div(add(add(div(x, mul(z, z)), z), z), 3)\n            z := div(add(add(div(x, mul(z, z)), z), z), 3)\n            z := div(add(add(div(x, mul(z, z)), z), z), 3)\n            z := div(add(add(div(x, mul(z, z)), z), z), 3)\n            z := div(add(add(div(x, mul(z, z)), z), z), 3)\n\n            z := sub(z, lt(div(x, mul(z, z)), z))\n        }\n    }\n\n    /// @dev Returns the square root of `x`, denominated in `WAD`, rounded down.\n    function sqrtWad(uint256 x) internal pure returns (uint256 z) {\n        unchecked {\n            if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18);\n            z = (1 + sqrt(x)) * 10 ** 9;\n            z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1;\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1)))\n        }\n    }\n\n    /// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down.\n    function cbrtWad(uint256 x) internal pure returns (uint256 z) {\n        unchecked {\n            if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36);\n            z = (1 + cbrt(x)) * 10 ** 12;\n            z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3;\n            x = fullMulDivUnchecked(x, 10 ** 36, z * z);\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := sub(z, lt(x, z))\n        }\n    }\n\n    /// @dev Returns the factorial of `x`.\n    function factorial(uint256 x) internal pure returns (uint256 result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            result := 1\n            if iszero(lt(x, 58)) {\n                mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.\n                revert(0x1c, 0x04)\n            }\n            for {} x { x := sub(x, 1) } { result := mul(result, x) }\n        }\n    }\n\n    /// @dev Returns the log2 of `x`.\n    /// Equivalent to computing the index of the most significant bit (MSB) of `x`.\n    /// Returns 0 if `x` is zero.\n    function log2(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(r, shl(3, lt(0xff, shr(r, x))))\n            // forgefmt: disable-next-item\n            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),\n                0x0706060506020504060203020504030106050205030304010505030400000000))\n        }\n    }\n\n    /// @dev Returns the log2 of `x`, rounded up.\n    /// Returns 0 if `x` is zero.\n    function log2Up(uint256 x) internal pure returns (uint256 r) {\n        r = log2(x);\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := add(r, lt(shl(r, 1), x))\n        }\n    }\n\n    /// @dev Returns the log10 of `x`.\n    /// Returns 0 if `x` is zero.\n    function log10(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(lt(x, 100000000000000000000000000000000000000)) {\n                x := div(x, 100000000000000000000000000000000000000)\n                r := 38\n            }\n            if iszero(lt(x, 100000000000000000000)) {\n                x := div(x, 100000000000000000000)\n                r := add(r, 20)\n            }\n            if iszero(lt(x, 10000000000)) {\n                x := div(x, 10000000000)\n                r := add(r, 10)\n            }\n            if iszero(lt(x, 100000)) {\n                x := div(x, 100000)\n                r := add(r, 5)\n            }\n            r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))\n        }\n    }\n\n    /// @dev Returns the log10 of `x`, rounded up.\n    /// Returns 0 if `x` is zero.\n    function log10Up(uint256 x) internal pure returns (uint256 r) {\n        r = log10(x);\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := add(r, lt(exp(10, r), x))\n        }\n    }\n\n    /// @dev Returns the log256 of `x`.\n    /// Returns 0 if `x` is zero.\n    function log256(uint256 x) internal pure returns (uint256 r) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))\n            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))\n            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n            r := or(r, shl(4, lt(0xffff, shr(r, x))))\n            r := or(shr(3, r), lt(0xff, shr(r, x)))\n        }\n    }\n\n    /// @dev Returns the log256 of `x`, rounded up.\n    /// Returns 0 if `x` is zero.\n    function log256Up(uint256 x) internal pure returns (uint256 r) {\n        r = log256(x);\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := add(r, lt(shl(shl(3, r), 1), x))\n        }\n    }\n\n    /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.\n    /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).\n    function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mantissa := x\n            if mantissa {\n                if iszero(mod(mantissa, 1000000000000000000000000000000000)) {\n                    mantissa := div(mantissa, 1000000000000000000000000000000000)\n                    exponent := 33\n                }\n                if iszero(mod(mantissa, 10000000000000000000)) {\n                    mantissa := div(mantissa, 10000000000000000000)\n                    exponent := add(exponent, 19)\n                }\n                if iszero(mod(mantissa, 1000000000000)) {\n                    mantissa := div(mantissa, 1000000000000)\n                    exponent := add(exponent, 12)\n                }\n                if iszero(mod(mantissa, 1000000)) {\n                    mantissa := div(mantissa, 1000000)\n                    exponent := add(exponent, 6)\n                }\n                if iszero(mod(mantissa, 10000)) {\n                    mantissa := div(mantissa, 10000)\n                    exponent := add(exponent, 4)\n                }\n                if iszero(mod(mantissa, 100)) {\n                    mantissa := div(mantissa, 100)\n                    exponent := add(exponent, 2)\n                }\n                if iszero(mod(mantissa, 10)) {\n                    mantissa := div(mantissa, 10)\n                    exponent := add(exponent, 1)\n                }\n            }\n        }\n    }\n\n    /// @dev Convenience function for packing `x` into a smaller number using `sci`.\n    /// The `mantissa` will be in bits [7..255] (the upper 249 bits).\n    /// The `exponent` will be in bits [0..6] (the lower 7 bits).\n    /// Use `SafeCastLib` to safely ensure that the `packed` number is small\n    /// enough to fit in the desired unsigned integer type:\n    /// ```\n    ///     uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));\n    /// ```\n    function packSci(uint256 x) internal pure returns (uint256 packed) {\n        (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.\n        /// @solidity memory-safe-assembly\n        assembly {\n            if shr(249, x) {\n                mstore(0x00, 0xce30380c) // `MantissaOverflow()`.\n                revert(0x1c, 0x04)\n            }\n            packed := or(shl(7, x), packed)\n        }\n    }\n\n    /// @dev Convenience function for unpacking a packed number from `packSci`.\n    function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {\n        unchecked {\n            unpacked = (packed >> 7) * 10 ** (packed & 0x7f);\n        }\n    }\n\n    /// @dev Returns the average of `x` and `y`. Rounds towards zero.\n    function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        unchecked {\n            z = (x & y) + ((x ^ y) >> 1);\n        }\n    }\n\n    /// @dev Returns the average of `x` and `y`. Rounds towards negative infinity.\n    function avg(int256 x, int256 y) internal pure returns (int256 z) {\n        unchecked {\n            z = (x >> 1) + (y >> 1) + (x & y & 1);\n        }\n    }\n\n    /// @dev Returns the absolute value of `x`.\n    function abs(int256 x) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(sar(255, x), add(sar(255, x), x))\n        }\n    }\n\n    /// @dev Returns the absolute distance between `x` and `y`.\n    function dist(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(mul(xor(sub(y, x), sub(x, y)), gt(x, y)), sub(y, x))\n        }\n    }\n\n    /// @dev Returns the absolute distance between `x` and `y`.\n    function dist(int256 x, int256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x))\n        }\n    }\n\n    /// @dev Returns the minimum of `x` and `y`.\n    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(x, mul(xor(x, y), lt(y, x)))\n        }\n    }\n\n    /// @dev Returns the minimum of `x` and `y`.\n    function min(int256 x, int256 y) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(x, mul(xor(x, y), slt(y, x)))\n        }\n    }\n\n    /// @dev Returns the maximum of `x` and `y`.\n    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(x, mul(xor(x, y), gt(y, x)))\n        }\n    }\n\n    /// @dev Returns the maximum of `x` and `y`.\n    function max(int256 x, int256 y) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(x, mul(xor(x, y), sgt(y, x)))\n        }\n    }\n\n    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.\n    function clamp(uint256 x, uint256 minValue, uint256 maxValue)\n        internal\n        pure\n        returns (uint256 z)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(x, mul(xor(x, minValue), gt(minValue, x)))\n            z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))\n        }\n    }\n\n    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.\n    function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))\n            z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))\n        }\n    }\n\n    /// @dev Returns greatest common divisor of `x` and `y`.\n    function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            for { z := x } y {} {\n                let t := y\n                y := mod(z, y)\n                z := t\n            }\n        }\n    }\n\n    /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`,\n    /// with `t` clamped between `begin` and `end` (inclusive).\n    /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).\n    /// If `begins == end`, returns `t <= begin ? a : b`.\n    function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end)\n        internal\n        pure\n        returns (uint256)\n    {\n        if (begin > end) {\n            t = ~t;\n            begin = ~begin;\n            end = ~end;\n        }\n        if (t <= begin) return a;\n        if (t >= end) return b;\n        unchecked {\n            if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin);\n            return a - fullMulDiv(a - b, t - begin, end - begin);\n        }\n    }\n\n    /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`.\n    /// with `t` clamped between `begin` and `end` (inclusive).\n    /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).\n    /// If `begins == end`, returns `t <= begin ? a : b`.\n    function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end)\n        internal\n        pure\n        returns (int256)\n    {\n        if (begin > end) {\n            t = int256(~uint256(t));\n            begin = int256(~uint256(begin));\n            end = int256(~uint256(end));\n        }\n        if (t <= begin) return a;\n        if (t >= end) return b;\n        // forgefmt: disable-next-item\n        unchecked {\n            if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b) - uint256(a),\n                uint256(t) - uint256(begin), uint256(end) - uint256(begin)));\n            return int256(uint256(a) - fullMulDiv(uint256(a) - uint256(b),\n                uint256(t) - uint256(begin), uint256(end) - uint256(begin)));\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                   RAW NUMBER OPERATIONS                    */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns `x + y`, without checking for overflow.\n    function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        unchecked {\n            z = x + y;\n        }\n    }\n\n    /// @dev Returns `x + y`, without checking for overflow.\n    function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {\n        unchecked {\n            z = x + y;\n        }\n    }\n\n    /// @dev Returns `x - y`, without checking for underflow.\n    function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        unchecked {\n            z = x - y;\n        }\n    }\n\n    /// @dev Returns `x - y`, without checking for underflow.\n    function rawSub(int256 x, int256 y) internal pure returns (int256 z) {\n        unchecked {\n            z = x - y;\n        }\n    }\n\n    /// @dev Returns `x * y`, without checking for overflow.\n    function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        unchecked {\n            z = x * y;\n        }\n    }\n\n    /// @dev Returns `x * y`, without checking for overflow.\n    function rawMul(int256 x, int256 y) internal pure returns (int256 z) {\n        unchecked {\n            z = x * y;\n        }\n    }\n\n    /// @dev Returns `x / y`, returning 0 if `y` is zero.\n    function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := div(x, y)\n        }\n    }\n\n    /// @dev Returns `x / y`, returning 0 if `y` is zero.\n    function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := sdiv(x, y)\n        }\n    }\n\n    /// @dev Returns `x % y`, returning 0 if `y` is zero.\n    function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mod(x, y)\n        }\n    }\n\n    /// @dev Returns `x % y`, returning 0 if `y` is zero.\n    function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := smod(x, y)\n        }\n    }\n\n    /// @dev Returns `(x + y) % d`, return 0 if `d` if zero.\n    function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := addmod(x, y, d)\n        }\n    }\n\n    /// @dev Returns `(x * y) % d`, return 0 if `d` if zero.\n    function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            z := mulmod(x, y, d)\n        }\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-upgradeable-5.1.0/proxy/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Storage of the initializable contract.\n     *\n     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n     * when using with upgradeable contracts.\n     *\n     * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n     */\n    struct InitializableStorage {\n        /**\n         * @dev Indicates that the contract has been initialized.\n         */\n        uint64 _initialized;\n        /**\n         * @dev Indicates that the contract is in the process of being initialized.\n         */\n        bool _initializing;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n    /**\n     * @dev The contract is already initialized.\n     */\n    error InvalidInitialization();\n\n    /**\n     * @dev The contract is not initializing.\n     */\n    error NotInitializing();\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint64 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n     * production.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        // Cache values to avoid duplicated sloads\n        bool isTopLevelCall = !$._initializing;\n        uint64 initialized = $._initialized;\n\n        // Allowed calls:\n        // - initialSetup: the contract is not in the initializing state and no previous version was\n        //                 initialized\n        // - construction: the contract is initialized at version 1 (no reininitialization) and the\n        //                 current contract is just being deployed\n        bool initialSetup = initialized == 0 && isTopLevelCall;\n        bool construction = initialized == 1 && address(this).code.length == 0;\n\n        if (!initialSetup && !construction) {\n            revert InvalidInitialization();\n        }\n        $._initialized = 1;\n        if (isTopLevelCall) {\n            $._initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            $._initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint64 version) {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing || $._initialized >= version) {\n            revert InvalidInitialization();\n        }\n        $._initialized = version;\n        $._initializing = true;\n        _;\n        $._initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        _checkInitializing();\n        _;\n    }\n\n    /**\n     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n     */\n    function _checkInitializing() internal view virtual {\n        if (!_isInitializing()) {\n            revert NotInitializing();\n        }\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing) {\n            revert InvalidInitialization();\n        }\n        if ($._initialized != type(uint64).max) {\n            $._initialized = type(uint64).max;\n            emit Initialized(type(uint64).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint64) {\n        return _getInitializableStorage()._initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _getInitializableStorage()._initializing;\n    }\n\n    /**\n     * @dev Returns a pointer to the storage namespace.\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n        assembly {\n            $.slot := INITIALIZABLE_STORAGE\n        }\n    }\n}\n"},{"file_path":"src/interfaces/Usdn/IUsdn.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC20Permit } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\";\n\nimport { IRebaseCallback } from \"./IRebaseCallback.sol\";\nimport { IUsdnErrors } from \"./IUsdnErrors.sol\";\nimport { IUsdnEvents } from \"./IUsdnEvents.sol\";\n\n/**\n * @title USDN token interface\n * @notice Implements the ERC-20 token standard as well as the EIP-2612 permit extension. Additional functions related\n * to the specifics of this token are included below.\n */\ninterface IUsdn is IERC20, IERC20Metadata, IERC20Permit, IUsdnEvents, IUsdnErrors {\n    /**\n     * @notice Returns the total number of shares in existence.\n     * @return shares_ The number of shares.\n     */\n    function totalShares() external view returns (uint256 shares_);\n\n    /**\n     * @notice Returns the number of shares owned by `account`.\n     * @param account The account to query.\n     * @return shares_ The number of shares.\n     */\n    function sharesOf(address account) external view returns (uint256 shares_);\n\n    /**\n     * @notice Transfers a given amount of shares from the `msg.sender` to `to`.\n     * @param to Recipient of the shares.\n     * @param value Number of shares to transfer.\n     * @return success_ Indicates whether the transfer was successfully executed.\n     */\n    function transferShares(address to, uint256 value) external returns (bool success_);\n\n    /**\n     * @notice Transfers a given amount of shares from the `from` to `to`.\n     * @dev There should be sufficient allowance for the spender. Be mindful of the rebase logic. The allowance is in\n     * tokens. So, after a rebase, the same amount of shares will be worth a higher amount of tokens. In that case,\n     * the allowance of the initial approval will not be enough to transfer the new amount of tokens. This can\n     * also happen when your transaction is in the mempool and the rebase happens before your transaction. Also note\n     * that the amount of tokens deduced from the allowance is rounded up, so the `convertToTokensRoundUp` function\n     * should be used when converting shares into an allowance value.\n     * @param from The owner of the shares.\n     * @param to Recipient of the shares.\n     * @param value Number of shares to transfer.\n     * @return success_ Indicates whether the transfer was successfully executed.\n     */\n    function transferSharesFrom(address from, address to, uint256 value) external returns (bool success_);\n\n    /**\n     * @notice Mints new shares, providing a token value.\n     * @dev Caller must have the MINTER_ROLE.\n     * @param to Account to receive the new shares.\n     * @param amount Amount of tokens to mint, is internally converted to the proper shares amounts.\n     */\n    function mint(address to, uint256 amount) external;\n\n    /**\n     * @notice Mints new shares, providing a share value.\n     * @dev Caller must have the MINTER_ROLE.\n     * @param to Account to receive the new shares.\n     * @param amount Amount of shares to mint.\n     * @return mintedTokens_ Amount of tokens that were minted (informational).\n     */\n    function mintShares(address to, uint256 amount) external returns (uint256 mintedTokens_);\n\n    /**\n     * @notice Destroys a `value` amount of tokens from the caller, reducing the total supply.\n     * @param value Amount of tokens to burn, is internally converted to the proper shares amounts.\n     */\n    function burn(uint256 value) external;\n\n    /**\n     * @notice Destroys a `value` amount of tokens from `account`, deducting from the caller's allowance.\n     * @param account Account to burn tokens from.\n     * @param value Amount of tokens to burn, is internally converted to the proper shares amounts.\n     */\n    function burnFrom(address account, uint256 value) external;\n\n    /**\n     * @notice Destroys a `value` amount of shares from the caller, reducing the total supply.\n     * @param value Amount of shares to burn.\n     */\n    function burnShares(uint256 value) external;\n\n    /**\n     * @notice Destroys a `value` amount of shares from `account`, deducting from the caller's allowance.\n     * @dev There should be sufficient allowance for the spender. Be mindful of the rebase logic. The allowance is in\n     * tokens. So, after a rebase, the same amount of shares will be worth a higher amount of tokens. In that case,\n     * the allowance of the initial approval will not be enough to transfer the new amount of tokens. This can\n     * also happen when your transaction is in the mempool and the rebase happens before your transaction. Also note\n     * that the amount of tokens deduced from the allowance is rounded up, so the `convertToTokensRoundUp` function\n     * should be used when converting shares into an allowance value.\n     * @param account Account to burn shares from.\n     * @param value Amount of shares to burn.\n     */\n    function burnSharesFrom(address account, uint256 value) external;\n\n    /**\n     * @notice Converts a number of tokens to the corresponding amount of shares.\n     * @dev The conversion reverts with `UsdnMaxTokensExceeded` if the corresponding amount of shares overflows.\n     * @param amountTokens The amount of tokens to convert to shares.\n     * @return shares_ The corresponding amount of shares.\n     */\n    function convertToShares(uint256 amountTokens) external view returns (uint256 shares_);\n\n    /**\n     * @notice Converts a number of shares to the corresponding amount of tokens.\n     * @dev The conversion never overflows as we are performing a division. The conversion rounds to the nearest amount\n     * of tokens that minimizes the error when converting back to shares.\n     * @param amountShares The amount of shares to convert to tokens.\n     * @return tokens_ The corresponding amount of tokens.\n     */\n    function convertToTokens(uint256 amountShares) external view returns (uint256 tokens_);\n\n    /**\n     * @notice Converts a number of shares to the corresponding amount of tokens, rounding up.\n     * @dev Use this function to determine the amount of a token approval, as we always round up when deducting from\n     * a token transfer allowance.\n     * @param amountShares The amount of shares to convert to tokens.\n     * @return tokens_ The corresponding amount of tokens, rounded up.\n     */\n    function convertToTokensRoundUp(uint256 amountShares) external view returns (uint256 tokens_);\n\n    /**\n     * @notice Returns the current maximum tokens supply, given the current divisor.\n     * @dev This function is used to check if a conversion operation would overflow.\n     * @return maxTokens_ The maximum number of tokens that can exist.\n     */\n    function maxTokens() external view returns (uint256 maxTokens_);\n\n    /**\n     * @notice Decreases the global divisor, which effectively grows all balances and the total supply.\n     * @dev If the provided divisor is larger than or equal to the current divisor value, no rebase will happen\n     * If the new divisor is smaller than `MIN_DIVISOR`, the value will be clamped to `MIN_DIVISOR`.\n     * Caller must have the `REBASER_ROLE`.\n     * @param newDivisor The new divisor, should be strictly smaller than the current one and greater or equal to\n     * `MIN_DIVISOR`.\n     * @return rebased_ Whether a rebase happened.\n     * @return oldDivisor_ The previous value of the divisor.\n     * @return callbackResult_ The result of the callback, if a rebase happened and a callback handler is defined.\n     */\n    function rebase(uint256 newDivisor)\n        external\n        returns (bool rebased_, uint256 oldDivisor_, bytes memory callbackResult_);\n\n    /**\n     * @notice Sets the rebase handler address.\n     * @dev Emits a `RebaseHandlerUpdated` event.\n     * If set to the zero address, no handler will be called after a rebase.\n     * Caller must have the `DEFAULT_ADMIN_ROLE`.\n     * @param newHandler The new handler address.\n     */\n    function setRebaseHandler(IRebaseCallback newHandler) external;\n\n    /* -------------------------------------------------------------------------- */\n    /*                             Dev view functions                             */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice Gets the current value of the divisor that converts between tokens and shares.\n     * @return divisor_ The current divisor.\n     */\n    function divisor() external view returns (uint256 divisor_);\n\n    /**\n     * @notice Gets the rebase handler address, which is called whenever a rebase happens.\n     * @return rebaseHandler_ The rebase handler address.\n     */\n    function rebaseHandler() external view returns (IRebaseCallback rebaseHandler_);\n\n    /**\n     * @notice Gets the minter role signature.\n     * @return minter_role_ The role signature.\n     */\n    function MINTER_ROLE() external pure returns (bytes32 minter_role_);\n\n    /**\n     * @notice Gets the rebaser role signature.\n     * @return rebaser_role_ The role signature.\n     */\n    function REBASER_ROLE() external pure returns (bytes32 rebaser_role_);\n\n    /**\n     * @notice Gets the maximum value of the divisor, which is also the initial value.\n     * @return maxDivisor_ The maximum divisor.\n     */\n    function MAX_DIVISOR() external pure returns (uint256 maxDivisor_);\n\n    /**\n     * @notice Gets the minimum acceptable value of the divisor.\n     * @dev The minimum divisor that can be set. This corresponds to a growth of 1B times. Technically, 1e5 would still\n     * work without precision errors.\n     * @return minDivisor_ The minimum divisor.\n     */\n    function MIN_DIVISOR() external pure returns (uint256 minDivisor_);\n}\n"},{"file_path":"src/UsdnProtocol/libraries/UsdnProtocolActionsLongLibrary.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { ERC165Checker } from \"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { SafeTransferLib } from \"solady/src/utils/SafeTransferLib.sol\";\n\nimport { PriceInfo } from \"../../interfaces/OracleMiddleware/IOracleMiddlewareTypes.sol\";\nimport { IPaymentCallback } from \"../../interfaces/UsdnProtocol/IPaymentCallback.sol\";\nimport { IUsdnProtocolErrors } from \"../../interfaces/UsdnProtocol/IUsdnProtocolErrors.sol\";\nimport { IUsdnProtocolEvents } from \"../../interfaces/UsdnProtocol/IUsdnProtocolEvents.sol\";\nimport { IUsdnProtocolTypes as Types } from \"../../interfaces/UsdnProtocol/IUsdnProtocolTypes.sol\";\nimport { Accumulator, HugeUint } from \"../../libraries/Accumulator.sol\";\nimport { TickMath } from \"../../libraries/TickMath.sol\";\nimport { UsdnProtocolActionsUtilsLibrary as ActionsUtils } from \"./UsdnProtocolActionsUtilsLibrary.sol\";\nimport { UsdnProtocolConstantsLibrary as Constants } from \"./UsdnProtocolConstantsLibrary.sol\";\nimport { UsdnProtocolCoreLibrary as Core } from \"./UsdnProtocolCoreLibrary.sol\";\nimport { UsdnProtocolLongLibrary as Long } from \"./UsdnProtocolLongLibrary.sol\";\nimport { UsdnProtocolUtilsLibrary as Utils } from \"./UsdnProtocolUtilsLibrary.sol\";\nimport { UsdnProtocolVaultLibrary as Vault } from \"./UsdnProtocolVaultLibrary.sol\";\n\nlibrary UsdnProtocolActionsLongLibrary {\n    using Accumulator for HugeUint.Uint512;\n    using SafeCast for uint256;\n    using SafeTransferLib for address;\n\n    /**\n     * @dev Data structure for the {_validateClosePositionWithAction} function.\n     * @param isLiquidationPending Whether a liquidation is pending.\n     * @param priceWithFees The price of the position with fees.\n     * @param liquidationPrice The liquidation price of the position.\n     * @param positionValue The value of the position. The amount the user will receive when closing the position.\n     */\n    struct ValidateClosePositionWithActionData {\n        bool isLiquidationPending;\n        uint128 priceWithFees;\n        uint128 liquidationPrice;\n        int256 positionValue;\n    }\n\n    /**\n     * @dev Data structure for the {_validateOpenPositionWithAction} function.\n     * @param currentLiqPenalty The current liquidation penalty parameter value.\n     * @param newPosId The new position id.\n     * @param liquidationPenalty The liquidation penalty of the tick we are considering.\n     */\n    struct MaxLeverageData {\n        uint24 currentLiqPenalty;\n        Types.PositionId newPosId;\n        uint24 liquidationPenalty;\n    }\n\n    /// @notice See {IUsdnProtocolActions.initiateOpenPosition}.\n    function initiateOpenPosition(\n        Types.InitiateOpenPositionParams memory params,\n        bytes calldata currentPriceData,\n        Types.PreviousActionsData calldata previousActionsData\n    ) external returns (bool isInitiated_, Types.PositionId memory posId_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (params.deadline < block.timestamp) {\n            revert IUsdnProtocolErrors.UsdnProtocolDeadlineExceeded();\n        }\n        uint64 securityDepositValue = s._securityDepositValue;\n        if (msg.value < securityDepositValue) {\n            revert IUsdnProtocolErrors.UsdnProtocolSecurityDepositTooLow();\n        }\n\n        uint256 balanceBefore = address(this).balance;\n        params.securityDepositValue = securityDepositValue;\n        uint256 validatorAmount;\n        (posId_, validatorAmount, isInitiated_) = _initiateOpenPosition(params, currentPriceData);\n\n        uint256 amountToRefund;\n        if (isInitiated_) {\n            unchecked {\n                amountToRefund += Vault._executePendingActionOrRevert(previousActionsData);\n            }\n        }\n\n        // refund any securityDeposit from a stale pending action to the validator\n        if (validatorAmount > 0) {\n            if (params.validator != msg.sender) {\n                balanceBefore -= validatorAmount;\n                Utils._refundEther(validatorAmount, payable(params.validator));\n            } else {\n                amountToRefund += validatorAmount;\n            }\n        }\n\n        Utils._refundExcessEther(securityDepositValue, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolActions.validateOpenPosition}.\n    function validateOpenPosition(\n        address payable validator,\n        bytes calldata openPriceData,\n        Types.PreviousActionsData calldata previousActionsData\n    ) external returns (Types.LongActionOutcome outcome_, Types.PositionId memory posId_) {\n        uint256 balanceBefore = address(this).balance;\n\n        uint256 amountToRefund;\n        bool isValidated;\n        bool isLiquidated;\n        (amountToRefund, isValidated, isLiquidated, posId_) = _validateOpenPosition(validator, openPriceData);\n        uint256 securityDeposit;\n        if (isValidated || isLiquidated) {\n            securityDeposit = Vault._executePendingActionOrRevert(previousActionsData);\n        }\n\n        if (isLiquidated) {\n            outcome_ = Types.LongActionOutcome.Liquidated;\n        } else if (!isValidated) {\n            outcome_ = Types.LongActionOutcome.PendingLiquidations;\n        }\n\n        if (msg.sender != validator) {\n            Utils._refundEther(amountToRefund, validator);\n            balanceBefore -= amountToRefund;\n            amountToRefund = securityDeposit;\n        } else {\n            amountToRefund += securityDeposit;\n        }\n        Utils._refundExcessEther(0, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolActions.initiateClosePosition}.\n    function initiateClosePosition(\n        Types.InitiateClosePositionParams memory params,\n        bytes calldata currentPriceData,\n        Types.PreviousActionsData calldata previousActionsData,\n        bytes calldata delegationSignature\n    ) external returns (Types.LongActionOutcome outcome_) {\n        if (params.deadline < block.timestamp) {\n            revert IUsdnProtocolErrors.UsdnProtocolDeadlineExceeded();\n        }\n        if (msg.value < params.securityDepositValue) {\n            revert IUsdnProtocolErrors.UsdnProtocolSecurityDepositTooLow();\n        }\n\n        uint256 balanceBefore = address(this).balance;\n        (uint256 validatorAmount, bool isInitiated, bool isLiquidated) =\n            _initiateClosePosition(params, currentPriceData, delegationSignature);\n\n        uint256 amountToRefund;\n        if (isInitiated || isLiquidated) {\n            unchecked {\n                amountToRefund += Vault._executePendingActionOrRevert(previousActionsData);\n            }\n        }\n\n        if (isLiquidated) {\n            outcome_ = Types.LongActionOutcome.Liquidated;\n        } else if (!isInitiated) {\n            outcome_ = Types.LongActionOutcome.PendingLiquidations;\n        }\n\n        // refund any securityDeposit from a stale pending action to the validator\n        if (validatorAmount > 0) {\n            if (params.validator != msg.sender) {\n                balanceBefore -= validatorAmount;\n                Utils._refundEther(validatorAmount, payable(params.validator));\n            } else {\n                amountToRefund += validatorAmount;\n            }\n        }\n\n        Utils._refundExcessEther(params.securityDepositValue, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolActions.validateClosePosition}.\n    function validateClosePosition(\n        address payable validator,\n        bytes calldata closePriceData,\n        Types.PreviousActionsData calldata previousActionsData\n    ) external returns (Types.LongActionOutcome outcome_) {\n        uint256 balanceBefore = address(this).balance;\n\n        (uint256 amountToRefund, bool isValidated, bool isLiquidated) =\n            _validateClosePosition(validator, closePriceData);\n        uint256 securityDeposit;\n        if (isValidated || isLiquidated) {\n            securityDeposit = Vault._executePendingActionOrRevert(previousActionsData);\n        }\n\n        if (isLiquidated) {\n            outcome_ = Types.LongActionOutcome.Liquidated;\n        } else if (!isValidated) {\n            outcome_ = Types.LongActionOutcome.PendingLiquidations;\n        }\n\n        if (msg.sender != validator) {\n            Utils._refundEther(amountToRefund, validator);\n            balanceBefore -= amountToRefund;\n            amountToRefund = securityDeposit;\n        } else {\n            amountToRefund += securityDeposit;\n        }\n        Utils._refundExcessEther(0, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /**\n     * @notice Validates an open position action.\n     * @param pending The pending action's data.\n     * @param priceData The current price data.\n     * @return isValidated_ Whether the action is validated.\n     * @return isLiquidated_ Whether the pending action is liquidated.\n     * @return posId_ The (potentially updated) position ID, or `NO_POSITION_TICK` in the `tick` field if the position\n     * was liquidated.\n     */\n    function _validateOpenPositionWithAction(Types.PendingAction memory pending, bytes calldata priceData)\n        public\n        returns (bool isValidated_, bool isLiquidated_, Types.PositionId memory posId_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (Types.ValidateOpenPositionData memory data, bool liquidated) =\n            _prepareValidateOpenPositionData(pending, priceData);\n\n        if (liquidated) {\n            posId_.tick = Constants.NO_POSITION_TICK;\n            return (false, true, posId_);\n        }\n\n        posId_ =\n            Types.PositionId({ tick: data.action.tick, tickVersion: data.action.tickVersion, index: data.action.index });\n        if (data.isLiquidationPending) {\n            return (false, false, posId_);\n        }\n\n        // leverage is always greater than one (`liquidationPrice` is positive)\n        // even if it drops below _minLeverage between the initiate and validate actions, we still allow it\n        // however, if the leverage exceeds max leverage, then we adjust the liquidation price (tick) to have a leverage\n        // of _maxLeverage\n        uint128 maxLeverage = uint128(s._maxLeverage);\n        if (data.leverage > maxLeverage) {\n            MaxLeverageData memory maxLeverageData;\n            // theoretical liquidation price for _maxLeverage\n            data.liqPriceWithoutPenalty = Utils._getLiquidationPrice(data.startPrice, maxLeverage);\n            // find corresponding tick and actual liq price with current penalty setting\n            maxLeverageData.currentLiqPenalty = s._liquidationPenalty;\n            (maxLeverageData.newPosId.tick, data.liqPriceWithoutPenalty) = Long._getTickFromDesiredLiqPrice(\n                data.liqPriceWithoutPenalty,\n                data.action.liqMultiplier,\n                s._tickSpacing,\n                maxLeverageData.currentLiqPenalty\n            );\n\n            // retrieve the actual penalty for this tick we want to use\n            maxLeverageData.liquidationPenalty = Long.getTickLiquidationPenalty(maxLeverageData.newPosId.tick);\n            // check if the penalty for that tick is different from the current setting\n            // if the penalty is the same, then `data.liqPriceWithoutPenalty` is already correct\n            if (maxLeverageData.liquidationPenalty != maxLeverageData.currentLiqPenalty) {\n                // the tick's imposed penalty is different from the current setting, so the `liqPriceWithoutPenalty` we\n                // got above can't be used to calculate the leverage\n                // we must instead use the tick's penalty to find the new `liqPriceWithoutPenalty` and calculate the\n                // total exposure\n\n                // note: In case the tick liquidation penalty is lower than the current setting, it might lead to a\n                // leverage that exceeds the max leverage slightly. We allow this behavior in this rare occurrence\n\n                // retrieve exact liquidation price without penalty\n                // we consider the liquidation multiplier as it was during the initiation, to ignore any funding\n                // that was due between the initiation and the validation\n                data.liqPriceWithoutPenalty = Utils._getEffectivePriceForTick(\n                    Utils._calcTickWithoutPenalty(maxLeverageData.newPosId.tick, maxLeverageData.liquidationPenalty),\n                    data.action.liqMultiplier\n                );\n            }\n\n            // move the position to its new tick, update its total exposure, and return the new tickVersion and index\n            // remove position from old tick completely\n            Long._removeAmountFromPosition(\n                data.action.tick, data.action.index, data.pos, data.pos.amount, data.pos.totalExpo\n            );\n\n            // if the last price is below the liquidation price without penalty of the new position, we are unable to\n            // calculate the new position's value\n            // this is extremely unlikely, but we have no other choice but to liquidate if it happens\n            if (data.lastPrice <= data.liqPriceWithoutPenalty) {\n                s._balanceLong -= data.oldPosValue;\n                s._balanceVault += data.oldPosValue;\n                // position was already removed from the tick above\n\n                emit IUsdnProtocolEvents.LiquidatedPosition(\n                    data.action.validator,\n                    Types.PositionId({\n                        tick: data.action.tick,\n                        tickVersion: data.action.tickVersion,\n                        index: data.action.index\n                    }),\n                    data.lastPrice,\n                    data.liqPriceWithoutPenalty\n                );\n                return (false, true, Types.PositionId({ tick: Constants.NO_POSITION_TICK, tickVersion: 0, index: 0 }));\n            }\n\n            // update position total exposure (because of new leverage / liq price)\n            data.pos.totalExpo =\n                Utils._calcPositionTotalExpo(data.pos.amount, data.startPrice, data.liqPriceWithoutPenalty);\n            // mark the position as validated\n            data.pos.validated = true;\n            // insert position into new tick\n            (maxLeverageData.newPosId.tickVersion, maxLeverageData.newPosId.index,) =\n                Core._saveNewPosition(maxLeverageData.newPosId.tick, data.pos, maxLeverageData.liquidationPenalty);\n\n            // adjust the balances to reflect the new value of the position\n            uint256 updatedPosValue =\n                Utils._positionValueOptimized(data.pos.totalExpo, data.lastPrice, data.liqPriceWithoutPenalty);\n            _validateOpenPositionUpdateBalances(updatedPosValue, data.oldPosValue);\n\n            emit IUsdnProtocolEvents.LiquidationPriceUpdated(\n                Types.PositionId({\n                    tick: data.action.tick,\n                    tickVersion: data.action.tickVersion,\n                    index: data.action.index\n                }),\n                maxLeverageData.newPosId\n            );\n            emit IUsdnProtocolEvents.ValidatedOpenPosition(\n                data.action.to, data.action.validator, data.pos.totalExpo, data.startPrice, maxLeverageData.newPosId\n            );\n\n            return (true, false, maxLeverageData.newPosId);\n        }\n\n        // calculate the new total exposure\n        uint128 expoBefore = data.pos.totalExpo;\n        uint128 expoAfter =\n            Utils._calcPositionTotalExpo(data.pos.amount, data.startPrice, data.liqPriceWithoutPenaltyNorFunding);\n\n        // update the total exposure of the position\n        data.pos.totalExpo = expoAfter;\n        // mark the position as validated\n        data.pos.validated = true;\n        // SSTORE\n        s._longPositions[data.tickHash][data.action.index] = data.pos;\n        // update the total exposure by adding the position's new exposure and removing the old one\n        // do not use += or it will underflow\n        s._totalExpo = s._totalExpo + expoAfter - expoBefore;\n\n        // update the tick data and the liqMultiplierAccumulator\n        {\n            Types.TickData storage tickData = s._tickData[data.tickHash];\n            uint256 unadjustedTickPrice =\n                TickMath.getPriceAtTick(Utils._calcTickWithoutPenalty(data.action.tick, data.liquidationPenalty));\n            tickData.totalExpo = tickData.totalExpo + expoAfter - expoBefore;\n            s._liqMultiplierAccumulator = s._liqMultiplierAccumulator.add(\n                HugeUint.wrap(expoAfter * unadjustedTickPrice)\n            ).sub(HugeUint.wrap(expoBefore * unadjustedTickPrice));\n        }\n\n        // adjust the balances to reflect the new value of the position\n        uint256 newPosValue = Utils._positionValueOptimized(expoAfter, data.lastPrice, data.liqPriceWithoutPenalty);\n        _validateOpenPositionUpdateBalances(newPosValue, data.oldPosValue);\n\n        isValidated_ = true;\n        emit IUsdnProtocolEvents.ValidatedOpenPosition(\n            data.action.to, data.action.validator, expoAfter, data.startPrice, posId_\n        );\n    }\n\n    /**\n     * @notice Initiates an open position action.\n     * @dev Consult the current oracle middleware implementation to know the expected format for the price data, using\n     * the {IUsdnProtocolTypes.ProtocolAction}'s `InitiateOpenPosition` action.\n     * The price validation might require payment according to the return value of the\n     * {IBaseOracleMiddleware.validationCost} function of the middleware.\n     * The position is immediately included in the protocol calculations with a temporary entry price (and thus\n     * leverage). The validation operation then updates the entry price and leverage with fresher data.\n     * @param params The parameters for the open position initiation.\n     * @param currentPriceData The current price data.\n     * @return posId_ The unique index of the opened position.\n     * @return amountToRefund_ If there are pending liquidations we'll refund the `securityDepositValue`,\n     * else we'll only refund the security deposit value of the stale pending action.\n     * @return isInitiated_ Whether the action is initiated.\n     */\n    function _initiateOpenPosition(Types.InitiateOpenPositionParams memory params, bytes calldata currentPriceData)\n        internal\n        returns (Types.PositionId memory posId_, uint256 amountToRefund_, bool isInitiated_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (params.to == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressTo();\n        }\n        if (params.validator == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressValidator();\n        }\n        if (params.amount == 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolZeroAmount();\n        }\n        if (params.amount < s._minLongPosition) {\n            revert IUsdnProtocolErrors.UsdnProtocolLongPositionTooSmall();\n        }\n\n        Types.InitiateOpenPositionData memory data = Long._prepareInitiateOpenPositionData(\n            Types.PrepareInitiateOpenPositionParams({\n                validator: params.validator,\n                amount: params.amount,\n                desiredLiqPrice: params.desiredLiqPrice,\n                userMaxPrice: params.userMaxPrice,\n                userMaxLeverage: params.userMaxLeverage,\n                currentPriceData: currentPriceData\n            })\n        );\n\n        if (data.isLiquidationPending) {\n            // value to indicate the position was not created\n            posId_.tick = Constants.NO_POSITION_TICK;\n            return (posId_, params.securityDepositValue, false);\n        }\n\n        // register position and adjust contract state\n        Types.Position memory long = Types.Position({\n            validated: false,\n            user: params.to,\n            amount: params.amount,\n            totalExpo: data.positionTotalExpo,\n            timestamp: uint40(block.timestamp)\n        });\n        (data.posId.tickVersion, data.posId.index,) =\n            Core._saveNewPosition(data.posId.tick, long, data.liquidationPenalty);\n        // because of the position fee, the position value is smaller than the amount\n        s._balanceLong += data.positionValue;\n        // positionValue must be smaller than or equal to amount, because the adjustedPrice (with fee) is larger than\n        // or equal to the current price\n        s._balanceVault += long.amount - data.positionValue;\n        posId_ = data.posId;\n\n        amountToRefund_ = Core._createOpenPendingAction(params.to, params.validator, params.securityDepositValue, data);\n\n        if (ERC165Checker.supportsInterface(msg.sender, type(IPaymentCallback).interfaceId)) {\n            Utils._transferCallback(s._asset, params.amount, address(this));\n        } else {\n            // slither-disable-next-line arbitrary-send-erc20\n            address(s._asset).safeTransferFrom(params.user, address(this), params.amount);\n        }\n\n        isInitiated_ = true;\n        emit IUsdnProtocolEvents.InitiatedOpenPosition(\n            params.to,\n            params.validator,\n            uint40(block.timestamp),\n            data.positionTotalExpo,\n            params.amount,\n            data.adjustedPrice,\n            posId_\n        );\n    }\n\n    /**\n     * @notice Retrieves the pending action data of the owner, try to validate it and clear it if successful.\n     * @param validator The address of the validator.\n     * @param priceData The price data for the pending action to validate.\n     * @return securityDepositValue_ The value of the security deposit to refund.\n     * @return isValidated_ Whether the action is validated.\n     * @return isLiquidated_ Whether the pending action is liquidated.\n     * @return posId_ The (potentially updated) position ID, or `NO_POSITION_TICK` in the `tick` field if the position\n     * was liquidated.\n     */\n    function _validateOpenPosition(address validator, bytes calldata priceData)\n        internal\n        returns (uint256 securityDepositValue_, bool isValidated_, bool isLiquidated_, Types.PositionId memory posId_)\n    {\n        (Types.PendingAction memory pending, uint128 rawIndex) = Core._getPendingActionOrRevert(validator);\n\n        // check type of action\n        if (pending.action != Types.ProtocolAction.ValidateOpenPosition) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingAction();\n        }\n        // sanity check\n        if (pending.validator != validator) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingAction();\n        }\n        (isValidated_, isLiquidated_, posId_) = _validateOpenPositionWithAction(pending, priceData);\n\n        if (isValidated_ || isLiquidated_) {\n            Utils._clearPendingAction(validator, rawIndex);\n            securityDepositValue_ = pending.securityDepositValue;\n        }\n    }\n\n    /**\n     * @notice Updates the protocol balances during {validateOpenPosition} to reflect the new entry price of the\n     * position.\n     * @dev We need to adjust the balances because the position that was created during the {initiateOpenPosition} might\n     * have gained or lost some value, and we need to reflect that the position value is now `newPosValue`.\n     * Any potential PnL on that temporary position must be \"cancelled\" so that it doesn't affect the other positions\n     * and the vault.\n     * @param newPosValue The new value of the position.\n     * @param oldPosValue The value of the position at the current price, using its old parameters.\n     */\n    function _validateOpenPositionUpdateBalances(uint256 newPosValue, uint256 oldPosValue) internal {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (newPosValue > oldPosValue) {\n            // the long side is missing some value, we need to take it from the vault\n            uint256 diff;\n            unchecked {\n                diff = newPosValue - oldPosValue;\n                uint256 balanceVault = s._balanceVault;\n                if (diff > balanceVault) {\n                    diff = balanceVault;\n                }\n                s._balanceVault = balanceVault - diff;\n            }\n            s._balanceLong += diff;\n        } else if (newPosValue < oldPosValue) {\n            // the long side has too much value, we need to give it to the vault side\n            uint256 diff;\n            unchecked {\n                diff = oldPosValue - newPosValue;\n                uint256 balanceLong = s._balanceLong;\n                if (diff > balanceLong) {\n                    diff = balanceLong;\n                }\n                s._balanceLong = balanceLong - diff;\n            }\n            s._balanceVault += diff;\n        }\n        // if both are equal, no action is needed\n    }\n\n    /**\n     * @notice Updates protocol balances, liquidate positions if necessary, then validate the open position action.\n     * @param pending The pending action data.\n     * @param priceData The price data for the pending action.\n     * @return data_ The {IUsdnProtocolTypes.ValidateOpenPositionData} data structure.\n     * @return isLiquidated_ Whether the position is liquidated.\n     */\n    function _prepareValidateOpenPositionData(Types.PendingAction memory pending, bytes calldata priceData)\n        internal\n        returns (Types.ValidateOpenPositionData memory data_, bool isLiquidated_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        data_.action = Utils._toLongPendingAction(pending);\n        PriceInfo memory currentPrice = Utils._getOraclePrice(\n            Types.ProtocolAction.ValidateOpenPosition,\n            data_.action.timestamp,\n            Utils._calcActionId(data_.action.validator, data_.action.timestamp),\n            priceData\n        );\n        // apply fees on price\n        data_.startPrice =\n            (currentPrice.price + currentPrice.price * s._positionFeeBps / Constants.BPS_DIVISOR).toUint128();\n\n        (, data_.isLiquidationPending) = Long._applyPnlAndFundingAndLiquidate(\n            currentPrice.neutralPrice,\n            currentPrice.timestamp,\n            s._liquidationIteration,\n            Types.ProtocolAction.ValidateOpenPosition,\n            priceData\n        );\n\n        uint256 version;\n        (data_.tickHash, version) = Utils._tickHash(data_.action.tick);\n        if (version != data_.action.tickVersion) {\n            // the current tick version doesn't match the version from the pending action\n            // this means the position has been liquidated in the meantime\n            emit IUsdnProtocolEvents.StalePendingActionRemoved(\n                data_.action.validator,\n                Types.PositionId({\n                    tick: data_.action.tick,\n                    tickVersion: data_.action.tickVersion,\n                    index: data_.action.index\n                })\n            );\n            return (data_, true);\n        }\n\n        if (data_.isLiquidationPending) {\n            return (data_, false);\n        }\n\n        data_.lastPrice = s._lastPrice;\n        uint128 liqPriceWithPenalty = Utils._getEffectivePriceForTick(data_.action.tick);\n        // a user that triggers this condition will be stuck in a validation loop until it liquidates its own position\n        // with the stored `_lastPrice`\n        if (data_.lastPrice <= liqPriceWithPenalty) {\n            data_.isLiquidationPending = true;\n            return (data_, false);\n        }\n\n        // get the position\n        data_.pos = s._longPositions[data_.tickHash][data_.action.index];\n        // re-calculate leverage\n        data_.liquidationPenalty = s._tickData[data_.tickHash].liquidationPenalty;\n        data_.liqPriceWithoutPenalty =\n            Utils._getEffectivePriceForTick(Utils._calcTickWithoutPenalty(data_.action.tick, data_.liquidationPenalty));\n\n        // calculate how much the position that was opened in the initiate is now worth (it might be too large or too\n        // small considering the new leverage and lastPrice). We will adjust the long and vault balances accordingly\n        // lastPrice is larger than or equal to liqPriceWithoutPenalty so the calc below does not underflow\n        data_.oldPosValue =\n            Utils._positionValueOptimized(data_.pos.totalExpo, data_.lastPrice, data_.liqPriceWithoutPenalty);\n\n        data_.liqPriceWithoutPenaltyNorFunding = Utils._getEffectivePriceForTick(\n            Utils._calcTickWithoutPenalty(data_.action.tick, data_.liquidationPenalty), data_.action.liqMultiplier\n        );\n\n        // if lastPrice > liqPriceWithPenalty\n        // but startPrice <= liqPriceWithPenalty OR startPrice <= liqPriceWithoutPenaltyNorFunding,\n        // then the user dodged liquidations. We still can't let the position open, because we can't calculate the\n        // leverage with a start price that is lower than a liquidation price, and we also can't liquidate the whole\n        // tick because other users could have opened positions in this tick after the user of the current position,\n        // our only choice is to liquidate this position only\n        if (data_.startPrice <= liqPriceWithPenalty || data_.startPrice <= data_.liqPriceWithoutPenaltyNorFunding) {\n            uint256 liquidationPrice = liqPriceWithPenalty;\n            // if the liquidation occurs because of liqPriceWithoutPenaltyNorFunding, use it as the effective price for\n            // the liquidation event\n            if (data_.startPrice > liqPriceWithPenalty && data_.startPrice <= data_.liqPriceWithoutPenaltyNorFunding) {\n                liquidationPrice = data_.liqPriceWithoutPenaltyNorFunding;\n            }\n\n            s._balanceLong -= data_.oldPosValue;\n            s._balanceVault += data_.oldPosValue;\n\n            Long._removeAmountFromPosition(\n                data_.action.tick, data_.action.index, data_.pos, data_.pos.amount, data_.pos.totalExpo\n            );\n\n            emit IUsdnProtocolEvents.LiquidatedPosition(\n                data_.action.validator,\n                Types.PositionId({\n                    tick: data_.action.tick,\n                    tickVersion: data_.action.tickVersion,\n                    index: data_.action.index\n                }),\n                data_.startPrice,\n                liquidationPrice\n            );\n\n            return (data_, true);\n        }\n\n        // calculate the leverage of the position without considering the penalty nor the funding by using the\n        // multiplier state at T+24\n        data_.leverage = Utils._getLeverage(data_.startPrice, data_.liqPriceWithoutPenaltyNorFunding);\n    }\n\n    /**\n     * @notice Initiates a close position action.\n     * @dev Consult the current oracle middleware implementation to know the expected format for the price data, using\n     * the {IUsdnProtocolTypes.ProtocolAction}'s `InitiateClosePosition` action.\n     * The price validation might require payment according to the return value of the\n     * {IBaseOracleMiddleware.validationCost} function of the middleware.\n     * If the current tick version is greater than the tick version of the position (when it was opened), then the\n     * position has been liquidated and this function will return 0.\n     * The position is taken out of the tick and put in a pending state during this operation. Thus, calculations don't\n     * consider this position anymore. The exit price (and thus profit) is not yet set definitively and will be done\n     * during the `validate` action.\n     * @param params The parameters for the close position initiation.\n     * @param currentPriceData The current price data.\n     * @param delegationSignature An EIP712 signature that proves the caller is authorized by the owner of the position\n     * to close it on their behalf.\n     * @return amountToRefund_ If there are pending liquidations we'll refund the `securityDepositValue`,\n     * else we'll only refund the security deposit value of the stale pending action.\n     * @return isInitiated_ Whether the action is initiated.\n     * @return isLiquidated_ Whether the position got liquidated by this call.\n     */\n    function _initiateClosePosition(\n        Types.InitiateClosePositionParams memory params,\n        bytes calldata currentPriceData,\n        bytes calldata delegationSignature\n    ) internal returns (uint256 amountToRefund_, bool isInitiated_, bool isLiquidated_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        Types.ClosePositionData memory data;\n        (data, isLiquidated_) = ActionsUtils._prepareClosePositionData(\n            Types.PrepareInitiateClosePositionParams({\n                to: params.to,\n                validator: params.validator,\n                posId: params.posId,\n                amountToClose: params.amountToClose,\n                userMinPrice: params.userMinPrice,\n                deadline: params.deadline,\n                currentPriceData: currentPriceData,\n                delegationSignature: delegationSignature,\n                domainSeparatorV4: params.domainSeparatorV4\n            })\n        );\n\n        if (isLiquidated_ || data.isLiquidationPending) {\n            // position was liquidated in this transaction or liquidations are pending\n            return (params.securityDepositValue, false, isLiquidated_);\n        }\n\n        amountToRefund_ = Core._createClosePendingAction(\n            params.to, params.validator, params.posId, params.amountToClose, params.securityDepositValue, data\n        );\n\n        s._balanceLong -= data.tempPositionValue;\n\n        Long._removeAmountFromPosition(\n            params.posId.tick, params.posId.index, data.pos, params.amountToClose, data.totalExpoToClose\n        );\n\n        isInitiated_ = true;\n        emit IUsdnProtocolEvents.InitiatedClosePosition(\n            data.pos.user,\n            params.validator,\n            params.to,\n            params.posId,\n            data.pos.amount,\n            params.amountToClose,\n            data.pos.totalExpo - data.totalExpoToClose\n        );\n    }\n\n    /**\n     * @notice Retrieves the pending action data of the validator, try to validate it and clear it if successful.\n     * @param validator The validator of the pending action.\n     * @param priceData The price data for the validator's pending action.\n     * @return securityDepositValue_ The value of the security deposit of the pending action.\n     * @return isValidated_ Whether the action is validated.\n     * @return isLiquidated_ Whether the pending action is liquidated.\n     */\n    function _validateClosePosition(address validator, bytes calldata priceData)\n        internal\n        returns (uint256 securityDepositValue_, bool isValidated_, bool isLiquidated_)\n    {\n        (Types.PendingAction memory pending, uint128 rawIndex) = Core._getPendingActionOrRevert(validator);\n\n        // check type of action\n        if (pending.action != Types.ProtocolAction.ValidateClosePosition) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingAction();\n        }\n        // sanity check\n        if (pending.validator != validator) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidPendingAction();\n        }\n\n        (isValidated_, isLiquidated_) = _validateClosePositionWithAction(pending, priceData);\n\n        if (isValidated_ || isLiquidated_) {\n            Utils._clearPendingAction(validator, rawIndex);\n            securityDepositValue_ = pending.securityDepositValue;\n        }\n    }\n\n    /**\n     * @notice Updates protocol balances, liquidate positions if necessary, then validate the close position action.\n     * @param pending The pending action data.\n     * @param priceData The price data for the action to validate.\n     * @return isValidated_ Whether the action is validated.\n     * @return isLiquidated_ Whether the pending action is liquidated.\n     */\n    function _validateClosePositionWithAction(Types.PendingAction memory pending, bytes calldata priceData)\n        internal\n        returns (bool isValidated_, bool isLiquidated_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        ValidateClosePositionWithActionData memory data;\n        Types.LongPendingAction memory long = Utils._toLongPendingAction(pending);\n\n        PriceInfo memory currentPrice = Utils._getOraclePrice(\n            Types.ProtocolAction.ValidateClosePosition,\n            long.timestamp,\n            Utils._calcActionId(long.validator, long.timestamp),\n            priceData\n        );\n\n        (, data.isLiquidationPending) = Long._applyPnlAndFundingAndLiquidate(\n            currentPrice.neutralPrice,\n            currentPrice.timestamp,\n            s._liquidationIteration,\n            Types.ProtocolAction.ValidateClosePosition,\n            priceData\n        );\n\n        // apply fees on price\n        data.priceWithFees =\n            (currentPrice.price - currentPrice.price * s._positionFeeBps / Constants.BPS_DIVISOR).toUint128();\n\n        // get liquidation price (with liq penalty) to check if the position was valid at `timestamp + validationDelay`\n        data.liquidationPrice = Utils._getEffectivePriceForTick(long.tick, long.liqMultiplier);\n\n        if (currentPrice.neutralPrice <= data.liquidationPrice) {\n            // position should be liquidated, we don't transfer assets to the user\n            // position was already removed from tick so no additional bookkeeping is necessary\n            // credit the full amount to the vault to preserve the total balance invariant\n            s._balanceVault += long.closeBoundedPositionValue;\n            emit IUsdnProtocolEvents.LiquidatedPosition(\n                long.validator, // not necessarily the position owner\n                Types.PositionId({ tick: long.tick, tickVersion: long.tickVersion, index: long.index }),\n                currentPrice.neutralPrice,\n                data.liquidationPrice\n            );\n            return (false, true);\n        }\n\n        if (data.isLiquidationPending) {\n            return (false, false);\n        }\n\n        int24 tickWithoutPenalty = Utils._calcTickWithoutPenalty(long.tick, long.closeLiqPenalty);\n        data.positionValue = Utils._positionValue(\n            long.closePosTotalExpo,\n            data.priceWithFees,\n            Utils._getEffectivePriceForTick(tickWithoutPenalty, long.liqMultiplier)\n        );\n\n        uint256 assetToTransfer;\n        if (data.positionValue > 0) {\n            assetToTransfer = uint256(data.positionValue);\n            // normally, the position value should be smaller than `long.closeBoundedPositionValue`\n            // (due to the position fee)\n            // we can send the difference (any remaining collateral) to the vault\n            // if the price increased since the initiation, it's possible that the position value is higher than the\n            // `long.closeBoundedPositionValue`. In that case, we need to take the missing assets from the vault\n            if (assetToTransfer < long.closeBoundedPositionValue) {\n                uint256 remainingCollateral;\n                unchecked {\n                    // since assetToTransfer is strictly smaller than closeBoundedPositionValue,\n                    // this operation can't underflow\n                    remainingCollateral = long.closeBoundedPositionValue - assetToTransfer;\n                }\n                s._balanceVault += remainingCollateral;\n            } else if (assetToTransfer > long.closeBoundedPositionValue) {\n                uint256 missingValue;\n                unchecked {\n                    // since assetToTransfer is strictly larger than closeBoundedPositionValue,\n                    // this operation can't underflow\n                    missingValue = assetToTransfer - long.closeBoundedPositionValue;\n                }\n                uint256 balanceVault = s._balanceVault;\n                // if the vault does not have enough balance left to pay out the missing value, we take what we can\n                if (missingValue > balanceVault) {\n                    s._balanceVault = 0;\n                    unchecked {\n                        // since `missingValue` is strictly larger than `balanceVault`,\n                        // their subtraction can't underflow\n                        // moreover, since (missingValue - balanceVault) is smaller than or equal to `missingValue`,\n                        // and since `missingValue` is smaller than or equal to `assetToTransfer`,\n                        // (missingValue - balanceVault) is smaller than or equal to `assetToTransfer`,\n                        // and their subtraction can't underflow\n                        assetToTransfer -= missingValue - balanceVault;\n                    }\n                } else {\n                    unchecked {\n                        // as `missingValue` is smaller than or equal to `balanceVault`, this operation can't underflow\n                        s._balanceVault = balanceVault - missingValue;\n                    }\n                }\n            }\n\n            if (assetToTransfer > 0) {\n                address(s._asset).safeTransfer(long.to, assetToTransfer);\n            }\n        } else {\n            // if the position value <= 0, including the fees and the Pyth confidence interval, no assets will be\n            // transferred. However, the `closeBoundedPositionValue` must still be credited to the vault\n\n            s._balanceVault += long.closeBoundedPositionValue;\n        }\n\n        isValidated_ = true;\n\n        emit IUsdnProtocolEvents.ValidatedClosePosition(\n            long.validator,\n            long.to,\n            Types.PositionId({ tick: long.tick, tickVersion: long.tickVersion, index: long.index }),\n            assetToTransfer,\n            assetToTransfer.toInt256() - Utils._toInt256(long.closeAmount)\n        );\n    }\n}\n"},{"file_path":"src/interfaces/Rebalancer/IRebalancerTypes.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/**\n * @title Rebalancer Types\n * @notice Defines all custom types used by the Rebalancer contract.\n */\ninterface IRebalancerTypes {\n    /**\n     * @notice Represents the deposit data of a user.\n     * @dev A value of zero for `initiateTimestamp` indicates that the deposit or withdrawal has been validated.\n     * @param initiateTimestamp The timestamp when the deposit or withdrawal was initiated.\n     * @param amount The amount of assets deposited by the user.\n     * @param entryPositionVersion The version of the position the user entered.\n     */\n    struct UserDeposit {\n        uint40 initiateTimestamp;\n        uint88 amount; // maximum 309'485'009 tokens with 18 decimals\n        uint128 entryPositionVersion;\n    }\n\n    /**\n     * @notice Represents data for a specific version of a position.\n     * @dev The difference between `amount` here and the amount saved in the USDN protocol is the liquidation bonus.\n     * @param amount The amount of assets used as collateral to open the position.\n     * @param tick The tick of the position.\n     * @param tickVersion The version of the tick.\n     * @param index The index of the position in the tick list.\n     * @param entryAccMultiplier The accumulated PnL multiplier of all positions up to this one.\n     */\n    struct PositionData {\n        uint128 amount;\n        int24 tick;\n        uint256 tickVersion;\n        uint256 index;\n        uint256 entryAccMultiplier;\n    }\n\n    /**\n     * @notice Defines parameters related to the validation process for rebalancer deposits and withdrawals.\n     * @dev If `validationDeadline` has passed, the user must wait until the cooldown duration has elapsed. Then, for\n     * deposit actions, the user must retrieve its funds using {IRebalancer.resetDepositAssets}. For withdrawal actions,\n     * the user can simply initiate a new withdrawal.\n     * @param validationDelay The minimum duration in seconds between an initiate action and the corresponding validate\n     * action.\n     * @param validationDeadline The maximum duration in seconds between an initiate action and the corresponding\n     * validate action.\n     * @param actionCooldown The duration in seconds from the initiate action during which the user can't interact with\n     * the rebalancer if the `validationDeadline` is exceeded.\n     * @param closeDelay The Duration in seconds from the last rebalancer long position opening during which the user\n     * can't perform an {IRebalancer.initiateClosePosition}.\n     */\n    struct TimeLimits {\n        uint64 validationDelay;\n        uint64 validationDeadline;\n        uint64 actionCooldown;\n        uint64 closeDelay;\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolActions.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IUsdnProtocolTypes } from \"./IUsdnProtocolTypes.sol\";\n\n/**\n * @title IUsdnProtocolActions\n * @notice Interface for the USDN Protocol Actions.\n */\ninterface IUsdnProtocolActions is IUsdnProtocolTypes {\n    /**\n     * @notice Initiates an open position action.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * Requires `_securityDepositValue` to be included in the transaction value. In case of pending liquidations, this\n     * function will not initiate the position (`isInitiated_` would be false).\n     * The user's input for price and leverage is not guaranteed due to the price difference between the initiate and\n     * validate actions.\n     * @param amount The amount of assets to deposit.\n     * @param desiredLiqPrice The desired liquidation price, including the penalty.\n     * @param userMaxPrice The user's wanted maximum price at which the position can be opened.\n     * @param userMaxLeverage The user's wanted maximum leverage for the new position.\n     * @param to The address that will owns of the position.\n     * @param validator The address that is supposed to validate the opening and receive the security deposit. If not\n     * an EOA, it must be a contract that implements a `receive` function.\n     * @param deadline The deadline for initiating the open position.\n     * @param currentPriceData The price data used for temporary leverage and entry price computations.\n     * @param previousActionsData The data needed to validate actionable pending actions.\n     * @return isInitiated_ Whether the position was successfully initiated. If false, the security deposit was refunded\n     * @return posId_ The unique position identifier. If the position was not initiated, the tick number will be\n     * `NO_POSITION_TICK`.\n     */\n    function initiateOpenPosition(\n        uint128 amount,\n        uint128 desiredLiqPrice,\n        uint128 userMaxPrice,\n        uint256 userMaxLeverage,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable returns (bool isInitiated_, PositionId memory posId_);\n\n    /**\n     * @notice Validates a pending open position action.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * It is possible for this operation to change the tick, tick version and index of the position, in which case we  emit\n     * the `LiquidationPriceUpdated` event.\n     * This function always sends the security deposit to the validator. So users wanting to earn the corresponding\n     * security deposit must use `validateActionablePendingActions`.\n     * In case liquidations are pending (`outcome_ == LongActionOutcome.PendingLiquidations`), the pending action will\n     * not be removed from the queue, and the user will have to try again.\n     * In case the position was liquidated by this call (`outcome_ == LongActionOutcome.Liquidated`), this function will\n     * refund the security deposit and remove the pending action from the queue.\n     * @param validator The address associated with the pending open position. If not an EOA, it must be a contract that\n     * implements a `receive` function.\n     * @param openPriceData The price data for the pending open position.\n     * @param previousActionsData The data needed to validate actionable pending actions.\n     * @return outcome_ The effect on the pending action (processed, liquidated, or pending liquidations).\n     * @return posId_ The position ID after validation (or `NO_POSITION_TICK` if liquidated).\n     */\n    function validateOpenPosition(\n        address payable validator,\n        bytes calldata openPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable returns (LongActionOutcome outcome_, PositionId memory posId_);\n\n    /**\n     * @notice Initiates a close position action.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * Requires `_securityDepositValue` to be included in the transaction value.\n     * If the current tick version is greater than the tick version of the position (when it was opened), then the\n     * position has been liquidated and the transaction will revert.\n     * In case liquidations are pending (`outcome_ == LongActionOutcome.PendingLiquidations`), the pending action will\n     * not be removed from the queue, and the user will have to try again.\n     * In case the position was liquidated by this call (`outcome_ == LongActionOutcome.Liquidated`), this function will\n     * refund the security deposit and remove the pending action from the queue.\n     * The user's input for the price is not guaranteed due to the price difference between the initiate and validate\n     * actions.\n     * @param posId The unique identifier of the position to close.\n     * @param amountToClose The amount of collateral to remove.\n     * @param userMinPrice The user's wanted minimum price for closing the position.\n     * @param to The address that will receive the assets.\n     * @param validator The address that is supposed to validate the closing and receive the security deposit. If not an\n     * EOA, it must be a contract that implements a `receive` function.\n     * @param deadline The deadline for initiating the close position.\n     * @param currentPriceData The price data for temporary calculations.\n     * @param previousActionsData The data needed to validate actionable pending actions.\n     * @param delegationSignature Optional EIP712 signature for delegated action.\n     * @return outcome_ The effect on the pending action (processed, liquidated, or pending liquidations).\n     */\n    function initiateClosePosition(\n        PositionId calldata posId,\n        uint128 amountToClose,\n        uint256 userMinPrice,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        PreviousActionsData calldata previousActionsData,\n        bytes calldata delegationSignature\n    ) external payable returns (LongActionOutcome outcome_);\n\n    /**\n     * @notice Validates a pending close position action.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * This function calculates the final exit price, determines the profit of the long position, and performs the\n     * payout.\n     * This function always sends the security deposit to the validator. So users wanting to earn the corresponding\n     * security deposit must use `validateActionablePendingActions`.\n     * In case liquidations are pending (`outcome_ == LongActionOutcome.PendingLiquidations`),\n     * the pending action will not be removed from the queue, and the user will have to try again.\n     * In case the position was liquidated by this call (`outcome_ == LongActionOutcome.Liquidated`),\n     * this function will refund the security deposit and remove the pending action from the queue.\n     * @param validator The address associated with the pending close position. If not an EOA, it must be a contract\n     * that implements a `receive` function.\n     * @param closePriceData The price data for the pending close position action.\n     * @param previousActionsData The data required to validate actionable pending actions.\n     * @return outcome_ The outcome of the action (processed, liquidated, or pending liquidations).\n     */\n    function validateClosePosition(\n        address payable validator,\n        bytes calldata closePriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable returns (LongActionOutcome outcome_);\n\n    /**\n     * @notice Initiates a deposit of assets into the vault to mint USDN.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * Requires `_securityDepositValue` to be included in the transaction value.\n     * In case liquidations are pending, this function might not initiate the deposit, and `success_` would be false.\n     * The user's input for the shares is not guaranteed due to the price difference between the initiate and validate\n     * actions.\n     * @param amount The amount of assets to deposit.\n     * @param sharesOutMin The minimum amount of USDN shares to receive.\n     * @param to The address that will receive the USDN tokens.\n     * @param validator The address that is supposed to validate the deposit and receive the security deposit. If not an\n     * EOA, it must be a contract that implements a `receive` function.\n     * @param deadline The deadline for initiating the deposit.\n     * @param currentPriceData The current price data.\n     * @param previousActionsData The data required to validate actionable pending actions.\n     * @return success_ Indicates whether the deposit was successfully initiated.\n     */\n    function initiateDeposit(\n        uint128 amount,\n        uint256 sharesOutMin,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable returns (bool success_);\n\n    /**\n     * @notice Validates a pending deposit action.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * This function always sends the security deposit to the validator. So users wanting to earn the corresponding\n     * security deposit must use `validateActionablePendingActions`.\n     * If liquidations are pending, the validation may fail, and `success_` would be false.\n     * @param validator The address associated with the pending deposit action. If not an EOA, it must be a contract\n     * that implements a `receive` function.\n     * @param depositPriceData The price data for the pending deposit action.\n     * @param previousActionsData The data required to validate actionable pending actions.\n     * @return success_ Indicates whether the deposit was successfully validated.\n     */\n    function validateDeposit(\n        address payable validator,\n        bytes calldata depositPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable returns (bool success_);\n\n    /**\n     * @notice Initiates a withdrawal of assets from the vault using USDN tokens.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * Requires `_securityDepositValue` to be included in the transaction value.\n     * Note that in case liquidations are pending, this function might not initiate the withdrawal, and `success_` would\n     * be false.\n     * The user's input for the minimum amount is not guaranteed due to the price difference between the initiate and\n     * validate actions.\n     * @param usdnShares The amount of USDN shares to burn.\n     * @param amountOutMin The minimum amount of assets to receive.\n     * @param to The address that will receive the assets.\n     * @param validator The address that is supposed to validate the withdrawal and receive the security deposit. If not\n     * an EOA, it must be a contract that implements a `receive` function.\n     * @param deadline The deadline for initiating the withdrawal.\n     * @param currentPriceData The current price data.\n     * @param previousActionsData The data required to validate actionable pending actions.\n     * @return success_ Indicates whether the withdrawal was successfully initiated.\n     */\n    function initiateWithdrawal(\n        uint152 usdnShares,\n        uint256 amountOutMin,\n        address to,\n        address payable validator,\n        uint256 deadline,\n        bytes calldata currentPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable returns (bool success_);\n\n    /**\n     * @notice Validates a pending withdrawal action.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * This function always sends the security deposit to the validator. So users wanting to earn the corresponding\n     * security deposit must use `validateActionablePendingActions`.\n     * In case liquidations are pending, this function might not validate the withdrawal, and `success_` would be false.\n     * @param validator The address associated with the pending withdrawal action. If not an EOA, it must be a contract\n     * that implements a `receive` function.\n     * @param withdrawalPriceData The price data for the pending withdrawal action.\n     * @param previousActionsData The data required to validate actionable pending actions.\n     * @return success_ Indicates whether the withdrawal was successfully validated.\n     */\n    function validateWithdrawal(\n        address payable validator,\n        bytes calldata withdrawalPriceData,\n        PreviousActionsData calldata previousActionsData\n    ) external payable returns (bool success_);\n\n    /**\n     * @notice Liquidates positions based on the provided asset price.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * Each tick is liquidated in constant time. The tick version is incremented for each liquidated tick.\n     * @param currentPriceData The price data.\n     * @return liquidatedTicks_ Information about the liquidated ticks.\n     */\n    function liquidate(bytes calldata currentPriceData)\n        external\n        payable\n        returns (LiqTickInfo[] memory liquidatedTicks_);\n\n    /**\n     * @notice Manually validates actionable pending actions.\n     * @dev Consult the current oracle middleware for price data format and possible oracle fee.\n     * The timestamp for each pending action is calculated by adding the `OracleMiddleware.validationDelay` to its\n     * initiation timestamp.\n     * @param previousActionsData The data required to validate actionable pending actions.\n     * @param maxValidations The maximum number of actionable pending actions to validate. At least one validation will\n     * be performed.\n     * @return validatedActions_ The number of successfully validated actions.\n     */\n    function validateActionablePendingActions(PreviousActionsData calldata previousActionsData, uint256 maxValidations)\n        external\n        payable\n        returns (uint256 validatedActions_);\n\n    /**\n     * @notice Transfers the ownership of a position to another address.\n     * @dev This function reverts if the caller is not the position owner, if the position does not exist, or if the new\n     * owner's address is the zero address.\n     * If the new owner is a contract that implements the `IOwnershipCallback` interface, its `ownershipCallback`\n     * function will be invoked after the transfer.\n     * @param posId The unique identifier of the position.\n     * @param newOwner The address of the new position owner.\n     * @param delegationSignature An optional EIP712 signature to authorize the transfer on the owner's behalf.\n     */\n    function transferPositionOwnership(PositionId calldata posId, address newOwner, bytes calldata delegationSignature)\n        external;\n\n    /**\n     * @notice Retrieves the domain separator used in EIP-712 signatures.\n     * @return domainSeparatorV4_ The domain separator compliant with EIP-712.\n     */\n    function domainSeparatorV4() external view returns (bytes32 domainSeparatorV4_);\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/utils/introspection/ERC165Checker.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165Checker.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Library used to query support of an interface declared via {IERC165}.\n *\n * Note that these functions return the actual result of the query: they do not\n * `revert` if an interface is not supported. It is up to the caller to decide\n * what to do in these cases.\n */\nlibrary ERC165Checker {\n    // As per the ERC-165 spec, no interface should ever match 0xffffffff\n    bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;\n\n    /**\n     * @dev Returns true if `account` supports the {IERC165} interface.\n     */\n    function supportsERC165(address account) internal view returns (bool) {\n        // Any contract that implements ERC-165 must explicitly indicate support of\n        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\n        return\n            supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&\n            !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);\n    }\n\n    /**\n     * @dev Returns true if `account` supports the interface defined by\n     * `interfaceId`. Support for {IERC165} itself is queried automatically.\n     *\n     * See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\n        // query support of both ERC-165 as per the spec and support of _interfaceId\n        return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);\n    }\n\n    /**\n     * @dev Returns a boolean array where each value corresponds to the\n     * interfaces passed in and whether they're supported or not. This allows\n     * you to batch check interfaces for a contract where your expectation\n     * is that some interfaces may not be supported.\n     *\n     * See {IERC165-supportsInterface}.\n     */\n    function getSupportedInterfaces(\n        address account,\n        bytes4[] memory interfaceIds\n    ) internal view returns (bool[] memory) {\n        // an array of booleans corresponding to interfaceIds and whether they're supported or not\n        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\n\n        // query support of ERC-165 itself\n        if (supportsERC165(account)) {\n            // query support of each interface in interfaceIds\n            for (uint256 i = 0; i < interfaceIds.length; i++) {\n                interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);\n            }\n        }\n\n        return interfaceIdsSupported;\n    }\n\n    /**\n     * @dev Returns true if `account` supports all the interfaces defined in\n     * `interfaceIds`. Support for {IERC165} itself is queried automatically.\n     *\n     * Batch-querying can lead to gas savings by skipping repeated checks for\n     * {IERC165} support.\n     *\n     * See {IERC165-supportsInterface}.\n     */\n    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\n        // query support of ERC-165 itself\n        if (!supportsERC165(account)) {\n            return false;\n        }\n\n        // query support of each interface in interfaceIds\n        for (uint256 i = 0; i < interfaceIds.length; i++) {\n            if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {\n                return false;\n            }\n        }\n\n        // all interfaces supported\n        return true;\n    }\n\n    /**\n     * @notice Query if a contract implements an interface, does not check ERC-165 support\n     * @param account The address of the contract to query for support of an interface\n     * @param interfaceId The interface identifier, as specified in ERC-165\n     * @return true if the contract at account indicates support of the interface with\n     * identifier interfaceId, false otherwise\n     * @dev Assumes that account contains a contract that supports ERC-165, otherwise\n     * the behavior of this method is undefined. This precondition can be checked\n     * with {supportsERC165}.\n     *\n     * Some precompiled contracts will falsely indicate support for a given interface, so caution\n     * should be exercised when using this function.\n     *\n     * Interface identification is specified in ERC-165.\n     */\n    function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {\n        // prepare call\n        bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));\n\n        // perform static call\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0x00)\n        }\n\n        return success && returnSize >= 0x20 && returnValue > 0;\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/access/IAccessControl.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev The `account` is missing a role.\n     */\n    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n    /**\n     * @dev The caller of a function is not the expected one.\n     *\n     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n     */\n    error AccessControlBadConfirmation();\n\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},{"file_path":"src/interfaces/Usdn/IUsdnErrors.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/**\n * @title Errors for the USDN token contract\n * @notice Defines all custom errors emitted by the USDN token contract.\n */\ninterface IUsdnErrors {\n    /**\n     * @dev The amount of tokens exceeds the maximum allowed limit.\n     * @param value The invalid token value.\n     */\n    error UsdnMaxTokensExceeded(uint256 value);\n\n    /**\n     * @dev The sender's share balance is insufficient.\n     * @param sender The sender's address.\n     * @param balance The current share balance of the sender.\n     * @param needed The required amount of shares for the transfer.\n     */\n    error UsdnInsufficientSharesBalance(address sender, uint256 balance, uint256 needed);\n\n    /// @dev The divisor value in storage is invalid (< 1).\n    error UsdnInvalidDivisor();\n}\n"},{"file_path":"src/interfaces/OracleMiddleware/IBaseOracleMiddleware.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IUsdnProtocolTypes as Types } from \"../UsdnProtocol/IUsdnProtocolTypes.sol\";\nimport { PriceInfo } from \"./IOracleMiddlewareTypes.sol\";\n\n/**\n * @title Base Oracle Middleware interface\n * @notice This interface exposes the only functions used or required by the USDN Protocol.\n * @dev Any current or future implementation of the oracle middleware must be compatible with\n * this interface without any modification.\n */\ninterface IBaseOracleMiddleware {\n    /**\n     * @notice Parse and validate `data` and returns the corresponding price data.\n     * @dev The data format is specific to the middleware and is simply forwarded from the user transaction's calldata.\n     * A fee amounting to exactly {validationCost} (with the same `data` and `action`) must be sent or the transaction\n     * will revert.\n     * @param actionId A unique identifier for the current action. This identifier can be used to link an `Initiate`\n     * call with the corresponding `Validate` call.\n     * @param targetTimestamp The target timestamp for validating the price data. For validation actions, this is the\n     * timestamp of the initiation.\n     * @param action Type of action for which the price is requested. The middleware may use this to alter the\n     * validation of the price or the returned price.\n     * @param data The data to be used to communicate with oracles, the format varies from middleware to middleware and\n     * can be different depending on the action.\n     * @return result_ The price and timestamp as {IOracleMiddlewareTypes.PriceInfo}.\n     */\n    function parseAndValidatePrice(\n        bytes32 actionId,\n        uint128 targetTimestamp,\n        Types.ProtocolAction action,\n        bytes calldata data\n    ) external payable returns (PriceInfo memory result_);\n\n    /**\n     * @notice Gets the required delay (in seconds) between the moment an action is initiated and the timestamp of the\n     * price data used to validate that action.\n     * @return delay_ The validation delay.\n     */\n    function getValidationDelay() external view returns (uint256 delay_);\n\n    /**\n     * @notice Gets The maximum amount of time (in seconds) after initiation during which a low-latency price oracle can\n     * be used for validation.\n     * @return delay_ The maximum delay for low-latency validation.\n     */\n    function getLowLatencyDelay() external view returns (uint16 delay_);\n\n    /**\n     * @notice Gets the number of decimals for the price.\n     * @return decimals_ The number of decimals.\n     */\n    function getDecimals() external view returns (uint8 decimals_);\n\n    /**\n     * @notice Returns the cost of one price validation for the given action (in native token).\n     * @param data Price data for which to get the fee.\n     * @param action Type of the action for which the price is requested.\n     * @return cost_ The cost of one price validation (in native token).\n     */\n    function validationCost(bytes calldata data, Types.ProtocolAction action) external view returns (uint256 cost_);\n}\n"},{"file_path":"src/UsdnProtocol/UsdnProtocolVault.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { IUsdnProtocolVault } from \"../interfaces/UsdnProtocol/IUsdnProtocolVault.sol\";\nimport { UsdnProtocolVaultLibrary as Vault } from \"./libraries/UsdnProtocolVaultLibrary.sol\";\n\nabstract contract UsdnProtocolVault is IUsdnProtocolVault {\n    /// @inheritdoc IUsdnProtocolVault\n    function usdnPrice(uint128 currentPrice, uint128 timestamp) external view returns (uint256 price_) {\n        return Vault.usdnPrice(currentPrice, timestamp);\n    }\n\n    /// @inheritdoc IUsdnProtocolVault\n    function usdnPrice(uint128 currentPrice) external view returns (uint256 price_) {\n        return Vault.usdnPrice(currentPrice);\n    }\n\n    /// @inheritdoc IUsdnProtocolVault\n    function vaultAssetAvailableWithFunding(uint128 currentPrice, uint128 timestamp)\n        external\n        view\n        returns (uint256 available_)\n    {\n        return Vault.vaultAssetAvailableWithFunding(currentPrice, timestamp);\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-upgradeable-5.1.0/access/AccessControlUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"@openzeppelin/contracts/access/IAccessControl.sol\";\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {ERC165Upgradeable} from \"../utils/introspection/ERC165Upgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {\n    struct RoleData {\n        mapping(address account => bool) hasRole;\n        bytes32 adminRole;\n    }\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl\n    struct AccessControlStorage {\n        mapping(bytes32 role => RoleData) _roles;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.AccessControl\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;\n\n    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {\n        assembly {\n            $.slot := AccessControlStorageLocation\n        }\n    }\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with an {AccessControlUnauthorizedAccount} error including the required role.\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    function __AccessControl_init() internal onlyInitializing {\n    }\n\n    function __AccessControl_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].hasRole[account];\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n     * is missing `role`.\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert AccessControlUnauthorizedAccount(account, role);\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n        if (callerConfirmation != _msgSender()) {\n            revert AccessControlBadConfirmation();\n        }\n\n        _revokeRole(role, callerConfirmation);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        $._roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (!hasRole(role, account)) {\n            $._roles[role].hasRole[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (hasRole(role, account)) {\n            $._roles[role].hasRole[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolCore.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/**\n * @title IUsdnProtocolCore\n * @notice Interface for the core layer of the USDN protocol.\n */\ninterface IUsdnProtocolCore {\n    /**\n     * @notice Computes the predicted funding value since the last state update for the specified timestamp.\n     * @dev The funding value, when multiplied by the long trading exposure, represents the asset balance to be\n     * transferred to the vault side, or to the long side if the value is negative.\n     * Reverts with `UsdnProtocolTimestampTooOld` if the given timestamp is older than the last state update.\n     * @param timestamp The timestamp to use for the computation.\n     * @return funding_ The funding magnitude (with `FUNDING_RATE_DECIMALS` decimals) since the last update timestamp.\n     * @return fundingPerDay_ The funding rate per day (with `FUNDING_RATE_DECIMALS` decimals).\n     * @return oldLongExpo_ The long trading exposure recorded at the last state update.\n     */\n    function funding(uint128 timestamp)\n        external\n        view\n        returns (int256 funding_, int256 fundingPerDay_, int256 oldLongExpo_);\n\n    /**\n     * @notice Initializes the protocol by making an initial deposit and creating the first long position.\n     * @dev This function can only be called once. No other user actions can be performed until the protocol\n     * is initialized.\n     * @param depositAmount The amount of assets to deposit.\n     * @param longAmount The amount of assets for the long position.\n     * @param desiredLiqPrice The desired liquidation price for the long position, excluding the liquidation penalty.\n     * @param currentPriceData The encoded current price data.\n     */\n    function initialize(\n        uint128 depositAmount,\n        uint128 longAmount,\n        uint128 desiredLiqPrice,\n        bytes calldata currentPriceData\n    ) external payable;\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/access/extensions/IAccessControlDefaultAdminRules.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/IAccessControlDefaultAdminRules.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"../IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlDefaultAdminRules declared to support ERC-165 detection.\n */\ninterface IAccessControlDefaultAdminRules is IAccessControl {\n    /**\n     * @dev The new default admin is not a valid default admin.\n     */\n    error AccessControlInvalidDefaultAdmin(address defaultAdmin);\n\n    /**\n     * @dev At least one of the following rules was violated:\n     *\n     * - The `DEFAULT_ADMIN_ROLE` must only be managed by itself.\n     * - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time.\n     * - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps.\n     */\n    error AccessControlEnforcedDefaultAdminRules();\n\n    /**\n     * @dev The delay for transferring the default admin delay is enforced and\n     * the operation must wait until `schedule`.\n     *\n     * NOTE: `schedule` can be 0 indicating there's no transfer scheduled.\n     */\n    error AccessControlEnforcedDefaultAdminDelay(uint48 schedule);\n\n    /**\n     * @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next\n     * address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule`\n     * passes.\n     */\n    event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule);\n\n    /**\n     * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule.\n     */\n    event DefaultAdminTransferCanceled();\n\n    /**\n     * @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next\n     * delay to be applied between default admin transfer after `effectSchedule` has passed.\n     */\n    event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule);\n\n    /**\n     * @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass.\n     */\n    event DefaultAdminDelayChangeCanceled();\n\n    /**\n     * @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder.\n     */\n    function defaultAdmin() external view returns (address);\n\n    /**\n     * @dev Returns a tuple of a `newAdmin` and an accept schedule.\n     *\n     * After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role\n     * by calling {acceptDefaultAdminTransfer}, completing the role transfer.\n     *\n     * A zero value only in `acceptSchedule` indicates no pending admin transfer.\n     *\n     * NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced.\n     */\n    function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule);\n\n    /**\n     * @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started.\n     *\n     * This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set\n     * the acceptance schedule.\n     *\n     * NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this\n     * function returns the new delay. See {changeDefaultAdminDelay}.\n     */\n    function defaultAdminDelay() external view returns (uint48);\n\n    /**\n     * @dev Returns a tuple of `newDelay` and an effect schedule.\n     *\n     * After the `schedule` passes, the `newDelay` will get into effect immediately for every\n     * new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}.\n     *\n     * A zero value only in `effectSchedule` indicates no pending delay change.\n     *\n     * NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay}\n     * will be zero after the effect schedule.\n     */\n    function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule);\n\n    /**\n     * @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance\n     * after the current timestamp plus a {defaultAdminDelay}.\n     *\n     * Requirements:\n     *\n     * - Only can be called by the current {defaultAdmin}.\n     *\n     * Emits a DefaultAdminRoleChangeStarted event.\n     */\n    function beginDefaultAdminTransfer(address newAdmin) external;\n\n    /**\n     * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.\n     *\n     * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function.\n     *\n     * Requirements:\n     *\n     * - Only can be called by the current {defaultAdmin}.\n     *\n     * May emit a DefaultAdminTransferCanceled event.\n     */\n    function cancelDefaultAdminTransfer() external;\n\n    /**\n     * @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.\n     *\n     * After calling the function:\n     *\n     * - `DEFAULT_ADMIN_ROLE` should be granted to the caller.\n     * - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder.\n     * - {pendingDefaultAdmin} should be reset to zero values.\n     *\n     * Requirements:\n     *\n     * - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`.\n     * - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed.\n     */\n    function acceptDefaultAdminTransfer() external;\n\n    /**\n     * @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting\n     * into effect after the current timestamp plus a {defaultAdminDelay}.\n     *\n     * This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this\n     * method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay}\n     * set before calling.\n     *\n     * The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then\n     * calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin}\n     * complete transfer (including acceptance).\n     *\n     * The schedule is designed for two scenarios:\n     *\n     * - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by\n     * {defaultAdminDelayIncreaseWait}.\n     * - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`.\n     *\n     * A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change.\n     *\n     * Requirements:\n     *\n     * - Only can be called by the current {defaultAdmin}.\n     *\n     * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event.\n     */\n    function changeDefaultAdminDelay(uint48 newDelay) external;\n\n    /**\n     * @dev Cancels a scheduled {defaultAdminDelay} change.\n     *\n     * Requirements:\n     *\n     * - Only can be called by the current {defaultAdmin}.\n     *\n     * May emit a DefaultAdminDelayChangeCanceled event.\n     */\n    function rollbackDefaultAdminDelay() external;\n\n    /**\n     * @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay})\n     * to take effect. Default to 5 days.\n     *\n     * When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with\n     * the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds)\n     * that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can\n     * be overrode for a custom {defaultAdminDelay} increase scheduling.\n     *\n     * IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise,\n     * there's a risk of setting a high new delay that goes into effect almost immediately without the\n     * possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds).\n     */\n    function defaultAdminDelayIncreaseWait() external view returns (uint48);\n}\n"},{"file_path":"src/UsdnProtocol/libraries/UsdnProtocolCoreLibrary.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { FixedPointMathLib } from \"solady/src/utils/FixedPointMathLib.sol\";\nimport { LibBitmap } from \"solady/src/utils/LibBitmap.sol\";\nimport { SafeTransferLib } from \"solady/src/utils/SafeTransferLib.sol\";\n\nimport { PriceInfo } from \"../../interfaces/OracleMiddleware/IOracleMiddlewareTypes.sol\";\nimport { IUsdn } from \"../../interfaces/Usdn/IUsdn.sol\";\nimport { IUsdnProtocolErrors } from \"../../interfaces/UsdnProtocol/IUsdnProtocolErrors.sol\";\nimport { IUsdnProtocolEvents } from \"../../interfaces/UsdnProtocol/IUsdnProtocolEvents.sol\";\nimport { IUsdnProtocolTypes as Types } from \"../../interfaces/UsdnProtocol/IUsdnProtocolTypes.sol\";\nimport { Accumulator, HugeUint } from \"../../libraries/Accumulator.sol\";\nimport { DoubleEndedQueue } from \"../../libraries/DoubleEndedQueue.sol\";\nimport { SignedMath } from \"../../libraries/SignedMath.sol\";\nimport { TickMath } from \"../../libraries/TickMath.sol\";\nimport { UsdnProtocolConstantsLibrary as Constants } from \"./UsdnProtocolConstantsLibrary.sol\";\nimport { UsdnProtocolLongLibrary as Long } from \"./UsdnProtocolLongLibrary.sol\";\nimport { UsdnProtocolUtilsLibrary as Utils } from \"./UsdnProtocolUtilsLibrary.sol\";\nimport { UsdnProtocolVaultLibrary as Vault } from \"./UsdnProtocolVaultLibrary.sol\";\n\nlibrary UsdnProtocolCoreLibrary {\n    using DoubleEndedQueue for DoubleEndedQueue.Deque;\n    using Accumulator for HugeUint.Uint512;\n    using LibBitmap for LibBitmap.Bitmap;\n    using SafeCast for uint256;\n    using SafeTransferLib for address;\n    using SignedMath for int256;\n\n    /// @notice See {IUsdnProtocolCore.initialize}.\n    function initialize(\n        uint128 depositAmount,\n        uint128 longAmount,\n        uint128 desiredLiqPrice,\n        bytes calldata currentPriceData\n    ) external {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        // since all USDN must be minted by the protocol, we check that the total supply is 0\n        IUsdn usdn = s._usdn;\n        if (usdn.totalSupply() != 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidUsdn(address(usdn));\n        }\n\n        PriceInfo memory currentPrice =\n            Utils._getOraclePrice(Types.ProtocolAction.Initialize, block.timestamp, \"\", currentPriceData);\n\n        s._lastUpdateTimestamp = uint128(block.timestamp);\n        s._lastPrice = currentPrice.price.toUint128();\n\n        (int24 tickWithPenalty, uint128 liqPriceWithoutPenalty) =\n            Long._getTickFromDesiredLiqPrice(desiredLiqPrice, s._liquidationPenalty);\n\n        _checkOpenPositionLeverage(currentPrice.price.toUint128(), liqPriceWithoutPenalty, s._maxLeverage);\n\n        uint128 positionTotalExpo =\n            Utils._calcPositionTotalExpo(longAmount, currentPrice.price.toUint128(), liqPriceWithoutPenalty);\n\n        _checkInitImbalance(positionTotalExpo, longAmount, depositAmount);\n\n        _createInitialDeposit(depositAmount, currentPrice.price.toUint128());\n\n        _createInitialPosition(longAmount, currentPrice.price.toUint128(), tickWithPenalty, positionTotalExpo);\n\n        Utils._refundEther(address(this).balance, payable(msg.sender));\n    }\n\n    /// @notice See {IUsdnProtocolFallback.removeBlockedPendingAction(address,address payable)}.\n    function removeBlockedPendingAction(address validator, address payable to) external {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 pendingActionIndex = s._pendingActions[validator];\n        if (pendingActionIndex == 0) {\n            // no pending action\n            // use the `rawIndex` variant below if for some reason the `_pendingActions` mapping is messed up\n            revert IUsdnProtocolErrors.UsdnProtocolNoPendingAction();\n        }\n        uint128 rawIndex = uint128(pendingActionIndex - 1);\n        _removeBlockedPendingAction(rawIndex, to, true);\n    }\n\n    /// @notice See {IUsdnProtocolFallback.removeBlockedPendingActionNoCleanup(address,address payable)}.\n    function removeBlockedPendingActionNoCleanup(address validator, address payable to) external {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 pendingActionIndex = s._pendingActions[validator];\n        if (pendingActionIndex == 0) {\n            // no pending action\n            // use the `rawIndex` variant below if for some reason the `_pendingActions` mapping is messed up\n            revert IUsdnProtocolErrors.UsdnProtocolNoPendingAction();\n        }\n        uint128 rawIndex = uint128(pendingActionIndex - 1);\n        _removeBlockedPendingAction(rawIndex, to, false);\n    }\n\n    /**\n     * @notice Prepares the pending action struct for the close position action and add it to the queue.\n     * @param to The address that will receive the assets.\n     * @param validator The validator for the pending action.\n     * @param posId The unique identifier of the position.\n     * @param amountToClose The amount of collateral to remove from the position's amount.\n     * @param securityDepositValue The value of the security deposit for the newly created pending action.\n     * @param data The close position data.\n     * @return amountToRefund_ The security deposit value of a stale pending action.\n     */\n    function _createClosePendingAction(\n        address to,\n        address validator,\n        Types.PositionId memory posId,\n        uint128 amountToClose,\n        uint64 securityDepositValue,\n        Types.ClosePositionData memory data\n    ) external returns (uint256 amountToRefund_) {\n        Types.LongPendingAction memory action = Types.LongPendingAction({\n            action: Types.ProtocolAction.ValidateClosePosition,\n            timestamp: uint40(block.timestamp),\n            closeLiqPenalty: data.liquidationPenalty,\n            to: to,\n            validator: validator,\n            securityDepositValue: securityDepositValue,\n            tick: posId.tick,\n            closeAmount: amountToClose,\n            closePosTotalExpo: data.totalExpoToClose,\n            tickVersion: posId.tickVersion,\n            index: posId.index,\n            liqMultiplier: Utils._calcFixedPrecisionMultiplier(data.lastPrice, data.longTradingExpo, data.liqMulAcc),\n            closeBoundedPositionValue: data.tempPositionValue\n        });\n        amountToRefund_ = _addPendingAction(validator, Utils._convertLongPendingAction(action));\n    }\n\n    /**\n     * @notice Prepares the pending action struct for a withdrawal and adds it to the queue.\n     * @param to The recipient of the assets.\n     * @param validator The address that is supposed to validate the withdrawal and receive the security deposit.\n     * @param usdnShares The amount of USDN shares to burn.\n     * @param securityDepositValue The value of the security deposit for the newly created pending action.\n     * @param data The withdrawal action data.\n     * @return amountToRefund_ Refund The security deposit value of a stale pending action.\n     */\n    function _createWithdrawalPendingAction(\n        address to,\n        address validator,\n        uint152 usdnShares,\n        uint64 securityDepositValue,\n        Vault.WithdrawalData memory data\n    ) external returns (uint256 amountToRefund_) {\n        Types.PendingAction memory action = Utils._convertWithdrawalPendingAction(\n            Types.WithdrawalPendingAction({\n                action: Types.ProtocolAction.ValidateWithdrawal,\n                timestamp: uint40(block.timestamp),\n                feeBps: data.feeBps,\n                to: to,\n                validator: validator,\n                securityDepositValue: securityDepositValue,\n                sharesLSB: Vault._calcWithdrawalAmountLSB(usdnShares),\n                sharesMSB: Vault._calcWithdrawalAmountMSB(usdnShares),\n                assetPrice: data.lastPrice,\n                totalExpo: data.totalExpo,\n                balanceVault: data.balanceVault,\n                balanceLong: data.balanceLong,\n                usdnTotalShares: data.usdnTotalShares\n            })\n        );\n        amountToRefund_ = _addPendingAction(validator, action);\n    }\n\n    /// @notice See {IUsdnProtocolFallback.getUserPendingAction}.\n    function getUserPendingAction(address validator) external view returns (Types.PendingAction memory action_) {\n        (action_,) = _getPendingAction(validator);\n    }\n\n    /// @notice See {IUsdnProtocolCore.funding}.\n    function funding(uint128 timestamp)\n        external\n        view\n        returns (int256 funding_, int256 fundingPerDay_, int256 oldLongExpo_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (funding_, fundingPerDay_, oldLongExpo_) = _funding(timestamp, s._EMA);\n    }\n\n    /**\n     * @notice Gets the predicted value of the long balance for the given asset price and timestamp.\n     * @dev The effects of the funding and any PnL of the long positions since the last contract state\n     * update is taken into account, as well as the fees. If the provided timestamp is older than the last state\n     * update, the function reverts with `UsdnProtocolTimestampTooOld`. The value cannot be below 0.\n     * @param currentPrice The given asset price.\n     * @param timestamp The timestamp corresponding to the given price.\n     * @return available_ The long balance value in assets.\n     * @return fee_ The protocol fees in asset units, either positive or negative.\n     */\n    function longAssetAvailableWithFunding(uint128 currentPrice, uint128 timestamp)\n        public\n        view\n        returns (uint256 available_, int256 fee_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (timestamp < s._lastUpdateTimestamp) {\n            revert IUsdnProtocolErrors.UsdnProtocolTimestampTooOld();\n        }\n\n        (int256 fundAsset,) = _fundingAsset(timestamp, s._EMA);\n        fee_ = fundAsset * Utils._toInt256(s._protocolFeeBps) / int256(Constants.BPS_DIVISOR);\n\n        int256 tempAvailable;\n        if (fundAsset > 0) {\n            tempAvailable = Utils._longAssetAvailable(currentPrice).safeSub(fundAsset);\n        } else {\n            // fees have the same sign as fundAsset (negative here), so we need to sub them\n            tempAvailable = Utils._longAssetAvailable(currentPrice).safeSub(fundAsset - fee_);\n        }\n\n        // clamp the value to 0\n        if (tempAvailable > 0) {\n            // cast is safe as tempAvailable cannot be below 0\n            available_ = uint256(tempAvailable);\n        }\n\n        uint256 maxLongBalance = _calcMaxLongBalance(s._totalExpo);\n        if (available_ > maxLongBalance) {\n            available_ = maxLongBalance;\n        }\n\n        uint256 totalBalance = s._balanceLong + s._balanceVault - FixedPointMathLib.abs(fee_);\n        if (available_ > totalBalance) {\n            available_ = totalBalance;\n        }\n    }\n\n    /// @notice See {IUsdnProtocolLong.longTradingExpoWithFunding}.\n    function longTradingExpoWithFunding(uint128 currentPrice, uint128 timestamp) public view returns (uint256 expo_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (uint256 available,) = longAssetAvailableWithFunding(currentPrice, timestamp);\n\n        expo_ = s._totalExpo - available;\n    }\n\n    /**\n     * @notice Checks if the position's leverage is in the authorized range of values.\n     * @param adjustedPrice The adjusted price of the asset.\n     * @param liqPriceWithoutPenalty The liquidation price of the position without the liquidation penalty.\n     * @param userMaxLeverage The maximum leverage allowed by the user for the newly created position.\n     */\n    function _checkOpenPositionLeverage(uint128 adjustedPrice, uint128 liqPriceWithoutPenalty, uint256 userMaxLeverage)\n        public\n        view\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        // calculate position leverage\n        // reverts if liquidationPrice >= entryPrice\n        uint256 leverage = Utils._getLeverage(adjustedPrice, liqPriceWithoutPenalty);\n\n        if (leverage < s._minLeverage) {\n            revert IUsdnProtocolErrors.UsdnProtocolLeverageTooLow();\n        }\n\n        uint256 protocolMaxLeverage = s._maxLeverage;\n        if (userMaxLeverage > protocolMaxLeverage) {\n            userMaxLeverage = protocolMaxLeverage;\n        }\n\n        if (leverage > userMaxLeverage) {\n            revert IUsdnProtocolErrors.UsdnProtocolLeverageTooHigh();\n        }\n    }\n\n    /**\n     * @notice Prepares the pending action struct for an open position and adds it to the queue.\n     * @param to The address that will be the owner of the position.\n     * @param validator The address which is supposed to validate the position and receive the\n     * security deposit.\n     * @param securityDepositValue The value of the security deposit for the newly created pending action.\n     * @param data The open position action data.\n     * @return amountToRefund_ The security deposit value of a stale pending action, if any was removed.\n     */\n    function _createOpenPendingAction(\n        address to,\n        address validator,\n        uint64 securityDepositValue,\n        Types.InitiateOpenPositionData memory data\n    ) public returns (uint256 amountToRefund_) {\n        Types.LongPendingAction memory action = Types.LongPendingAction({\n            action: Types.ProtocolAction.ValidateOpenPosition,\n            timestamp: uint40(block.timestamp),\n            closeLiqPenalty: 0,\n            to: to,\n            validator: validator,\n            securityDepositValue: securityDepositValue,\n            tick: data.posId.tick,\n            closeAmount: 0,\n            closePosTotalExpo: 0,\n            tickVersion: data.posId.tickVersion,\n            index: data.posId.index,\n            liqMultiplier: data.liqMultiplier,\n            closeBoundedPositionValue: 0\n        });\n        amountToRefund_ = _addPendingAction(validator, Utils._convertLongPendingAction(action));\n    }\n\n    /**\n     * @notice Computes the profits and losses on the long side, calculates the funding, applies protocol fees,\n     * updates the liquidation multiplier and determines the temporary new balances for each side.\n     * @dev This function updates the state of `_lastPrice`, `_lastUpdateTimestamp`, `_lastFunding`, but does not\n     * update the balances. This is left to the caller.\n     * @param currentPrice The current price.\n     * @param timestamp The timestamp of the current price.\n     * @return data_ The data containing the temporary long balance, the temporary vault\n     * balance, the last price and a flag indicating if the price is recent.\n     */\n    function _applyPnlAndFunding(uint128 currentPrice, uint128 timestamp)\n        public\n        returns (Types.ApplyPnlAndFundingData memory data_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        int256 fundAsset;\n        {\n            // cache variable for optimization\n            uint128 lastUpdateTimestamp = s._lastUpdateTimestamp;\n            // if the price is not fresh, do nothing\n            if (timestamp <= lastUpdateTimestamp) {\n                return Types.ApplyPnlAndFundingData({\n                    tempLongBalance: s._balanceLong.toInt256(),\n                    tempVaultBalance: s._balanceVault.toInt256(),\n                    lastPrice: s._lastPrice\n                });\n            }\n\n            // calculate the funding\n            int256 fundingPerDay;\n            (fundAsset, fundingPerDay) = _fundingAsset(timestamp, s._EMA);\n\n            s._lastFundingPerDay = fundingPerDay;\n            emit IUsdnProtocolEvents.LastFundingPerDayUpdated(fundingPerDay, timestamp);\n\n            // update the funding EMA (mutates the storage)\n            _updateEMA(fundingPerDay, timestamp - lastUpdateTimestamp);\n        }\n\n        // take protocol fee on the funding value\n        (int256 fee, int256 fundAssetWithFee) = _calculateFee(fundAsset);\n\n        // we subtract the fee from the total balance\n        int256 totalBalance = (s._balanceLong + s._balanceVault).toInt256() - fee;\n\n        // calculate new balances (for now, any bad debt has not been repaid, balances could become negative)\n        if (fundAsset > 0) {\n            // in case of positive funding, the long balance must be decremented by the totality of the funding amount\n            // however, since we deducted the fee amount from the total balance, the vault balance will be incremented\n            // only by the funding amount minus the fee amount\n            data_.tempLongBalance = Utils._longAssetAvailable(currentPrice).safeSub(fundAsset);\n        } else {\n            // in case of negative funding, the vault balance must be decremented by the totality of the funding amount\n            // however, since we deducted the fee amount from the total balance, the long balance will be incremented\n            // only by the funding amount minus the fee amount\n            data_.tempLongBalance = Utils._longAssetAvailable(currentPrice).safeSub(fundAssetWithFee);\n        }\n\n        uint256 maxLongBalance = _calcMaxLongBalance(s._totalExpo);\n        if (data_.tempLongBalance > 0 && uint256(data_.tempLongBalance) > maxLongBalance) {\n            data_.tempLongBalance = maxLongBalance.toInt256();\n        }\n\n        data_.tempVaultBalance = totalBalance.safeSub(data_.tempLongBalance);\n\n        // update state variables\n        s._lastPrice = currentPrice;\n        data_.lastPrice = currentPrice;\n        s._lastUpdateTimestamp = timestamp;\n    }\n\n    /**\n     * @notice Removes the pending action from the queue if its tick version doesn't match the current tick version,\n     * indicating that the tick was liquidated.\n     * @dev This is only applicable to `ValidateOpenPosition` pending actions.\n     * @param validator The address associated with the pending action.\n     * @return securityDepositValue_ The security deposit value of the removed stale pending action.\n     */\n    function _removeStalePendingAction(address validator) public returns (uint256 securityDepositValue_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (s._pendingActions[validator] == 0) {\n            return 0;\n        }\n        (Types.PendingAction memory action, uint128 rawIndex) = _getPendingAction(validator);\n        // the position is only at risk of being liquidated while pending if it is an open position action\n        if (action.action == Types.ProtocolAction.ValidateOpenPosition) {\n            Types.LongPendingAction memory openAction = Utils._toLongPendingAction(action);\n            uint256 version = s._tickVersion[openAction.tick];\n            if (version != openAction.tickVersion) {\n                securityDepositValue_ = openAction.securityDepositValue;\n                // the position was liquidated while pending\n                // remove the stale pending action\n                s._pendingActionsQueue.clearAt(rawIndex);\n                delete s._pendingActions[validator];\n                emit IUsdnProtocolEvents.StalePendingActionRemoved(\n                    validator,\n                    Types.PositionId({\n                        tick: openAction.tick,\n                        tickVersion: openAction.tickVersion,\n                        index: openAction.index\n                    })\n                );\n            }\n        }\n    }\n\n    /**\n     * @notice Adds a pending action to the queue and removes a possible stale pending action.\n     * @dev Reverts if there is already a pending action for this user.\n     * @param validator The address which is supposed to validate the position and receive the\n     * security deposit.\n     * @param action The pending action struct.\n     * @return amountToRefund_ The security deposit value of a stale pending action, if any was removed.\n     */\n    function _addPendingAction(address validator, Types.PendingAction memory action)\n        public\n        returns (uint256 amountToRefund_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        // check if there is a pending action that was liquidated and remove it\n        amountToRefund_ = _removeStalePendingAction(validator);\n        if (s._pendingActions[validator] > 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolPendingAction();\n        }\n        // add the action to the queue\n        uint128 rawIndex = s._pendingActionsQueue.pushBack(action);\n        // store the index shifted by one, so that zero means no pending action\n        s._pendingActions[validator] = uint256(rawIndex) + 1;\n    }\n\n    /**\n     * @notice Removes a blocked pending action and performs the minimal amount of cleanup necessary.\n     * @dev This function should only be called by the owner of the protocol, it serves as an escape hatch if a\n     * pending action ever gets stuck due to something reverting unexpectedly.\n     * From the user action timestamp, the caller must wait at least `REMOVE_BLOCKED_PENDING_ACTIONS_DELAY` after both\n     * `_lowLatencyValidatorDeadline` and `_onChainValidatorDeadline`.\n     * @param rawIndex The raw index of the pending action in the queue.\n     * @param to The recipient of the funds, which may include security deposit, assets and USDN tokens.\n     * @param cleanup If `true`, will attempt to perform more cleanup at the risk of reverting. Always try `true` first.\n     */\n    function _removeBlockedPendingAction(uint128 rawIndex, address payable to, bool cleanup) public {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        Types.PendingAction memory pending = s._pendingActionsQueue.atRaw(rawIndex);\n        if (\n            block.timestamp\n                < pending.timestamp + s._lowLatencyValidatorDeadline + s._onChainValidatorDeadline\n                    + Constants.REMOVE_BLOCKED_PENDING_ACTIONS_DELAY\n        ) {\n            revert IUsdnProtocolErrors.UsdnProtocolUnauthorized();\n        }\n\n        delete s._pendingActions[pending.validator];\n        s._pendingActionsQueue.clearAt(rawIndex);\n        if (pending.action == Types.ProtocolAction.ValidateDeposit && cleanup) {\n            // for pending deposits, we send back the locked assets\n            Types.DepositPendingAction memory deposit = Utils._toDepositPendingAction(pending);\n            s._pendingBalanceVault -= Utils._toInt256(deposit.amount);\n            address(s._asset).safeTransfer(to, deposit.amount);\n        } else if (pending.action == Types.ProtocolAction.ValidateWithdrawal && cleanup) {\n            // for pending withdrawals, we send the locked USDN\n            Types.WithdrawalPendingAction memory withdrawal = Utils._toWithdrawalPendingAction(pending);\n            uint256 shares = Utils._mergeWithdrawalAmountParts(withdrawal.sharesLSB, withdrawal.sharesMSB);\n            // calculate the pending amount after fees to update the pending vault balance\n            uint256 pendingAmountAfterFees = Utils._calcAmountToWithdraw(\n                shares, withdrawal.balanceVault, withdrawal.usdnTotalShares, withdrawal.feeBps\n            );\n            s._pendingBalanceVault += pendingAmountAfterFees.toInt256();\n            s._usdn.transferShares(to, shares);\n        } else if (pending.action == Types.ProtocolAction.ValidateOpenPosition) {\n            // for pending opens, we need to remove the position\n            Types.LongPendingAction memory open = Utils._toLongPendingAction(pending);\n            (bytes32 tHash, uint256 tickVersion) = Utils._tickHash(open.tick);\n            if (tickVersion == open.tickVersion) {\n                // we only need to modify storage if the pos was not liquidated already\n\n                int256 posValue;\n                if (cleanup) {\n                    posValue = Long.getPositionValue(\n                        Types.PositionId(open.tick, open.tickVersion, open.index), s._lastPrice, s._lastUpdateTimestamp\n                    );\n                }\n\n                // safe cleanup operations\n                Types.Position[] storage tickArray = s._longPositions[tHash];\n                Types.Position memory pos = tickArray[open.index];\n                delete s._longPositions[tHash][open.index];\n\n                // more cleanup operations\n                if (cleanup) {\n                    Types.TickData storage tickData = s._tickData[tHash];\n                    --s._totalLongPositions;\n                    tickData.totalPos -= 1;\n                    uint256 unadjustedTickPrice =\n                        TickMath.getPriceAtTick(Utils._calcTickWithoutPenalty(open.tick, tickData.liquidationPenalty));\n                    if (tickData.totalPos == 0) {\n                        // we removed the last position in the tick\n                        s._tickBitmap.unset(Utils._calcBitmapIndexFromTick(open.tick));\n                        // reset tick penalty\n                        tickData.liquidationPenalty = 0;\n                    }\n                    s._totalExpo -= pos.totalExpo;\n                    tickData.totalExpo -= pos.totalExpo;\n                    s._liqMultiplierAccumulator =\n                        s._liqMultiplierAccumulator.sub(HugeUint.wrap(unadjustedTickPrice * pos.totalExpo));\n                    if (posValue > 0) {\n                        s._balanceLong -= uint256(posValue);\n                        address(s._asset).safeTransfer(to, uint256(posValue));\n                    } else if (posValue < 0) {\n                        s._balanceLong += uint256(-posValue);\n                        s._balanceVault -= uint256(-posValue);\n                    }\n                }\n            }\n        } else if (pending.action == Types.ProtocolAction.ValidateClosePosition && cleanup) {\n            // for pending closes, the position is already out of the protocol\n            Types.LongPendingAction memory close = Utils._toLongPendingAction(pending);\n            // send the value of the position at the time of the initiate to the `to` address\n            address(s._asset).safeTransfer(to, close.closeBoundedPositionValue);\n            // as the assets were already removed from the long's balance, there are no additional steps needed\n        }\n\n        // we retrieve the security deposit\n        if (cleanup) {\n            // slither-disable-next-line arbitrary-send-eth\n            (bool success,) = to.call{ value: pending.securityDepositValue }(\"\");\n            if (!success) {\n                revert IUsdnProtocolErrors.UsdnProtocolEtherRefundFailed();\n            }\n        }\n    }\n\n    /**\n     * @notice Saves a new long position in the protocol, adjusting the tick data and global variables.\n     * @dev This method does not update the long balance.\n     * @param tick The tick to hold the new position.\n     * @param long The position to save.\n     * @param liquidationPenalty The liquidation penalty for the tick.\n     * @return tickVersion_ The version of the tick.\n     * @return index_ The index of the position in the tick array.\n     * @return liqMultiplierAccumulator_ The updated liquidation multiplier accumulator.\n     */\n    function _saveNewPosition(int24 tick, Types.Position memory long, uint24 liquidationPenalty)\n        public\n        returns (uint256 tickVersion_, uint256 index_, HugeUint.Uint512 memory liqMultiplierAccumulator_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        bytes32 tickHash;\n        (tickHash, tickVersion_) = Utils._tickHash(tick);\n\n        // add to tick array\n        Types.Position[] storage tickArray = s._longPositions[tickHash];\n        index_ = tickArray.length;\n        if (tick > s._highestPopulatedTick) {\n            // keep track of the highest populated tick\n            s._highestPopulatedTick = tick;\n\n            emit IUsdnProtocolEvents.HighestPopulatedTickUpdated(tick);\n        }\n        tickArray.push(long);\n\n        // adjust state\n        s._totalExpo += long.totalExpo;\n        ++s._totalLongPositions;\n\n        // update tick data\n        Types.TickData storage tickData = s._tickData[tickHash];\n        // the unadjusted tick price for the accumulator might be different depending\n        // if we already have positions in the tick or not\n        uint256 unadjustedTickPrice;\n        if (tickData.totalPos == 0) {\n            // first position in this tick, we need to reflect that it is populated\n            s._tickBitmap.set(Utils._calcBitmapIndexFromTick(tick));\n            // we store the data for this tick\n            tickData.totalExpo = long.totalExpo;\n            tickData.totalPos = 1;\n            tickData.liquidationPenalty = liquidationPenalty;\n            unadjustedTickPrice = TickMath.getPriceAtTick(Utils._calcTickWithoutPenalty(tick, liquidationPenalty));\n        } else {\n            tickData.totalExpo += long.totalExpo;\n            tickData.totalPos += 1;\n            // we do not need to adjust the tick's `liquidationPenalty` since it remains constant\n            unadjustedTickPrice =\n                TickMath.getPriceAtTick(Utils._calcTickWithoutPenalty(tick, tickData.liquidationPenalty));\n        }\n        // update the accumulator with the correct tick price (depending on the liquidation penalty value)\n        liqMultiplierAccumulator_ = s._liqMultiplierAccumulator.add(HugeUint.wrap(unadjustedTickPrice * long.totalExpo));\n        s._liqMultiplierAccumulator = liqMultiplierAccumulator_;\n    }\n\n    /**\n     * @notice Gets the pending action for a validator.\n     * @dev Reverts if there is no pending action for the validator.\n     * @param validator The address which is supposed to validate the position and receive the\n     * security deposit.\n     * @return action_ The pending action struct.\n     * @return rawIndex_ The raw index of the pending action in the queue.\n     */\n    function _getPendingActionOrRevert(address validator)\n        public\n        view\n        returns (Types.PendingAction memory action_, uint128 rawIndex_)\n    {\n        (action_, rawIndex_) = _getPendingAction(validator);\n        if (action_.action == Types.ProtocolAction.None) {\n            revert IUsdnProtocolErrors.UsdnProtocolNoPendingAction();\n        }\n    }\n\n    /**\n     * @notice Gets the predicted value of the funding (in asset units) since the last state update for the given\n     * timestamp.\n     * @dev If the provided timestamp is older than the last state update, the result will be zero.\n     * @param timestamp The targeted timestamp.\n     * @param ema The EMA of the funding rate.\n     * @return fundingAsset_ The number of asset tokens of funding (with asset decimals).\n     * @return fundingPerDay_ The funding rate (per day) with `FUNDING_RATE_DECIMALS` decimals.\n     */\n    function _fundingAsset(uint128 timestamp, int256 ema)\n        internal\n        view\n        returns (int256 fundingAsset_, int256 fundingPerDay_)\n    {\n        int256 oldLongExpo;\n        int256 fund;\n        (fund, fundingPerDay_, oldLongExpo) = _funding(timestamp, ema);\n        fundingAsset_ = fund.safeMul(oldLongExpo) / int256(10) ** Constants.FUNDING_RATE_DECIMALS;\n    }\n\n    /**\n     * @notice Updates the Exponential Moving Average (EMA) of the funding rate (per day).\n     * @dev This function is called every time the protocol state is updated.\n     * All required checks are done in the caller function {_applyPnlAndFunding}.\n     * If the number of seconds elapsed is greater than or equal to the EMA period, the EMA is updated to the last\n     * funding value.\n     * @param fundingPerDay The funding rate per day that was just calculated for the elapsed period.\n     * @param secondsElapsed The number of seconds elapsed since the last protocol action.\n     */\n    function _updateEMA(int256 fundingPerDay, uint128 secondsElapsed) internal {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        s._EMA = _calcEMA(fundingPerDay, secondsElapsed, s._EMAPeriod, s._EMA);\n    }\n\n    /**\n     * @notice Calculates the protocol fee and apply it to the funding asset amount.\n     * @dev The funding factor is only adjusted by the fee rate when the funding is negative (vault pays to the long\n     * side).\n     * @param fundAsset The funding asset amount to be used for the fee calculation.\n     * @return fee_ The absolute value of the calculated fee.\n     * @return fundAssetWithFee_ The updated funding asset amount after applying the fee.\n     */\n    function _calculateFee(int256 fundAsset) internal returns (int256 fee_, int256 fundAssetWithFee_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        int256 protocolFeeBps = Utils._toInt256(s._protocolFeeBps);\n        fee_ = fundAsset * protocolFeeBps / int256(Constants.BPS_DIVISOR);\n        // fundAsset and fee_ have the same sign, we can safely subtract them to reduce the absolute amount of asset\n        fundAssetWithFee_ = fundAsset - fee_;\n\n        if (fee_ < 0) {\n            // we want to return the absolute value of the fee\n            fee_ = -fee_;\n        }\n\n        s._pendingProtocolFee += uint256(fee_);\n    }\n\n    /**\n     * @notice Creates the initial deposit.\n     * @dev To be called from `initialize`.\n     * @param amount The initial deposit amount.\n     * @param price The current asset price.\n     */\n    function _createInitialDeposit(uint128 amount, uint128 price) internal {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        // transfer the assets for the deposit\n        address(s._asset).safeTransferFrom(msg.sender, address(this), amount);\n\n        s._balanceVault += amount;\n        emit IUsdnProtocolEvents.InitiatedDeposit(msg.sender, msg.sender, amount, 0, block.timestamp, 0);\n\n        // calculate the total minted amount of USDN shares (vault balance and total supply are zero for now, we assume\n        // the USDN price to be $1 per token)\n        // the decimals conversion here is necessary since we calculate an amount in tokens and we want the\n        // corresponding amount of shares\n        uint256 usdnSharesToMint = s._usdn.convertToShares(\n            FixedPointMathLib.fullMulDiv(\n                amount, price, 10 ** (s._assetDecimals + s._priceFeedDecimals - Constants.TOKENS_DECIMALS)\n            )\n        );\n        IUsdn usdn = s._usdn;\n        uint256 minUsdnSharesSupply = usdn.convertToShares(Constants.MIN_USDN_SUPPLY);\n        // mint the minimum amount and send it to the dead address so it can never be removed from the total supply\n        usdn.mintShares(Constants.DEAD_ADDRESS, minUsdnSharesSupply);\n        // mint the user's share\n        uint256 mintSharesToUser = usdnSharesToMint - minUsdnSharesSupply;\n        uint256 mintedTokens = usdn.mintShares(msg.sender, mintSharesToUser);\n\n        emit IUsdnProtocolEvents.ValidatedDeposit(\n            Constants.DEAD_ADDRESS, Constants.DEAD_ADDRESS, 0, Constants.MIN_USDN_SUPPLY, block.timestamp\n        );\n        emit IUsdnProtocolEvents.ValidatedDeposit(msg.sender, msg.sender, amount, mintedTokens, block.timestamp);\n    }\n\n    /**\n     * @notice Creates the initial long position.\n     * @dev To be called from `initialize`.\n     * @param amount The initial position amount.\n     * @param price The current asset price.\n     * @param tick The tick corresponding where the position should be stored.\n     * @param totalExpo The total expo of the position.\n     */\n    function _createInitialPosition(uint128 amount, uint128 price, int24 tick, uint128 totalExpo) internal {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        // transfer the assets for the long\n        address(s._asset).safeTransferFrom(msg.sender, address(this), amount);\n\n        Types.PositionId memory posId;\n        posId.tick = tick;\n        Types.Position memory long = Types.Position({\n            validated: true,\n            user: msg.sender,\n            amount: amount,\n            totalExpo: totalExpo,\n            timestamp: uint40(block.timestamp)\n        });\n        // save the position and update the state\n        (posId.tickVersion, posId.index,) = _saveNewPosition(posId.tick, long, s._liquidationPenalty);\n        s._balanceLong += long.amount;\n        emit IUsdnProtocolEvents.InitiatedOpenPosition(\n            msg.sender, msg.sender, long.timestamp, totalExpo, long.amount, price, posId\n        );\n        emit IUsdnProtocolEvents.ValidatedOpenPosition(msg.sender, msg.sender, totalExpo, price, posId);\n    }\n\n    /**\n     * @notice Gets the possible pending action for a validator.\n     * @dev Checks for the presence of a pending action for a validator, compares `action_.action` to\n     * `Types.ProtocolAction.None`. There is a pending action only if the action is different from\n     * `Types.ProtocolAction.None`.\n     * @param validator The address of the pending action which is supposed to validate the position and receive the\n     * security deposit.\n     * @return action_ The pending action struct if any, otherwise a zero-initialized struct.\n     * @return rawIndex_ The raw index of the pending action in the queue.\n     */\n    function _getPendingAction(address validator)\n        internal\n        view\n        returns (Types.PendingAction memory action_, uint128 rawIndex_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 pendingActionIndex = s._pendingActions[validator];\n        if (pendingActionIndex == 0) {\n            // no pending action\n            return (action_, rawIndex_);\n        }\n\n        rawIndex_ = uint128(pendingActionIndex - 1);\n        action_ = s._pendingActionsQueue.atRaw(rawIndex_);\n    }\n\n    /**\n     * @notice Checks if the initialize parameters lead to a balanced protocol.\n     * @dev Reverts if the imbalance is exceeded for the deposit or open long actions.\n     * @param positionTotalExpo The total expo of the deployer's long position.\n     * @param longAmount The amount (collateral) of the deployer's long position.\n     * @param depositAmount The amount of assets for the deployer's deposit.\n     */\n    function _checkInitImbalance(uint128 positionTotalExpo, uint128 longAmount, uint128 depositAmount) internal view {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        int256 longTradingExpo = Utils._toInt256(positionTotalExpo - longAmount);\n        int256 depositLimit = s._depositExpoImbalanceLimitBps;\n        // users should be able to open positions after initialization\n        // with at least 2 times the minimum amount required for a position without exceeding imbalance limits\n        int256 minAmount = int256(s._minLongPosition * 2);\n\n        if (depositLimit != 0) {\n            int256 imbalanceBps =\n                (Utils._toInt256(depositAmount) - longTradingExpo) * int256(Constants.BPS_DIVISOR) / longTradingExpo;\n            if (imbalanceBps > depositLimit) {\n                revert IUsdnProtocolErrors.UsdnProtocolImbalanceLimitReached(imbalanceBps);\n            }\n\n            // make sure that the minAmount can be added as vault balance without imbalancing the protocol\n            imbalanceBps = (Utils._toInt256(depositAmount) + minAmount - longTradingExpo)\n                * int256(Constants.BPS_DIVISOR) / longTradingExpo;\n            if (imbalanceBps > depositLimit) {\n                revert IUsdnProtocolErrors.UsdnProtocolMinInitAmount();\n            }\n        }\n\n        int256 openLimit = s._openExpoImbalanceLimitBps;\n        if (openLimit != 0) {\n            int256 imbalanceBps = (longTradingExpo - Utils._toInt256(depositAmount)) * int256(Constants.BPS_DIVISOR)\n                / Utils._toInt256(depositAmount);\n            if (imbalanceBps > openLimit) {\n                revert IUsdnProtocolErrors.UsdnProtocolImbalanceLimitReached(imbalanceBps);\n            }\n\n            // make sure that the minAmount can be added as trading expo without imbalancing the protocol\n            imbalanceBps = (longTradingExpo + minAmount - Utils._toInt256(depositAmount))\n                * int256(Constants.BPS_DIVISOR) / Utils._toInt256(depositAmount);\n            if (imbalanceBps > openLimit) {\n                revert IUsdnProtocolErrors.UsdnProtocolMinInitAmount();\n            }\n        }\n    }\n\n    /**\n     * @notice Computes the funding rate per day and the old long exposure.\n     * @param ema The EMA of the funding rate per day.\n     * @return fundingPerDay_ The funding rate per day with `FUNDING_RATE_DECIMALS` decimals.\n     * @return oldLongExpo_ The old long trading expo.\n     */\n    function _fundingPerDay(int256 ema) internal view returns (int256 fundingPerDay_, int256 oldLongExpo_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        // imbalanceIndex = (longExpo - vaultExpo) / max(longExpo, vaultExpo)\n        // fundingPerDay = (sign(imbalanceIndex) * imbalanceIndex^2 * fundingSF) + _EMA\n        // fundingPerDay = (sign(ImbalanceIndex) * (longExpo - vaultExpo)^2 * fundingSF / denominator) + _EMA\n        // with denominator = vaultExpo^2 if vaultExpo > longExpo, or longExpo^2 if longExpo > vaultExpo\n\n        oldLongExpo_ = s._totalExpo.toInt256().safeSub(s._balanceLong.toInt256());\n        int256 oldVaultExpo = s._balanceVault.toInt256();\n        int256 numerator = oldLongExpo_ - oldVaultExpo;\n        // optimization: if the numerator is zero, then we simply return the EMA\n        if (numerator == 0) {\n            return (ema, oldLongExpo_);\n        }\n\n        if (oldLongExpo_ <= 0) {\n            // if oldLongExpo is negative, then we cap the imbalance index to -1\n            // this should never happen, but for safety we handle it anyway\n            return (\n                -int256(s._fundingSF * 10 ** (Constants.FUNDING_RATE_DECIMALS - Constants.FUNDING_SF_DECIMALS)) + ema,\n                oldLongExpo_\n            );\n        } else if (oldVaultExpo == 0) {\n            // if oldVaultExpo is zero (can't be negative), then we cap the imbalance index to 1\n            return (\n                int256(s._fundingSF * 10 ** (Constants.FUNDING_RATE_DECIMALS - Constants.FUNDING_SF_DECIMALS)) + ema,\n                oldLongExpo_\n            );\n        }\n\n        // starting here, oldLongExpo and oldVaultExpo are always strictly positive\n        uint256 numeratorSquared = uint256(numerator * numerator);\n\n        uint256 denominator;\n        if (oldVaultExpo > oldLongExpo_) {\n            denominator = uint256(oldVaultExpo * oldVaultExpo);\n            fundingPerDay_ = -int256(\n                FixedPointMathLib.fullMulDiv(\n                    numeratorSquared,\n                    s._fundingSF * 10 ** (Constants.FUNDING_RATE_DECIMALS - Constants.FUNDING_SF_DECIMALS),\n                    denominator\n                )\n            ) + ema;\n        } else {\n            denominator = uint256(oldLongExpo_ * oldLongExpo_);\n            fundingPerDay_ = int256(\n                FixedPointMathLib.fullMulDiv(\n                    numeratorSquared,\n                    s._fundingSF * 10 ** (Constants.FUNDING_RATE_DECIMALS - Constants.FUNDING_SF_DECIMALS),\n                    denominator\n                )\n            ) + ema;\n        }\n    }\n\n    /**\n     * @notice Computes the funding value, funding rate value and the old long exposure.\n     * @dev Reverts if `timestamp` < `s._lastUpdateTimestamp`.\n     * @param timestamp The current timestamp.\n     * @param ema The EMA of the funding rate per day.\n     * @return funding_ The funding (proportion of long trading expo that needs to be transferred from one side to the\n     * other) with `FUNDING_RATE_DECIMALS` decimals. If positive, long side pays to vault side, otherwise it's the\n     * opposite.\n     * @return fundingPerDay_ The funding rate (per day) with `FUNDING_RATE_DECIMALS` decimals.\n     * @return oldLongExpo_ The old long trading expo.\n     */\n    function _funding(uint128 timestamp, int256 ema)\n        internal\n        view\n        returns (int256 funding_, int256 fundingPerDay_, int256 oldLongExpo_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (fundingPerDay_, oldLongExpo_) = _fundingPerDay(ema);\n\n        uint128 lastUpdateTimestamp = s._lastUpdateTimestamp;\n        if (timestamp < lastUpdateTimestamp) {\n            revert IUsdnProtocolErrors.UsdnProtocolTimestampTooOld();\n        }\n        // subtraction can't underflow, checked above\n        // conversion from uint128 to int256 is always safe\n        int256 elapsedSeconds;\n        unchecked {\n            elapsedSeconds = Utils._toInt256(timestamp - lastUpdateTimestamp);\n        }\n        if (elapsedSeconds == 0) {\n            return (0, fundingPerDay_, oldLongExpo_);\n        }\n\n        funding_ = fundingPerDay_.safeMul(elapsedSeconds).safeDiv(1 days);\n    }\n\n    /**\n     * @notice Calculates the new Exponential Moving Average.\n     * @param fundingPerDay The funding per day.\n     * @param secondsElapsed The number of seconds elapsed to be taken into account.\n     * @param emaPeriod The current EMA period.\n     * @param previousEMA The previous EMA value.\n     * @return newEMA_ The new EMA value.\n     */\n    function _calcEMA(int256 fundingPerDay, uint128 secondsElapsed, uint128 emaPeriod, int256 previousEMA)\n        internal\n        pure\n        returns (int256 newEMA_)\n    {\n        if (secondsElapsed >= emaPeriod) {\n            return fundingPerDay;\n        }\n\n        return (\n            fundingPerDay * Utils._toInt256(secondsElapsed) + previousEMA * Utils._toInt256(emaPeriod - secondsElapsed)\n        ) / Utils._toInt256(emaPeriod);\n    }\n\n    /**\n     * @notice Calculates the maximum value of the long balance for the provided total expo.\n     * @param totalExpo The total expo of the long side of the protocol.\n     * @return maxLongBalance_ The maximum value the long balance can reach.\n     */\n    function _calcMaxLongBalance(uint256 totalExpo) internal pure returns (uint256 maxLongBalance_) {\n        maxLongBalance_ = FixedPointMathLib.fullMulDiv(\n            totalExpo, (Constants.BPS_DIVISOR - Constants.MIN_LONG_TRADING_EXPO_BPS), Constants.BPS_DIVISOR\n        );\n    }\n}\n"},{"file_path":"src/UsdnProtocol/libraries/UsdnProtocolLongLibrary.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { HugeUint } from \"@smardex-solidity-libraries-1/HugeUint.sol\";\nimport { FixedPointMathLib } from \"solady/src/utils/FixedPointMathLib.sol\";\nimport { LibBitmap } from \"solady/src/utils/LibBitmap.sol\";\nimport { SafeTransferLib } from \"solady/src/utils/SafeTransferLib.sol\";\n\nimport { PriceInfo } from \"../../interfaces/OracleMiddleware/IOracleMiddlewareTypes.sol\";\nimport { IBaseRebalancer } from \"../../interfaces/Rebalancer/IBaseRebalancer.sol\";\nimport { IUsdn } from \"../../interfaces/Usdn/IUsdn.sol\";\nimport { IUsdnProtocolErrors } from \"../../interfaces/UsdnProtocol/IUsdnProtocolErrors.sol\";\nimport { IUsdnProtocolEvents } from \"../../interfaces/UsdnProtocol/IUsdnProtocolEvents.sol\";\nimport { IUsdnProtocolTypes as Types } from \"../../interfaces/UsdnProtocol/IUsdnProtocolTypes.sol\";\nimport { Accumulator, HugeUint } from \"../../libraries/Accumulator.sol\";\nimport { SignedMath } from \"../../libraries/SignedMath.sol\";\nimport { TickMath } from \"../../libraries/TickMath.sol\";\nimport { UsdnProtocolActionsUtilsLibrary as ActionsUtils } from \"./UsdnProtocolActionsUtilsLibrary.sol\";\nimport { UsdnProtocolConstantsLibrary as Constants } from \"./UsdnProtocolConstantsLibrary.sol\";\nimport { UsdnProtocolCoreLibrary as Core } from \"./UsdnProtocolCoreLibrary.sol\";\nimport { UsdnProtocolUtilsLibrary as Utils } from \"./UsdnProtocolUtilsLibrary.sol\";\nimport { UsdnProtocolVaultLibrary as Vault } from \"./UsdnProtocolVaultLibrary.sol\";\n\nlibrary UsdnProtocolLongLibrary {\n    using Accumulator for HugeUint.Uint512;\n    using LibBitmap for LibBitmap.Bitmap;\n    using SafeCast for int256;\n    using SafeCast for uint256;\n    using SafeTransferLib for address;\n    using SignedMath for int256;\n\n    /**\n     * @dev Structure to hold the temporary data during liquidations.\n     * @param tempLongBalance The updated long balance not saved into storage yet.\n     * @param tempVaultBalance The updated vault balance not saved into storage yet.\n     * @param currentTick The current tick (corresponding to the current asset price).\n     * @param iTick Tick iterator index.\n     * @param totalExpoToRemove The total exposure to remove due to liquidations.\n     * @param accumulatorValueToRemove The value to remove from the liquidation multiplier accumulator due to\n     * liquidations.\n     * @param longTradingExpo The long trading exposure.\n     * @param currentPrice The current price of the asset.\n     * @param accumulator The liquidation multiplier accumulator before liquidations.\n     * @param isLiquidationPending Whether some ticks are still populated above the current price (left to liquidate).\n     */\n    struct LiquidationData {\n        int256 tempLongBalance;\n        int256 tempVaultBalance;\n        int24 currentTick;\n        int24 iTick;\n        uint256 totalExpoToRemove;\n        uint256 accumulatorValueToRemove;\n        uint256 longTradingExpo;\n        uint256 currentPrice;\n        HugeUint.Uint512 accumulator;\n        bool isLiquidationPending;\n    }\n\n    /**\n     * @dev Data structure for the `_applyPnlAndFundingAndLiquidate` function.\n     * @param tempLongBalance The updated long balance not saved into storage yet.\n     * @param tempVaultBalance The updated vault balance not saved into storage yet.\n     * @param lastPrice The last price used to update the protocol.\n     * @param rebased A boolean indicating if the USDN token was rebased.\n     * @param callbackResult The result of the USDN rebase callback.\n     * @param rebalancerAction The action performed by the `_triggerRebalancer` function.\n     */\n    struct ApplyPnlAndFundingAndLiquidateData {\n        int256 tempLongBalance;\n        int256 tempVaultBalance;\n        uint128 lastPrice;\n        bool rebased;\n        bytes callbackResult;\n        Types.RebalancerAction rebalancerAction;\n    }\n\n    /**\n     * @dev Data structure for the `_triggerRebalancer` function.\n     * @param positionAmount The amount of assets in the rebalancer's position.\n     * @param rebalancerMaxLeverage The maximum leverage of the rebalancer.\n     * @param rebalancerPosId The ID of the rebalancer's position.\n     * @param positionValue The value of the rebalancer's position.\n     */\n    struct TriggerRebalancerData {\n        uint128 positionAmount;\n        uint256 rebalancerMaxLeverage;\n        Types.PositionId rebalancerPosId;\n        uint128 positionValue;\n    }\n\n    /// @notice See {IUsdnProtocolLong.getPositionValue}.\n    function getPositionValue(Types.PositionId calldata posId, uint128 price, uint128 timestamp)\n        external\n        view\n        returns (int256 value_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (Types.Position memory pos, uint24 liquidationPenalty) = ActionsUtils.getLongPosition(posId);\n        uint256 longTradingExpo = Core.longTradingExpoWithFunding(price, timestamp);\n        uint128 liqPrice = Utils._getEffectivePriceForTick(\n            Utils._calcTickWithoutPenalty(posId.tick, liquidationPenalty),\n            price,\n            longTradingExpo,\n            s._liqMultiplierAccumulator\n        );\n        value_ = Utils._positionValue(pos.totalExpo, price, liqPrice);\n    }\n\n    /// @notice See {IUsdnProtocolLong.getEffectiveTickForPrice(uint128)}.\n    function getEffectiveTickForPrice(uint128 price) external view returns (int24 tick_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        tick_ = getEffectiveTickForPrice(\n            price, s._lastPrice, s._totalExpo - s._balanceLong, s._liqMultiplierAccumulator, s._tickSpacing\n        );\n    }\n\n    /// @notice See {IUsdnProtocolLong.minTick}.\n    function minTick() public view returns (int24 tick_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        tick_ = TickMath.minUsableTick(s._tickSpacing);\n    }\n\n    /// @notice See {IUsdnProtocolLong.getTickLiquidationPenalty}.\n    function getTickLiquidationPenalty(int24 tick) public view returns (uint24 liquidationPenalty_) {\n        (bytes32 tickHash,) = Utils._tickHash(tick);\n        liquidationPenalty_ = _getTickLiquidationPenalty(tickHash);\n    }\n\n    /// @notice See {IUsdnProtocolLong.getEffectiveTickForPrice(uint128,uint256,uint256,HugeUint.Uint512,int24)}.\n    function getEffectiveTickForPrice(\n        uint128 price,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator,\n        int24 tickSpacing\n    ) public pure returns (int24 tick_) {\n        tick_ = _getEffectiveTickForPriceNoRounding(price, assetPrice, longTradingExpo, accumulator);\n\n        // round down to the next valid tick according to _tickSpacing (towards negative infinity)\n        tick_ = _roundTickDown(tick_, tickSpacing);\n    }\n\n    /**\n     * @notice Applies PnL, funding, and liquidates positions if necessary.\n     * @dev If there were any liquidations, it sends the rewards to the `msg.sender`.\n     * @param neutralPrice The neutral price for the asset.\n     * @param timestamp The timestamp at which the operation is performed.\n     * @param iterations The number of iterations for the liquidation process.\n     * @param action The type of action that is being performed by the user.\n     * @param priceData The data given to the oracle middleware corresponding to `neutralPrice`.\n     * @return liquidatedTicks_ Information about the liquidated ticks.\n     * @return isLiquidationPending_ If there are remaining ticks that can be liquidated.\n     */\n    function _applyPnlAndFundingAndLiquidate(\n        uint256 neutralPrice,\n        uint256 timestamp,\n        uint16 iterations,\n        Types.ProtocolAction action,\n        bytes calldata priceData\n    ) public returns (Types.LiqTickInfo[] memory liquidatedTicks_, bool isLiquidationPending_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        ApplyPnlAndFundingAndLiquidateData memory data;\n        {\n            Types.ApplyPnlAndFundingData memory temporaryData =\n                Core._applyPnlAndFunding(neutralPrice.toUint128(), timestamp.toUint128());\n            assembly {\n                mcopy(data, temporaryData, 128)\n            }\n        }\n\n        // liquidate with `_lastPrice` if there are pending liquidations, up to `iterations` ticks\n        Types.LiquidationsEffects memory liquidationEffects =\n            _liquidatePositions(data.lastPrice, iterations, data.tempLongBalance, data.tempVaultBalance);\n\n        isLiquidationPending_ = liquidationEffects.isLiquidationPending;\n        if (!isLiquidationPending_ && liquidationEffects.liquidatedTicks.length > 0) {\n            if (s._closeExpoImbalanceLimitBps > 0) {\n                (liquidationEffects.newLongBalance, liquidationEffects.newVaultBalance, data.rebalancerAction) =\n                _triggerRebalancer(\n                    data.lastPrice,\n                    liquidationEffects.newLongBalance,\n                    liquidationEffects.newVaultBalance,\n                    liquidationEffects.remainingCollateral\n                );\n            }\n        }\n\n        s._balanceLong = liquidationEffects.newLongBalance;\n        s._balanceVault = liquidationEffects.newVaultBalance;\n\n        (data.rebased, data.callbackResult) = _usdnRebase(data.lastPrice);\n\n        if (liquidationEffects.liquidatedTicks.length > 0) {\n            _sendRewardsToLiquidator(\n                liquidationEffects.liquidatedTicks,\n                data.lastPrice,\n                data.rebased,\n                data.rebalancerAction,\n                action,\n                data.callbackResult,\n                priceData\n            );\n        }\n\n        liquidatedTicks_ = liquidationEffects.liquidatedTicks;\n    }\n\n    /**\n     * @notice Prepares the data for the `initiateOpenPosition` function.\n     * @param params The parameters for the `_prepareInitiateOpenPositionData` function.\n     * @return data_ The transient data for the open position action.\n     */\n    function _prepareInitiateOpenPositionData(Types.PrepareInitiateOpenPositionParams calldata params)\n        public\n        returns (Types.InitiateOpenPositionData memory data_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        PriceInfo memory currentPrice = Utils._getOraclePrice(\n            Types.ProtocolAction.InitiateOpenPosition,\n            block.timestamp,\n            Utils._calcActionId(params.validator, uint128(block.timestamp)),\n            params.currentPriceData\n        );\n\n        uint128 neutralPrice = currentPrice.neutralPrice.toUint128();\n        (, data_.isLiquidationPending) = _applyPnlAndFundingAndLiquidate(\n            neutralPrice,\n            currentPrice.timestamp,\n            s._liquidationIteration,\n            Types.ProtocolAction.InitiateOpenPosition,\n            params.currentPriceData\n        );\n        // early return in case there are still pending liquidations\n        if (data_.isLiquidationPending) {\n            return data_;\n        }\n\n        uint128 lastPrice = s._lastPrice;\n        // add position fee\n        data_.adjustedPrice = (lastPrice + uint256(lastPrice) * s._positionFeeBps / Constants.BPS_DIVISOR).toUint128();\n\n        // check slippage\n        if (data_.adjustedPrice > params.userMaxPrice) {\n            revert IUsdnProtocolErrors.UsdnProtocolSlippageMaxPriceExceeded();\n        }\n\n        // gas savings, we only load the data once and use it for all conversions below\n        Types.TickPriceConversionData memory conversionData = Types.TickPriceConversionData({\n            // we need to take into account the funding for the trading exposure between\n            // the last price timestamp and now\n            tradingExpo: Core.longTradingExpoWithFunding(lastPrice, uint128(block.timestamp)),\n            accumulator: s._liqMultiplierAccumulator,\n            tickSpacing: s._tickSpacing\n        });\n\n        // we calculate the closest valid tick down for the desired liq price with liquidation penalty\n        data_.posId.tick = getEffectiveTickForPrice(\n            params.desiredLiqPrice,\n            lastPrice,\n            conversionData.tradingExpo,\n            conversionData.accumulator,\n            conversionData.tickSpacing\n        );\n        data_.liquidationPenalty = getTickLiquidationPenalty(data_.posId.tick);\n\n        // calculate effective liquidation price\n        uint128 liqPrice = Utils._getEffectivePriceForTick(\n            data_.posId.tick, lastPrice, conversionData.tradingExpo, conversionData.accumulator\n        );\n\n        // liquidation price must be at least x% below the current price\n        _checkSafetyMargin(lastPrice, liqPrice);\n\n        // remove liquidation penalty for leverage and total exposure calculations\n        uint128 liqPriceWithoutPenalty = Utils._getEffectivePriceForTick(\n            Utils._calcTickWithoutPenalty(data_.posId.tick, data_.liquidationPenalty),\n            lastPrice,\n            conversionData.tradingExpo,\n            conversionData.accumulator\n        );\n        Core._checkOpenPositionLeverage(data_.adjustedPrice, liqPriceWithoutPenalty, params.userMaxLeverage);\n\n        data_.positionTotalExpo =\n            Utils._calcPositionTotalExpo(params.amount, data_.adjustedPrice, liqPriceWithoutPenalty);\n        // the current price is known to be above the liquidation price because we checked the safety margin\n        data_.positionValue = Utils._positionValueOptimized(data_.positionTotalExpo, lastPrice, liqPriceWithoutPenalty);\n        _checkImbalanceLimitOpen(data_.positionTotalExpo, params.amount, data_.positionValue);\n\n        data_.liqMultiplier =\n            Utils._calcFixedPrecisionMultiplier(lastPrice, conversionData.tradingExpo, conversionData.accumulator);\n    }\n\n    /**\n     * @notice Removes `amountToRemove` from position `pos` then updates the tick data and the position.\n     * @dev This method does not update the long balance.\n     * If the amount to remove is greater than or equal to the position's total amount, the position is deleted instead.\n     * @param tick The tick the position is in.\n     * @param index Index of the position in the tick array.\n     * @param pos The position to remove the amount from.\n     * @param amountToRemove The amount to remove from the position.\n     * @param totalExpoToRemove The total exposure to remove from the position.\n     * @return liqMultiplierAccumulator_ The updated liquidation multiplier accumulator.\n     */\n    function _removeAmountFromPosition(\n        int24 tick,\n        uint256 index,\n        Types.Position memory pos,\n        uint128 amountToRemove,\n        uint128 totalExpoToRemove\n    ) public returns (HugeUint.Uint512 memory liqMultiplierAccumulator_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (bytes32 tickHash,) = Utils._tickHash(tick);\n        Types.TickData storage tickData = s._tickData[tickHash];\n        uint256 unadjustedTickPrice =\n            TickMath.getPriceAtTick(Utils._calcTickWithoutPenalty(tick, tickData.liquidationPenalty));\n        if (amountToRemove < pos.amount) {\n            Types.Position storage position = s._longPositions[tickHash][index];\n            position.totalExpo = pos.totalExpo - totalExpoToRemove;\n\n            unchecked {\n                position.amount = pos.amount - amountToRemove;\n            }\n        } else {\n            totalExpoToRemove = pos.totalExpo;\n            tickData.totalPos -= 1;\n            --s._totalLongPositions;\n\n            // remove from tick array (set to zero to avoid shifting indices)\n            delete s._longPositions[tickHash][index];\n            if (tickData.totalPos == 0) {\n                // we removed the last position in the tick\n                s._tickBitmap.unset(Utils._calcBitmapIndexFromTick(tick));\n                // reset tick penalty\n                tickData.liquidationPenalty = 0;\n            }\n        }\n\n        s._totalExpo -= totalExpoToRemove;\n        tickData.totalExpo -= totalExpoToRemove;\n        liqMultiplierAccumulator_ =\n            s._liqMultiplierAccumulator.sub(HugeUint.wrap(unadjustedTickPrice * totalExpoToRemove));\n        s._liqMultiplierAccumulator = liqMultiplierAccumulator_;\n    }\n\n    /**\n     * @notice Computes the tick number with penalty and liquidation price without penalty\n     * from the desired liquidation price.\n     * @dev This function first calculates a tick for the desired liquidation price (no rounding), then adds the penalty\n     * to the tick and rounds down to the nearest tick spacing. Then it subtracts the penalty from the final tick and\n     * calculates the corresponding liquidation price.\n     * @param desiredLiqPriceWithoutPenalty The desired liquidation price without penalty.\n     * @param liquidationPenalty The liquidation penalty.\n     * @return tickWithPenalty_ The tick number including the liquidation penalty.\n     * @return liqPriceWithoutPenalty_ The liquidation price without penalty.\n     */\n    function _getTickFromDesiredLiqPrice(uint128 desiredLiqPriceWithoutPenalty, uint24 liquidationPenalty)\n        public\n        view\n        returns (int24 tickWithPenalty_, uint128 liqPriceWithoutPenalty_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        return _getTickFromDesiredLiqPrice(\n            desiredLiqPriceWithoutPenalty,\n            s._lastPrice,\n            s._totalExpo - s._balanceLong,\n            s._liqMultiplierAccumulator,\n            s._tickSpacing,\n            liquidationPenalty\n        );\n    }\n\n    /**\n     * @notice Computes the tick number with penalty and liquidation price without penalty\n     * from the desired liquidation price and protocol state.\n     * @dev This function first calculates a tick for the desired liquidation price (no rounding), then adds the penalty\n     * to the tick and rounds down to the nearest tick spacing. Then it subtracts the penalty from the final tick and\n     * calculates the corresponding liquidation price.\n     * @param desiredLiqPriceWithoutPenalty The desired liquidation price without penalty.\n     * @param assetPrice The current price of the asset.\n     * @param longTradingExpo The trading exposure of the long side (total exposure - balance long).\n     * @param accumulator The liquidation multiplier accumulator.\n     * @param tickSpacing The tick spacing.\n     * @param liquidationPenalty The liquidation penalty.\n     * @return tickWithPenalty_ The tick number including the liquidation penalty.\n     * @return liqPriceWithoutPenalty_ The liquidation price without penalty.\n     */\n    function _getTickFromDesiredLiqPrice(\n        uint128 desiredLiqPriceWithoutPenalty,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator,\n        int24 tickSpacing,\n        uint24 liquidationPenalty\n    ) public pure returns (int24 tickWithPenalty_, uint128 liqPriceWithoutPenalty_) {\n        // get corresponding tick (not necessarily a multiple of tickSpacing)\n        int24 tempTickWithoutPenalty =\n            _getEffectiveTickForPriceNoRounding(desiredLiqPriceWithoutPenalty, assetPrice, longTradingExpo, accumulator);\n        // add the penalty to the tick and round down to the nearest multiple of tickSpacing\n        tickWithPenalty_ = tempTickWithoutPenalty + int24(liquidationPenalty);\n        tickWithPenalty_ = _roundTickDownWithPenalty(tickWithPenalty_, tickSpacing, liquidationPenalty);\n        liqPriceWithoutPenalty_ = Utils._getEffectivePriceForTick(\n            Utils._calcTickWithoutPenalty(tickWithPenalty_, liquidationPenalty),\n            assetPrice,\n            longTradingExpo,\n            accumulator\n        );\n    }\n\n    /**\n     * @notice Computes the tick number with penalty and liquidation price without penalty\n     * from the desired liquidation price and a fixed precision version of the liquidation multiplier accumulator.\n     * @dev This function first calculates a tick for the desired liquidation price (no rounding), then adds the penalty\n     * to the tick and rounds down to the nearest tick spacing. Then it subtracts the penalty from the final tick and\n     * calculates the corresponding liquidation price.\n     * @param desiredLiqPriceWithoutPenalty The desired liquidation price without penalty.\n     * @param liqMultiplier The liquidation price multiplier (with `LIQUIDATION_MULTIPLIER_DECIMALS` decimals).\n     * @param tickSpacing The tick spacing.\n     * @param liquidationPenalty The liquidation penalty.\n     * @return tickWithPenalty_ The tick number including the liquidation penalty.\n     * @return liqPriceWithoutPenalty_ The liquidation price without penalty.\n     */\n    function _getTickFromDesiredLiqPrice(\n        uint128 desiredLiqPriceWithoutPenalty,\n        uint256 liqMultiplier,\n        int24 tickSpacing,\n        uint24 liquidationPenalty\n    ) public pure returns (int24 tickWithPenalty_, uint128 liqPriceWithoutPenalty_) {\n        // get corresponding tick (not necessarily a multiple of tickSpacing)\n        int24 tempTickWithoutPenalty = _getEffectiveTickForPriceNoRounding(desiredLiqPriceWithoutPenalty, liqMultiplier);\n        // add the penalty to the tick and round down to the nearest multiple of tickSpacing\n        tickWithPenalty_ = tempTickWithoutPenalty + int24(liquidationPenalty);\n        tickWithPenalty_ = _roundTickDownWithPenalty(tickWithPenalty_, tickSpacing, liquidationPenalty);\n        liqPriceWithoutPenalty_ = Utils._getEffectivePriceForTick(\n            Utils._calcTickWithoutPenalty(tickWithPenalty_, liquidationPenalty), liqMultiplier\n        );\n    }\n\n    /**\n     * @notice Finds the highest tick that contains at least one position.\n     * @dev If there are no ticks with a position left, returns {minTick}.\n     * @param searchStart The tick to start searching from.\n     * @return tick_ The highest tick at or below `searchStart`.\n     */\n    function _findHighestPopulatedTick(int24 searchStart) public view returns (int24 tick_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 index = s._tickBitmap.findLastSet(Utils._calcBitmapIndexFromTick(searchStart));\n        if (index == LibBitmap.NOT_FOUND) {\n            tick_ = minTick();\n        } else {\n            tick_ = _calcTickFromBitmapIndex(index);\n        }\n    }\n\n    /**\n     * @notice Checks if a USDN rebase is required and adjust the divisor if needed.\n     * @dev Only call this function after `_applyPnlAndFunding` has been called to update the balances.\n     * @param assetPrice The current price of the underlying asset.\n     * @return rebased_ Whether a rebase was performed.\n     * @return callbackResult_ The rebase callback result, if any.\n     */\n    function _usdnRebase(uint128 assetPrice) internal returns (bool rebased_, bytes memory callbackResult_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        IUsdn usdn = s._usdn;\n        uint256 divisor = usdn.divisor();\n        if (divisor <= s._usdnMinDivisor) {\n            // no need to rebase, the USDN divisor cannot go lower\n            return (false, callbackResult_);\n        }\n\n        uint256 balanceVault = s._balanceVault;\n        uint8 assetDecimals = s._assetDecimals;\n        uint256 usdnTotalSupply = usdn.totalSupply();\n        uint256 uPrice = Vault._calcUsdnPrice(balanceVault, assetPrice, usdnTotalSupply, assetDecimals);\n        if (uPrice <= s._usdnRebaseThreshold) {\n            return (false, callbackResult_);\n        }\n\n        uint256 targetTotalSupply = _calcRebaseTotalSupply(balanceVault, assetPrice, s._targetUsdnPrice, assetDecimals);\n        uint256 newDivisor = FixedPointMathLib.fullMulDiv(usdnTotalSupply, divisor, targetTotalSupply);\n\n        // since the USDN token can call a handler after the rebase, we want to make sure we do not block the user\n        // action in case the rebase fails\n        try usdn.rebase(newDivisor) returns (bool rebased, uint256, bytes memory callbackResult) {\n            rebased_ = rebased;\n            callbackResult_ = callbackResult;\n        } catch { }\n    }\n\n    /**\n     * @notice Sends rewards to the liquidator.\n     * @dev Should still emit an event if liquidationRewards = 0 to better keep track of those anomalies as rewards for\n     * those will be managed off-chain.\n     * @param liquidatedTicks Information about the liquidated ticks.\n     * @param currentPrice The current price of the asset.\n     * @param rebased Whether a USDN rebase was performed.\n     * @param rebalancerAction The rebalancer action that was performed.\n     * @param action The protocol action that triggered liquidations.\n     * @param rebaseCallbackResult The rebase callback result, if any.\n     * @param priceData The data given to the oracle middleware to get a price.\n     */\n    function _sendRewardsToLiquidator(\n        Types.LiqTickInfo[] memory liquidatedTicks,\n        uint256 currentPrice,\n        bool rebased,\n        Types.RebalancerAction rebalancerAction,\n        Types.ProtocolAction action,\n        bytes memory rebaseCallbackResult,\n        bytes memory priceData\n    ) internal {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        // get how much we should give to the liquidator as rewards\n        uint256 liquidationRewards = s._liquidationRewardsManager.getLiquidationRewards(\n            liquidatedTicks, currentPrice, rebased, rebalancerAction, action, rebaseCallbackResult, priceData\n        );\n\n        // avoid underflows in the situation of extreme bad debt\n        if (s._balanceVault < liquidationRewards) {\n            liquidationRewards = s._balanceVault;\n        }\n\n        // update the vault's balance\n        unchecked {\n            s._balanceVault -= liquidationRewards;\n        }\n\n        // transfer rewards (assets) to the liquidator\n        address(s._asset).safeTransfer(msg.sender, liquidationRewards);\n\n        emit IUsdnProtocolEvents.LiquidatorRewarded(msg.sender, liquidationRewards);\n    }\n\n    /**\n     * @notice Triggers the rebalancer if the imbalance on the long side is too high.\n     * It will close the rebalancer's position (if there is one) and open a new one with the pending assets, the value\n     * of the previous position and the liquidation bonus (if available) with a leverage that would fill enough trading\n     * exposure to reach the desired imbalance, up to the max leverages.\n     * @dev Only call this function after liquidations are performed to have a non-zero `remainingCollateral` value.\n     * Will return the provided long and vault balances if no rebalancer is set or if the imbalance is not high enough.\n     * If `remainingCollateral` is negative, the rebalancer bonus will be 0.\n     * @param lastPrice The last price used to update the protocol.\n     * @param longBalance The balance of the long side.\n     * @param vaultBalance The balance of the vault side.\n     * @param remainingCollateral The collateral remaining after the liquidations.\n     * @return longBalance_ The updated long balance not saved into storage yet.\n     * @return vaultBalance_ The updated vault balance not saved into storage yet.\n     * @return action_ The action performed by this function.\n     */\n    function _triggerRebalancer(\n        uint128 lastPrice,\n        uint256 longBalance,\n        uint256 vaultBalance,\n        int256 remainingCollateral\n    ) internal returns (uint256 longBalance_, uint256 vaultBalance_, Types.RebalancerAction action_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        longBalance_ = longBalance;\n        vaultBalance_ = vaultBalance;\n        IBaseRebalancer rebalancer = s._rebalancer;\n\n        if (address(rebalancer) == address(0)) {\n            return (longBalance_, vaultBalance_, Types.RebalancerAction.None);\n        }\n\n        Types.CachedProtocolState memory cache;\n        {\n            int256 tempVaultBalance = vaultBalance.toInt256() + s._pendingBalanceVault;\n            // clamp the vault balance to 0 to avoid underflows\n            if (tempVaultBalance < 0) {\n                tempVaultBalance = 0;\n            }\n\n            cache = Types.CachedProtocolState({\n                totalExpo: s._totalExpo,\n                longBalance: longBalance,\n                // cast is safe as value cannot be negative\n                vaultBalance: uint256(tempVaultBalance),\n                tradingExpo: 0,\n                liqMultiplierAccumulator: s._liqMultiplierAccumulator\n            });\n        }\n\n        if (cache.totalExpo < cache.longBalance) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidLongExpo();\n        }\n\n        cache.tradingExpo = cache.totalExpo - cache.longBalance;\n\n        // calculate the bonus now and update the cache to make sure removing it from the vault doesn't push the\n        // imbalance above the threshold\n        uint128 bonus;\n        if (remainingCollateral > 0) {\n            bonus = (uint256(remainingCollateral) * s._rebalancerBonusBps / Constants.BPS_DIVISOR).toUint128();\n            if (bonus > cache.vaultBalance) {\n                bonus = cache.vaultBalance.toUint128();\n            }\n\n            cache.vaultBalance -= bonus;\n        }\n\n        {\n            int256 currentImbalance = Utils._calcImbalanceCloseBps(\n                cache.vaultBalance.toInt256(), cache.longBalance.toInt256(), cache.totalExpo\n            );\n\n            // if the imbalance is lower than the threshold, return\n            if (currentImbalance <= s._closeExpoImbalanceLimitBps) {\n                return (longBalance_, vaultBalance_, Types.RebalancerAction.NoImbalance);\n            }\n        }\n\n        TriggerRebalancerData memory data;\n        // the default value of `positionAmount` is the amount of pendingAssets in the rebalancer\n        (data.positionAmount, data.rebalancerMaxLeverage, data.rebalancerPosId) = rebalancer.getCurrentStateData();\n\n        // close the rebalancer position and get its value to open the next one\n        if (data.rebalancerPosId.tick != Constants.NO_POSITION_TICK) {\n            // cached values will be updated during this call\n            int256 realPositionValue = _flashClosePosition(data.rebalancerPosId, lastPrice, cache);\n\n            // if the position value is less than 0, it should have been liquidated but wasn't\n            // interrupt the whole rebalancer process because there are pending liquidations\n            if (realPositionValue < 0) {\n                return (longBalance_, vaultBalance_, Types.RebalancerAction.PendingLiquidation);\n            }\n\n            // cast is safe as realPositionValue cannot be lower than 0\n            data.positionValue = uint256(realPositionValue).toUint128();\n            data.positionAmount += data.positionValue;\n            longBalance_ -= data.positionValue;\n        } else if (data.positionAmount == 0) {\n            // avoid to update an empty rebalancer\n            return (longBalance_, vaultBalance_, Types.RebalancerAction.NoCloseNoOpen);\n        }\n\n        // if the amount in the position we wanted to open is below a fraction of the _minLongPosition setting,\n        // we are dealing with dust. So we should stop the process and gift the remaining value to the vault\n        if (data.positionAmount <= s._minLongPosition / 10_000) {\n            // make the rebalancer believe that the previous position was liquidated,\n            // and inform it that no new position was open so it can start anew\n            rebalancer.updatePosition(Types.PositionId(Constants.NO_POSITION_TICK, 0, 0), 0);\n            vaultBalance_ += data.positionValue;\n            return (longBalance_, vaultBalance_, Types.RebalancerAction.Closed);\n        }\n\n        // transfer the pending assets from the rebalancer to this contract\n        // slither-disable-next-line arbitrary-send-erc20\n        address(s._asset).safeTransferFrom(address(rebalancer), address(this), data.positionAmount - data.positionValue);\n\n        // add the bonus to the new rebalancer position and remove it from the vault\n        if (bonus > 0) {\n            // those operations will not underflow because the bonus is capped by `remainingCollateral`\n            // which was given to the vault before the trigger, so vaultBalance is always greater than or equal to bonus\n            vaultBalance_ -= bonus;\n            data.positionAmount += bonus;\n        }\n\n        Types.RebalancerPositionData memory posData =\n            _calcRebalancerPositionTick(lastPrice, data.positionAmount, data.rebalancerMaxLeverage, cache);\n\n        // open a new position for the rebalancer\n        Types.PositionId memory posId = _flashOpenPosition(\n            address(rebalancer),\n            lastPrice,\n            posData.tick,\n            posData.totalExpo,\n            posData.liquidationPenalty,\n            data.positionAmount\n        );\n\n        longBalance_ += data.positionAmount;\n\n        // call the rebalancer to update the public bookkeeping\n        rebalancer.updatePosition(posId, data.positionValue);\n\n        if (data.positionValue > 0) {\n            action_ = Types.RebalancerAction.ClosedOpened;\n        } else {\n            action_ = Types.RebalancerAction.Opened;\n        }\n    }\n\n    /**\n     * @notice Immediately opens a position with the given price.\n     * @dev Should only be used to open the rebalancer's position.\n     * @param user The address of the rebalancer.\n     * @param lastPrice The last price used to update the protocol.\n     * @param tick The tick the position should be opened in.\n     * @param posTotalExpo The total exposure of the position.\n     * @param liquidationPenalty The liquidation penalty of the tick.\n     * @param amount The amount of collateral in the position.\n     * @return posId_ The ID of the position that was created.\n     */\n    function _flashOpenPosition(\n        address user,\n        uint128 lastPrice,\n        int24 tick,\n        uint128 posTotalExpo,\n        uint24 liquidationPenalty,\n        uint128 amount\n    ) internal returns (Types.PositionId memory posId_) {\n        posId_.tick = tick;\n        Types.Position memory long = Types.Position({\n            validated: true,\n            user: user,\n            amount: amount,\n            totalExpo: posTotalExpo,\n            timestamp: uint40(block.timestamp)\n        });\n\n        // save the position on the provided tick\n        (posId_.tickVersion, posId_.index,) = Core._saveNewPosition(posId_.tick, long, liquidationPenalty);\n\n        // emit both initiate and validate events\n        // so the position is considered the same as other positions by event indexers\n        emit IUsdnProtocolEvents.InitiatedOpenPosition(\n            user, user, uint40(block.timestamp), posTotalExpo, long.amount, lastPrice, posId_\n        );\n        emit IUsdnProtocolEvents.ValidatedOpenPosition(user, user, posTotalExpo, lastPrice, posId_);\n    }\n\n    /**\n     * @notice Immediately closes a position with the given price.\n     * @dev Should only be used to close the rebalancer's position.\n     * @param posId The ID of the position to close.\n     * @param lastPrice The last price used to update the protocol.\n     * @param cache The cached state of the protocol, will be updated during this call.\n     * @return positionValue_ The value of the closed position.\n     */\n    function _flashClosePosition(\n        Types.PositionId memory posId,\n        uint128 lastPrice,\n        Types.CachedProtocolState memory cache\n    ) internal returns (int256 positionValue_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (bytes32 tickHash, uint256 version) = Utils._tickHash(posId.tick);\n        // if the tick version is outdated, the position was liquidated and its value is 0\n        if (posId.tickVersion != version) {\n            return positionValue_;\n        }\n\n        uint24 liquidationPenalty = s._tickData[tickHash].liquidationPenalty;\n        Types.Position memory pos = s._longPositions[tickHash][posId.index];\n\n        positionValue_ = Utils._positionValue(\n            pos.totalExpo,\n            lastPrice,\n            Utils._getEffectivePriceForTick(\n                Utils._calcTickWithoutPenalty(posId.tick, liquidationPenalty),\n                lastPrice,\n                cache.tradingExpo,\n                cache.liqMultiplierAccumulator\n            )\n        );\n\n        // if positionValue is lower than 0, return\n        if (positionValue_ < 0) {\n            return positionValue_;\n        }\n\n        // fully close the position and update the cache\n        cache.liqMultiplierAccumulator =\n            _removeAmountFromPosition(posId.tick, posId.index, pos, pos.amount, pos.totalExpo);\n\n        // update the cache\n        cache.totalExpo -= pos.totalExpo;\n        // cast is safe as positionValue cannot be lower than 0\n        if (cache.longBalance >= uint256(positionValue_)) {\n            cache.longBalance -= uint256(positionValue_);\n        } else {\n            // case is safe as the long balance is below the position value which is an int256\n            positionValue_ = int256(cache.longBalance);\n            cache.longBalance = 0;\n        }\n        cache.tradingExpo = cache.totalExpo - cache.longBalance;\n\n        // emit both initiate and validate events\n        // so the position is considered the same as other positions by event indexers\n        emit IUsdnProtocolEvents.InitiatedClosePosition(pos.user, pos.user, pos.user, posId, pos.amount, pos.amount, 0);\n        emit IUsdnProtocolEvents.ValidatedClosePosition(\n            pos.user, pos.user, posId, uint256(positionValue_), positionValue_ - Utils._toInt256(pos.amount)\n        );\n    }\n\n    /**\n     * @notice Liquidates positions that have a liquidation price lower than the current price.\n     * @param currentPrice The current price of the asset.\n     * @param iteration The maximum number of ticks to liquidate (minimum is 1).\n     * @param tempLongBalance The temporary long balance as calculated when applying the PnL and funding.\n     * @param tempVaultBalance The temporary vault balance as calculated when applying the PnL and funding.\n     * @return effects_ The effects of the liquidations on the protocol.\n     */\n    function _liquidatePositions(\n        uint256 currentPrice,\n        uint16 iteration,\n        int256 tempLongBalance,\n        int256 tempVaultBalance\n    ) internal returns (Types.LiquidationsEffects memory effects_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        LiquidationData memory data;\n        data.tempLongBalance = tempLongBalance;\n        data.tempVaultBalance = tempVaultBalance;\n        // cast is safe as tempLongBalance cannot exceed s._totalExpo\n        data.longTradingExpo = uint256(s._totalExpo.toInt256() - tempLongBalance);\n        data.currentPrice = currentPrice;\n        data.accumulator = s._liqMultiplierAccumulator;\n\n        // max iteration limit\n        if (iteration > Constants.MAX_LIQUIDATION_ITERATION) {\n            iteration = Constants.MAX_LIQUIDATION_ITERATION;\n        }\n\n        effects_.liquidatedTicks = new Types.LiqTickInfo[](iteration);\n\n        // For small prices (< ~1.025 gwei), the next tick can sometimes\n        // give a price that is exactly equal to the input. For this to be somewhat of an issue,\n        // we would need the tick spacing to be 1 and the price to fall to an extremely low price,\n        // which is unlikely, but should be considered for tokens with extremely high total supply\n        uint256 unadjustedPrice =\n            _unadjustPrice(data.currentPrice, data.currentPrice, data.longTradingExpo, data.accumulator);\n        data.currentTick = TickMath.getTickAtPrice(unadjustedPrice);\n        data.iTick = s._highestPopulatedTick;\n        uint256 i;\n        do {\n            uint256 index = s._tickBitmap.findLastSet(Utils._calcBitmapIndexFromTick(data.iTick));\n            if (index == LibBitmap.NOT_FOUND) {\n                // no populated ticks left\n                break;\n            }\n\n            data.iTick = _calcTickFromBitmapIndex(index);\n            if (data.iTick < data.currentTick) {\n                // all ticks that can be liquidated have been processed\n                break;\n            }\n\n            // we have found a non-empty tick that needs to be liquidated\n            (bytes32 tickHash,) = Utils._tickHash(data.iTick);\n\n            Types.TickData memory tickData = s._tickData[tickHash];\n            // update transient data\n            data.totalExpoToRemove += tickData.totalExpo;\n            uint256 unadjustedTickPrice =\n                TickMath.getPriceAtTick(Utils._calcTickWithoutPenalty(data.iTick, tickData.liquidationPenalty));\n            data.accumulatorValueToRemove += unadjustedTickPrice * tickData.totalExpo;\n            // update return values\n            effects_.liquidatedTicks[i] = Types.LiqTickInfo({\n                totalPositions: tickData.totalPos,\n                totalExpo: tickData.totalExpo,\n                remainingCollateral: _tickValue(\n                    data.iTick, data.currentPrice, data.longTradingExpo, data.accumulator, tickData\n                ),\n                tickPrice: Utils._getEffectivePriceForTick(\n                    data.iTick, data.currentPrice, data.longTradingExpo, data.accumulator\n                ),\n                priceWithoutPenalty: Utils._getEffectivePriceForTick(\n                    Utils._calcTickWithoutPenalty(data.iTick, tickData.liquidationPenalty),\n                    data.currentPrice,\n                    data.longTradingExpo,\n                    data.accumulator\n                )\n            });\n            effects_.liquidatedPositions += tickData.totalPos;\n            effects_.remainingCollateral += effects_.liquidatedTicks[i].remainingCollateral;\n\n            // reset tick by incrementing the tick version\n            ++s._tickVersion[data.iTick];\n            // update bitmap to reflect that the tick is empty\n            s._tickBitmap.unset(index);\n\n            emit IUsdnProtocolEvents.LiquidatedTick(\n                data.iTick,\n                s._tickVersion[data.iTick] - 1,\n                data.currentPrice,\n                effects_.liquidatedTicks[i].tickPrice,\n                effects_.liquidatedTicks[i].remainingCollateral\n            );\n\n            unchecked {\n                i++;\n            }\n        } while (i < iteration);\n        // shrink array\n        Types.LiqTickInfo[] memory liqTicks = effects_.liquidatedTicks;\n        assembly (\"memory-safe\") {\n            mstore(liqTicks, i)\n        }\n\n        _updateStateAfterLiquidation(data, effects_); // mutates `data`\n        effects_.isLiquidationPending = data.isLiquidationPending;\n        (effects_.newLongBalance, effects_.newVaultBalance) =\n            _handleNegativeBalances(data.tempLongBalance, data.tempVaultBalance);\n    }\n\n    /**\n     * @notice Updates the state of the contract according to the liquidation effects.\n     * @param data The liquidation data, which gets mutated by the function.\n     * @param effects The effects of the liquidations.\n     */\n    function _updateStateAfterLiquidation(LiquidationData memory data, Types.LiquidationsEffects memory effects)\n        internal\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        // update the state\n        s._totalLongPositions -= effects.liquidatedPositions;\n        s._totalExpo -= data.totalExpoToRemove;\n        s._liqMultiplierAccumulator = s._liqMultiplierAccumulator.sub(HugeUint.wrap(data.accumulatorValueToRemove));\n\n        // keep track of the highest populated tick\n        if (effects.liquidatedPositions != 0) {\n            int24 highestPopulatedTick;\n            if (data.iTick < data.currentTick) {\n                // all ticks above the current tick were liquidated\n                highestPopulatedTick = _findHighestPopulatedTick(data.currentTick);\n            } else {\n                // unsure if all ticks above the current tick were liquidated, but some were\n                highestPopulatedTick = _findHighestPopulatedTick(data.iTick);\n                data.isLiquidationPending = data.currentTick <= highestPopulatedTick;\n            }\n\n            s._highestPopulatedTick = highestPopulatedTick;\n            emit IUsdnProtocolEvents.HighestPopulatedTickUpdated(highestPopulatedTick);\n        }\n\n        // transfer remaining collateral to vault or pay bad debt\n        data.tempLongBalance -= effects.remainingCollateral;\n        data.tempVaultBalance += effects.remainingCollateral;\n    }\n\n    /**\n     * @notice Checks and reverts if the position's trading exposure exceeds the imbalance limits.\n     * @param openTotalExpoValue The total exposure of the position to open.\n     * @param collateralAmount The amount of collateral of the position.\n     * @param collateralAmountAfterFees The amount of collateral of the position after fees.\n     */\n    function _checkImbalanceLimitOpen(\n        uint256 openTotalExpoValue,\n        uint256 collateralAmount,\n        uint256 collateralAmountAfterFees\n    ) internal view {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        int256 openExpoImbalanceLimitBps = s._openExpoImbalanceLimitBps;\n\n        // early return in case limit is disabled\n        if (openExpoImbalanceLimitBps == 0) {\n            return;\n        }\n\n        int256 currentVaultExpo = s._balanceVault.toInt256().safeAdd(s._pendingBalanceVault).safeAdd(\n            (collateralAmount - collateralAmountAfterFees).toInt256()\n        );\n\n        int256 imbalanceBps = _calcImbalanceOpenBps(\n            currentVaultExpo, (s._balanceLong + collateralAmountAfterFees).toInt256(), s._totalExpo + openTotalExpoValue\n        );\n\n        if (imbalanceBps > openExpoImbalanceLimitBps) {\n            revert IUsdnProtocolErrors.UsdnProtocolImbalanceLimitReached(imbalanceBps);\n        }\n    }\n\n    /**\n     * @notice Calculates the tick of the rebalancer position to open.\n     * @dev The returned tick must give a leverage higher than or equal to the minimum leverage of the protocol\n     * and lower than or equal to the rebalancer and USDN protocol leverages (lowest of the 2).\n     * @param lastPrice The last price used to update the protocol.\n     * @param positionAmount The amount of assets in the position.\n     * @param rebalancerMaxLeverage The maximum leverage supported by the rebalancer.\n     * @param cache The cached protocol state values.\n     * @return posData_ The tick, total exposure and liquidation penalty for the rebalancer position.\n     */\n    function _calcRebalancerPositionTick(\n        uint128 lastPrice,\n        uint128 positionAmount,\n        uint256 rebalancerMaxLeverage,\n        Types.CachedProtocolState memory cache\n    ) internal view returns (Types.RebalancerPositionData memory posData_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        Types.CalcRebalancerPositionTickData memory data;\n\n        data.protocolMaxLeverage = s._maxLeverage;\n        if (rebalancerMaxLeverage > data.protocolMaxLeverage) {\n            rebalancerMaxLeverage = data.protocolMaxLeverage;\n        }\n\n        data.longImbalanceTargetBps = s._longImbalanceTargetBps;\n        // calculate the trading exposure missing to reach the imbalance target\n        uint256 targetTradingExpo = (\n            cache.vaultBalance * Constants.BPS_DIVISOR\n                / (int256(Constants.BPS_DIVISOR) + data.longImbalanceTargetBps).toUint256()\n        );\n\n        // make sure that the rebalancer was not triggered without a sufficient imbalance\n        // as we check the imbalance above, this should not happen\n        if (cache.tradingExpo >= targetTradingExpo) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidRebalancerTick();\n        }\n\n        uint256 tradingExpoToFill = targetTradingExpo - cache.tradingExpo;\n\n        // check that the trading exposure filled by the position would not exceed the max leverage\n        data.highestUsableTradingExpo =\n            positionAmount * rebalancerMaxLeverage / 10 ** Constants.LEVERAGE_DECIMALS - positionAmount;\n        if (data.highestUsableTradingExpo < tradingExpoToFill) {\n            tradingExpoToFill = data.highestUsableTradingExpo;\n        }\n\n        data.currentLiqPenalty = s._liquidationPenalty;\n        uint128 idealLiqPrice = _calcLiqPriceFromTradingExpo(lastPrice, positionAmount, tradingExpoToFill);\n\n        (posData_.tick, data.liqPriceWithoutPenalty) = _getTickFromDesiredLiqPrice(\n            idealLiqPrice,\n            lastPrice,\n            cache.tradingExpo,\n            cache.liqMultiplierAccumulator,\n            s._tickSpacing,\n            data.currentLiqPenalty\n        );\n\n        posData_.liquidationPenalty = getTickLiquidationPenalty(posData_.tick);\n        if (posData_.liquidationPenalty != data.currentLiqPenalty) {\n            data.liqPriceWithoutPenalty = Utils._getEffectivePriceForTick(\n                Utils._calcTickWithoutPenalty(posData_.tick, posData_.liquidationPenalty),\n                lastPrice,\n                cache.tradingExpo,\n                cache.liqMultiplierAccumulator\n            );\n        }\n        posData_.totalExpo = Utils._calcPositionTotalExpo(positionAmount, lastPrice, data.liqPriceWithoutPenalty);\n\n        // due to the rounding down, if the imbalance is still greater than the desired imbalance\n        // and the position is not at the max leverage, add one tick\n        if (\n            data.highestUsableTradingExpo != tradingExpoToFill\n                && Utils._calcImbalanceCloseBps(\n                    cache.vaultBalance.toInt256(),\n                    (cache.longBalance + positionAmount).toInt256(),\n                    cache.totalExpo + posData_.totalExpo\n                ) > data.longImbalanceTargetBps\n        ) {\n            posData_.tick += s._tickSpacing;\n            posData_.liquidationPenalty = getTickLiquidationPenalty(posData_.tick);\n            data.liqPriceWithoutPenalty = Utils._getEffectivePriceForTick(\n                Utils._calcTickWithoutPenalty(posData_.tick, posData_.liquidationPenalty),\n                lastPrice,\n                cache.tradingExpo,\n                cache.liqMultiplierAccumulator\n            );\n            posData_.totalExpo = Utils._calcPositionTotalExpo(positionAmount, lastPrice, data.liqPriceWithoutPenalty);\n        }\n    }\n\n    /**\n     * @notice Checks and reverts if the leverage of a position exceeds the safety margin.\n     * @param currentPrice The current price of the asset.\n     * @param liquidationPrice The liquidation price of the position.\n     */\n    function _checkSafetyMargin(uint128 currentPrice, uint128 liquidationPrice) internal view {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint128 maxLiquidationPrice =\n            (currentPrice * (Constants.BPS_DIVISOR - s._safetyMarginBps) / Constants.BPS_DIVISOR).toUint128();\n        if (liquidationPrice >= maxLiquidationPrice) {\n            revert IUsdnProtocolErrors.UsdnProtocolLiquidationPriceSafetyMargin(liquidationPrice, maxLiquidationPrice);\n        }\n    }\n\n    /**\n     * @notice Retrieves the liquidation penalty assigned to the given `tickHash`.\n     * @dev If there are no positions in it, returns the current setting from storage.\n     * @param tickHash The tick hash (hashed tick number + version).\n     * @return liquidationPenalty_ The liquidation penalty (in tick spacing units).\n     */\n    function _getTickLiquidationPenalty(bytes32 tickHash) internal view returns (uint24 liquidationPenalty_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        Types.TickData storage tickData = s._tickData[tickHash];\n        liquidationPenalty_ = tickData.totalPos != 0 ? tickData.liquidationPenalty : s._liquidationPenalty;\n    }\n\n    /**\n     * @dev Converts the given bitmap index to a tick number using the stored tick spacing.\n     * @param index The index into the bitmap.\n     * @return tick_ The tick corresponding to the index, a multiple of the tick spacing.\n     */\n    function _calcTickFromBitmapIndex(uint256 index) internal view returns (int24 tick_) {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        tick_ = _calcTickFromBitmapIndex(index, s._tickSpacing);\n    }\n\n    /**\n     * @notice Calculates the unadjusted price of a position's liquidation price, which can be used to find the\n     * corresponding tick.\n     * @param price An adjusted liquidation price (taking into account the effects of funding).\n     * @param assetPrice The current price of the asset.\n     * @param longTradingExpo The trading exposure of the long side (total exposure - balance long).\n     * @param accumulator The liquidation multiplier accumulator.\n     * @return unadjustedPrice_ The unadjusted price of `price`.\n     */\n    function _unadjustPrice(\n        uint256 price,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator\n    ) internal pure returns (uint256 unadjustedPrice_) {\n        if (accumulator.hi == 0 && accumulator.lo == 0) {\n            // no position in long, we assume a liquidation multiplier of 1.0\n            return price;\n        }\n        if (longTradingExpo == 0) {\n            // it is not possible to calculate the unadjusted price when the trading exposure is zero\n            revert IUsdnProtocolErrors.UsdnProtocolZeroLongTradingExpo();\n        }\n        // M = assetPrice * (totalExpo - balanceLong) / accumulator\n        // unadjustedPrice = price / M\n        // unadjustedPrice = price * accumulator / (assetPrice * (totalExpo - balanceLong))\n        HugeUint.Uint512 memory numerator = accumulator.mul(price);\n        unadjustedPrice_ = numerator.div(assetPrice * longTradingExpo);\n    }\n\n    /**\n     * @notice Calculates the unadjusted price of a position's liquidation price, which can be used to find the\n     * corresponding tick, with a fixed precision representation of the liquidation multiplier.\n     * @param price An adjusted liquidation price (taking into account the effects of funding).\n     * @param liqMultiplier The liquidation price multiplier, with `LIQUIDATION_MULTIPLIER_DECIMALS` decimals.\n     * @return unadjustedPrice_ The unadjusted price for the liquidation price.\n     */\n    function _unadjustPrice(uint256 price, uint256 liqMultiplier) internal pure returns (uint256 unadjustedPrice_) {\n        // unadjustedPrice = price / M\n        // unadjustedPrice = price * 10 ** LIQUIDATION_MULTIPLIER_DECIMALS / liqMultiplier\n        unadjustedPrice_ =\n            FixedPointMathLib.fullMulDiv(price, 10 ** Constants.LIQUIDATION_MULTIPLIER_DECIMALS, liqMultiplier);\n    }\n\n    /**\n     * @notice Calculates the value of a tick, knowing its contained total exposure and the current asset price.\n     * @param tick The tick number.\n     * @param currentPrice The current price of the asset.\n     * @param longTradingExpo The trading exposure of the long side.\n     * @param accumulator The liquidation multiplier accumulator.\n     * @param tickData The aggregated data of the tick.\n     * @return value_ The amount of asset tokens the tick is worth.\n     */\n    function _tickValue(\n        int24 tick,\n        uint256 currentPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator,\n        Types.TickData memory tickData\n    ) internal pure returns (int256 value_) {\n        uint128 liqPriceWithoutPenalty = Utils._getEffectivePriceForTick(\n            Utils._calcTickWithoutPenalty(tick, tickData.liquidationPenalty), currentPrice, longTradingExpo, accumulator\n        );\n\n        // value = totalExpo * (currentPrice - liqPriceWithoutPenalty) / currentPrice\n        // if the current price is lower than the liquidation price, we have effectively a negative value\n        if (currentPrice <= liqPriceWithoutPenalty) {\n            // we calculate the inverse and then change the sign\n            value_ = -int256(\n                FixedPointMathLib.fullMulDiv(tickData.totalExpo, liqPriceWithoutPenalty - currentPrice, currentPrice)\n            );\n        } else {\n            value_ = int256(\n                FixedPointMathLib.fullMulDiv(tickData.totalExpo, currentPrice - liqPriceWithoutPenalty, currentPrice)\n            );\n        }\n    }\n\n    /**\n     * @notice Calculates the liquidation price without penalty of a position to reach a certain trading exposure.\n     * @dev If the sum of `amount` and `tradingExpo` equals 0, reverts.\n     * @param currentPrice The price of the asset.\n     * @param amount The amount of asset used as collateral.\n     * @param tradingExpo The trading exposure.\n     * @return liqPrice_ The liquidation price without penalty.\n     */\n    function _calcLiqPriceFromTradingExpo(uint128 currentPrice, uint128 amount, uint256 tradingExpo)\n        internal\n        pure\n        returns (uint128 liqPrice_)\n    {\n        uint256 totalExpo = amount + tradingExpo;\n        if (totalExpo == 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolZeroTotalExpo();\n        }\n\n        liqPrice_ = FixedPointMathLib.fullMulDiv(currentPrice, tradingExpo, totalExpo).toUint128();\n    }\n\n    /**\n     * @dev Converts a bitmap index to a tick number using the provided tick spacing.\n     * @param index The index into the bitmap.\n     * @param tickSpacing The tick spacing to use.\n     * @return tick_ The tick corresponding to the index, a multiple of `tickSpacing`.\n     */\n    function _calcTickFromBitmapIndex(uint256 index, int24 tickSpacing) internal pure returns (int24 tick_) {\n        tick_ = int24( // cast to int24 is safe as index + TickMath.MIN_TICK cannot be above or below int24 limits\n            (\n                int256(index) // cast to int256 is safe as the index is lower than type(int24).max\n                    + TickMath.MIN_TICK // shift into negative\n                        / tickSpacing\n            ) * tickSpacing\n        );\n    }\n\n    /**\n     * @notice Handles negative balances by transferring assets from one side to the other.\n     * @dev Balances are unsigned integers and can't be negative.\n     * In theory, this can not happen anymore because we have more precise calculations with the\n     * `liqMultiplierAccumulator` compared to the old `liquidationMultiplier`.\n     * @param tempLongBalance The temporary long balance after liquidations\n     * @param tempVaultBalance The temporary vault balance after liquidations\n     * @return longBalance_ The new long balance after rebalancing\n     * @return vaultBalance_ The new vault balance after rebalancing\n     */\n    function _handleNegativeBalances(int256 tempLongBalance, int256 tempVaultBalance)\n        internal\n        pure\n        returns (uint256 longBalance_, uint256 vaultBalance_)\n    {\n        // this can happen if the funding is larger than the remaining balance in the long side after applying PnL\n        // test case: test_assetToTransferZeroBalance()\n        if (tempLongBalance < 0) {\n            tempVaultBalance += tempLongBalance;\n            tempLongBalance = 0;\n        }\n\n        // this can happen if there is not enough balance in the vault to pay the bad debt in the long side, for\n        // example if the protocol fees reduce the vault balance\n        // test case: test_funding_NegLong_ZeroVault()\n        if (tempVaultBalance < 0) {\n            tempLongBalance += tempVaultBalance;\n            tempVaultBalance = 0;\n        }\n\n        // in case the long balance is still negative, clamp it to 0\n        if (tempLongBalance < 0) {\n            tempLongBalance = 0;\n        }\n\n        longBalance_ = tempLongBalance.toUint256();\n        vaultBalance_ = tempVaultBalance.toUint256();\n    }\n\n    /**\n     * @notice Calculates the current imbalance for the open action checks.\n     * @dev If the value is positive, the long trading exposure is larger than the vault trading exposure.\n     * In case of an empty vault balance, returns `int256.max` since the resulting imbalance would be infinity.\n     * @param vaultExpo The vault exposure (including the pending vault balance and the fees of the position to open).\n     * @param longBalance The balance of the long side (including the long position to open).\n     * @param totalExpo The total exposure of the long side (including the long position to open).\n     * @return imbalanceBps_ The imbalance (in basis points).\n     */\n    function _calcImbalanceOpenBps(int256 vaultExpo, int256 longBalance, uint256 totalExpo)\n        internal\n        pure\n        returns (int256 imbalanceBps_)\n    {\n        // an imbalance cannot be calculated if the new vault exposure is zero or negative\n        if (vaultExpo <= 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolEmptyVault();\n        }\n\n        // imbalanceBps = (longTradingExpo - vaultExpo) / vaultExpo\n        // imbalanceBps = ((totalExpo - longBalance) - vaultExpo) / vaultExpo;\n        imbalanceBps_ = (totalExpo.toInt256() - longBalance).safeSub(vaultExpo).safeMul(int256(Constants.BPS_DIVISOR))\n            .safeDiv(vaultExpo);\n    }\n\n    /**\n     * @notice Calculates the tick corresponding to an unadjusted price, without rounding to the tick spacing.\n     * @param unadjustedPrice The unadjusted price.\n     * @return tick_ The tick number, bound by `MIN_TICK`.\n     */\n    function _unadjustedPriceToTick(uint256 unadjustedPrice) internal pure returns (int24 tick_) {\n        if (unadjustedPrice < TickMath.MIN_PRICE) {\n            return TickMath.MIN_TICK;\n        }\n\n        tick_ = TickMath.getTickAtPrice(unadjustedPrice);\n    }\n\n    /**\n     * @notice Rounds a tick down to a multiple of the tick spacing.\n     * @dev The function is bound by {minTick}, so the first tick which is a multiple of the tick spacing\n     * and greater than or equal to `MIN_TICK`.\n     * @param tick The tick number.\n     * @param tickSpacing The tick spacing.\n     * @return roundedTick_ The rounded tick number.\n     */\n    function _roundTickDown(int24 tick, int24 tickSpacing) internal pure returns (int24 roundedTick_) {\n        // round down to the next valid tick according to _tickSpacing (towards negative infinity)\n        if (tick < 0) {\n            // we round up the inverse number (positive) then invert it -> round towards negative infinity\n            roundedTick_ = -int24(int256(FixedPointMathLib.divUp(uint256(int256(-tick)), uint256(int256(tickSpacing)))))\n                * tickSpacing;\n            // avoid invalid ticks\n            int24 minUsableTick = TickMath.minUsableTick(tickSpacing);\n            if (roundedTick_ < minUsableTick) {\n                roundedTick_ = minUsableTick;\n            }\n        } else {\n            // rounding is desirable here\n            // slither-disable-next-line divide-before-multiply\n            roundedTick_ = (tick / tickSpacing) * tickSpacing;\n        }\n    }\n\n    /**\n     * @notice Rounds the given tick down to a multiple of the tick spacing .\n     * @dev The result will always be above `MIN_TICK` + liquidationPenalty.\n     * @param tickWithPenalty The tick number with the liquidation penalty.\n     * @param tickSpacing The tick spacing.\n     * @param liqPenalty The liquidation penalty.\n     * @return roundedTick_ The rounded tick number.\n     */\n    function _roundTickDownWithPenalty(int24 tickWithPenalty, int24 tickSpacing, uint24 liqPenalty)\n        internal\n        pure\n        returns (int24 roundedTick_)\n    {\n        if (tickWithPenalty < 0) {\n            // we round up the inverse number (positive) then invert it -> round towards negative infinity\n            roundedTick_ = -int24(int256(FixedPointMathLib.divUp(uint256(int256(-tickWithPenalty)), uint256(int256(tickSpacing)))))\n                * tickSpacing;\n            // avoid invalid ticks: we should be able to get the price for `tickWithPenalty_ - liquidationPenalty`\n            int24 minTickWithPenalty = TickMath.MIN_TICK + int24(liqPenalty);\n            if (roundedTick_ < minTickWithPenalty) {\n                roundedTick_ = minTickWithPenalty - (minTickWithPenalty % tickSpacing);\n            }\n        } else {\n            // rounding is desirable here\n            // slither-disable-next-line divide-before-multiply\n            roundedTick_ = (tickWithPenalty / tickSpacing) * tickSpacing;\n        }\n    }\n\n    /**\n     * @notice Calculates the effective tick for a given price without rounding to the tick spacing.\n     * @param price The price to be adjusted.\n     * @param assetPrice The current asset price.\n     * @param longTradingExpo The long trading exposure.\n     * @param accumulator The liquidation multiplier accumulator.\n     * @return tick_ The tick number.\n     */\n    function _getEffectiveTickForPriceNoRounding(\n        uint128 price,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator\n    ) internal pure returns (int24 tick_) {\n        // unadjust price with liquidation multiplier\n        uint256 unadjustedPrice = _unadjustPrice(price, assetPrice, longTradingExpo, accumulator);\n        tick_ = _unadjustedPriceToTick(unadjustedPrice);\n    }\n\n    /**\n     * @notice Calculates the effective tick for a given price without rounding to the tick spacing with a fixed\n     * precision representation of the liquidation multiplier.\n     * @param price The price to be adjusted.\n     * @param liqMultiplier The liquidation price multiplier (with `LIQUIDATION_MULTIPLIER_DECIMALS` decimals).\n     * @return tick_ The tick number.\n     */\n    function _getEffectiveTickForPriceNoRounding(uint128 price, uint256 liqMultiplier)\n        internal\n        pure\n        returns (int24 tick_)\n    {\n        // unadjust price with liquidation multiplier\n        uint256 unadjustedPrice = _unadjustPrice(price, liqMultiplier);\n        tick_ = _unadjustedPriceToTick(unadjustedPrice);\n    }\n\n    /**\n     * @notice Calculates the required USDN total supply to reach `targetPrice`.\n     * @param vaultBalance The balance of the vault.\n     * @param assetPrice The price of the underlying asset.\n     * @param targetPrice The target USDN price to reach.\n     * @param assetDecimals The number of decimals of the asset.\n     * @return totalSupply_ The required total supply to achieve `targetPrice`.\n     */\n    function _calcRebaseTotalSupply(uint256 vaultBalance, uint128 assetPrice, uint128 targetPrice, uint8 assetDecimals)\n        internal\n        pure\n        returns (uint256 totalSupply_)\n    {\n        totalSupply_ = FixedPointMathLib.fullMulDiv(\n            vaultBalance,\n            uint256(assetPrice) * 10 ** Constants.TOKENS_DECIMALS,\n            uint256(targetPrice) * 10 ** assetDecimals\n        );\n    }\n}\n"},{"file_path":"src/UsdnProtocol/libraries/UsdnProtocolUtilsLibrary.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { ERC165Checker } from \"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport { FixedPointMathLib } from \"solady/src/utils/FixedPointMathLib.sol\";\nimport { SafeTransferLib } from \"solady/src/utils/SafeTransferLib.sol\";\n\nimport { PriceInfo } from \"../../interfaces/OracleMiddleware/IOracleMiddlewareTypes.sol\";\nimport { IUsdn } from \"../../interfaces/Usdn/IUsdn.sol\";\nimport { IFeeCollectorCallback } from \"../../interfaces/UsdnProtocol/IFeeCollectorCallback.sol\";\nimport { IPaymentCallback } from \"../../interfaces/UsdnProtocol/IPaymentCallback.sol\";\nimport { IUsdnProtocolErrors } from \"../../interfaces/UsdnProtocol/IUsdnProtocolErrors.sol\";\nimport { IUsdnProtocolEvents } from \"../../interfaces/UsdnProtocol/IUsdnProtocolEvents.sol\";\nimport { IUsdnProtocolTypes as Types } from \"../../interfaces/UsdnProtocol/IUsdnProtocolTypes.sol\";\nimport { Accumulator, HugeUint } from \"../../libraries/Accumulator.sol\";\nimport { DoubleEndedQueue } from \"../../libraries/DoubleEndedQueue.sol\";\nimport { SignedMath } from \"../../libraries/SignedMath.sol\";\nimport { TickMath } from \"../../libraries/TickMath.sol\";\nimport { UsdnProtocolConstantsLibrary as Constants } from \"./UsdnProtocolConstantsLibrary.sol\";\n\n/**\n * @title USDN Protocol Utilities\n * @notice A library of utility functions for the `USDN protocol`. This library is not intended to be deployed as an\n * external library.\n * @dev All functions in this library must be marked as \"internal\".\n */\nlibrary UsdnProtocolUtilsLibrary {\n    using DoubleEndedQueue for DoubleEndedQueue.Deque;\n    using Accumulator for HugeUint.Uint512;\n    using SafeCast for uint256;\n    using SafeTransferLib for address;\n    using SignedMath for int256;\n\n    /**\n     * @notice Constant representing the storage slot for the protocol main storage.\n     * @dev Calculated as:\n     *  `keccak256(abi.encode(uint256(keccak256(\"UsdnProtocol.storage.main\")) - 1)) & ~bytes32(uint256(0xff))`\n     */\n    bytes32 private constant STORAGE_MAIN = 0xd143a936a6a372725e12535db83a2cfabcb3715dfd88bc350da3399604dc9700;\n\n    /**\n     * @notice Gets the main storage pointer.\n     * @return s_ The pointer to the main storage structure.\n     */\n    function _getMainStorage() internal pure returns (Types.Storage storage s_) {\n        assembly {\n            s_.slot := STORAGE_MAIN\n        }\n    }\n\n    /**\n     * @notice Refunds excess Ether to prevent unintended locking of funds.\n     * @param securityDepositValue The security deposit for the current action (zero for validation actions).\n     * @param amountToRefund The amount to refund to the user: the security deposit when executing an action for another\n     * user, and/or the initialization security deposit in the case of a validation action.\n     * @param balanceBefore The contract's balance before the action.\n     */\n    function _refundExcessEther(uint256 securityDepositValue, uint256 amountToRefund, uint256 balanceBefore) internal {\n        uint256 positive = amountToRefund + address(this).balance + msg.value;\n        uint256 negative = balanceBefore + securityDepositValue;\n\n        if (negative > positive) {\n            revert IUsdnProtocolErrors.UsdnProtocolUnexpectedBalance();\n        }\n\n        uint256 amount;\n        unchecked {\n            // we know that positive >= negative, so this subtraction is safe\n            amount = positive - negative;\n        }\n\n        _refundEther(amount, payable(msg.sender));\n    }\n\n    /**\n     * @notice Refunds Ether to a specified address.\n     * @param amount The amount of Ether to refund.\n     * @param to The address receiving the refund.\n     */\n    function _refundEther(uint256 amount, address payable to) internal {\n        if (to == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressTo();\n        }\n        if (amount != 0) {\n            // slither-disable-next-line arbitrary-send-eth\n            (bool success,) = to.call{ value: amount }(\"\");\n            if (!success) {\n                revert IUsdnProtocolErrors.UsdnProtocolEtherRefundFailed();\n            }\n        }\n    }\n\n    /**\n     * @notice Distributes the protocol fee to the fee collector if the pending amount exceeds the threshold.\n     * @dev Attempts to invoke the `feeCollectorCallback` function on the fee collector if supported.\n     */\n    function _checkPendingFee() internal {\n        Types.Storage storage s = _getMainStorage();\n\n        uint256 pendingFee = s._pendingProtocolFee;\n        if (pendingFee >= s._feeThreshold) {\n            address feeCollector = s._feeCollector;\n\n            emit IUsdnProtocolEvents.ProtocolFeeDistributed(feeCollector, pendingFee);\n            s._pendingProtocolFee = 0;\n            address(s._asset).safeTransfer(feeCollector, pendingFee);\n\n            if (ERC165Checker.supportsInterface(feeCollector, type(IFeeCollectorCallback).interfaceId)) {\n                IFeeCollectorCallback(feeCollector).feeCollectorCallback(pendingFee);\n            }\n        }\n    }\n\n    /**\n     * @notice Gets and validate the oracle price for a specified action and timestamp.\n     * @param action The protocol action being performed.\n     * @param timestamp The timestamp for which the price is queried.\n     * @param actionId The unique identifier of the action.\n     * @param priceData The encoded oracle price data.\n     * @return price_ The validated price information.\n     */\n    function _getOraclePrice(Types.ProtocolAction action, uint256 timestamp, bytes32 actionId, bytes calldata priceData)\n        internal\n        returns (PriceInfo memory price_)\n    {\n        Types.Storage storage s = _getMainStorage();\n\n        uint256 validationCost = s._oracleMiddleware.validationCost(priceData, action);\n        if (address(this).balance < validationCost) {\n            revert IUsdnProtocolErrors.UsdnProtocolInsufficientOracleFee();\n        }\n        // slither-disable-next-line arbitrary-send-eth\n        price_ = s._oracleMiddleware.parseAndValidatePrice{ value: validationCost }(\n            actionId, uint128(timestamp), action, priceData\n        );\n    }\n\n    /**\n     * @notice Clears the pending action of a user.\n     * @param user The user's address.\n     * @param rawIndex The `rawIndex` of the pending action in the queue.\n     */\n    function _clearPendingAction(address user, uint128 rawIndex) internal {\n        Types.Storage storage s = _getMainStorage();\n\n        s._pendingActionsQueue.clearAt(rawIndex);\n        delete s._pendingActions[user];\n    }\n\n    /**\n     * @notice Calculates the long balance, including unreflected PnL (excluding funding).\n     * @dev This function uses the latest total exposure, balance, and stored price as reference values. It adjusts the\n     * balance by adding the PnL resulting from the price change.\n     * @param currentPrice The current price of the asset.\n     * @return available_ The updated balance on the long side.\n     */\n    function _longAssetAvailable(uint128 currentPrice) internal view returns (int256 available_) {\n        Types.Storage storage s = _getMainStorage();\n\n        available_ = _longAssetAvailable(s._totalExpo, s._balanceLong, currentPrice, s._lastPrice);\n    }\n\n    /**\n     * @notice Calculates the hash of the given tick number and its current version.\n     * @param tick The tick number.\n     * @return hash_ The hash of the tick.\n     * @return version_ The version of the tick.\n     */\n    function _tickHash(int24 tick) internal view returns (bytes32 hash_, uint256 version_) {\n        Types.Storage storage s = _getMainStorage();\n\n        version_ = s._tickVersion[tick];\n        hash_ = _tickHash(tick, version_);\n    }\n\n    /**\n     * @notice Calculates the corresponding index of the given tick in the Bitmap, based on the storage tick spacing.\n     * @param tick The tick number, a multiple of the tick spacing.\n     * @return index_ The index into the Bitmap.\n     */\n    function _calcBitmapIndexFromTick(int24 tick) internal view returns (uint256 index_) {\n        Types.Storage storage s = _getMainStorage();\n\n        index_ = _calcBitmapIndexFromTick(tick, s._tickSpacing);\n    }\n\n    /**\n     * @notice Gets the effective price, accounting for funding, for a given tick.\n     * @param tick The tick number.\n     * @return price_ The effective price for the tick.\n     */\n    function _getEffectivePriceForTick(int24 tick) internal view returns (uint128 price_) {\n        Types.Storage storage s = _getMainStorage();\n\n        price_ =\n            _getEffectivePriceForTick(tick, s._lastPrice, s._totalExpo - s._balanceLong, s._liqMultiplierAccumulator);\n    }\n\n    /**\n     * @notice Generates a hash based on the tick and a version.\n     * @param tick The tick number.\n     * @param version The tick version.\n     * @return The hash value.\n     */\n    function _tickHash(int24 tick, uint256 version) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(tick, version));\n    }\n\n    /**\n     * @notice Converts a `uint128` to an `int256`.\n     * @param x The `uint128` value to convert.\n     * @return The resulting `int256` value.\n     */\n    function _toInt256(uint128 x) internal pure returns (int256) {\n        return int256(uint256(x));\n    }\n\n    /**\n     * @notice Optimized position value calculation when `posTotalExpo` is known to be a `uint128` and `currentPrice`\n     * is guaranteed to be above `liqPriceWithoutPenalty`.\n     * @param posTotalExpo The total exposure of the position.\n     * @param currentPrice The current asset price.\n     * @param liqPriceWithoutPenalty The liquidation price without penalty.\n     * @return posValue_ The calculated position value.\n     */\n    function _positionValueOptimized(uint128 posTotalExpo, uint128 currentPrice, uint128 liqPriceWithoutPenalty)\n        internal\n        pure\n        returns (uint256 posValue_)\n    {\n        // posValue_ = uint256(posTotalExpo) * (currentPrice - liqPriceWithoutPenalty) / currentPrice;\n        posValue_ = currentPrice - liqPriceWithoutPenalty;\n        unchecked {\n            // the multiplication cannot overflow because both operands are uint128\n            posValue_ *= posTotalExpo;\n        }\n        posValue_ /= currentPrice;\n    }\n\n    /**\n     * @notice Calculates the tick number without considering the liquidation penalty.\n     * @param tick The tick number that holds the position.\n     * @param liquidationPenalty The liquidation penalty, measured in ticks.\n     * @return tick_ The tick number adjusted to exclude the liquidation penalty.\n     */\n    function _calcTickWithoutPenalty(int24 tick, uint24 liquidationPenalty) internal pure returns (int24 tick_) {\n        tick_ = tick - int24(liquidationPenalty);\n    }\n\n    /**\n     * @notice Calculates the theoretical liquidation price of a position using its entry price and leverage.\n     * @param startPrice The entry price of the position.\n     * @param leverage The leverage of the position.\n     * @return price_ The computed liquidation price.\n     */\n    function _getLiquidationPrice(uint128 startPrice, uint128 leverage) internal pure returns (uint128 price_) {\n        price_ = (startPrice - ((uint256(10) ** Constants.LEVERAGE_DECIMALS * startPrice) / leverage)).toUint128();\n    }\n\n    /**\n     * @notice Calculates the leverage of a position using its entry price and liquidation price.\n     * @dev The calculation does not take into account the liquidation penalty.\n     * @param startPrice The entry price of the position.\n     * @param liquidationPrice The price at which the position would be liquidated.\n     * @return leverage_ The computed leverage value.\n     */\n    function _getLeverage(uint128 startPrice, uint128 liquidationPrice) internal pure returns (uint256 leverage_) {\n        if (startPrice <= liquidationPrice) {\n            // this situation is not allowed (newly open position must be solvent)\n            // also, the calculation below would underflow\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidLiquidationPrice(liquidationPrice, startPrice);\n        }\n\n        leverage_ = (10 ** Constants.LEVERAGE_DECIMALS * uint256(startPrice)) / (startPrice - liquidationPrice);\n    }\n\n    /**\n     * @notice Converts the given `LongPendingAction` to a `PendingAction`.\n     * @param action The long pending action.\n     * @return pendingAction_ The converted untyped pending action.\n     */\n    function _convertLongPendingAction(Types.LongPendingAction memory action)\n        internal\n        pure\n        returns (Types.PendingAction memory pendingAction_)\n    {\n        assembly {\n            pendingAction_ := action\n        }\n    }\n\n    /**\n     * @notice Converts the given `WithdrawalPendingAction` to a `PendingAction`.\n     * @param action The withdrawal pending action.\n     * @return pendingAction_ The converted untyped pending action.\n     */\n    function _convertWithdrawalPendingAction(Types.WithdrawalPendingAction memory action)\n        internal\n        pure\n        returns (Types.PendingAction memory pendingAction_)\n    {\n        assembly {\n            pendingAction_ := action\n        }\n    }\n\n    /**\n     * @notice Converts the given `DepositPendingAction` to a `PendingAction`.\n     * @param action The deposit pending action.\n     * @return pendingAction_ The converted untyped pending action.\n     */\n    function _convertDepositPendingAction(Types.DepositPendingAction memory action)\n        internal\n        pure\n        returns (Types.PendingAction memory pendingAction_)\n    {\n        assembly {\n            pendingAction_ := action\n        }\n    }\n\n    /**\n     * @notice Converts the given `PendingAction` to a `LongPendingAction`.\n     * @param action The untyped pending action.\n     * @return longAction_ The converted long pending action.\n     */\n    function _toLongPendingAction(Types.PendingAction memory action)\n        internal\n        pure\n        returns (Types.LongPendingAction memory longAction_)\n    {\n        assembly {\n            longAction_ := action\n        }\n    }\n\n    /**\n     * @notice Converts the given `PendingAction` to a `DepositPendingAction`.\n     * @param action The untyped pending action.\n     * @return vaultAction_ The converted deposit pending action.\n     */\n    function _toDepositPendingAction(Types.PendingAction memory action)\n        internal\n        pure\n        returns (Types.DepositPendingAction memory vaultAction_)\n    {\n        assembly {\n            vaultAction_ := action\n        }\n    }\n\n    /**\n     * @notice Converts the given `PendingAction` to a `WithdrawalPendingAction`.\n     * @param action The untyped pending action.\n     * @return vaultAction_ The converted withdrawal pending action.\n     */\n    function _toWithdrawalPendingAction(Types.PendingAction memory action)\n        internal\n        pure\n        returns (Types.WithdrawalPendingAction memory vaultAction_)\n    {\n        assembly {\n            vaultAction_ := action\n        }\n    }\n\n    /**\n     * @dev Calculates the corresponding index of the given tick in the Bitmap, based on the specified tick spacing.\n     * @param tick The tick, which must be a multiple of `tickSpacing`.\n     * @param tickSpacing The tick spacing to use.\n     * @return index_ The corresponding index into the Bitmap.\n     */\n    function _calcBitmapIndexFromTick(int24 tick, int24 tickSpacing) internal pure returns (uint256 index_) {\n        index_ = uint256( // cast is safe as the min tick is always above TickMath.MIN_TICK\n            (int256(tick) - TickMath.MIN_TICK) // shift into positive\n                / tickSpacing\n        );\n    }\n\n    /**\n     * @notice Merges the two parts of the withdrawal amount (USDN shares) stored in the `WithdrawalPendingAction`.\n     * @param sharesLSB The lower 24 bits of the USDN shares.\n     * @param sharesMSB The higher bits of the USDN shares.\n     * @return usdnShares_ The amount of USDN shares.\n     */\n    function _mergeWithdrawalAmountParts(uint24 sharesLSB, uint128 sharesMSB)\n        internal\n        pure\n        returns (uint256 usdnShares_)\n    {\n        usdnShares_ = sharesLSB | uint256(sharesMSB) << 24;\n    }\n\n    /**\n     * @notice Calculates the updated balance of the long side, considering unreflected PnL (excluding funding).\n     * @param totalExpo The total exposure of the long side.\n     * @param balanceLong The previous balance of the long side.\n     * @param newPrice The updated price of the asset.\n     * @param oldPrice The previous price used to calculate the prior balance.\n     * @return available_ The updated balance of the long side.\n     */\n    function _longAssetAvailable(uint256 totalExpo, uint256 balanceLong, uint128 newPrice, uint128 oldPrice)\n        internal\n        pure\n        returns (int256 available_)\n    {\n        int256 priceDiff = _toInt256(newPrice) - _toInt256(oldPrice);\n        uint256 tradingExpo = totalExpo - balanceLong;\n\n        int256 pnl = tradingExpo.toInt256().safeMul(priceDiff).safeDiv(_toInt256(newPrice));\n\n        available_ = balanceLong.toInt256().safeAdd(pnl);\n    }\n\n    /**\n     * @notice Calculates the imbalance between the vault and long sides.\n     * @dev A positive value indicates the long trading exposure is smaller than the vault's. If the trading exposure is\n     * equal to 0, the imbalance is infinite and `int256.max` is returned.\n     * @param vaultBalance The balance of the vault.\n     * @param longBalance The balance of the long side.\n     * @param totalExpo The total exposure of the long side.\n     * @return imbalanceBps_ The imbalance, expressed in basis points.\n     */\n    function _calcImbalanceCloseBps(int256 vaultBalance, int256 longBalance, uint256 totalExpo)\n        internal\n        pure\n        returns (int256 imbalanceBps_)\n    {\n        int256 tradingExpo = totalExpo.toInt256().safeSub(longBalance);\n        if (tradingExpo == 0) {\n            return type(int256).max;\n        }\n\n        // imbalanceBps_ = (vaultBalance - (totalExpo - longBalance)) * (totalExpo - longBalance)\n        imbalanceBps_ = (vaultBalance.safeSub(tradingExpo)).safeMul(int256(Constants.BPS_DIVISOR)).safeDiv(tradingExpo);\n    }\n\n    /**\n     * @notice Calculates the total exposure of a position.\n     * @dev Reverts if `startPrice <= liquidationPrice`.\n     * @param amount The amount of assets used as collateral.\n     * @param startPrice The asset price when the position was created.\n     * @param liquidationPrice The liquidation price of the position.\n     * @return totalExpo_ The total exposure of the position.\n     */\n    function _calcPositionTotalExpo(uint128 amount, uint128 startPrice, uint128 liquidationPrice)\n        internal\n        pure\n        returns (uint128 totalExpo_)\n    {\n        if (startPrice <= liquidationPrice) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidLiquidationPrice(liquidationPrice, startPrice);\n        }\n\n        totalExpo_ = FixedPointMathLib.fullMulDiv(amount, startPrice, startPrice - liquidationPrice).toUint128();\n    }\n\n    /**\n     * @notice Calculates the value of a position based on its liquidation price and the current asset price.\n     * @param positionTotalExpo The total exposure of the position.\n     * @param currentPrice The current price of the asset.\n     * @param liqPriceWithoutPenalty The liquidation price of the position without the liquidation penalty.\n     * @return value_ The position's value. Negative values indicate bad debt.\n     */\n    function _positionValue(uint128 positionTotalExpo, uint128 currentPrice, uint128 liqPriceWithoutPenalty)\n        internal\n        pure\n        returns (int256 value_)\n    {\n        if (currentPrice < liqPriceWithoutPenalty) {\n            value_ = -FixedPointMathLib.fullMulDiv(positionTotalExpo, liqPriceWithoutPenalty - currentPrice, currentPrice)\n                .toInt256();\n        } else {\n            value_ = FixedPointMathLib.fullMulDiv(\n                positionTotalExpo, currentPrice - liqPriceWithoutPenalty, currentPrice\n            ).toInt256();\n        }\n    }\n\n    /**\n     * @notice Calculates a fixed-precision representation of the liquidation price multiplier.\n     * @param assetPrice The current price of the asset.\n     * @param longTradingExpo The trading exposure of the long side.\n     * @param accumulator The liquidation multiplier accumulator.\n     * @return multiplier_ The liquidation price multiplier.\n     */\n    function _calcFixedPrecisionMultiplier(\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator\n    ) internal pure returns (uint256 multiplier_) {\n        if (accumulator.hi == 0 && accumulator.lo == 0) {\n            // no position in long, we assume a liquidation multiplier of 1.0\n            return 10 ** Constants.LIQUIDATION_MULTIPLIER_DECIMALS;\n        }\n        // M = assetPrice * longTradingExpo / accumulator\n        // with longTradingExpo = totalExpo - balanceLong\n        HugeUint.Uint512 memory numerator =\n            Accumulator.mul(10 ** Constants.LIQUIDATION_MULTIPLIER_DECIMALS, assetPrice * longTradingExpo);\n        multiplier_ = numerator.div(accumulator);\n    }\n\n    /**\n     * @notice Variant of `_adjustPrice` when a fixed precision representation of the liquidation multiplier is known.\n     * @param unadjustedPrice The unadjusted price for the tick.\n     * @param liqMultiplier The liquidation price multiplier.\n     * @return price_ The adjusted price for the tick.\n     */\n    function _adjustPrice(uint256 unadjustedPrice, uint256 liqMultiplier) internal pure returns (uint128 price_) {\n        // price = unadjustedPrice * M\n        price_ = FixedPointMathLib.fullMulDiv(\n            unadjustedPrice, liqMultiplier, 10 ** Constants.LIQUIDATION_MULTIPLIER_DECIMALS\n        ).toUint128();\n    }\n\n    /**\n     * @notice Calculates the amount of USDN shares to mint for a given amount of assets.\n     * @param amount The amount of assets to be converted into USDN.\n     * @param vaultBalance The current balance of the vault.\n     * @param usdnTotalShares The total supply of USDN shares.\n     * @return toMint_ The amount of USDN shares to mint.\n     */\n    function _calcMintUsdnShares(uint256 amount, uint256 vaultBalance, uint256 usdnTotalShares)\n        internal\n        pure\n        returns (uint256 toMint_)\n    {\n        if (vaultBalance == 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolEmptyVault();\n        }\n        // the amount of USDN shares to mint is calculated as follows:\n        // amountUsdn = amountAsset * priceAsset / priceUsdn,\n        // but since priceUsdn = vaultBalance * priceAsset / totalSupply, we can simplify to\n        // amountUsdn = amountAsset * totalSupply / vaultBalance, and\n        // sharesUsdn = amountAsset * totalShares / vaultBalance\n        toMint_ = FixedPointMathLib.fullMulDiv(amount, usdnTotalShares, vaultBalance);\n    }\n\n    /**\n     * @notice Calculates the amount of SDEX tokens to burn when minting USDN tokens.\n     * @dev The result is rounded up to ensure at least 1 wei of SDEX is burned.\n     * @param usdnAmount The amount of USDN to be minted.\n     * @param sdexBurnRatio The ratio of SDEX burned per minted USDN.\n     * @return sdexToBurn_ The amount of SDEX tokens to burn.\n     */\n    function _calcSdexToBurn(uint256 usdnAmount, uint32 sdexBurnRatio) internal pure returns (uint256 sdexToBurn_) {\n        sdexToBurn_ = FixedPointMathLib.fullMulDivUp(usdnAmount, sdexBurnRatio, Constants.SDEX_BURN_ON_DEPOSIT_DIVISOR);\n    }\n\n    /**\n     * @notice Calculates a unique identifier for a pending action.\n     * @dev This identifier can be used by the oracle middleware to link an `Initiate` call with the corresponding\n     * `Validate` call.\n     * @param validator The address of the validator.\n     * @param initiateTimestamp The timestamp of the `Initiate` action.\n     * @return actionId_ The unique action ID.\n     */\n    function _calcActionId(address validator, uint128 initiateTimestamp) internal pure returns (bytes32 actionId_) {\n        actionId_ = keccak256(abi.encodePacked(validator, initiateTimestamp));\n    }\n\n    /**\n     * @notice Calculates the amount of assets received when burning USDN shares, accounting for fees.\n     * @param usdnShares The amount of USDN shares to burn.\n     * @param vaultAvailableBalance The available amount of assets in the vault.\n     * @param usdnSharesTotalSupply The total supply of USDN shares.\n     * @param feeBps The fee in basis points.\n     * @return expectedAssetsAmount_ The expected amount of assets to be received after deducting fees.\n     */\n    function _calcAmountToWithdraw(\n        uint256 usdnShares,\n        uint256 vaultAvailableBalance,\n        uint256 usdnSharesTotalSupply,\n        uint256 feeBps\n    ) internal pure returns (uint256 expectedAssetsAmount_) {\n        // amount = amountUsdn * usdnPrice / assetPrice\n        //        = usdnShares * vaultAvailableBalance / usdnSharesTotalSupply\n        //\n        // amountAfterFees = amount - (amount * feeBps / BPS_DIVISOR)\n        //                 = usdnShares * (vaultAvailableBalance * (BPS_DIVISOR - feeBps))\n        //                              / (usdnSharesTotalSupply * BPS_DIVISOR)\n        // Note: the second division is moved out of the fullMulDiv to avoid an overflow in the denominator\n        expectedAssetsAmount_ = FixedPointMathLib.fullMulDiv(\n            usdnShares, vaultAvailableBalance * (Constants.BPS_DIVISOR - feeBps), usdnSharesTotalSupply\n        ) / Constants.BPS_DIVISOR;\n    }\n\n    /**\n     * @notice Calculates the available balance in the vault for a given price, excluding funding effects.\n     * @param totalExpo The total long exposure.\n     * @param balanceVault The previous balance of the vault.\n     * @param balanceLong The previous balance of the long side.\n     * @param newPrice The updated price.\n     * @param oldPrice The price used when the previous balances were calculated.\n     * @return available_ The available balance in the vault.\n     */\n    function _vaultAssetAvailable(\n        uint256 totalExpo,\n        uint256 balanceVault,\n        uint256 balanceLong,\n        uint128 newPrice,\n        uint128 oldPrice\n    ) internal pure returns (int256 available_) {\n        int256 totalBalance = balanceLong.toInt256().safeAdd(balanceVault.toInt256());\n        int256 newLongBalance = _longAssetAvailable(totalExpo, balanceLong, newPrice, oldPrice);\n\n        available_ = totalBalance.safeSub(newLongBalance);\n    }\n\n    /**\n     * @notice Adjusts the tick price by accounting for the effects of funding.\n     * @param unadjustedPrice The tick's unadjusted price.\n     * @param assetPrice The current price of the asset.\n     * @param longTradingExpo The trading exposure of the long side.\n     * @param accumulator The liquidation multiplier accumulator.\n     * @return price_ The adjusted tick price.\n     */\n    function _adjustPrice(\n        uint256 unadjustedPrice,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator\n    ) internal pure returns (uint128 price_) {\n        if (accumulator.hi == 0 && accumulator.lo == 0) {\n            // no position in long, we assume a liquidation multiplier of 1.0\n            return unadjustedPrice.toUint128();\n        }\n\n        // price = unadjustedPrice * M\n        // with M = assetPrice * (totalExpo - balanceLong) / accumulator\n        HugeUint.Uint512 memory numerator = Accumulator.mul(unadjustedPrice, assetPrice * longTradingExpo);\n        price_ = numerator.div(accumulator).toUint128();\n    }\n\n    /**\n     * @notice Invokes a callback on the `msg.sender` to transfer assets and verifies that they were received.\n     * @param token The ERC-20 token to transfer.\n     * @param amount The amount of tokens to transfer.\n     * @param to The recipient's address.\n     */\n    function _transferCallback(IERC20Metadata token, uint256 amount, address to) internal {\n        uint256 balanceBefore = token.balanceOf(to);\n        IPaymentCallback(msg.sender).transferCallback(token, amount, to);\n        uint256 balanceAfter = token.balanceOf(to);\n        if (balanceAfter != balanceBefore + amount) {\n            revert IUsdnProtocolErrors.UsdnProtocolPaymentCallbackFailed();\n        }\n    }\n\n    /**\n     * @notice Invokes a callback on the `msg.sender` to transfer USDN shares and verifies that they were received.\n     * @param usdn The address of the USDN token contract.\n     * @param shares The amount of USDN shares to transfer.\n     */\n    function _usdnTransferCallback(IUsdn usdn, uint256 shares) internal {\n        uint256 balanceBefore = usdn.sharesOf(address(this));\n        IPaymentCallback(msg.sender).usdnTransferCallback(usdn, shares);\n        uint256 balanceAfter = usdn.sharesOf(address(this));\n        if (balanceAfter != balanceBefore + shares) {\n            revert IUsdnProtocolErrors.UsdnProtocolPaymentCallbackFailed();\n        }\n    }\n\n    /**\n     * @notice Calculates the effective price for a tick, adjusted for funding effects.\n     * @param tick The tick number.\n     * @param assetPrice The current price of the asset.\n     * @param longTradingExpo The trading exposure of the long side.\n     * @param accumulator The liquidation multiplier accumulator.\n     * @return price_ The adjusted price for the tick.\n     */\n    function _getEffectivePriceForTick(\n        int24 tick,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator\n    ) internal pure returns (uint128 price_) {\n        price_ = _adjustPrice(TickMath.getPriceAtTick(tick), assetPrice, longTradingExpo, accumulator);\n    }\n\n    /**\n     * @notice Variant of `_getEffectivePriceForTick` when a fixed precision representation of the liquidation\n     * multiplier is known.\n     * @param tick The tick number.\n     * @param liqMultiplier The liquidation price multiplier.\n     * @return price_ The adjusted price for the tick.\n     */\n    function _getEffectivePriceForTick(int24 tick, uint256 liqMultiplier) internal pure returns (uint128 price_) {\n        price_ = _adjustPrice(TickMath.getPriceAtTick(tick), liqMultiplier);\n    }\n}\n"},{"file_path":"dependencies/solady-0.0.228/src/utils/UUPSUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice UUPS proxy mixin.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/UUPSUpgradeable.sol)\n/// @author Modified from OpenZeppelin\n/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol)\n///\n/// @dev Note:\n/// - This implementation is intended to be used with ERC1967 proxies.\n/// See: `LibClone.deployERC1967` and related functions.\n/// - This implementation is NOT compatible with legacy OpenZeppelin proxies\n/// which do not store the implementation at `_ERC1967_IMPLEMENTATION_SLOT`.\nabstract contract UUPSUpgradeable {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The upgrade failed.\n    error UpgradeFailed();\n\n    /// @dev The call is from an unauthorized call context.\n    error UnauthorizedCallContext();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         IMMUTABLES                         */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev For checking if the context is a delegate call.\n    uint256 private immutable __self = uint256(uint160(address(this)));\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                           EVENTS                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Emitted when the proxy's implementation is upgraded.\n    event Upgraded(address indexed implementation);\n\n    /// @dev `keccak256(bytes(\"Upgraded(address)\"))`.\n    uint256 private constant _UPGRADED_EVENT_SIGNATURE =\n        0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                          STORAGE                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The ERC-1967 storage slot for the implementation in the proxy.\n    /// `uint256(keccak256(\"eip1967.proxy.implementation\")) - 1`.\n    bytes32 internal constant _ERC1967_IMPLEMENTATION_SLOT =\n        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                      UUPS OPERATIONS                       */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Please override this function to check if `msg.sender` is authorized\n    /// to upgrade the proxy to `newImplementation`, reverting if not.\n    /// ```\n    ///     function _authorizeUpgrade(address) internal override onlyOwner {}\n    /// ```\n    function _authorizeUpgrade(address newImplementation) internal virtual;\n\n    /// @dev Returns the storage slot used by the implementation,\n    /// as specified in [ERC1822](https://eips.ethereum.org/EIPS/eip-1822).\n    ///\n    /// Note: The `notDelegated` modifier prevents accidental upgrades to\n    /// an implementation that is a proxy contract.\n    function proxiableUUID() public view virtual notDelegated returns (bytes32) {\n        // This function must always return `_ERC1967_IMPLEMENTATION_SLOT` to comply with ERC1967.\n        return _ERC1967_IMPLEMENTATION_SLOT;\n    }\n\n    /// @dev Upgrades the proxy's implementation to `newImplementation`.\n    /// Emits a {Upgraded} event.\n    ///\n    /// Note: Passing in empty `data` skips the delegatecall to `newImplementation`.\n    function upgradeToAndCall(address newImplementation, bytes calldata data)\n        public\n        payable\n        virtual\n        onlyProxy\n    {\n        _authorizeUpgrade(newImplementation);\n        /// @solidity memory-safe-assembly\n        assembly {\n            newImplementation := shr(96, shl(96, newImplementation)) // Clears upper 96 bits.\n            mstore(0x01, 0x52d1902d) // `proxiableUUID()`.\n            let s := _ERC1967_IMPLEMENTATION_SLOT\n            // Check if `newImplementation` implements `proxiableUUID` correctly.\n            if iszero(eq(mload(staticcall(gas(), newImplementation, 0x1d, 0x04, 0x01, 0x20)), s)) {\n                mstore(0x01, 0x55299b49) // `UpgradeFailed()`.\n                revert(0x1d, 0x04)\n            }\n            // Emit the {Upgraded} event.\n            log2(codesize(), 0x00, _UPGRADED_EVENT_SIGNATURE, newImplementation)\n            sstore(s, newImplementation) // Updates the implementation.\n\n            // Perform a delegatecall to `newImplementation` if `data` is non-empty.\n            if data.length {\n                // Forwards the `data` to `newImplementation` via delegatecall.\n                let m := mload(0x40)\n                calldatacopy(m, data.offset, data.length)\n                if iszero(delegatecall(gas(), newImplementation, m, data.length, codesize(), 0x00))\n                {\n                    // Bubble up the revert if the call reverts.\n                    returndatacopy(m, 0x00, returndatasize())\n                    revert(m, returndatasize())\n                }\n            }\n        }\n    }\n\n    /// @dev Requires that the execution is performed through a proxy.\n    modifier onlyProxy() {\n        uint256 s = __self;\n        /// @solidity memory-safe-assembly\n        assembly {\n            // To enable use cases with an immutable default implementation in the bytecode,\n            // (see: ERC6551Proxy), we don't require that the proxy address must match the\n            // value stored in the implementation slot, which may not be initialized.\n            if eq(s, address()) {\n                mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`.\n                revert(0x1c, 0x04)\n            }\n        }\n        _;\n    }\n\n    /// @dev Requires that the execution is NOT performed via delegatecall.\n    /// This is the opposite of `onlyProxy`.\n    modifier notDelegated() {\n        uint256 s = __self;\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(eq(s, address())) {\n                mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`.\n                revert(0x1c, 0x04)\n            }\n        }\n        _;\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-upgradeable-5.1.0/utils/ContextUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolLong.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { HugeUint } from \"@smardex-solidity-libraries-1/HugeUint.sol\";\n\nimport { IUsdnProtocolTypes } from \"./IUsdnProtocolTypes.sol\";\n\n/**\n * @title IUsdnProtocolLong\n * @notice Interface for the long side layer of the USDN protocol.\n */\ninterface IUsdnProtocolLong is IUsdnProtocolTypes {\n    /**\n     * @notice Gets the value of the lowest usable tick, taking into account the tick spacing.\n     * @dev Note that the effective minimum tick of a newly open long position also depends on the minimum allowed\n     * leverage value and the current value of the liquidation price multiplier.\n     * @return tick_ The lowest usable tick.\n     */\n    function minTick() external view returns (int24 tick_);\n\n    /**\n     * @notice Gets the liquidation price from a desired one by taking into account the tick rounding.\n     * @param desiredLiqPriceWithoutPenalty The desired liquidation price without the penalty.\n     * @param assetPrice The current price of the asset.\n     * @param longTradingExpo The trading exposition of the long side.\n     * @param accumulator The liquidation multiplier accumulator.\n     * @param tickSpacing The tick spacing.\n     * @param liquidationPenalty The liquidation penalty set on the tick.\n     * @return liqPrice_ The new liquidation price without the penalty.\n     */\n    function getLiqPriceFromDesiredLiqPrice(\n        uint128 desiredLiqPriceWithoutPenalty,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator,\n        int24 tickSpacing,\n        uint24 liquidationPenalty\n    ) external view returns (uint128 liqPrice_);\n\n    /**\n     * @notice Gets the value of a long position when the asset price is equal to the given price, at the given\n     * timestamp.\n     * @dev If the current price is smaller than the liquidation price of the position without the liquidation penalty,\n     * then the value of the position is negative.\n     * @param posId The unique position identifier.\n     * @param price The asset price.\n     * @param timestamp The timestamp of the price.\n     * @return value_ The position value in assets.\n     */\n    function getPositionValue(PositionId calldata posId, uint128 price, uint128 timestamp)\n        external\n        view\n        returns (int256 value_);\n\n    /**\n     * @notice Gets the tick number corresponding to a given price, accounting for funding effects.\n     * @dev Uses the stored parameters for calculation.\n     * @param price The asset price.\n     * @return tick_ The tick number, a multiple of the tick spacing.\n     */\n    function getEffectiveTickForPrice(uint128 price) external view returns (int24 tick_);\n\n    /**\n     * @notice Gets the tick number corresponding to a given price, accounting for funding effects.\n     * @param price The asset price.\n     * @param assetPrice The current price of the asset.\n     * @param longTradingExpo The trading exposition of the long side.\n     * @param accumulator The liquidation multiplier accumulator.\n     * @param tickSpacing The tick spacing.\n     * @return tick_ The tick number, a multiple of the tick spacing.\n     */\n    function getEffectiveTickForPrice(\n        uint128 price,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator,\n        int24 tickSpacing\n    ) external view returns (int24 tick_);\n\n    /**\n     * @notice Retrieves the liquidation penalty assigned to the given tick if there are positions in it, otherwise\n     * retrieve the current setting value from storage.\n     * @param tick The tick number.\n     * @return liquidationPenalty_ The liquidation penalty, in tick spacing units.\n     */\n    function getTickLiquidationPenalty(int24 tick) external view returns (uint24 liquidationPenalty_);\n\n    /**\n     * @notice Gets a long position identified by its tick, tick version and index.\n     * @param posId The unique position identifier.\n     * @return pos_ The position data.\n     * @return liquidationPenalty_ The liquidation penalty for that position.\n     */\n    function getLongPosition(PositionId calldata posId)\n        external\n        view\n        returns (Position memory pos_, uint24 liquidationPenalty_);\n\n    /**\n     * @notice Gets the predicted value of the long balance for the given asset price and timestamp.\n     * @dev The effects of the funding and any PnL of the long positions since the last contract state\n     * update is taken into account, as well as the fees. If the provided timestamp is older than the last state\n     * update, the function reverts with `UsdnProtocolTimestampTooOld`. The value cannot be below 0.\n     * @param currentPrice The given asset price.\n     * @param timestamp The timestamp corresponding to the given price.\n     * @return available_ The long balance value in assets.\n     */\n    function longAssetAvailableWithFunding(uint128 currentPrice, uint128 timestamp)\n        external\n        view\n        returns (uint256 available_);\n\n    /**\n     * @notice Gets the predicted value of the long trading exposure for the given asset price and timestamp.\n     * @dev The effects of the funding and any profit or loss of the long positions since the last contract state\n     * update is taken into account. If the provided timestamp is older than the last state update, the function reverts\n     * with `UsdnProtocolTimestampTooOld`. The value cannot be below 0.\n     * @param currentPrice The given asset price.\n     * @param timestamp The timestamp corresponding to the given price.\n     * @return expo_ The long trading exposure value in assets.\n     */\n    function longTradingExpoWithFunding(uint128 currentPrice, uint128 timestamp)\n        external\n        view\n        returns (uint256 expo_);\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IOwnershipCallback.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IERC165 } from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\nimport { IUsdnProtocolTypes as Types } from \"./IUsdnProtocolTypes.sol\";\n\n/**\n * @notice This interface can be implemented by contracts that wish to be notified when they become owner of a USDN\n * protocol position.\n * @dev The contract must implement the ERC-165 interface detection mechanism.\n */\ninterface IOwnershipCallback is IERC165 {\n    /**\n     * @notice Called by the USDN protocol on the new position owner after an ownership transfer occurs.\n     * @dev Implementers can use this callback to perform actions triggered by the ownership change.\n     * @param oldOwner The address of the previous position owner.\n     * @param posId The unique position identifier.\n     */\n    function ownershipCallback(address oldOwner, Types.PositionId calldata posId) external;\n}\n"},{"file_path":"src/libraries/TickMath.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.20;\n\nimport { FixedPointMathLib } from \"solady/src/utils/FixedPointMathLib.sol\";\n\n/**\n * @notice Converts between prices and ticks, where each tick represents an increase in price of 0.01%. Ticks are used\n * instead of liquidation prices to limit the number of possible buckets where a position can land, and allows for\n * batched liquidations.\n * @dev The formula for calculating the price from a tick is: `price = 1.0001^(tick)`.\n * The formula for calculating the tick from a price is: tick = `log_1.0001(price)`.\n */\nlibrary TickMath {\n    /// @dev The provided tick spacing is invalid (zero).\n    error TickMathInvalidTickSpacing();\n\n    /// @dev The provided tick is out of bounds.\n    error TickMathInvalidTick();\n\n    /// @dev The provided price is out of bounds.\n    error TickMathInvalidPrice();\n\n    /// @dev The minimum price we want to resolve is 10_000 wei (1e-14 USD), which equates to `1.0001^-322378`.\n    int24 public constant MIN_TICK = -322_378;\n\n    /// @dev The maximum tick is determined by the limits of the libraries used for math and testing.\n    int24 public constant MAX_TICK = 980_000;\n\n    /// @dev The minimum representable values for the price.\n    uint256 public constant MIN_PRICE = 10_000;\n\n    /// @dev The maximum representable values for the price.\n    uint256 public constant MAX_PRICE =\n        3_620_189_675_065_328_806_679_850_654_316_367_931_456_599_175_372_999_068_724_197;\n\n    /// @dev Pre-computed value for `ln(1.0001)`.\n    int256 public constant LN_BASE = 99_995_000_333_308;\n\n    /**\n     * @notice Gets the largest usable tick, given a tick spacing.\n     * @param tickSpacing Only uses ticks that are a multiple of this value.\n     * @return tick_ The largest tick that can be used.\n     */\n    function maxUsableTick(int24 tickSpacing) external pure returns (int24 tick_) {\n        if (tickSpacing == 0) {\n            revert TickMathInvalidTickSpacing();\n        }\n        unchecked {\n            // we want to round, so divide before multiply is desired\n            // slither-disable-next-line divide-before-multiply\n            tick_ = (MAX_TICK / tickSpacing) * tickSpacing;\n        }\n    }\n\n    /**\n     * @notice Gets the smallest usable tick, given a tick spacing.\n     * @param tickSpacing Only uses ticks that are a multiple of this value.\n     * @return tick_ The smallest tick that can be used.\n     */\n    function minUsableTick(int24 tickSpacing) external pure returns (int24 tick_) {\n        if (tickSpacing == 0) {\n            revert TickMathInvalidTickSpacing();\n        }\n        unchecked {\n            // we want to round, so divide before multiply is desired\n            // slither-disable-next-line divide-before-multiply\n            tick_ = (MIN_TICK / tickSpacing) * tickSpacing;\n        }\n    }\n\n    /**\n     * @notice Gets the price at a given tick.\n     * @dev Calculates the price as `1.0001^tick = e^(tick * ln(1.0001))`.\n     * @param tick The tick.\n     * @return price_ The corresponding price.\n     */\n    function getPriceAtTick(int24 tick) public pure returns (uint256 price_) {\n        if (tick > MAX_TICK) {\n            revert TickMathInvalidTick();\n        }\n        if (tick < MIN_TICK) {\n            revert TickMathInvalidTick();\n        }\n        price_ = uint256(FixedPointMathLib.expWad(tick * LN_BASE));\n    }\n\n    /**\n     * @notice Gets the tick corresponding to a price, rounded down towards negative infinity.\n     * @dev `log_1.0001(price) = ln(price)/ln(1.0001)` gives the tick.\n     * @param price The price.\n     * @return tick_ The largest tick whose price is less than or equal to the given price.\n     */\n    function getTickAtPrice(uint256 price) external pure returns (int24 tick_) {\n        if (price < MIN_PRICE) {\n            revert TickMathInvalidPrice();\n        }\n        if (price > MAX_PRICE) {\n            revert TickMathInvalidPrice();\n        }\n\n        int256 ln = FixedPointMathLib.lnWad(int256(price));\n        if (ln == 0) {\n            return 0;\n        } else if (ln < 0) {\n            // we round up the positive number then invert it -> round towards negative infinity\n            tick_ = -int24(int256(FixedPointMathLib.divUp(uint256(-ln), uint256(LN_BASE))));\n            if (tick_ < MIN_TICK) {\n                // avoid invalid ticks\n                tick_ = tick_ + 1;\n            }\n        } else {\n            // we round down the positive number -> round towards negative infinity\n            tick_ = int24(ln / LN_BASE);\n        }\n    }\n}\n"},{"file_path":"src/UsdnProtocol/libraries/UsdnProtocolConstantsLibrary.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nlibrary UsdnProtocolConstantsLibrary {\n    /// @notice Number of decimals used for a position's leverage.\n    uint8 internal constant LEVERAGE_DECIMALS = 21;\n\n    /// @notice Number of decimals used for the funding rate.\n    uint8 internal constant FUNDING_RATE_DECIMALS = 18;\n\n    /// @notice Number of decimals used for tokens within the protocol (excluding the asset).\n    uint8 internal constant TOKENS_DECIMALS = 18;\n\n    /// @notice Number of decimals used for the fixed representation of the liquidation multiplier.\n    uint8 internal constant LIQUIDATION_MULTIPLIER_DECIMALS = 38;\n\n    /// @notice Number of decimals in the scaling factor of the funding rate.\n    uint8 internal constant FUNDING_SF_DECIMALS = 3;\n\n    /**\n     * @notice Minimum leverage allowed for the rebalancer to open a position.\n     * @dev In edge cases where the rebalancer holds significantly more assets than the protocol,\n     * opening a position with the protocol's minimum leverage could cause a large overshoot of the target,\n     * potentially creating an even greater imbalance. To prevent this, the rebalancer can use leverage\n     * as low as the technical minimum (10 ** LEVERAGE_DECIMALS + 1).\n     */\n    uint256 internal constant REBALANCER_MIN_LEVERAGE = 10 ** LEVERAGE_DECIMALS + 1; // x1.000000000000000000001\n\n    /// @notice Divisor for the ratio of USDN to SDEX burned on deposit.\n    uint256 internal constant SDEX_BURN_ON_DEPOSIT_DIVISOR = 1e8;\n\n    /// @notice Divisor for basis point (BPS) values.\n    uint256 internal constant BPS_DIVISOR = 10_000;\n\n    /// @notice Maximum number of tick liquidations that can be processed per call.\n    uint16 internal constant MAX_LIQUIDATION_ITERATION = 10;\n\n    /// @notice Sentinel value indicating a `PositionId` that represents no position.\n    int24 internal constant NO_POSITION_TICK = type(int24).min;\n\n    /// @notice Address holding the minimum supply of USDN and the first minimum long position.\n    address internal constant DEAD_ADDRESS = address(0xdead);\n\n    /**\n     * @notice Delay after which a blocked pending action can be removed after `_lowLatencyValidatorDeadline` +\n     * `_onChainValidatorDeadline`.\n     */\n    uint16 internal constant REMOVE_BLOCKED_PENDING_ACTIONS_DELAY = 5 minutes;\n\n    /**\n     * @notice Minimum total supply of USDN allowed.\n     * @dev Upon the first deposit, this amount is sent to the dead address and becomes unrecoverable.\n     */\n    uint256 internal constant MIN_USDN_SUPPLY = 1000;\n\n    /**\n     * @notice Minimum margin between total exposure and long balance.\n     * @dev Ensures the balance long does not increase in a way that causes the trading exposure to\n     * fall below this margin. If this occurs, the balance long is clamped to the total exposure minus the margin.\n     */\n    uint256 internal constant MIN_LONG_TRADING_EXPO_BPS = 100;\n\n    /* -------------------------------------------------------------------------- */\n    /*                                   Setters                                  */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice Minimum iterations when searching for actionable pending actions in\n     * {IUsdnProtocolFallback.getActionablePendingActions}.\n     */\n    uint256 internal constant MIN_ACTIONABLE_PENDING_ACTIONS_ITER = 20;\n\n    /// @notice Minimum validation deadline for validators.\n    uint256 internal constant MIN_VALIDATION_DEADLINE = 60;\n\n    /// @notice Maximum validation deadline for validators.\n    uint256 internal constant MAX_VALIDATION_DEADLINE = 1 days;\n\n    /// @notice Maximum liquidation penalty allowed.\n    uint256 internal constant MAX_LIQUIDATION_PENALTY = 1500;\n\n    /// @notice Maximum safety margin allowed in basis points.\n    uint256 internal constant MAX_SAFETY_MARGIN_BPS = 2000;\n\n    /// @notice Maximum EMA (Exponential Moving Average) period allowed.\n    uint256 internal constant MAX_EMA_PERIOD = 90 days;\n\n    /// @notice Maximum position fee allowed in basis points.\n    uint256 internal constant MAX_POSITION_FEE_BPS = 2000;\n\n    /// @notice Maximum vault fee allowed in basis points.\n    uint256 internal constant MAX_VAULT_FEE_BPS = 2000;\n\n    /// @notice Maximum ratio of SDEX rewards allowed in basis points.\n    uint256 internal constant MAX_SDEX_REWARDS_RATIO_BPS = 1000;\n\n    /// @notice Maximum ratio of SDEX to burn per minted USDN on deposit (10%).\n    uint256 internal constant MAX_SDEX_BURN_RATIO = SDEX_BURN_ON_DEPOSIT_DIVISOR / 10;\n\n    /// @notice Maximum leverage allowed.\n    uint256 internal constant MAX_LEVERAGE = 100 * 10 ** LEVERAGE_DECIMALS;\n\n    /// @notice Maximum security deposit allowed.\n    uint256 internal constant MAX_SECURITY_DEPOSIT = 5 ether;\n\n    /// @notice The highest value allowed for the minimum long position setting.\n    uint256 internal constant MAX_MIN_LONG_POSITION = 10 ether;\n\n    /// @notice Maximum protocol fee allowed in basis points.\n    uint16 internal constant MAX_PROTOCOL_FEE_BPS = 3000;\n\n    /* -------------------------------------------------------------------------- */\n    /*                                   EIP712                                   */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice EIP712 typehash for {IUsdnProtocolActions.initiateClosePosition}.\n     * @dev Used within EIP712 messages for domain-specific signing, enabling recovery of the signer\n     * via [ECDSA-recover](https://docs.openzeppelin.com/contracts/5.x/api/utils#ECDSA).\n     */\n    bytes32 internal constant INITIATE_CLOSE_TYPEHASH = keccak256(\n        \"InitiateClosePositionDelegation(bytes32 posIdHash,uint128 amountToClose,uint256 userMinPrice,address to,uint256 deadline,address positionOwner,address positionCloser,uint256 nonce)\"\n    );\n\n    /**\n     * @notice EIP712 typehash for {IUsdnProtocolActions.transferPositionOwnership}.\n     * @dev Used within EIP712 messages for domain-specific signing, enabling recovery of the signer\n     * via [ECDSA-recover](https://docs.openzeppelin.com/contracts/5.x/api/utils#ECDSA).\n     */\n    bytes32 internal constant TRANSFER_POSITION_OWNERSHIP_TYPEHASH = keccak256(\n        \"TransferPositionOwnershipDelegation(bytes32 posIdHash,address positionOwner,address newPositionOwner,address delegatedAddress,uint256 nonce)\"\n    );\n\n    /* -------------------------------------------------------------------------- */\n    /*                                Roles hashes                                */\n    /* -------------------------------------------------------------------------- */\n\n    /// @notice Role signature for setting external contracts.\n    bytes32 public constant SET_EXTERNAL_ROLE = keccak256(\"SET_EXTERNAL_ROLE\");\n\n    /// @notice Role signature for performing critical protocol actions.\n    bytes32 public constant CRITICAL_FUNCTIONS_ROLE = keccak256(\"CRITICAL_FUNCTIONS_ROLE\");\n\n    /// @notice Role signature for setting protocol parameters.\n    bytes32 public constant SET_PROTOCOL_PARAMS_ROLE = keccak256(\"SET_PROTOCOL_PARAMS_ROLE\");\n\n    /// @notice Role signature for setting USDN parameters.\n    bytes32 public constant SET_USDN_PARAMS_ROLE = keccak256(\"SET_USDN_PARAMS_ROLE\");\n\n    /// @notice Role signature for configuring protocol options with minimal impact.\n    bytes32 public constant SET_OPTIONS_ROLE = keccak256(\"SET_OPTIONS_ROLE\");\n\n    /// @notice Role signature for upgrading the protocol implementation.\n    bytes32 public constant PROXY_UPGRADE_ROLE = keccak256(\"PROXY_UPGRADE_ROLE\");\n\n    /// @notice Role signature for pausing the protocol.\n    bytes32 public constant PAUSER_ROLE = keccak256(\"PAUSER_ROLE\");\n\n    /// @notice Role signature for unpausing the protocol.\n    bytes32 public constant UNPAUSER_ROLE = keccak256(\"UNPAUSER_ROLE\");\n\n    /// @notice Admin role for managing the `SET_EXTERNAL_ROLE`.\n    bytes32 public constant ADMIN_SET_EXTERNAL_ROLE = keccak256(\"ADMIN_SET_EXTERNAL_ROLE\");\n\n    /// @notice Admin role for managing the `CRITICAL_FUNCTIONS_ROLE`.\n    bytes32 public constant ADMIN_CRITICAL_FUNCTIONS_ROLE = keccak256(\"ADMIN_CRITICAL_FUNCTIONS_ROLE\");\n\n    /// @notice Admin role for managing the `SET_PROTOCOL_PARAMS_ROLE`.\n    bytes32 public constant ADMIN_SET_PROTOCOL_PARAMS_ROLE = keccak256(\"ADMIN_SET_PROTOCOL_PARAMS_ROLE\");\n\n    /// @notice Admin role for managing the `SET_USDN_PARAMS_ROLE`.\n    bytes32 public constant ADMIN_SET_USDN_PARAMS_ROLE = keccak256(\"ADMIN_SET_USDN_PARAMS_ROLE\");\n\n    /// @notice Admin role for managing the `SET_OPTIONS_ROLE`.\n    bytes32 public constant ADMIN_SET_OPTIONS_ROLE = keccak256(\"ADMIN_SET_OPTIONS_ROLE\");\n\n    /// @notice Admin role for managing the `PROXY_UPGRADE_ROLE`.\n    bytes32 public constant ADMIN_PROXY_UPGRADE_ROLE = keccak256(\"ADMIN_PROXY_UPGRADE_ROLE\");\n\n    /// @notice Admin role for managing the `PAUSER_ROLE`.\n    bytes32 public constant ADMIN_PAUSER_ROLE = keccak256(\"ADMIN_PAUSER_ROLE\");\n\n    /// @notice Admin role for managing the `UNPAUSER_ROLE`.\n    bytes32 public constant ADMIN_UNPAUSER_ROLE = keccak256(\"ADMIN_UNPAUSER_ROLE\");\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-upgradeable-5.1.0/utils/introspection/ERC165Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165 {\n    function __ERC165_init() internal onlyInitializing {\n    }\n\n    function __ERC165_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-upgradeable-5.1.0/access/extensions/AccessControlDefaultAdminRulesUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlDefaultAdminRules.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControlDefaultAdminRules} from \"@openzeppelin/contracts/access/extensions/IAccessControlDefaultAdminRules.sol\";\nimport {AccessControlUpgradeable} from \"../AccessControlUpgradeable.sol\";\nimport {IAccessControl} from \"@openzeppelin/contracts/access/IAccessControl.sol\";\nimport {SafeCast} from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {IERC5313} from \"@openzeppelin/contracts/interfaces/IERC5313.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows specifying special rules to manage\n * the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions\n * over other roles that may potentially have privileged rights in the system.\n *\n * If a specific role doesn't have an admin role assigned, the holder of the\n * `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it.\n *\n * This contract implements the following risk mitigations on top of {AccessControl}:\n *\n * * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced.\n * * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account.\n * * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted.\n * * The delay can be changed by scheduling, see {changeDefaultAdminDelay}.\n * * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`.\n *\n * Example usage:\n *\n * ```solidity\n * contract MyToken is AccessControlDefaultAdminRules {\n *   constructor() AccessControlDefaultAdminRules(\n *     3 days,\n *     msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder\n *    ) {}\n * }\n * ```\n */\nabstract contract AccessControlDefaultAdminRulesUpgradeable is Initializable, IAccessControlDefaultAdminRules, IERC5313, AccessControlUpgradeable {\n    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControlDefaultAdminRules\n    struct AccessControlDefaultAdminRulesStorage {\n        // pending admin pair read/written together frequently\n        address _pendingDefaultAdmin;\n        uint48 _pendingDefaultAdminSchedule; // 0 == unset\n\n        uint48 _currentDelay;\n        address _currentDefaultAdmin;\n\n        // pending delay pair read/written together frequently\n        uint48 _pendingDelay;\n        uint48 _pendingDelaySchedule; // 0 == unset\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.AccessControlDefaultAdminRules\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant AccessControlDefaultAdminRulesStorageLocation = 0xeef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400;\n\n    function _getAccessControlDefaultAdminRulesStorage() private pure returns (AccessControlDefaultAdminRulesStorage storage $) {\n        assembly {\n            $.slot := AccessControlDefaultAdminRulesStorageLocation\n        }\n    }\n\n    /**\n     * @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address.\n     */\n    function __AccessControlDefaultAdminRules_init(uint48 initialDelay, address initialDefaultAdmin) internal onlyInitializing {\n        __AccessControlDefaultAdminRules_init_unchained(initialDelay, initialDefaultAdmin);\n    }\n\n    function __AccessControlDefaultAdminRules_init_unchained(uint48 initialDelay, address initialDefaultAdmin) internal onlyInitializing {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        if (initialDefaultAdmin == address(0)) {\n            revert AccessControlInvalidDefaultAdmin(address(0));\n        }\n        $._currentDelay = initialDelay;\n        _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev See {IERC5313-owner}.\n     */\n    function owner() public view virtual returns (address) {\n        return defaultAdmin();\n    }\n\n    ///\n    /// Override AccessControl role management\n    ///\n\n    /**\n     * @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`.\n     */\n    function grantRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {\n        if (role == DEFAULT_ADMIN_ROLE) {\n            revert AccessControlEnforcedDefaultAdminRules();\n        }\n        super.grantRole(role, account);\n    }\n\n    /**\n     * @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`.\n     */\n    function revokeRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {\n        if (role == DEFAULT_ADMIN_ROLE) {\n            revert AccessControlEnforcedDefaultAdminRules();\n        }\n        super.revokeRole(role, account);\n    }\n\n    /**\n     * @dev See {AccessControl-renounceRole}.\n     *\n     * For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling\n     * {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule\n     * has also passed when calling this function.\n     *\n     * After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions.\n     *\n     * NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin},\n     * thereby disabling any functionality that is only available for it, and the possibility of reassigning a\n     * non-administrated role.\n     */\n    function renounceRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {\n            (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();\n            if (newDefaultAdmin != address(0) || !_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {\n                revert AccessControlEnforcedDefaultAdminDelay(schedule);\n            }\n            delete $._pendingDefaultAdminSchedule;\n        }\n        super.renounceRole(role, account);\n    }\n\n    /**\n     * @dev See {AccessControl-_grantRole}.\n     *\n     * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the\n     * role has been previously renounced.\n     *\n     * NOTE: Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE`\n     * assignable again. Make sure to guarantee this is the expected behavior in your implementation.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        if (role == DEFAULT_ADMIN_ROLE) {\n            if (defaultAdmin() != address(0)) {\n                revert AccessControlEnforcedDefaultAdminRules();\n            }\n            $._currentDefaultAdmin = account;\n        }\n        return super._grantRole(role, account);\n    }\n\n    /**\n     * @dev See {AccessControl-_revokeRole}.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {\n            delete $._currentDefaultAdmin;\n        }\n        return super._revokeRole(role, account);\n    }\n\n    /**\n     * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {\n        if (role == DEFAULT_ADMIN_ROLE) {\n            revert AccessControlEnforcedDefaultAdminRules();\n        }\n        super._setRoleAdmin(role, adminRole);\n    }\n\n    ///\n    /// AccessControlDefaultAdminRules accessors\n    ///\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function defaultAdmin() public view virtual returns (address) {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        return $._currentDefaultAdmin;\n    }\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        return ($._pendingDefaultAdmin, $._pendingDefaultAdminSchedule);\n    }\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function defaultAdminDelay() public view virtual returns (uint48) {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        uint48 schedule = $._pendingDelaySchedule;\n        return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? $._pendingDelay : $._currentDelay;\n    }\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        schedule = $._pendingDelaySchedule;\n        return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? ($._pendingDelay, schedule) : (0, 0);\n    }\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) {\n        return 5 days;\n    }\n\n    ///\n    /// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin\n    ///\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {\n        _beginDefaultAdminTransfer(newAdmin);\n    }\n\n    /**\n     * @dev See {beginDefaultAdminTransfer}.\n     *\n     * Internal function without access restriction.\n     */\n    function _beginDefaultAdminTransfer(address newAdmin) internal virtual {\n        uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay();\n        _setPendingDefaultAdmin(newAdmin, newSchedule);\n        emit DefaultAdminTransferScheduled(newAdmin, newSchedule);\n    }\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {\n        _cancelDefaultAdminTransfer();\n    }\n\n    /**\n     * @dev See {cancelDefaultAdminTransfer}.\n     *\n     * Internal function without access restriction.\n     */\n    function _cancelDefaultAdminTransfer() internal virtual {\n        _setPendingDefaultAdmin(address(0), 0);\n    }\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function acceptDefaultAdminTransfer() public virtual {\n        (address newDefaultAdmin, ) = pendingDefaultAdmin();\n        if (_msgSender() != newDefaultAdmin) {\n            // Enforce newDefaultAdmin explicit acceptance.\n            revert AccessControlInvalidDefaultAdmin(_msgSender());\n        }\n        _acceptDefaultAdminTransfer();\n    }\n\n    /**\n     * @dev See {acceptDefaultAdminTransfer}.\n     *\n     * Internal function without access restriction.\n     */\n    function _acceptDefaultAdminTransfer() internal virtual {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        (address newAdmin, uint48 schedule) = pendingDefaultAdmin();\n        if (!_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {\n            revert AccessControlEnforcedDefaultAdminDelay(schedule);\n        }\n        _revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());\n        _grantRole(DEFAULT_ADMIN_ROLE, newAdmin);\n        delete $._pendingDefaultAdmin;\n        delete $._pendingDefaultAdminSchedule;\n    }\n\n    ///\n    /// AccessControlDefaultAdminRules public and internal setters for defaultAdminDelay/pendingDefaultAdminDelay\n    ///\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {\n        _changeDefaultAdminDelay(newDelay);\n    }\n\n    /**\n     * @dev See {changeDefaultAdminDelay}.\n     *\n     * Internal function without access restriction.\n     */\n    function _changeDefaultAdminDelay(uint48 newDelay) internal virtual {\n        uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay);\n        _setPendingDelay(newDelay, newSchedule);\n        emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule);\n    }\n\n    /**\n     * @inheritdoc IAccessControlDefaultAdminRules\n     */\n    function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {\n        _rollbackDefaultAdminDelay();\n    }\n\n    /**\n     * @dev See {rollbackDefaultAdminDelay}.\n     *\n     * Internal function without access restriction.\n     */\n    function _rollbackDefaultAdminDelay() internal virtual {\n        _setPendingDelay(0, 0);\n    }\n\n    /**\n     * @dev Returns the amount of seconds to wait after the `newDelay` will\n     * become the new {defaultAdminDelay}.\n     *\n     * The value returned guarantees that if the delay is reduced, it will go into effect\n     * after a wait that honors the previously set delay.\n     *\n     * See {defaultAdminDelayIncreaseWait}.\n     */\n    function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) {\n        uint48 currentDelay = defaultAdminDelay();\n\n        // When increasing the delay, we schedule the delay change to occur after a period of \"new delay\" has passed, up\n        // to a maximum given by defaultAdminDelayIncreaseWait, by default 5 days. For example, if increasing from 1 day\n        // to 3 days, the new delay will come into effect after 3 days. If increasing from 1 day to 10 days, the new\n        // delay will come into effect after 5 days. The 5 day wait period is intended to be able to fix an error like\n        // using milliseconds instead of seconds.\n        //\n        // When decreasing the delay, we wait the difference between \"current delay\" and \"new delay\". This guarantees\n        // that an admin transfer cannot be made faster than \"current delay\" at the time the delay change is scheduled.\n        // For example, if decreasing from 10 days to 3 days, the new delay will come into effect after 7 days.\n        return\n            newDelay > currentDelay\n                ? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48\n                : currentDelay - newDelay;\n    }\n\n    ///\n    /// Private setters\n    ///\n\n    /**\n     * @dev Setter of the tuple for pending admin and its schedule.\n     *\n     * May emit a DefaultAdminTransferCanceled event.\n     */\n    function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        (, uint48 oldSchedule) = pendingDefaultAdmin();\n\n        $._pendingDefaultAdmin = newAdmin;\n        $._pendingDefaultAdminSchedule = newSchedule;\n\n        // An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted.\n        if (_isScheduleSet(oldSchedule)) {\n            // Emit for implicit cancellations when another default admin was scheduled.\n            emit DefaultAdminTransferCanceled();\n        }\n    }\n\n    /**\n     * @dev Setter of the tuple for pending delay and its schedule.\n     *\n     * May emit a DefaultAdminDelayChangeCanceled event.\n     */\n    function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private {\n        AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();\n        uint48 oldSchedule = $._pendingDelaySchedule;\n\n        if (_isScheduleSet(oldSchedule)) {\n            if (_hasSchedulePassed(oldSchedule)) {\n                // Materialize a virtual delay\n                $._currentDelay = $._pendingDelay;\n            } else {\n                // Emit for implicit cancellations when another delay was scheduled.\n                emit DefaultAdminDelayChangeCanceled();\n            }\n        }\n\n        $._pendingDelay = newDelay;\n        $._pendingDelaySchedule = newSchedule;\n    }\n\n    ///\n    /// Private helpers\n    ///\n\n    /**\n     * @dev Defines if an `schedule` is considered set. For consistency purposes.\n     */\n    function _isScheduleSet(uint48 schedule) private pure returns (bool) {\n        return schedule != 0;\n    }\n\n    /**\n     * @dev Defines if an `schedule` is considered passed. For consistency purposes.\n     */\n    function _hasSchedulePassed(uint48 schedule) private view returns (bool) {\n        return schedule < block.timestamp;\n    }\n}\n"},{"file_path":"dependencies/solady-0.0.228/src/utils/SafeTransferLib.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)\n/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)\n///\n/// @dev Note:\n/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.\n/// - For ERC20s, this implementation won't check that a token has code,\n///   responsibility is delegated to the caller.\nlibrary SafeTransferLib {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       CUSTOM ERRORS                        */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The ETH transfer has failed.\n    error ETHTransferFailed();\n\n    /// @dev The ERC20 `transferFrom` has failed.\n    error TransferFromFailed();\n\n    /// @dev The ERC20 `transfer` has failed.\n    error TransferFailed();\n\n    /// @dev The ERC20 `approve` has failed.\n    error ApproveFailed();\n\n    /// @dev The Permit2 operation has failed.\n    error Permit2Failed();\n\n    /// @dev The Permit2 amount must be less than `2**160 - 1`.\n    error Permit2AmountOverflow();\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         CONSTANTS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.\n    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;\n\n    /// @dev Suggested gas stipend for contract receiving ETH to perform a few\n    /// storage reads and writes, but low enough to prevent griefing.\n    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;\n\n    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.\n    bytes32 internal constant DAI_DOMAIN_SEPARATOR =\n        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;\n\n    /// @dev The address for the WETH9 contract on Ethereum mainnet.\n    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n    /// @dev The canonical Permit2 address.\n    /// [Github](https://github.com/Uniswap/permit2)\n    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)\n    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                       ETH OPERATIONS                       */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.\n    //\n    // The regular variants:\n    // - Forwards all remaining gas to the target.\n    // - Reverts if the target reverts.\n    // - Reverts if the current contract has insufficient balance.\n    //\n    // The force variants:\n    // - Forwards with an optional gas stipend\n    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).\n    // - If the target reverts, or if the gas stipend is exhausted,\n    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.\n    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.\n    // - Reverts if the current contract has insufficient balance.\n    //\n    // The try variants:\n    // - Forwards with a mandatory gas stipend.\n    // - Instead of reverting, returns whether the transfer succeeded.\n\n    /// @dev Sends `amount` (in wei) ETH to `to`.\n    function safeTransferETH(address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n\n    /// @dev Sends all the ETH in the current contract to `to`.\n    function safeTransferAllETH(address to) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Transfer all the ETH and check if it succeeded or not.\n            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n\n    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.\n    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if lt(selfbalance(), amount) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.\n    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.\n    function forceSafeTransferETH(address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            if lt(selfbalance(), amount) {\n                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.\n    function forceSafeTransferAllETH(address to) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // forgefmt: disable-next-item\n            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n                mstore(0x00, to) // Store the address in scratch space.\n                mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n            }\n        }\n    }\n\n    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.\n    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)\n        internal\n        returns (bool success)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)\n        }\n    }\n\n    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.\n    function trySafeTransferAllETH(address to, uint256 gasStipend)\n        internal\n        returns (bool success)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)\n        }\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                      ERC20 OPERATIONS                      */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n    /// Reverts upon failure.\n    ///\n    /// The `from` account must have at least `amount` approved for\n    /// the current contract to manage.\n    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Cache the free memory pointer.\n            mstore(0x60, amount) // Store the `amount` argument.\n            mstore(0x40, to) // Store the `to` argument.\n            mstore(0x2c, shl(96, from)) // Store the `from` argument.\n            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x60, 0) // Restore the zero slot to zero.\n            mstore(0x40, m) // Restore the free memory pointer.\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n    ///\n    /// The `from` account must have at least `amount` approved for the current contract to manage.\n    function trySafeTransferFrom(address token, address from, address to, uint256 amount)\n        internal\n        returns (bool success)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Cache the free memory pointer.\n            mstore(0x60, amount) // Store the `amount` argument.\n            mstore(0x40, to) // Store the `to` argument.\n            mstore(0x2c, shl(96, from)) // Store the `from` argument.\n            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.\n            success :=\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n                )\n            mstore(0x60, 0) // Restore the zero slot to zero.\n            mstore(0x40, m) // Restore the free memory pointer.\n        }\n    }\n\n    /// @dev Sends all of ERC20 `token` from `from` to `to`.\n    /// Reverts upon failure.\n    ///\n    /// The `from` account must have their entire balance approved for the current contract to manage.\n    function safeTransferAllFrom(address token, address from, address to)\n        internal\n        returns (uint256 amount)\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40) // Cache the free memory pointer.\n            mstore(0x40, to) // Store the `to` argument.\n            mstore(0x2c, shl(96, from)) // Store the `from` argument.\n            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n            // Read the balance, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.\n            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x60, 0) // Restore the zero slot to zero.\n            mstore(0x40, m) // Restore the free memory pointer.\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.\n    /// Reverts upon failure.\n    function safeTransfer(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sends all of ERC20 `token` from the current contract to `to`.\n    /// Reverts upon failure.\n    function safeTransferAll(address token, address to) internal returns (uint256 amount) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.\n            mstore(0x20, address()) // Store the address of the current contract.\n            // Read the balance, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x14, to) // Store the `to` argument.\n            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.\n            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.\n            // Perform the transfer, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.\n    /// Reverts upon failure.\n    function safeApprove(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n            // Perform the approval, reverting upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.\n                revert(0x1c, 0x04)\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.\n    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,\n    /// then retries the approval again (some tokens, e.g. USDT, requires this).\n    /// Reverts upon failure.\n    function safeApproveWithRetry(address token, address to, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, to) // Store the `to` argument.\n            mstore(0x34, amount) // Store the `amount` argument.\n            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n            // Perform the approval, retrying upon failure.\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                )\n            ) {\n                mstore(0x34, 0) // Store 0 for the `amount`.\n                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.\n                mstore(0x34, amount) // Store back the original `amount`.\n                // Retry the approval, reverting upon failure.\n                if iszero(\n                    and(\n                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n                    )\n                ) {\n                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.\n                    revert(0x1c, 0x04)\n                }\n            }\n            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n        }\n    }\n\n    /// @dev Returns the amount of ERC20 `token` owned by `account`.\n    /// Returns zero if the `token` does not exist.\n    function balanceOf(address token, address account) internal view returns (uint256 amount) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x14, account) // Store the `account` argument.\n            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n            amount :=\n                mul( // The arguments of `mul` are evaluated from right to left.\n                    mload(0x20),\n                    and( // The arguments of `and` are evaluated from right to left.\n                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)\n                    )\n                )\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n    /// If the initial attempt fails, try to use Permit2 to transfer the token.\n    /// Reverts upon failure.\n    ///\n    /// The `from` account must have at least `amount` approved for the current contract to manage.\n    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {\n        if (!trySafeTransferFrom(token, from, to, amount)) {\n            permit2TransferFrom(token, from, to, amount);\n        }\n    }\n\n    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.\n    /// Reverts upon failure.\n    function permit2TransferFrom(address token, address from, address to, uint256 amount)\n        internal\n    {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40)\n            mstore(add(m, 0x74), shr(96, shl(96, token)))\n            mstore(add(m, 0x54), amount)\n            mstore(add(m, 0x34), to)\n            mstore(add(m, 0x20), shl(96, from))\n            // `transferFrom(address,address,uint160,address)`.\n            mstore(m, 0x36c78516000000000000000000000000)\n            let p := PERMIT2\n            let exists := eq(chainid(), 1)\n            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }\n            if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) {\n                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.\n                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)\n            }\n        }\n    }\n\n    /// @dev Permit a user to spend a given amount of\n    /// another user's tokens via native EIP-2612 permit if possible, falling\n    /// back to Permit2 if native permit fails or is not implemented on the token.\n    function permit2(\n        address token,\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        bool success;\n        /// @solidity memory-safe-assembly\n        assembly {\n            for {} shl(96, xor(token, WETH9)) {} {\n                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.\n                if iszero(\n                    and( // The arguments of `and` are evaluated from right to left.\n                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.\n                        // Gas stipend to limit gas burn for tokens that don't refund gas when\n                        // an non-existing function is called. 5K should be enough for a SLOAD.\n                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)\n                    )\n                ) { break }\n                // After here, we can be sure that token is a contract.\n                let m := mload(0x40)\n                mstore(add(m, 0x34), spender)\n                mstore(add(m, 0x20), shl(96, owner))\n                mstore(add(m, 0x74), deadline)\n                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {\n                    mstore(0x14, owner)\n                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.\n                    mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))\n                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.\n                    // `nonces` is already at `add(m, 0x54)`.\n                    // `1` is already stored at `add(m, 0x94)`.\n                    mstore(add(m, 0xb4), and(0xff, v))\n                    mstore(add(m, 0xd4), r)\n                    mstore(add(m, 0xf4), s)\n                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)\n                    break\n                }\n                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.\n                mstore(add(m, 0x54), amount)\n                mstore(add(m, 0x94), and(0xff, v))\n                mstore(add(m, 0xb4), r)\n                mstore(add(m, 0xd4), s)\n                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)\n                break\n            }\n        }\n        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);\n    }\n\n    /// @dev Simple permit on the Permit2 contract.\n    function simplePermit2(\n        address token,\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let m := mload(0x40)\n            mstore(m, 0x927da105) // `allowance(address,address,address)`.\n            {\n                let addressMask := shr(96, not(0))\n                mstore(add(m, 0x20), and(addressMask, owner))\n                mstore(add(m, 0x40), and(addressMask, token))\n                mstore(add(m, 0x60), and(addressMask, spender))\n                mstore(add(m, 0xc0), and(addressMask, spender))\n            }\n            let p := mul(PERMIT2, iszero(shr(160, amount)))\n            if iszero(\n                and( // The arguments of `and` are evaluated from right to left.\n                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.\n                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)\n                )\n            ) {\n                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.\n                revert(add(0x18, shl(2, iszero(p))), 0x04)\n            }\n            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).\n            // `owner` is already `add(m, 0x20)`.\n            // `token` is already at `add(m, 0x40)`.\n            mstore(add(m, 0x60), amount)\n            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.\n            // `nonce` is already at `add(m, 0xa0)`.\n            // `spender` is already at `add(m, 0xc0)`.\n            mstore(add(m, 0xe0), deadline)\n            mstore(add(m, 0x100), 0x100) // `signature` offset.\n            mstore(add(m, 0x120), 0x41) // `signature` length.\n            mstore(add(m, 0x140), r)\n            mstore(add(m, 0x160), s)\n            mstore(add(m, 0x180), shl(248, v))\n            if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {\n                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.\n                revert(0x1c, 0x04)\n            }\n        }\n    }\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IPaymentCallback.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { IERC165 } from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\nimport { IUsdn } from \"../Usdn/IUsdn.sol\";\n\n/**\n * @notice This interface can be implemented by contracts that wish to transfer tokens during initiate actions.\n * @dev The contract must implement the ERC-165 interface detection mechanism.\n */\ninterface IPaymentCallback is IERC165 {\n    /**\n     * @notice Triggered by the USDN protocol to transfer asset tokens during `initiate` actions.\n     * @dev Implementations must ensure that the `msg.sender` is the USDN protocol for security purposes.\n     * @param token The address of the ERC20 token to be transferred.\n     * @param amount The amount of tokens to transfer.\n     * @param to The recipient's address.\n     */\n    function transferCallback(IERC20Metadata token, uint256 amount, address to) external;\n\n    /**\n     * @notice Triggered by the USDN protocol during the {IUsdnProtocolActions.initiateWithdrawal} process to transfer\n     * USDN shares.\n     * @dev Implementations must verify that the `msg.sender` is the USDN protocol.\n     * @param usdn The address of the USDN protocol.\n     * @param shares The number of USDN shares to transfer to the protocol (`msg.sender`).\n     */\n    function usdnTransferCallback(IUsdn usdn, uint256 shares) external;\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/token/ERC20/extensions/IERC20Permit.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-upgradeable-5.1.0/utils/cryptography/EIP712Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.20;\n\nimport {MessageHashUtils} from \"@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol\";\nimport {IERC5267} from \"@openzeppelin/contracts/interfaces/IERC5267.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose\n * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract\n * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to\n * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain\n * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the\n * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.\n */\nabstract contract EIP712Upgradeable is Initializable, IERC5267 {\n    bytes32 private constant TYPE_HASH =\n        keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.EIP712\n    struct EIP712Storage {\n        /// @custom:oz-renamed-from _HASHED_NAME\n        bytes32 _hashedName;\n        /// @custom:oz-renamed-from _HASHED_VERSION\n        bytes32 _hashedVersion;\n\n        string _name;\n        string _version;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.EIP712\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant EIP712StorageLocation = 0xa16a46d94261c7517cc8ff89f61c0ce93598e3c849801011dee649a6a557d100;\n\n    function _getEIP712Storage() private pure returns (EIP712Storage storage $) {\n        assembly {\n            $.slot := EIP712StorageLocation\n        }\n    }\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    function __EIP712_init(string memory name, string memory version) internal onlyInitializing {\n        __EIP712_init_unchained(name, version);\n    }\n\n    function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {\n        EIP712Storage storage $ = _getEIP712Storage();\n        $._name = name;\n        $._version = version;\n\n        // Reset prior values in storage if upgrading\n        $._hashedName = 0;\n        $._hashedVersion = 0;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        return _buildDomainSeparator();\n    }\n\n    function _buildDomainSeparator() private view returns (bytes32) {\n        return keccak256(abi.encode(TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), block.chainid, address(this)));\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n\n    /**\n     * @dev See {IERC-5267}.\n     */\n    function eip712Domain()\n        public\n        view\n        virtual\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        )\n    {\n        EIP712Storage storage $ = _getEIP712Storage();\n        // If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized\n        // and the EIP712 domain is not reliable, as it will be missing name and version.\n        require($._hashedName == 0 && $._hashedVersion == 0, \"EIP712: Uninitialized\");\n\n        return (\n            hex\"0f\", // 01111\n            _EIP712Name(),\n            _EIP712Version(),\n            block.chainid,\n            address(this),\n            bytes32(0),\n            new uint256[](0)\n        );\n    }\n\n    /**\n     * @dev The name parameter for the EIP712 domain.\n     *\n     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n     * are a concern.\n     */\n    function _EIP712Name() internal view virtual returns (string memory) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        return $._name;\n    }\n\n    /**\n     * @dev The version parameter for the EIP712 domain.\n     *\n     * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs\n     * are a concern.\n     */\n    function _EIP712Version() internal view virtual returns (string memory) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        return $._version;\n    }\n\n    /**\n     * @dev The hash of the name parameter for the EIP712 domain.\n     *\n     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.\n     */\n    function _EIP712NameHash() internal view returns (bytes32) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        string memory name = _EIP712Name();\n        if (bytes(name).length > 0) {\n            return keccak256(bytes(name));\n        } else {\n            // If the name is empty, the contract may have been upgraded without initializing the new storage.\n            // We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.\n            bytes32 hashedName = $._hashedName;\n            if (hashedName != 0) {\n                return hashedName;\n            } else {\n                return keccak256(\"\");\n            }\n        }\n    }\n\n    /**\n     * @dev The hash of the version parameter for the EIP712 domain.\n     *\n     * NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.\n     */\n    function _EIP712VersionHash() internal view returns (bytes32) {\n        EIP712Storage storage $ = _getEIP712Storage();\n        string memory version = _EIP712Version();\n        if (bytes(version).length > 0) {\n            return keccak256(bytes(version));\n        } else {\n            // If the version is empty, the contract may have been upgraded without initializing the new storage.\n            // We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.\n            bytes32 hashedVersion = $._hashedVersion;\n            if (hashedVersion != 0) {\n                return hashedVersion;\n            } else {\n                return keccak256(\"\");\n            }\n        }\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolVault.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/**\n * @title IUsdnProtocolVault\n * @notice Interface for the vault layer of the USDN protocol.\n */\ninterface IUsdnProtocolVault {\n    /**\n     * @notice Calculates the predicted USDN token price based on the given asset price and timestamp.\n     * @dev The effects of the funding and the PnL of the long positions since the last contract state update are taken\n     * into account.\n     * @param currentPrice The current or predicted asset price.\n     * @param timestamp The timestamp corresponding to `currentPrice`.\n     * @return price_ The predicted USDN token price.\n     */\n    function usdnPrice(uint128 currentPrice, uint128 timestamp) external view returns (uint256 price_);\n\n    /**\n     * @notice Calculates the USDN token price based on the given asset price at the current timestamp.\n     * @dev The effects of the funding and the PnL of the long positions since the last contract state update are taken\n     * into account.\n     * @param currentPrice The asset price at `block.timestamp`.\n     * @return price_ The calculated USDN token price.\n     */\n    function usdnPrice(uint128 currentPrice) external view returns (uint256 price_);\n\n    /**\n     * @notice Gets the amount of assets in the vault for the given asset price and timestamp.\n     * @dev The effects of the funding, the PnL of the long positions and the accumulated fees since the last contract\n     * state update are taken into account, but not liquidations. If the provided timestamp is older than the last\n     * state update, the function reverts with `UsdnProtocolTimestampTooOld`.\n     * @param currentPrice The current or predicted asset price.\n     * @param timestamp The timestamp corresponding to `currentPrice` (must not be earlier than `_lastUpdateTimestamp`).\n     * @return available_ The available vault balance (cannot be less than 0).\n     */\n    function vaultAssetAvailableWithFunding(uint128 currentPrice, uint128 timestamp)\n        external\n        view\n        returns (uint256 available_);\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/utils/cryptography/MessageHashUtils.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MessageHashUtils.sol)\n\npragma solidity ^0.8.20;\n\nimport {Strings} from \"../Strings.sol\";\n\n/**\n * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.\n *\n * The library provides methods for generating a hash of a message that conforms to the\n * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]\n * specifications.\n */\nlibrary MessageHashUtils {\n    /**\n     * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n     * `0x45` (`personal_sign` messages).\n     *\n     * The digest is calculated by prefixing a bytes32 `messageHash` with\n     * `\"\\x19Ethereum Signed Message:\\n32\"` and hashing the result. It corresponds with the\n     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.\n     *\n     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with\n     * keccak256, although any bytes32 value can be safely used because the final digest will\n     * be re-hashed.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, \"\\x19Ethereum Signed Message:\\n32\") // 32 is the bytes-length of messageHash\n            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix\n            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)\n        }\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n     * `0x45` (`personal_sign` messages).\n     *\n     * The digest is calculated by prefixing an arbitrary `message` with\n     * `\"\\x19Ethereum Signed Message:\\n\" + len(message)` and hashing the result. It corresponds with the\n     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {\n        return\n            keccak256(bytes.concat(\"\\x19Ethereum Signed Message:\\n\", bytes(Strings.toString(message.length)), message));\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n     * `0x00` (data with intended validator).\n     *\n     * The digest is calculated by prefixing an arbitrary `data` with `\"\\x19\\x00\"` and the intended\n     * `validator` address. Then hashing the result.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(hex\"19_00\", validator, data));\n    }\n\n    /**\n     * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).\n     *\n     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with\n     * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.\n     *\n     * See {ECDSA-recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {\n        assembly (\"memory-safe\") {\n            let ptr := mload(0x40)\n            mstore(ptr, hex\"19_01\")\n            mstore(add(ptr, 0x02), domainSeparator)\n            mstore(add(ptr, 0x22), structHash)\n            digest := keccak256(ptr, 0x42)\n        }\n    }\n}\n"},{"file_path":"src/libraries/Accumulator.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.20;\n\nimport { HugeUint } from \"@smardex-solidity-libraries-1/HugeUint.sol\";\n\n/**\n * @notice Library to operate on the liquidation multiplier accumulator values (512-bit integers).\n * @dev This is a wrapper for `HugeUint` that is deployed to its own address and called via `delegatecall`.\n */\nlibrary Accumulator {\n    /**\n     * @notice Calculates the sum `a + b` of two 512-bit unsigned integers.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return res_ The sum of `a` and `b`.\n     */\n    function add(HugeUint.Uint512 memory a, HugeUint.Uint512 memory b)\n        external\n        pure\n        returns (HugeUint.Uint512 memory res_)\n    {\n        res_ = HugeUint.add(a, b);\n    }\n\n    /**\n     * @notice Calculates the difference `a - b` of two 512-bit unsigned integers.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return res_ The difference `a - b`.\n     */\n    function sub(HugeUint.Uint512 memory a, HugeUint.Uint512 memory b)\n        external\n        pure\n        returns (HugeUint.Uint512 memory res_)\n    {\n        res_ = HugeUint.sub(a, b);\n    }\n\n    /**\n     * @notice Calculates the product `a * b` of two 256-bit unsigned integers using the Chinese remainder theorem.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return res_ The product `a * b` of the operands as an unsigned 512-bit integer.\n     */\n    function mul(uint256 a, uint256 b) external pure returns (HugeUint.Uint512 memory res_) {\n        res_ = HugeUint.mul(a, b);\n    }\n\n    /**\n     * @notice Calculates the product `a * b` of a 512-bit unsigned integer and a 256-bit unsigned integer.\n     * @param a The first operand.\n     * @param b The second operand.\n     * @return res_ The product `a * b` of the operands as an unsigned 512-bit integer.\n     */\n    function mul(HugeUint.Uint512 memory a, uint256 b) external pure returns (HugeUint.Uint512 memory res_) {\n        res_ = HugeUint.mul(a, b);\n    }\n\n    /**\n     * @notice Calculates the division `floor(a / b)` of a 512-bit unsigned integer by an unsigned 256-bit integer.\n     * @param a The numerator as a 512-bit unsigned integer.\n     * @param b The denominator as a 256-bit unsigned integer.\n     * @return res_ The division `floor(a / b)` of the operands as an unsigned 256-bit integer.\n     */\n    function div(HugeUint.Uint512 memory a, uint256 b) external pure returns (uint256 res_) {\n        res_ = HugeUint.div(a, b);\n    }\n\n    /**\n     * @notice Computes the division floor(a/b) of two 512-bit integers, knowing the result fits inside a uint256.\n     * @param a The numerator as a 512-bit integer.\n     * @param b The denominator as a 512-bit integer.\n     * @return res_ The quotient floor(a/b).\n     */\n    function div(HugeUint.Uint512 memory a, HugeUint.Uint512 memory b) external pure returns (uint256 res_) {\n        res_ = HugeUint.div(a, b);\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/utils/Strings.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Strings.sol)\n\npragma solidity ^0.8.20;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n    uint8 private constant ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev The `value` string doesn't fit in the specified `length`.\n     */\n    error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            assembly (\"memory-safe\") {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                assembly (\"memory-safe\") {\n                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toStringSigned(int256 value) internal pure returns (string memory) {\n        return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        uint256 localValue = value;\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = HEX_DIGITS[localValue & 0xf];\n            localValue >>= 4;\n        }\n        if (localValue != 0) {\n            revert StringsInsufficientHexLength(value, length);\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n     * representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal\n     * representation, according to EIP-55.\n     */\n    function toChecksumHexString(address addr) internal pure returns (string memory) {\n        bytes memory buffer = bytes(toHexString(addr));\n\n        // hash the hex part of buffer (skip length + 2 bytes, length 40)\n        uint256 hashValue;\n        assembly (\"memory-safe\") {\n            hashValue := shr(96, keccak256(add(buffer, 0x22), 40))\n        }\n\n        for (uint256 i = 41; i > 1; --i) {\n            // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)\n            if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {\n                // case shift by xoring with 0x20\n                buffer[i] ^= 0x20;\n            }\n            hashValue >>= 4;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"},{"file_path":"src/interfaces/Usdn/IRebaseCallback.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\ninterface IRebaseCallback {\n    /**\n     * @notice Called by the USDN token after a rebase has happened.\n     * @param oldDivisor The value of the divisor before the rebase.\n     * @param newDivisor The value of the divisor after the rebase (necessarily smaller than `oldDivisor`).\n     * @return result_ Arbitrary data that will be forwarded to the caller of `rebase`.\n     */\n    function rebaseCallback(uint256 oldDivisor, uint256 newDivisor) external returns (bytes memory result_);\n}\n"},{"file_path":"src/UsdnProtocol/UsdnProtocolLong.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { HugeUint } from \"@smardex-solidity-libraries-1/HugeUint.sol\";\n\nimport { IUsdnProtocolLong } from \"../interfaces/UsdnProtocol/IUsdnProtocolLong.sol\";\nimport { UsdnProtocolActionsUtilsLibrary as ActionsUtils } from \"./libraries/UsdnProtocolActionsUtilsLibrary.sol\";\nimport { UsdnProtocolCoreLibrary as Core } from \"./libraries/UsdnProtocolCoreLibrary.sol\";\nimport { UsdnProtocolLongLibrary as Long } from \"./libraries/UsdnProtocolLongLibrary.sol\";\n\nabstract contract UsdnProtocolLong is IUsdnProtocolLong {\n    /// @inheritdoc IUsdnProtocolLong\n    function minTick() external view returns (int24 tick_) {\n        return Long.minTick();\n    }\n\n    /// @inheritdoc IUsdnProtocolLong\n    function getLiqPriceFromDesiredLiqPrice(\n        uint128 desiredLiqPriceWithoutPenalty,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator,\n        int24 tickSpacing,\n        uint24 liquidationPenalty\n    ) external pure returns (uint128 liqPrice_) {\n        (, liqPrice_) = Long._getTickFromDesiredLiqPrice(\n            desiredLiqPriceWithoutPenalty, assetPrice, longTradingExpo, accumulator, tickSpacing, liquidationPenalty\n        );\n    }\n\n    /// @inheritdoc IUsdnProtocolLong\n    function getPositionValue(PositionId calldata posId, uint128 price, uint128 timestamp)\n        external\n        view\n        returns (int256 value_)\n    {\n        return Long.getPositionValue(posId, price, timestamp);\n    }\n\n    /// @inheritdoc IUsdnProtocolLong\n    function getEffectiveTickForPrice(uint128 price) external view returns (int24 tick_) {\n        return Long.getEffectiveTickForPrice(price);\n    }\n\n    /// @inheritdoc IUsdnProtocolLong\n    function getEffectiveTickForPrice(\n        uint128 price,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator,\n        int24 tickSpacing\n    ) external pure returns (int24 tick_) {\n        return Long.getEffectiveTickForPrice(price, assetPrice, longTradingExpo, accumulator, tickSpacing);\n    }\n\n    /// @inheritdoc IUsdnProtocolLong\n    function getTickLiquidationPenalty(int24 tick) external view returns (uint24 liquidationPenalty_) {\n        return Long.getTickLiquidationPenalty(tick);\n    }\n\n    /// @inheritdoc IUsdnProtocolLong\n    function getLongPosition(PositionId memory posId)\n        external\n        view\n        returns (Position memory pos_, uint24 liquidationPenalty_)\n    {\n        return ActionsUtils.getLongPosition(posId);\n    }\n\n    /// @inheritdoc IUsdnProtocolLong\n    function longAssetAvailableWithFunding(uint128 currentPrice, uint128 timestamp)\n        external\n        view\n        returns (uint256 available_)\n    {\n        (available_,) = Core.longAssetAvailableWithFunding(currentPrice, timestamp);\n    }\n\n    /// @inheritdoc IUsdnProtocolLong\n    function longTradingExpoWithFunding(uint128 currentPrice, uint128 timestamp)\n        external\n        view\n        returns (uint256 expo_)\n    {\n        return Core.longTradingExpoWithFunding(currentPrice, timestamp);\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/interfaces/IERC5267.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)\n\npragma solidity ^0.8.20;\n\ninterface IERC5267 {\n    /**\n     * @dev MAY be emitted to signal that the domain could have changed.\n     */\n    event EIP712DomainChanged();\n\n    /**\n     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712\n     * signature.\n     */\n    function eip712Domain()\n        external\n        view\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        );\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolEvents.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IUsdnProtocolTypes } from \"./IUsdnProtocolTypes.sol\";\n\n/**\n * @title IUsdnProtocolEvents\n * @notice Events for the USDN Protocol\n */\ninterface IUsdnProtocolEvents is IUsdnProtocolTypes {\n    /**\n     * @notice User initiates a deposit.\n     * @param to The address that will receive the USDN tokens.\n     * @param validator The address that will receive the security deposit.\n     * @param amount The amount of assets that were deposited.\n     * @param feeBps The fee in basis points.\n     * @param timestamp The timestamp of the action.\n     * @param sdexBurned The amount of SDEX tokens burned.\n     */\n    event InitiatedDeposit(\n        address indexed to,\n        address indexed validator,\n        uint256 amount,\n        uint256 feeBps,\n        uint256 timestamp,\n        uint256 sdexBurned\n    );\n\n    /**\n     * @notice User validates a deposit.\n     * @param to The address that received the USDN tokens.\n     * @param validator The address that received the security deposit.\n     * @param amountAfterFees The amount of assets that were deposited after fees.\n     * @param usdnMinted The amount of USDN that was minted.\n     * @param timestamp The timestamp of the `InitiatedDeposit` action.\n     */\n    event ValidatedDeposit(\n        address indexed to, address indexed validator, uint256 amountAfterFees, uint256 usdnMinted, uint256 timestamp\n    );\n\n    /**\n     * @notice User initiates a withdrawal.\n     * @param to The address that will receive the assets.\n     * @param validator The address that will receive the security deposit.\n     * @param usdnAmount The amount of USDN that will be burned.\n     * @param feeBps The fee in basis points.\n     * @param timestamp The timestamp of the action.\n     */\n    event InitiatedWithdrawal(\n        address indexed to, address indexed validator, uint256 usdnAmount, uint256 feeBps, uint256 timestamp\n    );\n\n    /**\n     * @notice User validates a withdrawal.\n     * @param to The address that received the assets.\n     * @param validator The address that received the security deposit.\n     * @param amountWithdrawnAfterFees The amount of assets that were withdrawn after fees.\n     * @param usdnBurned The amount of USDN that was burned.\n     * @param timestamp The timestamp of the `InitiatedWithdrawal` action.\n     */\n    event ValidatedWithdrawal(\n        address indexed to,\n        address indexed validator,\n        uint256 amountWithdrawnAfterFees,\n        uint256 usdnBurned,\n        uint256 timestamp\n    );\n\n    /**\n     * @notice User initiates the opening of a long position.\n     * @param owner The address that owns the position.\n     * @param validator The address that will receive the security deposit.\n     * @param timestamp The timestamp of the action.\n     * @param totalExpo The initial total expo of the position (pending validation).\n     * @param amount The amount of assets that were deposited as collateral.\n     * @param startPrice The asset price at the moment of the position creation (pending validation).\n     * @param posId The unique position identifier.\n     */\n    event InitiatedOpenPosition(\n        address indexed owner,\n        address indexed validator,\n        uint40 timestamp,\n        uint128 totalExpo,\n        uint128 amount,\n        uint128 startPrice,\n        PositionId posId\n    );\n\n    /**\n     * @notice User validates the opening of a long position.\n     * @param owner The address that owns the position.\n     * @param validator The address that received the security deposit.\n     * @param totalExpo The total expo of the position.\n     * @param newStartPrice The asset price at the moment of the position creation (final).\n     * @param posId The unique position identifier.\n     * If changed compared to `InitiatedOpenLong`, then `LiquidationPriceUpdated` will be emitted too.\n     */\n    event ValidatedOpenPosition(\n        address indexed owner, address indexed validator, uint128 totalExpo, uint128 newStartPrice, PositionId posId\n    );\n\n    /**\n     * @notice The position was moved from one tick to another.\n     * @param oldPosId The old position identifier.\n     * @param newPosId The new position identifier.\n     */\n    event LiquidationPriceUpdated(PositionId oldPosId, PositionId newPosId);\n\n    /**\n     * @notice User initiates the closing of all or part of a long position.\n     * @param owner The owner of this position.\n     * @param validator The address that received the security deposit.\n     * @param to The address that will receive the assets.\n     * @param posId The unique position identifier.\n     * @param originalAmount The amount of collateral originally on the position.\n     * @param amountToClose The amount of collateral to close from the position.\n     * If the entirety of the position is being closed, this value equals `originalAmount`.\n     * @param totalExpoRemaining The total expo remaining in the position.\n     * If the entirety of the position is being closed, this value is zero.\n     */\n    event InitiatedClosePosition(\n        address indexed owner,\n        address indexed validator,\n        address indexed to,\n        PositionId posId,\n        uint128 originalAmount,\n        uint128 amountToClose,\n        uint128 totalExpoRemaining\n    );\n\n    /**\n     * @notice User validates the closing of a long position.\n     * @param validator The address that received the security deposit.\n     * @param to The address that received the assets.\n     * @param posId The unique position identifier.\n     * @param amountReceived The amount of assets that were sent to the user.\n     * @param profit The profit that the user made.\n     */\n    event ValidatedClosePosition(\n        address indexed validator, address indexed to, PositionId posId, uint256 amountReceived, int256 profit\n    );\n\n    /**\n     * @notice The tick is liquidated.\n     * @param tick The liquidated tick.\n     * @param oldTickVersion The liquidated tick version.\n     * @param liquidationPrice The asset price at the moment of liquidation.\n     * @param effectiveTickPrice The effective liquidated tick price.\n     * @param remainingCollateral The amount of asset that was left in the tick, which was transferred to the vault if\n     * positive, or was taken from the vault if negative.\n     */\n    event LiquidatedTick(\n        int24 indexed tick,\n        uint256 indexed oldTickVersion,\n        uint256 liquidationPrice,\n        uint256 effectiveTickPrice,\n        int256 remainingCollateral\n    );\n\n    /**\n     * @notice The position is individually liquidated.\n     * @param user The validator of the action, not necessarily the owner of the position.\n     * @param posId The unique identifier for the position that was liquidated.\n     * @param liquidationPrice The asset price at the moment of liquidation.\n     * @param effectiveTickPrice The effective liquidated tick price.\n     */\n    event LiquidatedPosition(\n        address indexed user, PositionId posId, uint256 liquidationPrice, uint256 effectiveTickPrice\n    );\n\n    /**\n     * @notice User's position was liquidated while pending validation and we removed the pending action.\n     * @param validator The validator address.\n     * @param posId The unique position identifier.\n     */\n    event StalePendingActionRemoved(address indexed validator, PositionId posId);\n\n    /**\n     * @notice The position fee is updated.\n     * @param positionFee The new position fee (in basis points).\n     */\n    event PositionFeeUpdated(uint256 positionFee);\n\n    /**\n     * @notice The vault fee is updated.\n     * @param vaultFee The new vault fee (in basis points).\n     */\n    event VaultFeeUpdated(uint256 vaultFee);\n\n    /**\n     * @notice The SDEX rewards ratio is updated.\n     * @param ratio The new ratio (in basis points).\n     */\n    event SdexRewardsRatioUpdated(uint16 ratio);\n\n    /**\n     * @notice The rebalancer bonus is updated.\n     * @param bonus The new bonus (in basis points).\n     */\n    event RebalancerBonusUpdated(uint256 bonus);\n\n    /**\n     * @notice The ratio of USDN to SDEX tokens to burn on deposit is updated.\n     * @param newRatio The new ratio.\n     */\n    event BurnSdexOnDepositRatioUpdated(uint256 newRatio);\n\n    /**\n     * @notice The deposit value is updated.\n     * @param securityDepositValue The new deposit value.\n     */\n    event SecurityDepositValueUpdated(uint256 securityDepositValue);\n\n    /**\n     * @notice The oracle middleware is updated.\n     * @param newMiddleware The new oracle middleware address.\n     */\n    event OracleMiddlewareUpdated(address newMiddleware);\n\n    /**\n     * @notice The minimum leverage of the rebalancer is updated.\n     * @param newMinLeverage The new value for the minimum leverage.\n     */\n    event RebalancerMinLeverageUpdated(uint256 newMinLeverage);\n\n    /**\n     * @notice The `minLeverage` is updated.\n     * @param newMinLeverage The new `minLeverage`.\n     */\n    event MinLeverageUpdated(uint256 newMinLeverage);\n\n    /**\n     * @notice The `maxLeverage` is updated.\n     * @param newMaxLeverage The new `maxLeverage`.\n     */\n    event MaxLeverageUpdated(uint256 newMaxLeverage);\n\n    /**\n     * @notice The `lowLatencyValidatorDeadline` and `onChainValidatorDeadline` are updated.\n     * @param newLowLatencyValidatorDeadline The new deadline for low-latency validation (offset from the initiate\n     * action timestamp).\n     * @param newOnChainValidatorDeadline The new deadline for on-chain validation (offset from the initiate action\n     * timestamp + the oracle middleware's low-latency delay).\n     */\n    event ValidatorDeadlinesUpdated(uint128 newLowLatencyValidatorDeadline, uint128 newOnChainValidatorDeadline);\n\n    /**\n     * @notice The `liquidationPenalty` is updated.\n     * @param newLiquidationPenalty The new `liquidationPenalty`.\n     */\n    event LiquidationPenaltyUpdated(uint24 newLiquidationPenalty);\n\n    /**\n     * @notice The `safetyMargin` is updated.\n     * @param newSafetyMargin The new `safetyMargin`.\n     */\n    event SafetyMarginBpsUpdated(uint256 newSafetyMargin);\n\n    /**\n     * @notice The `liquidationIteration` is updated.\n     * @param newLiquidationIteration The new `liquidationIteration`.\n     */\n    event LiquidationIterationUpdated(uint16 newLiquidationIteration);\n\n    /**\n     * @notice The EMAPeriod is updated.\n     * @param newEMAPeriod The new EMAPeriod.\n     */\n    event EMAPeriodUpdated(uint128 newEMAPeriod);\n\n    /**\n     * @notice The `fundingSF` is updated.\n     * @param newFundingSF The new `fundingSF`.\n     */\n    event FundingSFUpdated(uint256 newFundingSF);\n\n    /**\n     * @notice Emitted when a user (liquidator) successfully liquidated positions.\n     * @param liquidator The address that initiated the liquidation.\n     * @param rewards The amount of tokens the liquidator received in rewards.\n     */\n    event LiquidatorRewarded(address indexed liquidator, uint256 rewards);\n\n    /**\n     * @notice The `LiquidationRewardsManager` contract is updated.\n     * @param newAddress The address of the new (current) contract.\n     */\n    event LiquidationRewardsManagerUpdated(address newAddress);\n\n    /**\n     * @notice The rebalancer contract is updated.\n     * @param newAddress The address of the new (current) contract.\n     */\n    event RebalancerUpdated(address newAddress);\n\n    /**\n     * @notice The pending protocol fee is distributed.\n     * @param feeCollector The collector's address.\n     * @param amount The amount of fee transferred.\n     */\n    event ProtocolFeeDistributed(address feeCollector, uint256 amount);\n\n    /**\n     * @notice The protocol fee is updated.\n     * @param feeBps The new fee in basis points.\n     */\n    event FeeBpsUpdated(uint256 feeBps);\n\n    /**\n     * @notice The fee collector is updated.\n     * @param feeCollector The new fee collector address.\n     */\n    event FeeCollectorUpdated(address feeCollector);\n\n    /**\n     * @notice The fee threshold is updated.\n     * @param feeThreshold The new fee threshold.\n     */\n    event FeeThresholdUpdated(uint256 feeThreshold);\n\n    /**\n     * @notice The target USDN price is updated.\n     * @param price The new target USDN price.\n     */\n    event TargetUsdnPriceUpdated(uint128 price);\n\n    /**\n     * @notice The USDN rebase threshold is updated.\n     * @param threshold The new target USDN price.\n     */\n    event UsdnRebaseThresholdUpdated(uint128 threshold);\n\n    /**\n     * @notice Imbalance limits are updated.\n     * @param newOpenLimitBps The new open limit.\n     * @param newDepositLimitBps The new deposit limit.\n     * @param newWithdrawalLimitBps The new withdrawal limit.\n     * @param newCloseLimitBps The new close limit.\n     * @param newRebalancerCloseLimitBps The new close limit for the rebalancer's position.\n     * @param newLongImbalanceTargetBps The new long imbalance target.\n     */\n    event ImbalanceLimitsUpdated(\n        uint256 newOpenLimitBps,\n        uint256 newDepositLimitBps,\n        uint256 newWithdrawalLimitBps,\n        uint256 newCloseLimitBps,\n        uint256 newRebalancerCloseLimitBps,\n        int256 newLongImbalanceTargetBps\n    );\n\n    /**\n     * @notice The minimum long position is updated.\n     * @param minLongPosition The new minimum long position.\n     */\n    event MinLongPositionUpdated(uint256 minLongPosition);\n\n    /**\n     * @notice The highest populated tick is updated.\n     * @param tick The new highest populated tick.\n     */\n    event HighestPopulatedTickUpdated(int24 tick);\n\n    /**\n     * @notice Security deposit is refunded.\n     * @param pendingActionValidator Address of the default validator.\n     * @param receivedBy Address of the user that received the security deposit.\n     * @param amount Amount of security deposit refunded.\n     */\n    event SecurityDepositRefunded(address indexed pendingActionValidator, address indexed receivedBy, uint256 amount);\n\n    /**\n     * @notice Position changes ownership.\n     * @param posId The unique position ID.\n     * @param oldOwner The old owner.\n     * @param newOwner The new owner.\n     */\n    event PositionOwnershipTransferred(PositionId posId, address indexed oldOwner, address indexed newOwner);\n\n    /**\n     * @notice The last funding per day is updated.\n     * @param lastFundingPerDay The new funding per day.\n     * @param lastUpdateTimestamp The timestamp for which the funding per day was calculated.\n     */\n    event LastFundingPerDayUpdated(int256 lastFundingPerDay, uint256 lastUpdateTimestamp);\n\n    /**\n     * @notice The protocol balance of SDEX has been burned.\n     * @param amount The amount of SDEX that was burned.\n     * @param rewards The amount of rewards that were distributed to the caller.\n     */\n    event SdexBurned(uint256 amount, uint256 rewards);\n}\n"},{"file_path":"src/libraries/SignedMath.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.20;\n\n/**\n * @notice Performs signed math operations safely, reverting with a custom error in case of overflow.\n */\nlibrary SignedMath {\n    /**\n     * @dev The signed `add` operation overflowed.\n     * @param lhs The left-hand side operand.\n     * @param rhs The right-hand side operand.\n     */\n    error SignedMathOverflowedAdd(int256 lhs, int256 rhs);\n\n    /**\n     * @dev The signed `sub` operation overflowed.\n     * @param lhs The left-hand side operand.\n     * @param rhs The right-hand side operand.\n     */\n    error SignedMathOverflowedSub(int256 lhs, int256 rhs);\n\n    /**\n     * @dev The signed `mul` operation overflowed.\n     * @param lhs The left-hand side operand.\n     * @param rhs The right-hand side operand.\n     */\n    error SignedMathOverflowedMul(int256 lhs, int256 rhs);\n\n    /**\n     * @dev The signed `div` operation overflowed.\n     * @param lhs The left-hand side operand.\n     * @param rhs The right-hand side operand.\n     */\n    error SignedMathOverflowedDiv(int256 lhs, int256 rhs);\n\n    /**\n     * @dev A division by zero occurred.\n     * @param lhs The left-hand side operand.\n     */\n    error SignedMathDivideByZero(int256 lhs);\n\n    /**\n     * @notice Safely adds two signed integers, reverting on overflow.\n     * @param lhs The left-hand side operand.\n     * @param rhs The right-hand side operand.\n     * @return res_ The result of `lhs + rhs`.\n     */\n    function safeAdd(int256 lhs, int256 rhs) internal pure returns (int256 res_) {\n        unchecked {\n            res_ = lhs + rhs;\n            if (lhs >= 0 && res_ < rhs) {\n                revert SignedMathOverflowedAdd(lhs, rhs);\n            }\n            if (lhs < 0 && res_ > rhs) {\n                revert SignedMathOverflowedAdd(lhs, rhs);\n            }\n        }\n    }\n\n    /**\n     * @notice Safely subtracts two signed integers, reverting on overflow.\n     * @param lhs The left-hand side operand.\n     * @param rhs The right-hand side operand.\n     * @return res_ The result of `lhs - rhs`.\n     */\n    function safeSub(int256 lhs, int256 rhs) internal pure returns (int256 res_) {\n        unchecked {\n            res_ = lhs - rhs;\n            if (rhs >= 0 && res_ > lhs) {\n                revert SignedMathOverflowedSub(lhs, rhs);\n            }\n            if (rhs < 0 && res_ < lhs) {\n                revert SignedMathOverflowedSub(lhs, rhs);\n            }\n        }\n    }\n\n    /**\n     * @notice Safely multiplies two signed integers, reverting on overflow.\n     * @param lhs The left-hand side operand.\n     * @param rhs The right-hand side operand.\n     * @return res_ The result of `lhs * rhs`.\n     */\n    function safeMul(int256 lhs, int256 rhs) internal pure returns (int256 res_) {\n        unchecked {\n            if (lhs == 0) {\n                return 0;\n            }\n            res_ = lhs * rhs;\n            // there is a special case where the first condition below does not catch the overflow: `lhs = -1` and\n            // `rhs = type(int256).min`\n            // in such a case, `res_` overflows and is equal to `type(int256).min`. Then, `res_ / lhs` also overflows\n            // and is equal to `type(int256).min`, so the condition does not catch it. We add a condition\n            // for this specific case. This is not a problem when lhs and rhs are swapped, because\n            // `res_ / type(int256).min` equals `1` which is not equal to `-1`\n            if (res_ / lhs != rhs || (rhs == type(int256).min && lhs == -1)) {\n                revert SignedMathOverflowedMul(lhs, rhs);\n            }\n        }\n    }\n\n    /**\n     * @notice Safely divides two signed integers, reverting on division by zero.\n     * @param lhs The left-hand side operand.\n     * @param rhs The right-hand side operand.\n     * @return res_ The result of `lhs / rhs`.\n     */\n    function safeDiv(int256 lhs, int256 rhs) internal pure returns (int256 res_) {\n        unchecked {\n            if (rhs == 0) {\n                revert SignedMathDivideByZero(lhs);\n            }\n            // there is a special case where the division would overflow because\n            // `abs(type(int256).min) > type(int256).max`. So if `lhs = type(int256).min` and `rhs = -1`, the result\n            // would be `-type(int256).min` which does not fit in a `int256`. We add a condition for this specific case\n            if (lhs == type(int256).min && rhs == -1) {\n                revert SignedMathOverflowedDiv(lhs, rhs);\n            }\n            res_ = lhs / rhs;\n        }\n    }\n}\n"},{"file_path":"src/UsdnProtocol/libraries/UsdnProtocolActionsUtilsLibrary.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.26;\n\nimport { ECDSA } from \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport { MessageHashUtils } from \"@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol\";\nimport { ERC165Checker } from \"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\";\nimport { SafeCast } from \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport { PriceInfo } from \"../../interfaces/OracleMiddleware/IOracleMiddlewareTypes.sol\";\nimport { IOwnershipCallback } from \"../../interfaces/UsdnProtocol/IOwnershipCallback.sol\";\nimport { IUsdnProtocolErrors } from \"../../interfaces/UsdnProtocol/IUsdnProtocolErrors.sol\";\nimport { IUsdnProtocolEvents } from \"../../interfaces/UsdnProtocol/IUsdnProtocolEvents.sol\";\nimport { IUsdnProtocolTypes as Types } from \"../../interfaces/UsdnProtocol/IUsdnProtocolTypes.sol\";\nimport { DoubleEndedQueue } from \"../../libraries/DoubleEndedQueue.sol\";\nimport { SignedMath } from \"../../libraries/SignedMath.sol\";\nimport { UsdnProtocolActionsLongLibrary as ActionsLong } from \"./UsdnProtocolActionsLongLibrary.sol\";\nimport { UsdnProtocolConstantsLibrary as Constants } from \"./UsdnProtocolConstantsLibrary.sol\";\nimport { UsdnProtocolCoreLibrary as Core } from \"./UsdnProtocolCoreLibrary.sol\";\nimport { UsdnProtocolLongLibrary as Long } from \"./UsdnProtocolLongLibrary.sol\";\nimport { UsdnProtocolUtilsLibrary as Utils } from \"./UsdnProtocolUtilsLibrary.sol\";\nimport { UsdnProtocolVaultLibrary as Vault } from \"./UsdnProtocolVaultLibrary.sol\";\n\nlibrary UsdnProtocolActionsUtilsLibrary {\n    using DoubleEndedQueue for DoubleEndedQueue.Deque;\n    using SafeCast for uint256;\n    using SignedMath for int256;\n\n    /**\n     * @dev Data structure for the transient state of the {_validateMultipleActionable} function.\n     * @param pending The candidate pending action to validate.\n     * @param frontRawIndex The raw index of the front of the queue.\n     * @param rawIndex The raw index of the candidate pending action in the queue.\n     * @param executed Indicates whether the pending action has been executed.\n     * @param liq Indicates whether the pending action has been liquidated.\n     */\n    struct ValidateMultipleActionableData {\n        Types.PendingAction pending;\n        uint128 frontRawIndex;\n        uint128 rawIndex;\n        bool executed;\n        bool liq;\n    }\n\n    /// @notice See {IUsdnProtocolActions.liquidate}.\n    function liquidate(bytes calldata currentPriceData)\n        external\n        returns (Types.LiqTickInfo[] memory liquidatedTicks_)\n    {\n        uint256 balanceBefore = address(this).balance;\n        PriceInfo memory currentPrice = Utils._getOraclePrice(Types.ProtocolAction.Liquidation, 0, \"\", currentPriceData);\n\n        (liquidatedTicks_,) = Long._applyPnlAndFundingAndLiquidate(\n            currentPrice.neutralPrice,\n            currentPrice.timestamp,\n            Constants.MAX_LIQUIDATION_ITERATION,\n            Types.ProtocolAction.Liquidation,\n            currentPriceData\n        );\n\n        Utils._refundExcessEther(0, 0, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolActions.validateActionablePendingActions}.\n    function validateActionablePendingActions(\n        Types.PreviousActionsData calldata previousActionsData,\n        uint256 maxValidations\n    ) external returns (uint256 validatedActions_) {\n        uint256 balanceBefore = address(this).balance;\n\n        uint256 amountToRefund;\n        (validatedActions_, amountToRefund) = _validateMultipleActionable(previousActionsData, maxValidations);\n\n        Utils._refundExcessEther(0, amountToRefund, balanceBefore);\n        Utils._checkPendingFee();\n    }\n\n    /// @notice See {IUsdnProtocolActions.transferPositionOwnership}.\n    function transferPositionOwnership(\n        Types.PositionId calldata posId,\n        address newOwner,\n        bytes calldata delegationSignature,\n        bytes32 domainSeparatorV4\n    ) external {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (bytes32 tickHash, uint256 version) = Utils._tickHash(posId.tick);\n        if (posId.tickVersion != version) {\n            revert IUsdnProtocolErrors.UsdnProtocolOutdatedTick(version, posId.tickVersion);\n        }\n        Types.Position storage pos = s._longPositions[tickHash][posId.index];\n\n        if (newOwner == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressTo();\n        }\n\n        address oldOwner = pos.user;\n        if (msg.sender != oldOwner) {\n            if (delegationSignature.length == 0) {\n                revert IUsdnProtocolErrors.UsdnProtocolUnauthorized();\n            } else {\n                _verifyTransferPositionOwnershipDelegation(\n                    posId, oldOwner, newOwner, delegationSignature, domainSeparatorV4\n                );\n            }\n        }\n\n        pos.user = newOwner;\n\n        if (ERC165Checker.supportsInterface(newOwner, type(IOwnershipCallback).interfaceId)) {\n            IOwnershipCallback(newOwner).ownershipCallback(oldOwner, posId);\n        }\n\n        emit IUsdnProtocolEvents.PositionOwnershipTransferred(posId, oldOwner, newOwner);\n    }\n\n    /**\n     * @notice Checks and reverts if the withdrawn value breaks the imbalance limits.\n     * @param withdrawalValue The withdrawal value in asset.\n     * @param totalExpo The current total exposure of the long side.\n     */\n    function _checkImbalanceLimitWithdrawal(uint256 withdrawalValue, uint256 totalExpo) external view {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        int256 withdrawalExpoImbalanceLimitBps = s._withdrawalExpoImbalanceLimitBps;\n\n        // early return in case limit is disabled\n        if (withdrawalExpoImbalanceLimitBps == 0) {\n            return;\n        }\n\n        int256 newVaultExpo =\n            s._balanceVault.toInt256().safeAdd(s._pendingBalanceVault).safeSub(withdrawalValue.toInt256());\n\n        // an imbalance cannot be calculated if the new vault exposure is zero or negative\n        if (newVaultExpo <= 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolEmptyVault();\n        }\n\n        int256 imbalanceBps = (totalExpo - s._balanceLong).toInt256().safeSub(newVaultExpo).safeMul(\n            int256(Constants.BPS_DIVISOR)\n        ).safeDiv(newVaultExpo);\n\n        if (imbalanceBps > withdrawalExpoImbalanceLimitBps) {\n            revert IUsdnProtocolErrors.UsdnProtocolImbalanceLimitReached(imbalanceBps);\n        }\n    }\n\n    /**\n     * @notice Checks and reverts if the deposited value breaks the imbalance limits.\n     * @param depositValue The deposit value in asset.\n     */\n    function _checkImbalanceLimitDeposit(uint256 depositValue) external view {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        int256 depositExpoImbalanceLimitBps = s._depositExpoImbalanceLimitBps;\n\n        // early return in case limit is disabled\n        if (depositExpoImbalanceLimitBps == 0) {\n            return;\n        }\n\n        int256 currentLongExpo = (s._totalExpo - s._balanceLong).toInt256();\n\n        // cannot be calculated\n        if (currentLongExpo == 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidLongExpo();\n        }\n\n        int256 newVaultExpo = s._balanceVault.toInt256().safeAdd(s._pendingBalanceVault).safeAdd(int256(depositValue));\n\n        int256 imbalanceBps =\n            newVaultExpo.safeSub(currentLongExpo).safeMul(int256(Constants.BPS_DIVISOR)).safeDiv(currentLongExpo);\n\n        if (imbalanceBps > depositExpoImbalanceLimitBps) {\n            revert IUsdnProtocolErrors.UsdnProtocolImbalanceLimitReached(imbalanceBps);\n        }\n    }\n\n    /// @notice See {IUsdnProtocolLong.getLongPosition}.\n    function getLongPosition(Types.PositionId memory posId)\n        public\n        view\n        returns (Types.Position memory pos_, uint24 liquidationPenalty_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (bytes32 tickHash, uint256 version) = Utils._tickHash(posId.tick);\n        if (posId.tickVersion != version) {\n            revert IUsdnProtocolErrors.UsdnProtocolOutdatedTick(version, posId.tickVersion);\n        }\n        pos_ = s._longPositions[tickHash][posId.index];\n        liquidationPenalty_ = s._tickData[tickHash].liquidationPenalty;\n    }\n\n    /**\n     * @notice Updates the protocol state, then prepares the data for the initiate close position action.\n     * @dev Reverts if the imbalance limit is reached, or if any checks in {_checkInitiateClosePosition} fail.\n     * Returns without creating a pending action if the position gets liquidated in this transaction or if there are\n     * still positions pending liquidation.\n     * @param params The parameters for the {_prepareClosePositionData} function.\n     * @return data_ The close position data.\n     * @return liquidated_ Indicates whether the position was liquidated.\n     */\n    function _prepareClosePositionData(Types.PrepareInitiateClosePositionParams calldata params)\n        public\n        returns (Types.ClosePositionData memory data_, bool liquidated_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        (data_.pos, data_.liquidationPenalty) = getLongPosition(params.posId);\n\n        _checkInitiateClosePosition(data_.pos, params);\n\n        PriceInfo memory currentPrice = Utils._getOraclePrice(\n            Types.ProtocolAction.InitiateClosePosition,\n            block.timestamp,\n            Utils._calcActionId(params.validator, uint128(block.timestamp)),\n            params.currentPriceData\n        );\n\n        (, data_.isLiquidationPending) = Long._applyPnlAndFundingAndLiquidate(\n            currentPrice.neutralPrice,\n            currentPrice.timestamp,\n            s._liquidationIteration,\n            Types.ProtocolAction.InitiateClosePosition,\n            params.currentPriceData\n        );\n\n        uint256 version = s._tickVersion[params.posId.tick];\n        if (version != params.posId.tickVersion) {\n            // the current tick version doesn't match the version from the position,\n            // that means that the position has been liquidated in this transaction\n            return (data_, true);\n        }\n\n        if (data_.isLiquidationPending) {\n            return (data_, false);\n        }\n\n        data_.lastPrice = s._lastPrice;\n        // add the position fee\n        uint256 adjustedPrice =\n            (data_.lastPrice - data_.lastPrice * s._positionFeeBps / Constants.BPS_DIVISOR).toUint128();\n        if (adjustedPrice < params.userMinPrice) {\n            revert IUsdnProtocolErrors.UsdnProtocolSlippageMinPriceExceeded();\n        }\n\n        data_.totalExpoToClose = (uint256(data_.pos.totalExpo) * params.amountToClose / data_.pos.amount).toUint128();\n        data_.longTradingExpo = Core.longTradingExpoWithFunding(data_.lastPrice, uint128(block.timestamp));\n        data_.liqMulAcc = s._liqMultiplierAccumulator;\n\n        // the approximate value position to remove is calculated with `_lastPrice`, so not taking into account\n        // any fees. This way, the removal of the position doesn't affect the liquidation multiplier calculations\n\n        // to have maximum precision, we do not pre-compute the liquidation multiplier with a fixed\n        // precision just now, we will store it in the pending action later, to be used in the validate action\n        int24 tick = Utils._calcTickWithoutPenalty(params.posId.tick, data_.liquidationPenalty);\n        uint128 liqPriceWithoutPenalty =\n            Utils._getEffectivePriceForTick(tick, data_.lastPrice, data_.longTradingExpo, data_.liqMulAcc);\n\n        uint256 balanceLong = s._balanceLong;\n\n        data_.tempPositionValue =\n            _assetToRemove(balanceLong, data_.lastPrice, liqPriceWithoutPenalty, data_.totalExpoToClose);\n\n        // we perform the imbalance check with the full position value subtracted from the long side, which is\n        // representative of the state of the balances after this initiate action\n        _checkImbalanceLimitClose(data_.totalExpoToClose, data_.tempPositionValue);\n    }\n\n    /**\n     * @notice Validates multiple actionable pending actions.\n     * @param previousActionsData The data for the actions to validate (price and raw indices).\n     * @param maxValidations The maximum number of validations to perform.\n     * @return validatedActions_ The number of actions successfully validated.\n     * @return amountToRefund_ The total amount of security deposits to be refunded.\n     */\n    function _validateMultipleActionable(Types.PreviousActionsData calldata previousActionsData, uint256 maxValidations)\n        internal\n        returns (uint256 validatedActions_, uint256 amountToRefund_)\n    {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 length = previousActionsData.rawIndices.length;\n        if (previousActionsData.priceData.length != length || length < 1) {\n            return (0, 0);\n        }\n        if (maxValidations > length) {\n            maxValidations = length;\n        }\n        uint128 lowLatencyDeadline = s._lowLatencyValidatorDeadline;\n        uint16 middlewareLowLatencyDelay = s._oracleMiddleware.getLowLatencyDelay();\n        uint128 onChainDeadline = s._onChainValidatorDeadline;\n        uint256 i;\n        do {\n            if (s._pendingActionsQueue.empty()) {\n                break;\n            }\n            ValidateMultipleActionableData memory data; // avoid stack too deep\n            // perform cleanup on the queue if needed\n            (data.pending, data.frontRawIndex) = s._pendingActionsQueue.front();\n            if (data.pending.timestamp == 0) {\n                s._pendingActionsQueue.popFront();\n            }\n\n            // check if the pending action is actionable and validate it\n            data.rawIndex = previousActionsData.rawIndices[i];\n            if (data.rawIndex != data.frontRawIndex) {\n                // only get the pending action if we didn't already get it via `front` above\n                if (!s._pendingActionsQueue.isValid(data.rawIndex)) {\n                    // the raw index is not in the queue, let's keep looking\n                    unchecked {\n                        i++;\n                    }\n                    continue;\n                }\n                data.pending = s._pendingActionsQueue.atRaw(data.rawIndex);\n            }\n            if (_isActionable(data.pending.timestamp, lowLatencyDeadline, middlewareLowLatencyDelay, onChainDeadline)) {\n                if (data.pending.action == Types.ProtocolAction.ValidateDeposit) {\n                    data.executed = Vault._validateDepositWithAction(data.pending, previousActionsData.priceData[i]);\n                } else if (data.pending.action == Types.ProtocolAction.ValidateWithdrawal) {\n                    data.executed = Vault._validateWithdrawalWithAction(data.pending, previousActionsData.priceData[i]);\n                } else if (data.pending.action == Types.ProtocolAction.ValidateOpenPosition) {\n                    (data.executed, data.liq,) =\n                        ActionsLong._validateOpenPositionWithAction(data.pending, previousActionsData.priceData[i]);\n                } else if (data.pending.action == Types.ProtocolAction.ValidateClosePosition) {\n                    (data.executed, data.liq) =\n                        ActionsLong._validateClosePositionWithAction(data.pending, previousActionsData.priceData[i]);\n                }\n            } else {\n                // not actionable or empty pending action, let's keep looking\n                unchecked {\n                    i++;\n                }\n                continue;\n            }\n            if (data.executed || data.liq) {\n                // validation was performed, let's update the return values and cleanup\n                Utils._clearPendingAction(data.pending.validator, data.rawIndex);\n                amountToRefund_ += data.pending.securityDepositValue;\n                unchecked {\n                    validatedActions_++;\n                }\n                emit IUsdnProtocolEvents.SecurityDepositRefunded(\n                    data.pending.validator, msg.sender, data.pending.securityDepositValue\n                );\n            } else {\n                // if we didn't perform a validation, this likely means that there are pending liquidations, we stop\n                break;\n            }\n            unchecked {\n                i++;\n            }\n        } while (i < maxValidations);\n    }\n\n    /**\n     * @notice Checks whether a pending action is actionable, allowing any user to validate it and claim the security\n     * deposit.\n     * @dev Between `initiateTimestamp` and `initiateTimestamp + lowLatencyDeadline`,\n     * the validator receives the security deposit.\n     * Between `initiateTimestamp + lowLatencyDelay` and `initiateTimestamp + lowLatencyDelay + onChainDeadline`,\n     * the validator also receives the security deposit.\n     * Outside of those periods, the security deposit goes to the user validating the pending action.\n     * @param initiateTimestamp The timestamp at which the action was initiated.\n     * @param lowLatencyDeadline The deadline after which the action is actionable within a low latency oracle.\n     * @param lowLatencyDelay The amount of time the action can be validated with a low latency oracle.\n     * @param onChainDeadline The deadline after which the action is actionable with an on-chain oracle.\n     * @return actionable_ Indicates whether the pending action is actionable.\n     */\n    function _isActionable(\n        uint256 initiateTimestamp,\n        uint256 lowLatencyDeadline,\n        uint256 lowLatencyDelay,\n        uint256 onChainDeadline\n    ) internal view returns (bool actionable_) {\n        if (initiateTimestamp == 0) {\n            return false;\n        }\n        if (block.timestamp <= initiateTimestamp + lowLatencyDelay) {\n            // the validation must happen with a low-latency oracle\n            actionable_ = block.timestamp > initiateTimestamp + lowLatencyDeadline;\n        } else {\n            // the validation must happen with an on-chain oracle\n            actionable_ = block.timestamp > initiateTimestamp + lowLatencyDelay + onChainDeadline;\n        }\n    }\n\n    /**\n     * @notice Checks the close vault imbalance limit state.\n     * @dev Ensures that the protocol does not imbalance more than the close limit on the vault side, otherwise revert.\n     * @param posTotalExpoToClose The total exposure to remove from the position.\n     * @param posValueToClose The value to remove from the position (and the long balance).\n     */\n    function _checkImbalanceLimitClose(uint256 posTotalExpoToClose, uint256 posValueToClose) internal view {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        int256 closeExpoImbalanceLimitBps;\n        if (msg.sender == address(s._rebalancer)) {\n            closeExpoImbalanceLimitBps = s._rebalancerCloseExpoImbalanceLimitBps;\n        } else {\n            closeExpoImbalanceLimitBps = s._closeExpoImbalanceLimitBps;\n        }\n\n        // early return in case limit is disabled\n        if (closeExpoImbalanceLimitBps == 0) {\n            return;\n        }\n\n        int256 newLongBalance = s._balanceLong.toInt256().safeSub(posValueToClose.toInt256());\n        uint256 newTotalExpo = s._totalExpo - posTotalExpoToClose;\n        int256 currentVaultExpo = s._balanceVault.toInt256().safeAdd(s._pendingBalanceVault);\n\n        int256 imbalanceBps = Utils._calcImbalanceCloseBps(currentVaultExpo, newLongBalance, newTotalExpo);\n\n        if (imbalanceBps > closeExpoImbalanceLimitBps) {\n            revert IUsdnProtocolErrors.UsdnProtocolImbalanceLimitReached(imbalanceBps);\n        }\n    }\n\n    /**\n     * @notice Performs checks for the initiate close position action.\n     * @param pos The position to close.\n     * @param params The parameters for the {_prepareClosePositionData} function.\n     */\n    function _checkInitiateClosePosition(\n        Types.Position memory pos,\n        Types.PrepareInitiateClosePositionParams calldata params\n    ) internal {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        if (params.to == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressTo();\n        }\n        if (params.validator == address(0)) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidAddressValidator();\n        }\n        if (!pos.validated) {\n            revert IUsdnProtocolErrors.UsdnProtocolPositionNotValidated();\n        }\n        if (params.amountToClose == 0) {\n            revert IUsdnProtocolErrors.UsdnProtocolZeroAmount();\n        }\n        if (params.amountToClose > pos.amount) {\n            revert IUsdnProtocolErrors.UsdnProtocolAmountToCloseHigherThanPositionAmount(\n                params.amountToClose, pos.amount\n            );\n        }\n\n        if (msg.sender != pos.user) {\n            if (params.delegationSignature.length == 0) {\n                revert IUsdnProtocolErrors.UsdnProtocolUnauthorized();\n            } else {\n                _verifyInitiateCloseDelegation(params, pos.user);\n            }\n        }\n\n        // make sure the remaining position is higher than _minLongPosition\n        // for the Rebalancer, we allow users to close their position fully in every case\n        uint128 remainingAmount = pos.amount - params.amountToClose;\n        if (remainingAmount > 0 && remainingAmount < s._minLongPosition && !s._isRebalancer[msg.sender]) {\n            revert IUsdnProtocolErrors.UsdnProtocolLongPositionTooSmall();\n        }\n    }\n\n    /**\n     * @notice Calculates how much assets must be removed from the long balance due to a position closing.\n     * @dev The amount is bound by the amount of assets available on the long side.\n     * @param balanceLong The balance of the long side.\n     * @param price The price to use for the position value calculation.\n     * @param liqPriceWithoutPenalty The liquidation price without penalty.\n     * @param posExpo The total exposure to remove from the position.\n     * @return boundedPosValue_ The amount of assets to remove from the long balance.\n     */\n    function _assetToRemove(uint256 balanceLong, uint128 price, uint128 liqPriceWithoutPenalty, uint128 posExpo)\n        internal\n        pure\n        returns (uint256 boundedPosValue_)\n    {\n        // calculate position value\n        int256 positionValue = Utils._positionValue(posExpo, price, liqPriceWithoutPenalty);\n\n        if (positionValue <= 0) {\n            // should not happen, unless we did not manage to liquidate all ticks that needed to be liquidated during\n            // the initiateClosePosition\n            boundedPosValue_ = 0;\n        } else if (uint256(positionValue) > balanceLong) {\n            boundedPosValue_ = balanceLong;\n        } else {\n            boundedPosValue_ = uint256(positionValue);\n        }\n    }\n\n    /**\n     * @notice Performs the {IUsdnProtocolActions.initiateClosePosition} EIP712 delegation signature verification.\n     * @dev Reverts if the function arguments don't match those included in the signature\n     * and if the signer isn't the owner of the position.\n     * @param params The parameters for the {_prepareClosePositionData} function.\n     * @param positionOwner The position owner.\n     */\n    function _verifyInitiateCloseDelegation(\n        Types.PrepareInitiateClosePositionParams calldata params,\n        address positionOwner\n    ) internal {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 nonce = s._nonce[positionOwner];\n        bytes32 digest = MessageHashUtils.toTypedDataHash(\n            params.domainSeparatorV4,\n            keccak256(\n                abi.encode(\n                    Constants.INITIATE_CLOSE_TYPEHASH,\n                    keccak256(abi.encode(params.posId)),\n                    params.amountToClose,\n                    params.userMinPrice,\n                    params.to,\n                    params.deadline,\n                    positionOwner,\n                    msg.sender,\n                    nonce\n                )\n            )\n        );\n\n        if (ECDSA.recover(digest, params.delegationSignature) != positionOwner) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidDelegationSignature();\n        }\n\n        s._nonce[positionOwner] = nonce + 1;\n    }\n\n    /**\n     * @notice Performs the {IUsdnProtocolActions.transferPositionOwnership} EIP712 delegation signature verification.\n     * @dev Reverts if the function arguments don't match those included in the signature\n     * and if the signer isn't the owner of the position.\n     * @param posId The unique identifier of the position.\n     * @param positionOwner The current position owner.\n     * @param newPositionOwner The new position owner.\n     * @param delegationSignature An EIP712 signature that proves the caller is authorized by the owner of the position\n     * to transfer the ownership to a different address on his behalf.\n     * @param domainSeparatorV4 The domain separator v4.\n     */\n    function _verifyTransferPositionOwnershipDelegation(\n        Types.PositionId calldata posId,\n        address positionOwner,\n        address newPositionOwner,\n        bytes calldata delegationSignature,\n        bytes32 domainSeparatorV4\n    ) internal {\n        Types.Storage storage s = Utils._getMainStorage();\n\n        uint256 nonce = s._nonce[positionOwner];\n        bytes32 digest = MessageHashUtils.toTypedDataHash(\n            domainSeparatorV4,\n            keccak256(\n                abi.encode(\n                    Constants.TRANSFER_POSITION_OWNERSHIP_TYPEHASH,\n                    keccak256(abi.encode(posId)),\n                    positionOwner,\n                    newPositionOwner,\n                    msg.sender,\n                    nonce\n                )\n            )\n        );\n\n        if (ECDSA.recover(digest, delegationSignature) != positionOwner) {\n            revert IUsdnProtocolErrors.UsdnProtocolInvalidDelegationSignature();\n        }\n\n        s._nonce[positionOwner] = nonce + 1;\n    }\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IFeeCollectorCallback.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IERC165 } from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/**\n * @notice Interface for a fee collector contract to receive callbacks from the USDN protocol upon fee collection.\n * @dev Implementing contracts must support the ERC-165 interface detection mechanism.\n */\ninterface IFeeCollectorCallback is IERC165 {\n    /**\n     * @notice Called by the USDN protocol on the fee collector contract when the fee threshold is reached.\n     * @param feeAmount The amount of the fee that was transferred to the fee collector.\n     */\n    function feeCollectorCallback(uint256 feeAmount) external;\n}\n"},{"file_path":"src/interfaces/Usdn/IUsdnEvents.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IRebaseCallback } from \"./IRebaseCallback.sol\";\n\n/**\n * @title Events for the USDN token contract\n * @notice Defines all custom events emitted by the USDN token contract.\n */\ninterface IUsdnEvents {\n    /**\n     * @notice The divisor was updated, emitted during a rebase.\n     * @param oldDivisor The divisor value before the rebase.\n     * @param newDivisor The new divisor value.\n     */\n    event Rebase(uint256 oldDivisor, uint256 newDivisor);\n\n    /**\n     * @notice The rebase handler address was updated.\n     * @dev The rebase handler is a contract that is called when a rebase occurs.\n     * @param newHandler The address of the new rebase handler contract.\n     */\n    event RebaseHandlerUpdated(IRebaseCallback newHandler);\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-upgradeable-5.1.0/utils/PausableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable\n    struct PausableStorage {\n        bool _paused;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Pausable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;\n\n    function _getPausableStorage() private pure returns (PausableStorage storage $) {\n        assembly {\n            $.slot := PausableStorageLocation\n        }\n    }\n\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    /**\n     * @dev The operation failed because the contract is paused.\n     */\n    error EnforcedPause();\n\n    /**\n     * @dev The operation failed because the contract is not paused.\n     */\n    error ExpectedPause();\n\n    /**\n     * @dev Initializes the contract in unpaused state.\n     */\n    function __Pausable_init() internal onlyInitializing {\n        __Pausable_init_unchained();\n    }\n\n    function __Pausable_init_unchained() internal onlyInitializing {\n        PausableStorage storage $ = _getPausableStorage();\n        $._paused = false;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        _requireNotPaused();\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        _requirePaused();\n        _;\n    }\n\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        PausableStorage storage $ = _getPausableStorage();\n        return $._paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        if (paused()) {\n            revert EnforcedPause();\n        }\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        if (!paused()) {\n            revert ExpectedPause();\n        }\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        PausableStorage storage $ = _getPausableStorage();\n        $._paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        PausableStorage storage $ = _getPausableStorage();\n        $._paused = false;\n        emit Unpaused(_msgSender());\n    }\n}\n"},{"file_path":"src/interfaces/Rebalancer/IBaseRebalancer.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IUsdnProtocolTypes as Types } from \"../UsdnProtocol/IUsdnProtocolTypes.sol\";\nimport { IRebalancerTypes } from \"./IRebalancerTypes.sol\";\n\ninterface IBaseRebalancer {\n    /**\n     * @notice Returns the necessary data for the USDN protocol to update the position.\n     * @return pendingAssets_ The amount of assets that are pending inclusion in the protocol.\n     * @return maxLeverage_ The maximum leverage of the rebalancer.\n     * @return currentPosId_ The ID of the current position (`tick` == `NO_POSITION_TICK` if no position).\n     */\n    function getCurrentStateData()\n        external\n        view\n        returns (uint128 pendingAssets_, uint256 maxLeverage_, Types.PositionId memory currentPosId_);\n\n    /**\n     * @notice Returns the minimum amount of assets a user can deposit in the rebalancer.\n     * @return minAssetDeposit_ The minimum amount of assets that can be deposited by a user.\n     */\n    function getMinAssetDeposit() external view returns (uint256 minAssetDeposit_);\n\n    /**\n     * @notice Returns the data regarding the assets deposited by the provided user.\n     * @param user The address of the user.\n     * @return data_ The data regarding the assets deposited by the provided user.\n     */\n    function getUserDepositData(address user) external view returns (IRebalancerTypes.UserDeposit memory data_);\n\n    /**\n     * @notice Indicates that the previous version of the position was closed and a new one was opened.\n     * @dev If `previousPosValue` equals 0, it means the previous version got liquidated.\n     * @param newPosId The position ID of the new position.\n     * @param previousPosValue The amount of assets left in the previous position.\n     */\n    function updatePosition(Types.PositionId calldata newPosId, uint128 previousPosValue) external;\n\n    /* -------------------------------------------------------------------------- */\n    /*                                    Admin                                   */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice Sets the minimum amount of assets to be deposited by a user.\n     * @dev The new minimum amount must be greater than or equal to the minimum long position of the USDN protocol.\n     * This function can only be called by the owner or the USDN protocol.\n     * @param minAssetDeposit The new minimum amount of assets to be deposited.\n     */\n    function setMinAssetDeposit(uint256 minAssetDeposit) external;\n}\n"},{"file_path":"src/interfaces/OracleMiddleware/IOracleMiddlewareTypes.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/**\n * @notice The price and timestamp returned by the oracle middleware.\n * @param price The validated asset price, potentially adjusted by the middleware.\n * @param neutralPrice The neutral/average price of the asset.\n * @param timestamp The timestamp of the price data.\n */\nstruct PriceInfo {\n    uint256 price;\n    uint256 neutralPrice;\n    uint256 timestamp;\n}\n\n/**\n * @notice The price and timestamp returned by the Chainlink oracle.\n * @param price The asset price formatted by the middleware.\n * @param timestamp When the price was published on chain.\n */\nstruct ChainlinkPriceInfo {\n    int256 price;\n    uint256 timestamp;\n}\n\n/**\n * @notice Representation of a Pyth price with a uint256 price.\n * @param price The price of the asset.\n * @param conf The confidence interval around the price (in dollars, absolute value).\n * @param publishTime Unix timestamp describing when the price was published.\n */\nstruct FormattedPythPrice {\n    uint256 price;\n    uint256 conf;\n    uint256 publishTime;\n}\n\n/**\n * @notice The price and timestamp returned by the Redstone oracle.\n * @param price The asset price formatted by the middleware.\n * @param timestamp The timestamp of the price data.\n */\nstruct RedstonePriceInfo {\n    uint256 price;\n    uint256 timestamp;\n}\n\n/**\n * @notice The different confidence interval of a Pyth price.\n * @dev Applied to the neutral price and available as `price`.\n * @param Up Adjusted price at the upper bound of the confidence interval.\n * @param Down Adjusted price at the lower bound of the confidence interval.\n * @param None Neutral price without adjustment.\n */\nenum ConfidenceInterval {\n    Up,\n    Down,\n    None\n}\n"},{"file_path":"src/interfaces/LiquidationRewardsManager/IBaseLiquidationRewardsManager.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IUsdnProtocolTypes as Types } from \"../UsdnProtocol/IUsdnProtocolTypes.sol\";\n\n/**\n * @title IBaseLiquidationRewardsManager\n * @notice This interface exposes the only function used by the UsdnProtocol.\n * @dev Future implementations of the rewards manager must implement this interface without modifications.\n */\ninterface IBaseLiquidationRewardsManager {\n    /**\n     * @notice Computes the amount of assets to reward a liquidator.\n     * @param liquidatedTicks Information about the liquidated ticks.\n     * @param currentPrice The current price of the asset.\n     * @param rebased Indicates whether a USDN rebase was performed.\n     * @param rebalancerAction The action performed by the {UsdnProtocolLongLibrary._triggerRebalancer} function.\n     * @param action The type of protocol action that triggered the liquidation.\n     * @param rebaseCallbackResult The result of the rebase callback, if any.\n     * @param priceData The oracle price data, if any. This can be used to differentiate rewards based on the oracle\n     * used to provide the liquidation price.\n     * @return assetRewards_ The amount of asset tokens to reward the liquidator.\n     */\n    function getLiquidationRewards(\n        Types.LiqTickInfo[] calldata liquidatedTicks,\n        uint256 currentPrice,\n        bool rebased,\n        Types.RebalancerAction rebalancerAction,\n        Types.ProtocolAction action,\n        bytes calldata rebaseCallbackResult,\n        bytes calldata priceData\n    ) external view returns (uint256 assetRewards_);\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/utils/math/Math.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Floor, // Toward negative infinity\n        Ceil, // Toward positive infinity\n        Trunc, // Toward zero\n        Expand // Away from zero\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, with an success flag (no overflow).\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n     *\n     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n     * one branch when needed, making this function more expensive.\n     */\n    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n        unchecked {\n            // branchless ternary works because:\n            // b ^ (a ^ b) == a\n            // b ^ 0 == b\n            return b ^ ((a ^ b) * SafeCast.toUint(condition));\n        }\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return ternary(a > b, a, b);\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return ternary(a < b, a, b);\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds towards infinity instead\n     * of rounding towards zero.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            // Guarantee the same behavior as in a regular Solidity division.\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n\n        // The following calculation ensures accurate ceiling division without overflow.\n        // Since a is non-zero, (a - 1) / b will not overflow.\n        // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n        // but the largest value we can obtain is type(uint256).max - 1, which happens\n        // when a = type(uint256).max and b = 1.\n        unchecked {\n            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n        }\n    }\n\n    /**\n     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n     * denominator == 0.\n     *\n     * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n     * Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n            // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2²⁵⁶ + prod0.\n            uint256 prod0 = x * y; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n            if (denominator <= prod1) {\n                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n            }\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n            uint256 twos = denominator & (0 - denominator);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n            // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n            // works in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n            inverse *= 2 - denominator * inverse; // inverse mod 2³²\n            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n            // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n    }\n\n    /**\n     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n     *\n     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n     *\n     * If the input value is not inversible, 0 is returned.\n     *\n     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n     */\n    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n        unchecked {\n            if (n == 0) return 0;\n\n            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n            // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n            // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n            // ax + ny = 1\n            // ax = 1 + (-y)n\n            // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n            // If the remainder is 0 the gcd is n right away.\n            uint256 remainder = a % n;\n            uint256 gcd = n;\n\n            // Therefore the initial coefficients are:\n            // ax + ny = gcd(a, n) = n\n            // 0a + 1n = n\n            int256 x = 0;\n            int256 y = 1;\n\n            while (remainder != 0) {\n                uint256 quotient = gcd / remainder;\n\n                (gcd, remainder) = (\n                    // The old remainder is the next gcd to try.\n                    remainder,\n                    // Compute the next remainder.\n                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n                    // where gcd is at most n (capped to type(uint256).max)\n                    gcd - remainder * quotient\n                );\n\n                (x, y) = (\n                    // Increment the coefficient of a.\n                    y,\n                    // Decrement the coefficient of n.\n                    // Can overflow, but the result is casted to uint256 so that the\n                    // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n                    x - y * int256(quotient)\n                );\n            }\n\n            if (gcd != 1) return 0; // No inverse exists.\n            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n        }\n    }\n\n    /**\n     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n     *\n     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n     *\n     * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n     */\n    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n        unchecked {\n            return Math.modExp(a, p - 2, p);\n        }\n    }\n\n    /**\n     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n     *\n     * Requirements:\n     * - modulus can't be zero\n     * - underlying staticcall to precompile must succeed\n     *\n     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n     * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n     * interpreted as 0.\n     */\n    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n        (bool success, uint256 result) = tryModExp(b, e, m);\n        if (!success) {\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n     * to operate modulo 0 or if the underlying precompile reverted.\n     *\n     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n     * of a revert, but the result may be incorrectly interpreted as 0.\n     */\n    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n        if (m == 0) return (false, 0);\n        assembly (\"memory-safe\") {\n            let ptr := mload(0x40)\n            // | Offset    | Content    | Content (Hex)                                                      |\n            // |-----------|------------|--------------------------------------------------------------------|\n            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n            // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n            // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n            mstore(ptr, 0x20)\n            mstore(add(ptr, 0x20), 0x20)\n            mstore(add(ptr, 0x40), 0x20)\n            mstore(add(ptr, 0x60), b)\n            mstore(add(ptr, 0x80), e)\n            mstore(add(ptr, 0xa0), m)\n\n            // Given the result < m, it's guaranteed to fit in 32 bytes,\n            // so we can use the memory scratch space located at offset 0.\n            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n            result := mload(0x00)\n        }\n    }\n\n    /**\n     * @dev Variant of {modExp} that supports inputs of arbitrary length.\n     */\n    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n        (bool success, bytes memory result) = tryModExp(b, e, m);\n        if (!success) {\n            Panic.panic(Panic.DIVISION_BY_ZERO);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n     */\n    function tryModExp(\n        bytes memory b,\n        bytes memory e,\n        bytes memory m\n    ) internal view returns (bool success, bytes memory result) {\n        if (_zeroBytes(m)) return (false, new bytes(0));\n\n        uint256 mLen = m.length;\n\n        // Encode call args in result and move the free memory pointer\n        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n        assembly (\"memory-safe\") {\n            let dataPtr := add(result, 0x20)\n            // Write result on top of args to avoid allocating extra memory.\n            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n            // Overwrite the length.\n            // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n            mstore(result, mLen)\n            // Set the memory pointer after the returned data.\n            mstore(0x40, add(dataPtr, mLen))\n        }\n    }\n\n    /**\n     * @dev Returns whether the provided byte array is zero.\n     */\n    function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n        for (uint256 i = 0; i < byteArray.length; ++i) {\n            if (byteArray[i] != 0) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n     * towards zero.\n     *\n     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n     * using integer operations.\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        unchecked {\n            // Take care of easy edge cases when a == 0 or a == 1\n            if (a <= 1) {\n                return a;\n            }\n\n            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n            // the current value as `ε_n = | x_n - sqrt(a) |`.\n            //\n            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n            // bigger than any uint256.\n            //\n            // By noticing that\n            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n            // to the msb function.\n            uint256 aa = a;\n            uint256 xn = 1;\n\n            if (aa >= (1 << 128)) {\n                aa >>= 128;\n                xn <<= 64;\n            }\n            if (aa >= (1 << 64)) {\n                aa >>= 64;\n                xn <<= 32;\n            }\n            if (aa >= (1 << 32)) {\n                aa >>= 32;\n                xn <<= 16;\n            }\n            if (aa >= (1 << 16)) {\n                aa >>= 16;\n                xn <<= 8;\n            }\n            if (aa >= (1 << 8)) {\n                aa >>= 8;\n                xn <<= 4;\n            }\n            if (aa >= (1 << 4)) {\n                aa >>= 4;\n                xn <<= 2;\n            }\n            if (aa >= (1 << 2)) {\n                xn <<= 1;\n            }\n\n            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n            //\n            // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n            // This is going to be our x_0 (and ε_0)\n            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n            // From here, Newton's method give us:\n            // x_{n+1} = (x_n + a / x_n) / 2\n            //\n            // One should note that:\n            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n            //              = ((x_n² + a) / (2 * x_n))² - a\n            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n            //              = (x_n² - a)² / (2 * x_n)²\n            //              = ((x_n² - a) / (2 * x_n))²\n            //              ≥ 0\n            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n            //\n            // This gives us the proof of quadratic convergence of the sequence:\n            // ε_{n+1} = | x_{n+1} - sqrt(a) |\n            //         = | (x_n + a / x_n) / 2 - sqrt(a) |\n            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n            //         = | (x_n - sqrt(a))² / (2 * x_n) |\n            //         = | ε_n² / (2 * x_n) |\n            //         = ε_n² / | (2 * x_n) |\n            //\n            // For the first iteration, we have a special case where x_0 is known:\n            // ε_1 = ε_0² / | (2 * x_0) |\n            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))\n            //     ≤ 2**(e-3) / 3\n            //     ≤ 2**(e-3-log2(3))\n            //     ≤ 2**(e-4.5)\n            //\n            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n            // ε_{n+1} = ε_n² / | (2 * x_n) |\n            //         ≤ (2**(e-k))² / (2 * 2**(e-1))\n            //         ≤ 2**(2*e-2*k) / 2**e\n            //         ≤ 2**(e-2*k)\n            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above\n            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5\n            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9\n            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18\n            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36\n            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72\n\n            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n            // sqrt(a) or sqrt(a) + 1.\n            return xn - SafeCast.toUint(xn > a / xn);\n        }\n    }\n\n    /**\n     * @dev Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        uint256 exp;\n        unchecked {\n            exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);\n            value >>= exp;\n            result += exp;\n\n            exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);\n            value >>= exp;\n            result += exp;\n\n            result += SafeCast.toUint(value > 1);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256 of a positive value rounded towards zero.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        uint256 isGt;\n        unchecked {\n            isGt = SafeCast.toUint(value > (1 << 128) - 1);\n            value >>= isGt * 128;\n            result += isGt * 16;\n\n            isGt = SafeCast.toUint(value > (1 << 64) - 1);\n            value >>= isGt * 64;\n            result += isGt * 8;\n\n            isGt = SafeCast.toUint(value > (1 << 32) - 1);\n            value >>= isGt * 32;\n            result += isGt * 4;\n\n            isGt = SafeCast.toUint(value > (1 << 16) - 1);\n            value >>= isGt * 16;\n            result += isGt * 2;\n\n            result += SafeCast.toUint(value > (1 << 8) - 1);\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n        }\n    }\n\n    /**\n     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n     */\n    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n        return uint8(rounding) % 2 == 1;\n    }\n}\n"},{"file_path":"dependencies/solady-0.0.228/src/utils/LibBitmap.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {LibBit} from \"./LibBit.sol\";\n\n/// @notice Library for storage of packed unsigned booleans.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)\n/// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol)\nlibrary LibBitmap {\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         CONSTANTS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev The constant returned when a bitmap scan does not find a result.\n    uint256 internal constant NOT_FOUND = type(uint256).max;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                          STRUCTS                           */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev A bitmap in storage.\n    struct Bitmap {\n        mapping(uint256 => uint256) map;\n    }\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         OPERATIONS                         */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    /// @dev Returns the boolean value of the bit at `index` in `bitmap`.\n    function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) {\n        // It is better to set `isSet` to either 0 or 1, than zero vs non-zero.\n        // Both cost the same amount of gas, but the former allows the returned value\n        // to be reused without cleaning the upper bits.\n        uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1;\n        /// @solidity memory-safe-assembly\n        assembly {\n            isSet := b\n        }\n    }\n\n    /// @dev Updates the bit at `index` in `bitmap` to true.\n    function set(Bitmap storage bitmap, uint256 index) internal {\n        bitmap.map[index >> 8] |= (1 << (index & 0xff));\n    }\n\n    /// @dev Updates the bit at `index` in `bitmap` to false.\n    function unset(Bitmap storage bitmap, uint256 index) internal {\n        bitmap.map[index >> 8] &= ~(1 << (index & 0xff));\n    }\n\n    /// @dev Flips the bit at `index` in `bitmap`.\n    /// Returns the boolean result of the flipped bit.\n    function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x20, bitmap.slot)\n            mstore(0x00, shr(8, index))\n            let storageSlot := keccak256(0x00, 0x40)\n            let shift := and(index, 0xff)\n            let storageValue := xor(sload(storageSlot), shl(shift, 1))\n            // It makes sense to return the `newIsSet`,\n            // as it allow us to skip an additional warm `sload`,\n            // and it costs minimal gas (about 15),\n            // which may be optimized away if the returned value is unused.\n            newIsSet := and(1, shr(shift, storageValue))\n            sstore(storageSlot, storageValue)\n        }\n    }\n\n    /// @dev Updates the bit at `index` in `bitmap` to `shouldSet`.\n    function setTo(Bitmap storage bitmap, uint256 index, bool shouldSet) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x20, bitmap.slot)\n            mstore(0x00, shr(8, index))\n            let storageSlot := keccak256(0x00, 0x40)\n            let storageValue := sload(storageSlot)\n            let shift := and(index, 0xff)\n            sstore(\n                storageSlot,\n                // Unsets the bit at `shift` via `and`, then sets its new value via `or`.\n                or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet))))\n            )\n        }\n    }\n\n    /// @dev Consecutively sets `amount` of bits starting from the bit at `start`.\n    function setBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let max := not(0)\n            let shift := and(start, 0xff)\n            mstore(0x20, bitmap.slot)\n            mstore(0x00, shr(8, start))\n            if iszero(lt(add(shift, amount), 257)) {\n                let storageSlot := keccak256(0x00, 0x40)\n                sstore(storageSlot, or(sload(storageSlot), shl(shift, max)))\n                let bucket := add(mload(0x00), 1)\n                let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))\n                amount := and(add(amount, shift), 0xff)\n                shift := 0\n                for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {\n                    mstore(0x00, bucket)\n                    sstore(keccak256(0x00, 0x40), max)\n                }\n                mstore(0x00, bucket)\n            }\n            let storageSlot := keccak256(0x00, 0x40)\n            sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max))))\n        }\n    }\n\n    /// @dev Consecutively unsets `amount` of bits starting from the bit at `start`.\n    function unsetBatch(Bitmap storage bitmap, uint256 start, uint256 amount) internal {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let shift := and(start, 0xff)\n            mstore(0x20, bitmap.slot)\n            mstore(0x00, shr(8, start))\n            if iszero(lt(add(shift, amount), 257)) {\n                let storageSlot := keccak256(0x00, 0x40)\n                sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0)))))\n                let bucket := add(mload(0x00), 1)\n                let bucketEnd := add(mload(0x00), shr(8, add(amount, shift)))\n                amount := and(add(amount, shift), 0xff)\n                shift := 0\n                for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } {\n                    mstore(0x00, bucket)\n                    sstore(keccak256(0x00, 0x40), 0)\n                }\n                mstore(0x00, bucket)\n            }\n            let storageSlot := keccak256(0x00, 0x40)\n            sstore(\n                storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))\n            )\n        }\n    }\n\n    /// @dev Returns number of set bits within a range by\n    /// scanning `amount` of bits starting from the bit at `start`.\n    function popCount(Bitmap storage bitmap, uint256 start, uint256 amount)\n        internal\n        view\n        returns (uint256 count)\n    {\n        unchecked {\n            uint256 bucket = start >> 8;\n            uint256 shift = start & 0xff;\n            if (!(amount + shift < 257)) {\n                count = LibBit.popCount(bitmap.map[bucket] >> shift);\n                uint256 bucketEnd = bucket + ((amount + shift) >> 8);\n                amount = (amount + shift) & 0xff;\n                shift = 0;\n                for (++bucket; bucket != bucketEnd; ++bucket) {\n                    count += LibBit.popCount(bitmap.map[bucket]);\n                }\n            }\n            count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount));\n        }\n    }\n\n    /// @dev Returns the index of the most significant set bit in `[0..upTo]`.\n    /// If no set bit is found, returns `NOT_FOUND`.\n    function findLastSet(Bitmap storage bitmap, uint256 upTo)\n        internal\n        view\n        returns (uint256 setBitIndex)\n    {\n        setBitIndex = NOT_FOUND;\n        uint256 bucket = upTo >> 8;\n        uint256 bits;\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, bucket)\n            mstore(0x20, bitmap.slot)\n            let offset := and(0xff, not(upTo)) // `256 - (255 & upTo) - 1`.\n            bits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40))))\n            if iszero(or(bits, iszero(bucket))) {\n                for {} 1 {} {\n                    bucket := add(bucket, setBitIndex) // `sub(bucket, 1)`.\n                    mstore(0x00, bucket)\n                    bits := sload(keccak256(0x00, 0x40))\n                    if or(bits, iszero(bucket)) { break }\n                }\n            }\n        }\n        if (bits != 0) {\n            setBitIndex = (bucket << 8) | LibBit.fls(bits);\n            /// @solidity memory-safe-assembly\n            assembly {\n                setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, upTo)))\n            }\n        }\n    }\n\n    /// @dev Returns the index of the least significant unset bit in `[begin..upTo]`.\n    /// If no unset bit is found, returns `NOT_FOUND`.\n    function findFirstUnset(Bitmap storage bitmap, uint256 begin, uint256 upTo)\n        internal\n        view\n        returns (uint256 unsetBitIndex)\n    {\n        unsetBitIndex = NOT_FOUND;\n        uint256 bucket = begin >> 8;\n        uint256 negBits;\n        /// @solidity memory-safe-assembly\n        assembly {\n            mstore(0x00, bucket)\n            mstore(0x20, bitmap.slot)\n            let offset := and(0xff, begin)\n            negBits := shl(offset, shr(offset, not(sload(keccak256(0x00, 0x40)))))\n            if iszero(negBits) {\n                let lastBucket := shr(8, upTo)\n                for {} 1 {} {\n                    bucket := add(bucket, 1)\n                    mstore(0x00, bucket)\n                    negBits := not(sload(keccak256(0x00, 0x40)))\n                    if or(negBits, gt(bucket, lastBucket)) { break }\n                }\n                if gt(bucket, lastBucket) {\n                    negBits := shl(and(0xff, not(upTo)), shr(and(0xff, not(upTo)), negBits))\n                }\n            }\n        }\n        if (negBits != 0) {\n            uint256 r = (bucket << 8) | LibBit.ffs(negBits);\n            /// @solidity memory-safe-assembly\n            assembly {\n                unsetBitIndex := or(r, sub(0, or(gt(r, upTo), lt(r, begin))))\n            }\n        }\n    }\n}\n"},{"file_path":"src/utils/InitializableReentrancyGuard.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\n/**\n * @title Reentrancy Guard with Initializer Check\n * @notice Contract module that helps prevent reentrant calls to a function and ensures the initializer has been called.\n * Based on the OpenZeppelin implementation.\n */\nabstract contract InitializableReentrancyGuard {\n    /// @notice The uninitialized state of the contract.\n    uint256 private constant UNINITIALIZED = 0;\n    /// @notice The state of the contract before entering a function.\n    uint256 private constant NOT_ENTERED = 1;\n    /// @notice The state of the contract after entering a function.\n    uint256 private constant ENTERED = 2;\n\n    /**\n     * @custom:storage-location erc7201:InitializableReentrancyGuard.storage.status\n     * @notice The storage structure of the contract.\n     * @dev Booleans are more expensive than uint256 or any type that takes up a full word because each write operation\n     * emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean and then write\n     * back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.\n     * @param _status The state of the contract.\n     */\n    struct InitializableReentrancyGuardStorage {\n        /// @notice The state of the contract.\n        uint256 _status;\n    }\n\n    /**\n     * @notice The storage slot of the {InitializableReentrancyGuardStorage} struct.\n     * @dev `keccak256(abi.encode(uint256(keccak256(\"InitializableReentrancyGuard.storage.status\")) - 1)) &\n     * ~bytes32(uint256(0xff))`\n     */\n    bytes32 private constant STORAGE_STATUS = 0x6f33a3bc64034eea47937f56d5e165f09a61a6a995142939d6f3e40f101ea600;\n\n    /**\n     * @notice Gets the struct pointer of the contract storage.\n     * @return s_ The pointer to the struct.\n     */\n    function _getInitializableReentrancyGuardStorage()\n        internal\n        pure\n        returns (InitializableReentrancyGuardStorage storage s_)\n    {\n        assembly {\n            s_.slot := STORAGE_STATUS\n        }\n    }\n\n    /// @dev Unauthorized reentrant call.\n    error InitializableReentrancyGuardReentrantCall();\n\n    /// @dev Contract was not yet initialized.\n    error InitializableReentrancyGuardUninitialized();\n\n    /// @dev Contract was already initialized.\n    error InitializableReentrancyGuardInvalidInitialization();\n\n    /// @notice Initializes the storage slot on first deployment.\n    function __initializeReentrancyGuard_init() internal {\n        InitializableReentrancyGuardStorage storage s = _getInitializableReentrancyGuardStorage();\n\n        s._status = UNINITIALIZED;\n    }\n\n    /**\n     * @notice Reverts if the contract is not initialized or in case of a reentrancy.\n     * @dev Prevents a contract from calling itself, directly or indirectly, or using it in an uninitialized state.\n     * Calling an {initializedAndNonReentrant} function before the {IUsdnProtocolCore.initialize} function was called\n     * will revert. Calling an {initializedAndNonReentrant} function from another {initializedAndNonReentrant} function\n     * is not supported.\n     */\n    modifier initializedAndNonReentrant() {\n        _checkInitialized();\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    /// @notice Reverts if the contract is initialized, or sets it as initialized.\n    modifier protocolInitializer() {\n        _checkUninitialized();\n        _;\n\n        InitializableReentrancyGuardStorage storage s = _getInitializableReentrancyGuardStorage();\n\n        s._status = NOT_ENTERED; // mark initialized\n    }\n\n    /// @notice Reverts if the contract is not initialized.\n    function _checkInitialized() private view {\n        InitializableReentrancyGuardStorage storage s = _getInitializableReentrancyGuardStorage();\n\n        if (s._status == UNINITIALIZED) {\n            revert InitializableReentrancyGuardUninitialized();\n        }\n    }\n\n    /// @notice Reverts if the contract is initialized.\n    function _checkUninitialized() internal view {\n        InitializableReentrancyGuardStorage storage s = _getInitializableReentrancyGuardStorage();\n\n        if (s._status != UNINITIALIZED) {\n            revert InitializableReentrancyGuardInvalidInitialization();\n        }\n    }\n\n    /// @notice Reverts if `_status` is `ENTERED`, or sets it to `ENTERED`.\n    function _nonReentrantBefore() private {\n        InitializableReentrancyGuardStorage storage s = _getInitializableReentrancyGuardStorage();\n\n        // on the first call to `nonReentrant`, `_status` will be `NOT_ENTERED`\n        if (s._status == ENTERED) {\n            revert InitializableReentrancyGuardReentrantCall();\n        }\n\n        // any calls to `nonReentrant` after this point will fail\n        s._status = ENTERED;\n    }\n\n    /// @notice Sets `_status` to `NOT_ENTERED`\n    function _nonReentrantAfter() private {\n        InitializableReentrancyGuardStorage storage s = _getInitializableReentrancyGuardStorage();\n\n        // by storing the original value once again, a refund is triggered (see https://eips.ethereum.org/EIPS/eip-2200)\n        s._status = NOT_ENTERED;\n    }\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolTypes.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { HugeUint } from \"@smardex-solidity-libraries-1/HugeUint.sol\";\nimport { LibBitmap } from \"solady/src/utils/LibBitmap.sol\";\n\nimport { DoubleEndedQueue } from \"../../libraries/DoubleEndedQueue.sol\";\nimport { IBaseLiquidationRewardsManager } from \"../LiquidationRewardsManager/IBaseLiquidationRewardsManager.sol\";\nimport { IBaseOracleMiddleware } from \"../OracleMiddleware/IBaseOracleMiddleware.sol\";\nimport { IBaseRebalancer } from \"../Rebalancer/IBaseRebalancer.sol\";\nimport { IUsdn } from \"../Usdn/IUsdn.sol\";\n\ninterface IUsdnProtocolTypes {\n    /**\n     * @notice All possible action types for the protocol.\n     * @dev This is used for pending actions and to interact with the oracle middleware.\n     * @param None No particular action.\n     * @param Initialize The contract is being initialized.\n     * @param InitiateDeposit Initiating a `deposit` action.\n     * @param ValidateDeposit Validating a `deposit` action.\n     * @param InitiateWithdrawal Initiating a `withdraw` action.\n     * @param ValidateWithdrawal Validating a `withdraw` action.\n     * @param InitiateOpenPosition Initiating an `open` position action.\n     * @param ValidateOpenPosition Validating an `open` position action.\n     * @param InitiateClosePosition Initiating a `close` position action.\n     * @param ValidateClosePosition Validating a `close` position action.\n     * @param Liquidation The price is requested for a liquidation action.\n     */\n    enum ProtocolAction {\n        None,\n        Initialize,\n        InitiateDeposit,\n        ValidateDeposit,\n        InitiateWithdrawal,\n        ValidateWithdrawal,\n        InitiateOpenPosition,\n        ValidateOpenPosition,\n        InitiateClosePosition,\n        ValidateClosePosition,\n        Liquidation\n    }\n\n    /**\n     * @notice The outcome of the call targeting a long position.\n     * @param Processed The call did what it was supposed to do.\n     * An initiate close has been completed / a pending action was validated.\n     * @param Liquidated The position has been liquidated by this call.\n     * @param PendingLiquidations The call cannot be completed because of pending liquidations.\n     * Try calling the {IUsdnProtocolActions.liquidate} function with a fresh price to unblock the situation.\n     */\n    enum LongActionOutcome {\n        Processed,\n        Liquidated,\n        PendingLiquidations\n    }\n\n    /**\n     * @notice Classifies how far in its logic the {UsdnProtocolLongLibrary._triggerRebalancer} function made it to.\n     * @dev Used to estimate the gas spent by the function call to more accurately calculate liquidation rewards.\n     * @param None The rebalancer is not set.\n     * @param NoImbalance The protocol imbalance is not reached.\n     * @param PendingLiquidation The rebalancer position should be liquidated.\n     * @param NoCloseNoOpen The action neither closes nor opens a position.\n     * @param Closed The action only closes a position.\n     * @param Opened The action only opens a position.\n     * @param ClosedOpened The action closes and opens a position.\n     */\n    enum RebalancerAction {\n        None,\n        NoImbalance,\n        PendingLiquidation,\n        NoCloseNoOpen,\n        Closed,\n        Opened,\n        ClosedOpened\n    }\n\n    /**\n     * @notice Information about a long user position.\n     * @param validated Whether the position was validated.\n     * @param timestamp The timestamp of the position start.\n     * @param user The user's address.\n     * @param totalExpo The total exposure of the position (0 for vault deposits). The product of the initial\n     * collateral and the initial leverage.\n     * @param amount The amount of initial collateral in the position.\n     */\n    struct Position {\n        bool validated; // 1 byte\n        uint40 timestamp; // 5 bytes. Max 1_099_511_627_775 (36812-02-20 01:36:15)\n        address user; // 20 bytes\n        uint128 totalExpo; // 16 bytes. Max 340_282_366_920_938_463_463.374_607_431_768_211_455 ether\n        uint128 amount; // 16 bytes\n    }\n\n    /**\n     * @notice A pending action in the queue.\n     * @param action The action type.\n     * @param timestamp The timestamp of the initiate action.\n     * @param var0 See {DepositPendingAction}, {WithdrawalPendingAction} and {LongPendingAction}.\n     * @param to The target of the action.\n     * @param validator The address that is supposed to validate the action.\n     * @param securityDepositValue The security deposit of the pending action.\n     * @param var1 See {DepositPendingAction}, {WithdrawalPendingAction} and {LongPendingAction}.\n     * @param var2 See {DepositPendingAction}, {WithdrawalPendingAction} and {LongPendingAction}.\n     * @param var3 See {DepositPendingAction}, {WithdrawalPendingAction} and {LongPendingAction}.\n     * @param var4 See {DepositPendingAction}, {WithdrawalPendingAction} and {LongPendingAction}.\n     * @param var5 See {DepositPendingAction}, {WithdrawalPendingAction} and {LongPendingAction}.\n     * @param var6 See {DepositPendingAction}, {WithdrawalPendingAction} and {LongPendingAction}.\n     * @param var7 See {DepositPendingAction}, {WithdrawalPendingAction} and {LongPendingAction}.\n     */\n    struct PendingAction {\n        ProtocolAction action; // 1 byte\n        uint40 timestamp; // 5 bytes\n        uint24 var0; // 3 bytes\n        address to; // 20 bytes\n        address validator; // 20 bytes\n        uint64 securityDepositValue; // 8 bytes\n        int24 var1; // 3 bytes\n        uint128 var2; // 16 bytes\n        uint128 var3; // 16 bytes\n        uint256 var4; // 32 bytes\n        uint256 var5; // 32 bytes\n        uint256 var6; // 32 bytes\n        uint256 var7; // 32 bytes\n    }\n\n    /**\n     * @notice A pending action in the queue for a vault deposit.\n     * @param action The action type.\n     * @param timestamp The timestamp of the initiate action.\n     * @param feeBps Fee for the deposit, in BPS.\n     * @param to The recipient of the funds.\n     * @param validator The address that is supposed to validate the action.\n     * @param securityDepositValue The security deposit of the pending action.\n     * @param _unused Unused field to align the struct to `PendingAction`.\n     * @param amount The amount of assets of the pending deposit.\n     * @param assetPrice The price of the asset at the time of the last update.\n     * @param totalExpo The total exposure at the time of the last update.\n     * @param balanceVault The balance of the vault at the time of the last update.\n     * @param balanceLong The balance of the long position at the time of the last update.\n     * @param usdnTotalShares The total supply of USDN shares at the time of the action.\n     */\n    struct DepositPendingAction {\n        ProtocolAction action; // 1 byte\n        uint40 timestamp; // 5 bytes\n        uint24 feeBps; // 3 bytes\n        address to; // 20 bytes\n        address validator; // 20 bytes\n        uint64 securityDepositValue; // 8 bytes\n        uint24 _unused; // 3 bytes\n        uint128 amount; // 16 bytes\n        uint128 assetPrice; // 16 bytes\n        uint256 totalExpo; // 32 bytes\n        uint256 balanceVault; // 32 bytes\n        uint256 balanceLong; // 32 bytes\n        uint256 usdnTotalShares; // 32 bytes\n    }\n\n    /**\n     * @notice A pending action in the queue for a vault withdrawal.\n     * @param action The action type.\n     * @param timestamp The timestamp of the initiate action.\n     * @param feeBps Fee for the withdrawal, in BPS.\n     * @param to The recipient of the funds.\n     * @param validator The address that is supposed to validate the action.\n     * @param securityDepositValue The security deposit of the pending action.\n     * @param sharesLSB 3 least significant bytes of the withdrawal shares amount (uint152).\n     * @param sharesMSB 16 most significant bytes of the withdrawal shares amount (uint152).\n     * @param assetPrice The price of the asset at the time of the last update.\n     * @param totalExpo The total exposure at the time of the last update.\n     * @param balanceVault The balance of the vault at the time of the last update.\n     * @param balanceLong The balance of the long position at the time of the last update.\n     * @param usdnTotalShares The total shares supply of USDN at the time of the action.\n     */\n    struct WithdrawalPendingAction {\n        ProtocolAction action; // 1 byte\n        uint40 timestamp; // 5 bytes\n        uint24 feeBps; // 3 bytes\n        address to; // 20 bytes\n        address validator; // 20 bytes\n        uint64 securityDepositValue; // 8 bytes\n        uint24 sharesLSB; // 3 bytes\n        uint128 sharesMSB; // 16 bytes\n        uint128 assetPrice; // 16 bytes\n        uint256 totalExpo; // 32 bytes\n        uint256 balanceVault; // 32 bytes\n        uint256 balanceLong; // 32 bytes\n        uint256 usdnTotalShares; // 32 bytes\n    }\n\n    /**\n     * @notice A pending action in the queue for a long position.\n     * @param action The action type.\n     * @param timestamp The timestamp of the initiate action.\n     * @param closeLiqPenalty The liquidation penalty of the tick (only used when closing a position).\n     * @param to The recipient of the position.\n     * @param validator The address that is supposed to validate the action.\n     * @param securityDepositValue The security deposit of the pending action.\n     * @param tick The tick of the position.\n     * @param closeAmount The portion of the initial position amount to close (only used when closing a position).\n     * @param closePosTotalExpo The total expo of the position (only used when closing a position).\n     * @param tickVersion The version of the tick.\n     * @param index The index of the position in the tick list.\n     * @param liqMultiplier A fixed precision representation of the liquidation multiplier (with\n     * `LIQUIDATION_MULTIPLIER_DECIMALS` decimals) used to calculate the effective price for a given tick number.\n     * @param closeBoundedPositionValue The amount that was removed from the long balance on\n     * {IUsdnProtocolActions.initiateClosePosition} (only used when closing a position).\n     */\n    struct LongPendingAction {\n        ProtocolAction action; // 1 byte\n        uint40 timestamp; // 5 bytes\n        uint24 closeLiqPenalty; // 3 bytes\n        address to; // 20 bytes\n        address validator; // 20 bytes\n        uint64 securityDepositValue; // 8 bytes\n        int24 tick; // 3 bytes\n        uint128 closeAmount; // 16 bytes\n        uint128 closePosTotalExpo; // 16 bytes\n        uint256 tickVersion; // 32 bytes\n        uint256 index; // 32 bytes\n        uint256 liqMultiplier; // 32 bytes\n        uint256 closeBoundedPositionValue; // 32 bytes\n    }\n\n    /**\n     * @notice The data allowing to validate an actionable pending action.\n     * @param priceData An array of bytes, each representing the data to be forwarded to the oracle middleware to\n     * validate a pending action in the queue.\n     * @param rawIndices An array of raw indices in the pending actions queue, in the same order as the corresponding\n     * priceData.\n     */\n    struct PreviousActionsData {\n        bytes[] priceData;\n        uint128[] rawIndices;\n    }\n\n    /**\n     * @notice Information of a liquidated tick.\n     * @param totalPositions The total number of positions in the tick.\n     * @param totalExpo The total expo of the tick.\n     * @param remainingCollateral The remaining collateral after liquidation.\n     * @param tickPrice The corresponding price.\n     * @param priceWithoutPenalty The price without the liquidation penalty.\n     */\n    struct LiqTickInfo {\n        uint256 totalPositions;\n        uint256 totalExpo;\n        int256 remainingCollateral;\n        uint128 tickPrice;\n        uint128 priceWithoutPenalty;\n    }\n\n    /**\n     * @notice The effects of executed liquidations on the protocol.\n     * @param liquidatedPositions The total number of liquidated positions.\n     * @param remainingCollateral The remaining collateral after liquidation.\n     * @param newLongBalance The new balance of the long side.\n     * @param newVaultBalance The new balance of the vault side.\n     * @param isLiquidationPending Whether some ticks are still populated above the current price (left to liquidate).\n     * @param liquidatedTicks Information about the liquidated ticks.\n     */\n    struct LiquidationsEffects {\n        uint256 liquidatedPositions;\n        int256 remainingCollateral;\n        uint256 newLongBalance;\n        uint256 newVaultBalance;\n        bool isLiquidationPending;\n        LiqTickInfo[] liquidatedTicks;\n    }\n\n    /**\n     * @notice Accumulator for tick data.\n     * @param totalExpo The sum of the total expo of each position in the tick.\n     * @param totalPos The number of positions in the tick.\n     * @param liquidationPenalty The liquidation penalty for the positions in the tick.\n     * @dev Since the liquidation penalty is a parameter that can be updated, we need to ensure that positions that get\n     * created with a given penalty, use this penalty throughout their lifecycle. As such, once a tick gets populated by\n     * a first position, it gets assigned the current liquidation penalty parameter value and can't use another value\n     * until it gets liquidated or all positions exit the tick.\n     */\n    struct TickData {\n        uint256 totalExpo;\n        uint248 totalPos;\n        uint24 liquidationPenalty;\n    }\n\n    /**\n     * @notice The unique identifier for a long position.\n     * @param tick The tick of the position.\n     * @param tickVersion The version of the tick.\n     * @param index The index of the position in the tick list.\n     */\n    struct PositionId {\n        int24 tick;\n        uint256 tickVersion;\n        uint256 index;\n    }\n\n    /**\n     * @notice Parameters for the internal {UsdnProtocolActionsLongLibrary._initiateOpenPosition} function.\n     * @param user The address of the user initiating the open position.\n     * @param to The address that will be the owner of the position.\n     * @param validator The address that is supposed to validate the action.\n     * @param amount The amount of assets to deposit.\n     * @param desiredLiqPrice The desired liquidation price, including the liquidation penalty.\n     * @param userMaxPrice The maximum price at which the position can be opened. The userMaxPrice is compared with the\n     * price after confidence interval, penalty, etc...\n     * @param userMaxLeverage The maximum leverage for the newly created position.\n     * @param deadline The deadline of the open position to be initiated.\n     * @param securityDepositValue The value of the security deposit for the newly created pending action.\n     * @param currentPriceData The current price data (used to calculate the temporary leverage and entry price,\n     * pending validation).\n     */\n    struct InitiateOpenPositionParams {\n        address user;\n        address to;\n        address validator;\n        uint128 amount;\n        uint128 desiredLiqPrice;\n        uint128 userMaxPrice;\n        uint256 userMaxLeverage;\n        uint256 deadline;\n        uint64 securityDepositValue;\n    }\n\n    /**\n     * @notice Parameters for the internal {UsdnProtocolLongLibrary._prepareInitiateOpenPosition} function.\n     * @param validator The address that is supposed to validate the action.\n     * @param amount The amount of assets to deposit.\n     * @param desiredLiqPrice The desired liquidation price, including the liquidation penalty.\n     * @param userMaxPrice The maximum price at which the position can be opened. The userMaxPrice is compared with the\n     * price after confidence interval, penalty, etc...\n     * @param userMaxLeverage The maximum leverage for the newly created position.\n     * @param currentPriceData The current price data.\n     */\n    struct PrepareInitiateOpenPositionParams {\n        address validator;\n        uint128 amount;\n        uint128 desiredLiqPrice;\n        uint256 userMaxPrice;\n        uint256 userMaxLeverage;\n        bytes currentPriceData;\n    }\n\n    /**\n     * @notice Parameters for the internal {UsdnProtocolActionsUtilsLibrary._prepareClosePositionData} function.\n     * @param to The recipient of the funds.\n     * @param validator The address that is supposed to validate the action.\n     * @param posId The unique identifier of the position.\n     * @param amountToClose The amount of collateral to remove from the position's amount.\n     * @param userMinPrice The minimum price at which the position can be closed.\n     * @param deadline The deadline until the position can be closed.\n     * @param currentPriceData The current price data.\n     * @param delegationSignature An EIP712 signature that proves the caller is authorized by the owner of the position\n     * to close it on their behalf.\n     * @param domainSeparatorV4 The domain separator v4.\n     */\n    struct PrepareInitiateClosePositionParams {\n        address to;\n        address validator;\n        PositionId posId;\n        uint128 amountToClose;\n        uint256 userMinPrice;\n        uint256 deadline;\n        bytes currentPriceData;\n        bytes delegationSignature;\n        bytes32 domainSeparatorV4;\n    }\n\n    /**\n     * @notice Parameters for the internal {UsdnProtocolActionsLongLibrary._initiateClosePosition} function.\n     * @param to The recipient of the funds.\n     * @param validator The address that is supposed to validate the action.\n     * @param posId The unique identifier of the position.\n     * @param amountToClose The amount to close.\n     * @param userMinPrice The minimum price at which the position can be closed.\n     * @param deadline The deadline of the close position to be initiated.\n     * @param securityDepositValue The value of the security deposit for the newly created pending action.\n     * @param domainSeparatorV4 The domain separator v4 for EIP712 signature.\n     */\n    struct InitiateClosePositionParams {\n        address to;\n        address payable validator;\n        uint256 deadline;\n        PositionId posId;\n        uint128 amountToClose;\n        uint256 userMinPrice;\n        uint64 securityDepositValue;\n        bytes32 domainSeparatorV4;\n    }\n\n    /**\n     * @dev Structure to hold the transient data during {UsdnProtocolActionsLongLibrary._initiateClosePosition}\n     * @param pos The position to close.\n     * @param liquidationPenalty The liquidation penalty.\n     * @param totalExpoToClose The total expo to close.\n     * @param lastPrice The price after the last balances update.\n     * @param tempPositionValue The bounded value of the position that was removed from the long balance.\n     * @param longTradingExpo The long trading expo.\n     * @param liqMulAcc The liquidation multiplier accumulator.\n     * @param isLiquidationPending Whether some ticks are still populated above the current price (left to liquidate).\n     */\n    struct ClosePositionData {\n        Position pos;\n        uint24 liquidationPenalty;\n        uint128 totalExpoToClose;\n        uint128 lastPrice;\n        uint256 tempPositionValue;\n        uint256 longTradingExpo;\n        HugeUint.Uint512 liqMulAcc;\n        bool isLiquidationPending;\n    }\n\n    /**\n     * @dev Structure to hold the transient data during {UsdnProtocolActionsLongLibrary._validateOpenPosition}.\n     * @param action The long pending action.\n     * @param startPrice The new entry price of the position.\n     * @param lastPrice The price of the last balances update.\n     * @param tickHash The tick hash.\n     * @param pos The position object.\n     * @param liqPriceWithoutPenaltyNorFunding The liquidation price without penalty nor funding used to calculate the\n     * user leverage and the new total expo.\n     * @param liqPriceWithoutPenalty The new liquidation price without penalty.\n     * @param leverage The new leverage.\n     * @param oldPosValue The value of the position according to the old entry price and the _lastPrice.\n     * @param liquidationPenalty The liquidation penalty for the position's tick.\n     * @param isLiquidationPending Whether some ticks are still populated above the current price (left to liquidate).\n     */\n    struct ValidateOpenPositionData {\n        LongPendingAction action;\n        uint128 startPrice;\n        uint128 lastPrice;\n        bytes32 tickHash;\n        Position pos;\n        uint128 liqPriceWithoutPenaltyNorFunding;\n        uint128 liqPriceWithoutPenalty;\n        uint256 leverage;\n        uint256 oldPosValue;\n        uint24 liquidationPenalty;\n        bool isLiquidationPending;\n    }\n\n    /**\n     * @dev Structure to hold the transient data during {UsdnProtocolActionsLongLibrary._initiateOpenPosition}.\n     * @param adjustedPrice The adjusted price with position fees applied.\n     * @param posId The unique identifier of the position.\n     * @param liquidationPenalty The liquidation penalty.\n     * @param positionTotalExpo The total expo of the position. The product of the initial collateral and the initial\n     * leverage.\n     * @param positionValue The value of the position, taking into account the position fee.\n     * @param liqMultiplier The liquidation multiplier represented with fixed precision.\n     * @param isLiquidationPending Whether some ticks are still populated above the current price (left to liquidate).\n     */\n    struct InitiateOpenPositionData {\n        uint128 adjustedPrice;\n        PositionId posId;\n        uint24 liquidationPenalty;\n        uint128 positionTotalExpo;\n        uint256 positionValue;\n        uint256 liqMultiplier;\n        bool isLiquidationPending;\n    }\n\n    /**\n     * @notice Structure to hold the state of the protocol.\n     * @param totalExpo The long total expo.\n     * @param tradingExpo The long trading expo.\n     * @param longBalance The long balance.\n     * @param vaultBalance The vault balance.\n     * @param liqMultiplierAccumulator The liquidation multiplier accumulator.\n     */\n    struct CachedProtocolState {\n        uint256 totalExpo;\n        uint256 tradingExpo;\n        uint256 longBalance;\n        uint256 vaultBalance;\n        HugeUint.Uint512 liqMultiplierAccumulator;\n    }\n\n    /**\n     * @notice Structure to hold transient data during the {UsdnProtocolActionsLongLibrary._calcRebalancerPositionTick}\n     * function.\n     * @param protocolMaxLeverage The protocol maximum leverage.\n     * @param longImbalanceTargetBps The long imbalance target in basis points.\n     * @param tradingExpoToFill The trading expo to fill.\n     * @param highestUsableTradingExpo The highest usable trading expo.\n     * @param currentLiqPenalty The current liquidation penalty.\n     * @param liqPriceWithoutPenalty The liquidation price without penalty.\n     */\n    struct CalcRebalancerPositionTickData {\n        uint256 protocolMaxLeverage;\n        int256 longImbalanceTargetBps;\n        uint256 tradingExpoToFill;\n        uint256 highestUsableTradingExpo;\n        uint24 currentLiqPenalty;\n        uint128 liqPriceWithoutPenalty;\n    }\n\n    /**\n     * @notice Structure to hold the return values of the {UsdnProtocolActionsLongLibrary._calcRebalancerPositionTick}\n     * function.\n     * @param tick The tick of the rebalancer position, includes liquidation penalty.\n     * @param totalExpo The total expo of the rebalancer position.\n     * @param liquidationPenalty The liquidation penalty of the tick.\n     */\n    struct RebalancerPositionData {\n        int24 tick;\n        uint128 totalExpo;\n        uint24 liquidationPenalty;\n    }\n\n    /**\n     * @notice Data structure for the {UsdnProtocolCoreLibrary._applyPnlAndFunding} function.\n     * @param tempLongBalance The new balance of the long side, could be negative (temporarily).\n     * @param tempVaultBalance The new balance of the vault side, could be negative (temporarily).\n     * @param lastPrice The last price.\n     */\n    struct ApplyPnlAndFundingData {\n        int256 tempLongBalance;\n        int256 tempVaultBalance;\n        uint128 lastPrice;\n    }\n\n    /**\n     * @notice Data structure for tick to price conversion functions.\n     * @param tradingExpo The long side trading expo.\n     * @param accumulator The liquidation multiplier accumulator.\n     * @param tickSpacing The tick spacing.\n     */\n    struct TickPriceConversionData {\n        uint256 tradingExpo;\n        HugeUint.Uint512 accumulator;\n        int24 tickSpacing;\n    }\n\n    /**\n     * @custom:storage-location erc7201:UsdnProtocol.storage.main.\n     * @notice Structure to hold the state of the protocol.\n     * @param _tickSpacing The liquidation tick spacing for storing long positions.\n     * A tick spacing of 1 is equivalent to a 0.01% increase in liquidation price between ticks. A tick spacing of\n     * 100 is equivalent to a ~1.005% increase in liquidation price between ticks.\n     * @param _asset The asset ERC20 contract.\n     * Assets with a blacklist are not supported because the protocol would be DoS if transfers revert.\n     * @param _assetDecimals The number of decimals used by the `_asset`.\n     * @param _priceFeedDecimals The price feed decimals (18).\n     * @param _usdn The USDN ERC20 contract.\n     * @param _sdex The SDEX ERC20 contract.\n     * @param _usdnMinDivisor The minimum divisor for USDN.\n     * @param _oracleMiddleware The oracle middleware contract.\n     * @param _liquidationRewardsManager The liquidation rewards manager contract.\n     * @param _rebalancer The rebalancer contract.\n     * @param _isRebalancer Whether an address is or has been a rebalancer.\n     * @param _minLeverage The minimum leverage for a position.\n     * @param _maxLeverage The maximum leverage for a position.\n     * @param _lowLatencyValidatorDeadline The deadline for a user to confirm their action with a low-latency oracle.\n     * After this deadline, any user can validate the action with the low-latency oracle until the\n     * OracleMiddleware's _lowLatencyDelay. This is an offset compared to the timestamp of the initiate action.\n     * @param _onChainValidatorDeadline The deadline for a user to confirm their action with an on-chain oracle.\n     * After this deadline, any user can validate the action with the on-chain oracle. This is an offset compared\n     * to the timestamp of the initiate action + the oracle middleware's _lowLatencyDelay.\n     * @param _safetyMarginBps Safety margin for the liquidation price of newly open positions, in basis points.\n     * @param _liquidationIteration The number of iterations to perform during the user's action (in tick).\n     * @param _protocolFeeBps The protocol fee in basis points.\n     * @param _rebalancerBonusBps Part of the remaining collateral that is given as a bonus to the Rebalancer upon\n     * liquidation of a tick, in basis points. The rest is sent to the Vault balance.\n     * @param _liquidationPenalty The liquidation penalty (in ticks).\n     * @param _EMAPeriod The moving average period of the funding rate.\n     * @param _fundingSF The scaling factor (SF) of the funding rate.\n     * @param _feeThreshold The threshold above which the fee will be sent.\n     * @param _openExpoImbalanceLimitBps The imbalance limit of the long expo for open actions (in basis points).\n     * As soon as the difference between the vault expo and the long expo exceeds this basis point limit in favor\n     * of long the open rebalancing mechanism is triggered, preventing the opening of a new long position.\n     * @param _withdrawalExpoImbalanceLimitBps The imbalance limit of the long expo for withdrawal actions (in basis\n     * points). As soon as the difference between vault expo and long expo exceeds this basis point limit in favor of\n     * long, the withdrawal rebalancing mechanism is triggered, preventing the withdrawal of the existing vault\n     * position.\n     * @param _depositExpoImbalanceLimitBps The imbalance limit of the vault expo for deposit actions (in basis points).\n     * As soon as the difference between the vault expo and the long expo exceeds this basis point limit in favor\n     * of the vault, the deposit vault rebalancing mechanism is triggered, preventing the opening of a new vault\n     * position.\n     * @param _closeExpoImbalanceLimitBps The imbalance limit of the vault expo for close actions (in basis points).\n     * As soon as the difference between the vault expo and the long expo exceeds this basis point limit in favor\n     * of the vault, the close rebalancing mechanism is triggered, preventing the close of an existing long position.\n     * @param _rebalancerCloseExpoImbalanceLimitBps The imbalance limit of the vault expo for close actions from the\n     * rebalancer (in basis points). As soon as the difference between the vault expo and the long expo exceeds this\n     * basis point limit in favor of the vault, the close rebalancing mechanism is triggered, preventing the close of an\n     * existing long position from the rebalancer contract.\n     * @param _longImbalanceTargetBps The target imbalance on the long side (in basis points)\n     * This value will be used to calculate how much of the missing trading expo the rebalancer position will try\n     * to compensate. A negative value means the rebalancer will compensate enough to go above the equilibrium. A\n     * positive value means the rebalancer will compensate but stay below the equilibrium.\n     * @param _positionFeeBps The position fee in basis points.\n     * @param _vaultFeeBps The fee for vault deposits and withdrawals, in basis points.\n     * @param _sdexRewardsRatioBps The ratio of SDEX rewards to send to the user (in basis points).\n     * @param _sdexBurnOnDepositRatio The ratio of USDN to SDEX tokens to burn on deposit.\n     * @param _feeCollector The fee collector's address.\n     * @param _securityDepositValue The deposit required for a new position.\n     * @param _targetUsdnPrice The nominal (target) price of USDN (with _priceFeedDecimals).\n     * @param _usdnRebaseThreshold The USDN price threshold to trigger a rebase (with _priceFeedDecimals).\n     * @param _minLongPosition The minimum long position size (with `_assetDecimals`).\n     * @param _lastFundingPerDay The funding rate calculated at the last update timestamp.\n     * @param _lastPrice The price of the asset during the last balances update (with price feed decimals).\n     * @param _lastUpdateTimestamp The timestamp of the last balances update.\n     * @param _pendingProtocolFee The pending protocol fee accumulator.\n     * @param _pendingActions The pending actions by the user (1 per user max).\n     * The value stored is an index into the `pendingActionsQueue` deque, shifted by one. A value of 0 means no\n     * pending action. Since the deque uses uint128 indices, the highest index will not overflow when adding one.\n     * @param _pendingActionsQueue The queue of pending actions.\n     * @param _balanceVault The balance of deposits (with `_assetDecimals`).\n     * @param _pendingBalanceVault The unreflected balance change due to pending vault actions (with `_assetDecimals`).\n     * @param _EMA The exponential moving average of the funding (0.0003 at initialization).\n     * @param _balanceLong The balance of long positions (with `_assetDecimals`).\n     * @param _totalExpo The total exposure of the long positions (with `_assetDecimals`).\n     * @param _liqMultiplierAccumulator The accumulator used to calculate the liquidation multiplier.\n     * This is the sum, for all ticks, of the total expo of positions inside the tick, multiplied by the\n     * unadjusted price of the tick which is `_tickData[tickHash].liquidationPenalty` below\n     * The unadjusted price is obtained with `TickMath.getPriceAtTick.\n     * @param _tickVersion The liquidation tick version.\n     * @param _longPositions The long positions per versioned tick (liquidation price).\n     * @param _tickData Accumulated data for a given tick and tick version.\n     * @param _highestPopulatedTick The highest tick with a position.\n     * @param _totalLongPositions Cache of the total long positions count.\n     * @param _tickBitmap The bitmap used to quickly find populated ticks.\n     * @param _protocolFallbackAddr The address of the fallback contract.\n     * @param _nonce The user EIP712 nonce.\n     */\n    struct Storage {\n        // immutable\n        int24 _tickSpacing;\n        IERC20Metadata _asset;\n        uint8 _assetDecimals;\n        uint8 _priceFeedDecimals;\n        IUsdn _usdn;\n        IERC20Metadata _sdex;\n        uint256 _usdnMinDivisor;\n        // parameters\n        IBaseOracleMiddleware _oracleMiddleware;\n        IBaseLiquidationRewardsManager _liquidationRewardsManager;\n        IBaseRebalancer _rebalancer;\n        mapping(address => bool) _isRebalancer;\n        uint256 _minLeverage;\n        uint256 _maxLeverage;\n        uint128 _lowLatencyValidatorDeadline;\n        uint128 _onChainValidatorDeadline;\n        uint256 _safetyMarginBps;\n        uint16 _liquidationIteration;\n        uint16 _protocolFeeBps;\n        uint16 _rebalancerBonusBps;\n        uint24 _liquidationPenalty;\n        uint128 _EMAPeriod;\n        uint256 _fundingSF;\n        uint256 _feeThreshold;\n        int256 _openExpoImbalanceLimitBps;\n        int256 _withdrawalExpoImbalanceLimitBps;\n        int256 _depositExpoImbalanceLimitBps;\n        int256 _closeExpoImbalanceLimitBps;\n        int256 _rebalancerCloseExpoImbalanceLimitBps;\n        int256 _longImbalanceTargetBps;\n        uint16 _positionFeeBps;\n        uint16 _vaultFeeBps;\n        uint16 _sdexRewardsRatioBps;\n        uint32 _sdexBurnOnDepositRatio;\n        address _feeCollector;\n        uint64 _securityDepositValue;\n        uint128 _targetUsdnPrice;\n        uint128 _usdnRebaseThreshold;\n        uint256 _minLongPosition;\n        // state\n        int256 _lastFundingPerDay;\n        uint128 _lastPrice;\n        uint128 _lastUpdateTimestamp;\n        uint256 _pendingProtocolFee;\n        // pending actions queue\n        mapping(address => uint256) _pendingActions;\n        DoubleEndedQueue.Deque _pendingActionsQueue;\n        // vault\n        uint256 _balanceVault;\n        int256 _pendingBalanceVault;\n        // long positions\n        int256 _EMA;\n        uint256 _balanceLong;\n        uint256 _totalExpo;\n        HugeUint.Uint512 _liqMultiplierAccumulator;\n        mapping(int24 => uint256) _tickVersion;\n        mapping(bytes32 => Position[]) _longPositions;\n        mapping(bytes32 => TickData) _tickData;\n        int24 _highestPopulatedTick;\n        uint256 _totalLongPositions;\n        LibBitmap.Bitmap _tickBitmap;\n        // fallback\n        address _protocolFallbackAddr;\n        // EIP712\n        mapping(address => uint256) _nonce;\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/utils/math/SafeCast.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n    /**\n     * @dev Value doesn't fit in an uint of `bits` size.\n     */\n    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n    /**\n     * @dev An int value doesn't fit in an uint of `bits` size.\n     */\n    error SafeCastOverflowedIntToUint(int256 value);\n\n    /**\n     * @dev Value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n    /**\n     * @dev An uint value doesn't fit in an int of `bits` size.\n     */\n    error SafeCastOverflowedUintToInt(uint256 value);\n\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        if (value > type(uint248).max) {\n            revert SafeCastOverflowedUintDowncast(248, value);\n        }\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        if (value > type(uint240).max) {\n            revert SafeCastOverflowedUintDowncast(240, value);\n        }\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        if (value > type(uint232).max) {\n            revert SafeCastOverflowedUintDowncast(232, value);\n        }\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        if (value > type(uint224).max) {\n            revert SafeCastOverflowedUintDowncast(224, value);\n        }\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        if (value > type(uint216).max) {\n            revert SafeCastOverflowedUintDowncast(216, value);\n        }\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        if (value > type(uint208).max) {\n            revert SafeCastOverflowedUintDowncast(208, value);\n        }\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        if (value > type(uint200).max) {\n            revert SafeCastOverflowedUintDowncast(200, value);\n        }\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        if (value > type(uint192).max) {\n            revert SafeCastOverflowedUintDowncast(192, value);\n        }\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        if (value > type(uint184).max) {\n            revert SafeCastOverflowedUintDowncast(184, value);\n        }\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        if (value > type(uint176).max) {\n            revert SafeCastOverflowedUintDowncast(176, value);\n        }\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        if (value > type(uint168).max) {\n            revert SafeCastOverflowedUintDowncast(168, value);\n        }\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        if (value > type(uint160).max) {\n            revert SafeCastOverflowedUintDowncast(160, value);\n        }\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        if (value > type(uint152).max) {\n            revert SafeCastOverflowedUintDowncast(152, value);\n        }\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        if (value > type(uint144).max) {\n            revert SafeCastOverflowedUintDowncast(144, value);\n        }\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        if (value > type(uint136).max) {\n            revert SafeCastOverflowedUintDowncast(136, value);\n        }\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        if (value > type(uint128).max) {\n            revert SafeCastOverflowedUintDowncast(128, value);\n        }\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        if (value > type(uint120).max) {\n            revert SafeCastOverflowedUintDowncast(120, value);\n        }\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        if (value > type(uint112).max) {\n            revert SafeCastOverflowedUintDowncast(112, value);\n        }\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        if (value > type(uint104).max) {\n            revert SafeCastOverflowedUintDowncast(104, value);\n        }\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        if (value > type(uint96).max) {\n            revert SafeCastOverflowedUintDowncast(96, value);\n        }\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        if (value > type(uint88).max) {\n            revert SafeCastOverflowedUintDowncast(88, value);\n        }\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        if (value > type(uint80).max) {\n            revert SafeCastOverflowedUintDowncast(80, value);\n        }\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        if (value > type(uint72).max) {\n            revert SafeCastOverflowedUintDowncast(72, value);\n        }\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        if (value > type(uint64).max) {\n            revert SafeCastOverflowedUintDowncast(64, value);\n        }\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        if (value > type(uint56).max) {\n            revert SafeCastOverflowedUintDowncast(56, value);\n        }\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        if (value > type(uint48).max) {\n            revert SafeCastOverflowedUintDowncast(48, value);\n        }\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        if (value > type(uint40).max) {\n            revert SafeCastOverflowedUintDowncast(40, value);\n        }\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        if (value > type(uint32).max) {\n            revert SafeCastOverflowedUintDowncast(32, value);\n        }\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        if (value > type(uint24).max) {\n            revert SafeCastOverflowedUintDowncast(24, value);\n        }\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        if (value > type(uint16).max) {\n            revert SafeCastOverflowedUintDowncast(16, value);\n        }\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        if (value > type(uint8).max) {\n            revert SafeCastOverflowedUintDowncast(8, value);\n        }\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        if (value < 0) {\n            revert SafeCastOverflowedIntToUint(value);\n        }\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(248, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(240, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(232, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(224, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(216, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(208, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(200, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(192, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(184, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(176, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(168, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(160, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(152, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(144, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(136, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(128, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(120, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(112, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(104, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(96, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(88, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(80, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(72, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(64, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(56, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(48, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(40, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(32, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(24, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(16, value);\n        }\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        if (downcasted != value) {\n            revert SafeCastOverflowedIntDowncast(8, value);\n        }\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        if (value > uint256(type(int256).max)) {\n            revert SafeCastOverflowedUintToInt(value);\n        }\n        return int256(value);\n    }\n\n    /**\n     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n     */\n    function toUint(bool b) internal pure returns (uint256 u) {\n        assembly (\"memory-safe\") {\n            u := iszero(iszero(b))\n        }\n    }\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolFallback.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport { HugeUint } from \"@smardex-solidity-libraries-1/HugeUint.sol\";\n\nimport { IBaseLiquidationRewardsManager } from \"../LiquidationRewardsManager/IBaseLiquidationRewardsManager.sol\";\nimport { IBaseOracleMiddleware } from \"../OracleMiddleware/IBaseOracleMiddleware.sol\";\nimport { IBaseRebalancer } from \"../Rebalancer/IBaseRebalancer.sol\";\nimport { IUsdn } from \"../Usdn/IUsdn.sol\";\nimport { IUsdnProtocolTypes } from \"./IUsdnProtocolTypes.sol\";\n\n/**\n * @title IUsdnProtocolFallback\n * @notice Interface for the USDN protocol fallback functions\n */\ninterface IUsdnProtocolFallback is IUsdnProtocolTypes {\n    /**\n     * @notice Retrieves the list of pending actions that must be validated by the next user action in the protocol.\n     * @dev If this function returns a non-empty list of pending actions, then the next user action MUST include the\n     * corresponding list of price update data and raw indices as the last parameter. The user that processes those\n     * pending actions will receive the corresponding security deposit.\n     * @param currentUser The address of the user that will submit the price signatures for third-party actions\n     * validations. This is used to filter out their actions from the returned list.\n     * @param lookAhead Additionally to pending actions which are actionable at this moment `block.timestamp`, the\n     * function will also return pending actions which will be actionable `lookAhead` seconds later. It is recommended\n     * to use a non-zero value in order to account for the interval where the validation transaction will be pending. A\n     * value of 30 seconds should already account for most situations and avoid reverts in case an action becomes\n     * actionable after a user submits their transaction.\n     * @param maxIter The maximum number of iterations when looking through the queue to find actionable pending\n     * actions. This value will be clamped to [MIN_ACTIONABLE_PENDING_ACTIONS_ITER,_pendingActionsQueue.length()].\n     * @return actions_ The pending actions if any, otherwise an empty array.\n     * @return rawIndices_ The raw indices of the actionable pending actions in the queue if any, otherwise an empty\n     * array. Each entry corresponds to the action in the `actions_` array, at the same index.\n     */\n    function getActionablePendingActions(address currentUser, uint256 lookAhead, uint256 maxIter)\n        external\n        view\n        returns (PendingAction[] memory actions_, uint128[] memory rawIndices_);\n\n    /**\n     * @notice Retrieves the pending action with `user` as the given validator.\n     * @param user The user's address.\n     * @return action_ The pending action if any, otherwise a struct with all fields set to zero and\n     * `ProtocolAction.None`.\n     */\n    function getUserPendingAction(address user) external view returns (PendingAction memory action_);\n\n    /**\n     * @notice Computes the hash generated from the given tick number and version.\n     * @param tick The tick number.\n     * @param version The tick version.\n     * @return hash_ The hash of the given tick number and version.\n     */\n    function tickHash(int24 tick, uint256 version) external pure returns (bytes32 hash_);\n\n    /**\n     * @notice Computes the liquidation price of the given tick number, taking into account the effects of funding.\n     * @dev Uses the values from storage for the various variables. Note that ticks that are\n     * not a multiple of the tick spacing cannot contain a long position.\n     * @param tick The tick number.\n     * @return price_ The liquidation price.\n     */\n    function getEffectivePriceForTick(int24 tick) external view returns (uint128 price_);\n\n    /**\n     * @notice Computes the liquidation price of the given tick number, taking into account the effects of funding.\n     * @dev Uses the given values instead of the ones from the storage. Note that ticks that are not a multiple of the\n     * tick spacing cannot contain a long position.\n     * @param tick The tick number.\n     * @param assetPrice The current/projected price of the asset.\n     * @param longTradingExpo The trading exposure of the long side (total expo - balance long).\n     * @param accumulator The liquidation multiplier accumulator.\n     * @return price_ The liquidation price.\n     */\n    function getEffectivePriceForTick(\n        int24 tick,\n        uint256 assetPrice,\n        uint256 longTradingExpo,\n        HugeUint.Uint512 memory accumulator\n    ) external view returns (uint128 price_);\n\n    /**\n     * @notice Computes an estimate of the amount of assets received when withdrawing.\n     * @dev The result is a rough estimate and does not take into account rebases and liquidations.\n     * @param usdnShares The amount of USDN shares to use in the withdrawal.\n     * @param price The current/projected price of the asset.\n     * @param timestamp The The timestamp corresponding to `price`.\n     * @return assetExpected_ The expected amount of assets to be received.\n     */\n    function previewWithdraw(uint256 usdnShares, uint128 price, uint128 timestamp)\n        external\n        view\n        returns (uint256 assetExpected_);\n\n    /**\n     * @notice Computes an estimate of USDN tokens to be minted and SDEX tokens to be burned when depositing.\n     * @dev The result is a rough estimate and does not take into account rebases and liquidations.\n     * @param amount The amount of assets to deposit.\n     * @param price The current/projected price of the asset.\n     * @param timestamp The timestamp corresponding to `price`.\n     * @return usdnSharesExpected_ The amount of USDN shares to be minted.\n     * @return sdexToBurn_ The amount of SDEX tokens to be burned.\n     */\n    function previewDeposit(uint256 amount, uint128 price, uint128 timestamp)\n        external\n        view\n        returns (uint256 usdnSharesExpected_, uint256 sdexToBurn_);\n\n    /**\n     * @notice Refunds the security deposit to the given validator if it has a liquidated initiated long position.\n     * @dev The security deposit is always sent to the validator even if the pending action is actionable.\n     * @param validator The address of the validator (must be payable as it will receive some native currency).\n     */\n    function refundSecurityDeposit(address payable validator) external;\n\n    /// @notice Sends the accumulated SDEX token fees to the dead address. This function can be called by anyone.\n    function burnSdex() external;\n\n    /* -------------------------------------------------------------------------- */\n    /*                               Admin functions                              */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice Removes a stuck pending action and performs the minimal amount of cleanup necessary.\n     * @dev This function can only be called by the owner of the protocol, it serves as an escape hatch if a\n     * pending action ever gets stuck due to something internal reverting unexpectedly.\n     * It will not refund any fees or burned SDEX.\n     * @param validator The address of the validator of the stuck pending action.\n     * @param to Where the retrieved funds should be sent (security deposit, assets, usdn). Must be payable.\n     */\n    function removeBlockedPendingAction(address validator, address payable to) external;\n\n    /**\n     * @notice Removes a stuck pending action with no cleanup.\n     * @dev This function can only be called by the owner of the protocol, it serves as an escape hatch if a\n     * pending action ever gets stuck due to something internal reverting unexpectedly.\n     * Always try to use `removeBlockedPendingAction` first, and only call this function if the other one fails.\n     * It will not refund any fees or burned SDEX.\n     * @param validator The address of the validator of the stuck pending action.\n     * @param to Where the retrieved funds should be sent (security deposit, assets, usdn). Must be payable.\n     */\n    function removeBlockedPendingActionNoCleanup(address validator, address payable to) external;\n\n    /**\n     * @notice Removes a stuck pending action and performs the minimal amount of cleanup necessary.\n     * @dev This function can only be called by the owner of the protocol, it serves as an escape hatch if a\n     * pending action ever gets stuck due to something internal reverting unexpectedly.\n     * It will not refund any fees or burned SDEX.\n     * @param rawIndex The raw index of the stuck pending action.\n     * @param to Where the retrieved funds should be sent (security deposit, assets, usdn). Must be payable.\n     */\n    function removeBlockedPendingAction(uint128 rawIndex, address payable to) external;\n\n    /**\n     * @notice Removes a stuck pending action with no cleanup.\n     * @dev This function can only be called by the owner of the protocol, it serves as an escape hatch if a\n     * pending action ever gets stuck due to something internal reverting unexpectedly.\n     * Always try to use `removeBlockedPendingAction` first, and only call this function if the other one fails.\n     * It will not refund any fees or burned SDEX.\n     * @param rawIndex The raw index of the stuck pending action.\n     * @param to Where the retrieved funds should be sent (security deposit, assets, usdn). Must be payable.\n     */\n    function removeBlockedPendingActionNoCleanup(uint128 rawIndex, address payable to) external;\n\n    /* -------------------------------------------------------------------------- */\n    /*                             Immutables getters                             */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice The number of ticks between usable ticks. Only tick numbers that are a multiple of the tick spacing can\n     * be used for storing long positions.\n     * @dev A tick spacing of 1 is equivalent to a 0.01% increase in price between ticks. A tick spacing of 100 is.\n     * equivalent to a ~1.005% increase in price between ticks.\n     * @return tickSpacing_ The tick spacing.\n     */\n    function getTickSpacing() external view returns (int24 tickSpacing_);\n\n    /**\n     * @notice Gets the address of the protocol's underlying asset (ERC20 token).\n     * @return asset_ The address of the asset token.\n     */\n    function getAsset() external view returns (IERC20Metadata asset_);\n\n    /**\n     * @notice Gets the address of the SDEX ERC20 token.\n     * @return sdex_ The address of the SDEX token.\n     */\n    function getSdex() external view returns (IERC20Metadata sdex_);\n\n    /**\n     * @notice Gets the number of decimals of the asset's price feed.\n     * @return decimals_ The number of decimals of the asset's price feed.\n     */\n    function getPriceFeedDecimals() external view returns (uint8 decimals_);\n\n    /**\n     * @notice Gets the number of decimals of the underlying asset token.\n     * @return decimals_ The number of decimals of the asset token.\n     */\n    function getAssetDecimals() external view returns (uint8 decimals_);\n\n    /**\n     * @notice Gets the address of the USDN ERC20 token.\n     * @return usdn_ The address of USDN ERC20 token.\n     */\n    function getUsdn() external view returns (IUsdn usdn_);\n\n    /**\n     * @notice Gets the `MIN_DIVISOR` constant of the USDN token.\n     * @dev Check the USDN contract for more information.\n     * @return minDivisor_ The `MIN_DIVISOR` constant of the USDN token.\n     */\n    function getUsdnMinDivisor() external view returns (uint256 minDivisor_);\n\n    /* -------------------------------------------------------------------------- */\n    /*                             Parameters getters                             */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice Gets the oracle middleware contract.\n     * @return oracleMiddleware_ The address of the oracle middleware contract.\n     */\n    function getOracleMiddleware() external view returns (IBaseOracleMiddleware oracleMiddleware_);\n\n    /**\n     * @notice Gets the liquidation rewards manager contract.\n     * @return liquidationRewardsManager_ The address of the liquidation rewards manager contract.\n     */\n    function getLiquidationRewardsManager()\n        external\n        view\n        returns (IBaseLiquidationRewardsManager liquidationRewardsManager_);\n\n    /**\n     * @notice Gets the rebalancer contract.\n     * @return rebalancer_ The address of the rebalancer contract.\n     */\n    function getRebalancer() external view returns (IBaseRebalancer rebalancer_);\n\n    /**\n     * @notice Gets the lowest leverage that can be used to open a long position.\n     * @return minLeverage_ The minimum leverage (with `LEVERAGE_DECIMALS` decimals).\n     */\n    function getMinLeverage() external view returns (uint256 minLeverage_);\n\n    /**\n     * @notice Gets the highest leverage that can be used to open a long position.\n     * @dev A position can have a leverage a bit higher than this value under specific conditions involving\n     * a change to the liquidation penalty setting.\n     * @return maxLeverage_ The maximum leverage value (with `LEVERAGE_DECIMALS` decimals).\n     */\n    function getMaxLeverage() external view returns (uint256 maxLeverage_);\n\n    /**\n     * @notice Gets the deadline of the exclusivity period for the validator of a pending action with a low-latency\n     * oracle.\n     * @dev After this deadline, any user can validate the action with the low-latency oracle until the\n     * OracleMiddleware's `_lowLatencyDelay`, and retrieve the security deposit for the pending action.\n     * @return deadline_ The low-latency validation deadline of a validator (in seconds).\n     */\n    function getLowLatencyValidatorDeadline() external view returns (uint128 deadline_);\n\n    /**\n     * @notice Gets the deadline of the exclusivity period for the validator to confirm their action with the on-chain\n     * oracle.\n     * @dev After this deadline, any user can validate the pending action with the on-chain oracle and retrieve its\n     * security deposit.\n     * @return deadline_ The on-chain validation deadline of a validator (in seconds)\n     */\n    function getOnChainValidatorDeadline() external view returns (uint128 deadline_);\n\n    /**\n     * @notice Gets the liquidation penalty applied to the liquidation price when opening a position.\n     * @return liquidationPenalty_ The liquidation penalty (in ticks).\n     */\n    function getLiquidationPenalty() external view returns (uint24 liquidationPenalty_);\n\n    /**\n     * @notice Gets the safety margin for the liquidation price of newly open positions.\n     * @return safetyMarginBps_ The safety margin (in basis points).\n     */\n    function getSafetyMarginBps() external view returns (uint256 safetyMarginBps_);\n\n    /**\n     * @notice Gets the number of tick liquidations to perform when attempting to\n     * liquidate positions during user actions.\n     * @return iterations_ The number of iterations for liquidations during user actions.\n     */\n    function getLiquidationIteration() external view returns (uint16 iterations_);\n\n    /**\n     * @notice Gets the time frame for the EMA calculations.\n     * @dev The EMA is set to the last funding rate when the time elapsed between 2 actions is greater than this value.\n     * @return period_ The time frame of the EMA (in seconds).\n     */\n    function getEMAPeriod() external view returns (uint128 period_);\n\n    /**\n     * @notice Gets the scaling factor (SF) of the funding rate.\n     * @return scalingFactor_ The scaling factor (with `FUNDING_SF_DECIMALS` decimals).\n     */\n    function getFundingSF() external view returns (uint256 scalingFactor_);\n\n    /**\n     * @notice Gets the fee taken by the protocol during the application of funding.\n     * @return feeBps_ The fee applied to the funding (in basis points).\n     */\n    function getProtocolFeeBps() external view returns (uint16 feeBps_);\n\n    /**\n     * @notice Gets the fee applied when a long position is opened or closed.\n     * @return feeBps_ The fee applied to a long position (in basis points).\n     */\n    function getPositionFeeBps() external view returns (uint16 feeBps_);\n\n    /**\n     * @notice Gets the fee applied during a vault deposit or withdrawal.\n     * @return feeBps_ The fee applied to a vault action (in basis points).\n     */\n    function getVaultFeeBps() external view returns (uint16 feeBps_);\n\n    /**\n     * @notice Gets the rewards ratio given to the caller when burning SDEX tokens.\n     * @return rewardsBps_ The rewards ratio (in basis points).\n     */\n    function getSdexRewardsRatioBps() external view returns (uint16 rewardsBps_);\n\n    /**\n     * @notice Gets the part of the remaining collateral given as a bonus to the Rebalancer upon liquidation of a tick.\n     * @return bonusBps_ The fraction of the remaining collateral for the Rebalancer bonus (in basis points).\n     */\n    function getRebalancerBonusBps() external view returns (uint16 bonusBps_);\n\n    /**\n     * @notice Gets the ratio of SDEX tokens to burn per minted USDN.\n     * @return ratio_ The ratio (to be divided by SDEX_BURN_ON_DEPOSIT_DIVISOR).\n     */\n    function getSdexBurnOnDepositRatio() external view returns (uint32 ratio_);\n\n    /**\n     * @notice Gets the amount of native tokens used as security deposit when opening a new position.\n     * @return securityDeposit_ The amount of assets to use as a security deposit (in ether).\n     */\n    function getSecurityDepositValue() external view returns (uint64 securityDeposit_);\n\n    /**\n     * @notice Gets the threshold to reach to send accumulated fees to the fee collector.\n     * @return threshold_ The amount of accumulated fees to reach (in `_assetDecimals`).\n     */\n    function getFeeThreshold() external view returns (uint256 threshold_);\n\n    /**\n     * @notice Gets the address of the fee collector.\n     * @return feeCollector_ The address of the fee collector.\n     */\n    function getFeeCollector() external view returns (address feeCollector_);\n\n    /**\n     * @notice Returns the amount of time to wait before an action can be validated.\n     * @dev This is also the amount of time to add to the initiate action timestamp to fetch the correct price data to\n     * validate said action with a low-latency oracle.\n     * @return delay_ The validation delay (in seconds).\n     */\n    function getMiddlewareValidationDelay() external view returns (uint256 delay_);\n\n    /**\n     * @notice Gets the expo imbalance limit when depositing assets (in basis points).\n     * @return depositExpoImbalanceLimitBps_ The deposit expo imbalance limit.\n     */\n    function getDepositExpoImbalanceLimitBps() external view returns (int256 depositExpoImbalanceLimitBps_);\n\n    /**\n     * @notice Gets the expo imbalance limit when withdrawing assets (in basis points).\n     * @return withdrawalExpoImbalanceLimitBps_ The withdrawal expo imbalance limit.\n     */\n    function getWithdrawalExpoImbalanceLimitBps() external view returns (int256 withdrawalExpoImbalanceLimitBps_);\n\n    /**\n     * @notice Gets the expo imbalance limit when opening a position (in basis points).\n     * @return openExpoImbalanceLimitBps_ The open expo imbalance limit.\n     */\n    function getOpenExpoImbalanceLimitBps() external view returns (int256 openExpoImbalanceLimitBps_);\n\n    /**\n     * @notice Gets the expo imbalance limit when closing a position (in basis points).\n     * @return closeExpoImbalanceLimitBps_ The close expo imbalance limit.\n     */\n    function getCloseExpoImbalanceLimitBps() external view returns (int256 closeExpoImbalanceLimitBps_);\n\n    /**\n     * @notice Returns the limit of the imbalance in bps to close the rebalancer position.\n     * @return rebalancerCloseExpoImbalanceLimitBps_ The limit of the imbalance in bps to close the rebalancer position.\n     */\n    function getRebalancerCloseExpoImbalanceLimitBps()\n        external\n        view\n        returns (int256 rebalancerCloseExpoImbalanceLimitBps_);\n\n    /**\n     * @notice Returns the imbalance desired on the long side after the creation of a rebalancer position.\n     * @dev The creation of the rebalancer position aims for this target but does not guarantee reaching it.\n     * @return targetLongImbalance_ The target long imbalance.\n     */\n    function getLongImbalanceTargetBps() external view returns (int256 targetLongImbalance_);\n\n    /**\n     * @notice Gets the nominal (target) price of USDN.\n     * @return price_ The price of the USDN token after a rebase (in `_priceFeedDecimals`).\n     */\n    function getTargetUsdnPrice() external view returns (uint128 price_);\n\n    /**\n     * @notice Gets the USDN token price above which a rebase should occur.\n     * @return threshold_ The rebase threshold (in `_priceFeedDecimals`).\n     */\n    function getUsdnRebaseThreshold() external view returns (uint128 threshold_);\n\n    /**\n     * @notice Gets the minimum collateral amount when opening a long position.\n     * @return minLongPosition_ The minimum amount (with `_assetDecimals`).\n     */\n    function getMinLongPosition() external view returns (uint256 minLongPosition_);\n\n    /* -------------------------------------------------------------------------- */\n    /*                                State getters                               */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice Gets the value of the funding rate at the last timestamp (`getLastUpdateTimestamp`).\n     * @return lastFunding_ The last value of the funding rate (per day) with `FUNDING_RATE_DECIMALS` decimals.\n     */\n    function getLastFundingPerDay() external view returns (int256 lastFunding_);\n\n    /**\n     * @notice Gets the neutral price of the asset used during the last update of the vault and long balances.\n     * @return lastPrice_ The most recent known price of the asset (in `_priceFeedDecimals`).\n     */\n    function getLastPrice() external view returns (uint128 lastPrice_);\n\n    /**\n     * @notice Gets the timestamp of the last time a fresh price was provided.\n     * @return lastTimestamp_ The timestamp of the last update.\n     */\n    function getLastUpdateTimestamp() external view returns (uint128 lastTimestamp_);\n\n    /**\n     * @notice Gets the fees that were accumulated by the contract and are yet to be sent\n     * to the fee collector (in `_assetDecimals`).\n     * @return protocolFees_ The amount of accumulated fees still in the contract.\n     */\n    function getPendingProtocolFee() external view returns (uint256 protocolFees_);\n\n    /**\n     * @notice Gets the amount of assets backing the USDN token.\n     * @return balanceVault_ The amount of assets on the vault side (in `_assetDecimals`).\n     */\n    function getBalanceVault() external view returns (uint256 balanceVault_);\n\n    /**\n     * @notice Gets the pending balance updates due to pending vault actions.\n     * @return pendingBalanceVault_ The unreflected balance change due to pending vault actions (in `_assetDecimals`).\n     */\n    function getPendingBalanceVault() external view returns (int256 pendingBalanceVault_);\n\n    /**\n     * @notice Gets the exponential moving average of the funding rate per day.\n     * @return ema_ The exponential moving average of the funding rate per day.\n     */\n    function getEMA() external view returns (int256 ema_);\n\n    /**\n     * @notice Gets the summed value of all the currently open long positions at `_lastUpdateTimestamp`.\n     * @return balanceLong_ The balance of the long side (in `_assetDecimals`).\n     */\n    function getBalanceLong() external view returns (uint256 balanceLong_);\n\n    /**\n     * @notice Gets the total exposure of all currently open long positions.\n     * @return totalExpo_ The total exposure of the longs (in `_assetDecimals`).\n     */\n    function getTotalExpo() external view returns (uint256 totalExpo_);\n\n    /**\n     * @notice Gets the accumulator used to calculate the liquidation multiplier.\n     * @return accumulator_ The liquidation multiplier accumulator.\n     */\n    function getLiqMultiplierAccumulator() external view returns (HugeUint.Uint512 memory accumulator_);\n\n    /**\n     * @notice Gets the current version of the given tick.\n     * @param tick The tick number.\n     * @return tickVersion_ The version of the tick.\n     */\n    function getTickVersion(int24 tick) external view returns (uint256 tickVersion_);\n\n    /**\n     * @notice Gets the tick data for the current tick version.\n     * @param tick The tick number.\n     * @return tickData_ The tick data.\n     */\n    function getTickData(int24 tick) external view returns (TickData memory tickData_);\n\n    /**\n     * @notice Gets the long position at the provided tick and index.\n     * @param tick The tick number.\n     * @param index The position index.\n     * @return position_ The long position.\n     */\n    function getCurrentLongPosition(int24 tick, uint256 index) external view returns (Position memory position_);\n\n    /**\n     * @notice Gets the highest tick that has an open position.\n     * @return tick_ The highest populated tick.\n     */\n    function getHighestPopulatedTick() external view returns (int24 tick_);\n\n    /**\n     * @notice Gets the total number of long positions currently open.\n     * @return totalLongPositions_ The number of long positions.\n     */\n    function getTotalLongPositions() external view returns (uint256 totalLongPositions_);\n\n    /**\n     * @notice Gets the address of the fallback contract.\n     * @return fallback_ The address of the fallback contract.\n     */\n    function getFallbackAddress() external view returns (address fallback_);\n\n    /**\n     * @notice Gets the pause status of the USDN protocol.\n     * @return isPaused_ True if it's paused, false otherwise.\n     */\n    function isPaused() external view returns (bool isPaused_);\n\n    /**\n     * @notice Gets the nonce a user can use to generate a delegation signature.\n     * @dev This is to prevent replay attacks when using an eip712 delegation signature.\n     * @param user The address of the user.\n     * @return nonce_ The user's nonce.\n     */\n    function getNonce(address user) external view returns (uint256 nonce_);\n\n    /* -------------------------------------------------------------------------- */\n    /*                                   Setters                                  */\n    /* -------------------------------------------------------------------------- */\n\n    /**\n     * @notice Replaces the OracleMiddleware contract with a new implementation.\n     * @dev Cannot be the 0 address.\n     * @param newOracleMiddleware The address of the new contract.\n     */\n    function setOracleMiddleware(IBaseOracleMiddleware newOracleMiddleware) external;\n\n    /**\n     * @notice Sets the fee collector address.\n     * @dev  Cannot be the zero address.\n     * @param newFeeCollector The address of the fee collector.\n     */\n    function setFeeCollector(address newFeeCollector) external;\n\n    /**\n     * @notice Replaces the LiquidationRewardsManager contract with a new implementation.\n     * @dev Cannot be the 0 address.\n     * @param newLiquidationRewardsManager The address of the new contract.\n     */\n    function setLiquidationRewardsManager(IBaseLiquidationRewardsManager newLiquidationRewardsManager) external;\n\n    /**\n     * @notice Replaces the Rebalancer contract with a new implementation.\n     * @param newRebalancer The address of the new contract.\n     */\n    function setRebalancer(IBaseRebalancer newRebalancer) external;\n\n    /**\n     * @notice Sets the new deadlines of the exclusivity period for the validator to confirm its action and get its\n     * security deposit back.\n     * @param newLowLatencyValidatorDeadline The new exclusivity deadline for low-latency validation (offset from\n     * initiate timestamp).\n     * @param newOnChainValidatorDeadline The new exclusivity deadline for on-chain validation (offset from initiate\n     * timestamp + oracle middleware's low latency delay).\n     */\n    function setValidatorDeadlines(uint128 newLowLatencyValidatorDeadline, uint128 newOnChainValidatorDeadline)\n        external;\n\n    /**\n     * @notice Sets the minimum long position size.\n     * @dev This value is used to prevent users from opening positions that are too small and not worth liquidating.\n     * @param newMinLongPosition The new minimum long position size (with `_assetDecimals`).\n     */\n    function setMinLongPosition(uint256 newMinLongPosition) external;\n\n    /**\n     * @notice Sets the new minimum leverage for a position.\n     * @param newMinLeverage The new minimum leverage.\n     */\n    function setMinLeverage(uint256 newMinLeverage) external;\n\n    /**\n     * @notice Sets the new maximum leverage for a position.\n     * @param newMaxLeverage The new maximum leverage.\n     */\n    function setMaxLeverage(uint256 newMaxLeverage) external;\n\n    /**\n     * @notice Sets the new liquidation penalty (in ticks).\n     * @param newLiquidationPenalty The new liquidation penalty.\n     */\n    function setLiquidationPenalty(uint24 newLiquidationPenalty) external;\n\n    /**\n     * @notice Sets the new exponential moving average period of the funding rate.\n     * @param newEMAPeriod The new EMA period.\n     */\n    function setEMAPeriod(uint128 newEMAPeriod) external;\n\n    /**\n     * @notice Sets the new scaling factor (SF) of the funding rate.\n     * @param newFundingSF The new scaling factor (SF) of the funding rate.\n     */\n    function setFundingSF(uint256 newFundingSF) external;\n\n    /**\n     * @notice Sets the protocol fee.\n     * @dev Fees are charged when the funding is applied (Example: 50 bps -> 0.5%).\n     * @param newFeeBps The fee to be charged (in basis points).\n     */\n    function setProtocolFeeBps(uint16 newFeeBps) external;\n\n    /**\n     * @notice Sets the position fee.\n     * @param newPositionFee The new position fee (in basis points).\n     */\n    function setPositionFeeBps(uint16 newPositionFee) external;\n\n    /**\n     * @notice Sets the vault fee.\n     * @param newVaultFee The new vault fee (in basis points).\n     */\n    function setVaultFeeBps(uint16 newVaultFee) external;\n\n    /**\n     * @notice Sets the rewards ratio given to the caller when burning SDEX tokens.\n     * @param newRewardsBps The new rewards ratio (in basis points).\n     */\n    function setSdexRewardsRatioBps(uint16 newRewardsBps) external;\n\n    /**\n     * @notice Sets the rebalancer bonus.\n     * @param newBonus The bonus (in basis points).\n     */\n    function setRebalancerBonusBps(uint16 newBonus) external;\n\n    /**\n     * @notice Sets the ratio of SDEX tokens to burn per minted USDN.\n     * @param newRatio The new ratio.\n     */\n    function setSdexBurnOnDepositRatio(uint32 newRatio) external;\n\n    /**\n     * @notice Sets the security deposit value.\n     * @dev The maximum value of the security deposit is 2^64 - 1 = 18446744073709551615 = 18.4 ethers.\n     * @param securityDepositValue The security deposit value.\n     * This value cannot be greater than MAX_SECURITY_DEPOSIT.\n     */\n    function setSecurityDepositValue(uint64 securityDepositValue) external;\n\n    /**\n     * @notice Sets the imbalance limits (in basis point).\n     * @dev `newLongImbalanceTargetBps` needs to be lower than `newCloseLimitBps` and\n     * higher than the additive inverse of `newWithdrawalLimitBps`.\n     * @param newOpenLimitBps The new open limit.\n     * @param newDepositLimitBps The new deposit limit.\n     * @param newWithdrawalLimitBps The new withdrawal limit.\n     * @param newCloseLimitBps The new close limit.\n     * @param newRebalancerCloseLimitBps The new rebalancer close limit.\n     * @param newLongImbalanceTargetBps The new target imbalance limit for the long side.\n     * A positive value will target below equilibrium, a negative one will target above equilibrium.\n     * If negative, the rebalancerCloseLimit will be useless since the minimum value is 1.\n     */\n    function setExpoImbalanceLimits(\n        uint256 newOpenLimitBps,\n        uint256 newDepositLimitBps,\n        uint256 newWithdrawalLimitBps,\n        uint256 newCloseLimitBps,\n        uint256 newRebalancerCloseLimitBps,\n        int256 newLongImbalanceTargetBps\n    ) external;\n\n    /**\n     * @notice Sets the new safety margin for the liquidation price of newly open positions.\n     * @param newSafetyMarginBps The new safety margin (in basis points).\n     */\n    function setSafetyMarginBps(uint256 newSafetyMarginBps) external;\n\n    /**\n     * @notice Sets the new number of liquidations iteration for user actions.\n     * @param newLiquidationIteration The new number of liquidation iteration.\n     */\n    function setLiquidationIteration(uint16 newLiquidationIteration) external;\n\n    /**\n     * @notice Sets the minimum amount of fees to be collected before they can be withdrawn.\n     * @param newFeeThreshold The minimum amount of fees to be collected before they can be withdrawn.\n     */\n    function setFeeThreshold(uint256 newFeeThreshold) external;\n\n    /**\n     * @notice Sets the target USDN price.\n     * @dev When a rebase of USDN occurs, it will bring the price back down to this value.\n     * @param newPrice The new target price (with `_priceFeedDecimals`).\n     * This value cannot be greater than `_usdnRebaseThreshold`.\n     */\n    function setTargetUsdnPrice(uint128 newPrice) external;\n\n    /**\n     * @notice Sets the USDN rebase threshold.\n     * @dev When the price of USDN exceeds this value, a rebase will be triggered.\n     * @param newThreshold The new threshold value (with `_priceFeedDecimals`).\n     * This value cannot be smaller than `_targetUsdnPrice` or greater than uint128(2 * 10 ** s._priceFeedDecimals)\n     */\n    function setUsdnRebaseThreshold(uint128 newThreshold) external;\n\n    /**\n     * @notice Pauses related USDN protocol functions.\n     * @dev Pauses simultaneously all initiate/validate, refundSecurityDeposit and transferPositionOwnership functions.\n     * Before pausing, this function will call `_applyPnlAndFunding` with `_lastPrice` and the current timestamp.\n     * This is done to stop the funding rate from accumulating while the protocol is paused. Be sure to call {unpause}\n     * to update `_lastUpdateTimestamp` when unpausing.\n     */\n    function pause() external;\n\n    /**\n     * @notice Pauses related USDN protocol functions without applying PnLs and the funding.\n     * @dev Pauses simultaneously all initiate/validate, refundSecurityDeposit and transferPositionOwnership functions.\n     * This safe version will not call `_applyPnlAndFunding` before pausing.\n     */\n    function pauseSafe() external;\n\n    /**\n     * @notice Unpauses related USDN protocol functions.\n     * @dev Unpauses simultaneously all initiate/validate, refundSecurityDeposit and transferPositionOwnership\n     * functions. This function will set `_lastUpdateTimestamp` to the current timestamp to prevent any funding during\n     * the pause. Only meant to be called after a {pause} call.\n     */\n    function unpause() external;\n\n    /**\n     * @notice Unpauses related USDN protocol functions without updating `_lastUpdateTimestamp`.\n     * @dev Unpauses simultaneously all initiate/validate, refundSecurityDeposit and transferPositionOwnership\n     * functions. This safe version will not set `_lastUpdateTimestamp` to the current timestamp.\n     */\n    function unpauseSafe() external;\n}\n"},{"file_path":"src/interfaces/UsdnProtocol/IUsdnProtocolImpl.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport { IAccessControlDefaultAdminRules } from\n    \"@openzeppelin/contracts/access/extensions/IAccessControlDefaultAdminRules.sol\";\nimport { IERC5267 } from \"@openzeppelin/contracts/interfaces/IERC5267.sol\";\nimport { IERC20Metadata } from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport { IBaseLiquidationRewardsManager } from \"../LiquidationRewardsManager/IBaseLiquidationRewardsManager.sol\";\nimport { IBaseOracleMiddleware } from \"../OracleMiddleware/IBaseOracleMiddleware.sol\";\nimport { IUsdn } from \"../Usdn/IUsdn.sol\";\nimport { IUsdnProtocolActions } from \"./IUsdnProtocolActions.sol\";\nimport { IUsdnProtocolCore } from \"./IUsdnProtocolCore.sol\";\nimport { IUsdnProtocolFallback } from \"./IUsdnProtocolFallback.sol\";\nimport { IUsdnProtocolLong } from \"./IUsdnProtocolLong.sol\";\nimport { IUsdnProtocolVault } from \"./IUsdnProtocolVault.sol\";\n\n/**\n * @title IUsdnProtocolImpl\n * @notice Interface for the implementation of the USDN protocol (completed with {IUsdnProtocolFallback})\n */\ninterface IUsdnProtocolImpl is\n    IUsdnProtocolActions,\n    IUsdnProtocolVault,\n    IUsdnProtocolLong,\n    IUsdnProtocolCore,\n    IAccessControlDefaultAdminRules,\n    IERC5267\n{\n    /**\n     * @notice Initializes the protocol's storage with the given values.\n     * @dev This function should be called on deployment when creating the proxy.\n     * It can only be called once.\n     * @param usdn The USDN ERC20 contract address (must have a total supply of 0).\n     * @param sdex The SDEX ERC20 contract address.\n     * @param asset The ERC20 contract address of the token held in the vault.\n     * @param oracleMiddleware The oracle middleware contract address.\n     * @param liquidationRewardsManager The liquidation rewards manager contract address.\n     * @param tickSpacing The number of ticks between usable ticks.\n     * @param feeCollector The address that will receive the protocol fees.\n     * @param protocolFallback The address of the contract that contains the remaining functions of the protocol.\n     * Any call with a function signature not present in this contract will be delegated to the fallback contract.\n     */\n    function initializeStorage(\n        IUsdn usdn,\n        IERC20Metadata sdex,\n        IERC20Metadata asset,\n        IBaseOracleMiddleware oracleMiddleware,\n        IBaseLiquidationRewardsManager liquidationRewardsManager,\n        int24 tickSpacing,\n        address feeCollector,\n        IUsdnProtocolFallback protocolFallback\n    ) external;\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.1.0/utils/math/SignedMath.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n     *\n     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n     * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n     * one branch when needed, making this function more expensive.\n     */\n    function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {\n        unchecked {\n            // branchless ternary works because:\n            // b ^ (a ^ b) == a\n            // b ^ 0 == b\n            return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));\n        }\n    }\n\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return ternary(a > b, a, b);\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return ternary(a < b, a, b);\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // Formula from the \"Bit Twiddling Hacks\" by Sean Eron Anderson.\n            // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,\n            // taking advantage of the most significant (or \"sign\" bit) in two's complement representation.\n            // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,\n            // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).\n            int256 mask = n >> 255;\n\n            // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.\n            return uint256((n + mask) ^ mask);\n        }\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"uint48","name":"schedule","type":"uint48"}],"name":"AccessControlEnforcedDefaultAdminDelay","type":"error"},{"inputs":[],"name":"AccessControlEnforcedDefaultAdminRules","type":"error"},{"inputs":[{"internalType":"address","name":"defaultAdmin","type":"address"}],"name":"AccessControlInvalidDefaultAdmin","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"InitializableReentrancyGuardInvalidInitialization","type":"error"},{"inputs":[],"name":"InitializableReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"InitializableReentrancyGuardUninitialized","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"UnauthorizedCallContext","type":"error"},{"inputs":[],"name":"UpgradeFailed","type":"error"},{"inputs":[],"name":"UsdnProtocolAmountReceivedTooSmall","type":"error"},{"inputs":[{"internalType":"uint128","name":"amountToClose","type":"uint128"},{"internalType":"uint128","name":"positionAmount","type":"uint128"}],"name":"UsdnProtocolAmountToCloseHigherThanPositionAmount","type":"error"},{"inputs":[],"name":"UsdnProtocolDeadlineExceeded","type":"error"},{"inputs":[],"name":"UsdnProtocolDepositTooSmall","type":"error"},{"inputs":[],"name":"UsdnProtocolEmptyVault","type":"error"},{"inputs":[],"name":"UsdnProtocolEtherRefundFailed","type":"error"},{"inputs":[{"internalType":"int256","name":"imbalanceBps","type":"int256"}],"name":"UsdnProtocolImbalanceLimitReached","type":"error"},{"inputs":[],"name":"UsdnProtocolInsufficientOracleFee","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidAddressTo","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidAddressValidator","type":"error"},{"inputs":[{"internalType":"uint8","name":"assetDecimals","type":"uint8"}],"name":"UsdnProtocolInvalidAssetDecimals","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidBurnSdexOnDepositRatio","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidDelegationSignature","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidEMAPeriod","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidExpoImbalanceLimit","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidFeeCollector","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidFundingSF","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidLiquidationIteration","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidLiquidationPenalty","type":"error"},{"inputs":[{"internalType":"uint128","name":"liquidationPrice","type":"uint128"},{"internalType":"uint128","name":"startPrice","type":"uint128"}],"name":"UsdnProtocolInvalidLiquidationPrice","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidLiquidationRewardsManagerAddress","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidLongExpo","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidLongImbalanceTarget","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidMaxLeverage","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidMiddlewareAddress","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidMiddlewareLowLatencyDelay","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidMinLeverage","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidMinLongPosition","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidPendingAction","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidPendingActionData","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidPositionFee","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidProtocolFeeBps","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidRebalancerBonus","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidRebalancerMinAssetDeposit","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidRebalancerMinLeverage","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidRebalancerTick","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidSafetyMarginBps","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidSdexRewardsRatio","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidSecurityDeposit","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidTargetUsdnPrice","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidTokenDecimals","type":"error"},{"inputs":[{"internalType":"address","name":"usdnAddress","type":"address"}],"name":"UsdnProtocolInvalidUsdn","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidUsdnRebaseThreshold","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidValidatorDeadline","type":"error"},{"inputs":[],"name":"UsdnProtocolInvalidVaultFee","type":"error"},{"inputs":[],"name":"UsdnProtocolLeverageTooHigh","type":"error"},{"inputs":[],"name":"UsdnProtocolLeverageTooLow","type":"error"},{"inputs":[{"internalType":"uint128","name":"liquidationPrice","type":"uint128"},{"internalType":"uint128","name":"maxLiquidationPrice","type":"uint128"}],"name":"UsdnProtocolLiquidationPriceSafetyMargin","type":"error"},{"inputs":[],"name":"UsdnProtocolLongPositionTooSmall","type":"error"},{"inputs":[],"name":"UsdnProtocolMinInitAmount","type":"error"},{"inputs":[],"name":"UsdnProtocolNoPendingAction","type":"error"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"UsdnProtocolNotEligibleForRefund","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentVersion","type":"uint256"},{"internalType":"uint256","name":"providedVersion","type":"uint256"}],"name":"UsdnProtocolOutdatedTick","type":"error"},{"inputs":[],"name":"UsdnProtocolPaymentCallbackFailed","type":"error"},{"inputs":[],"name":"UsdnProtocolPendingAction","type":"error"},{"inputs":[],"name":"UsdnProtocolPositionNotValidated","type":"error"},{"inputs":[],"name":"UsdnProtocolSecurityDepositTooLow","type":"error"},{"inputs":[],"name":"UsdnProtocolSlippageMaxPriceExceeded","type":"error"},{"inputs":[],"name":"UsdnProtocolSlippageMinPriceExceeded","type":"error"},{"inputs":[],"name":"UsdnProtocolTimestampTooOld","type":"error"},{"inputs":[],"name":"UsdnProtocolUnauthorized","type":"error"},{"inputs":[],"name":"UsdnProtocolUnexpectedBalance","type":"error"},{"inputs":[],"name":"UsdnProtocolZeroAmount","type":"error"},{"inputs":[],"name":"UsdnProtocolZeroLongTradingExpo","type":"error"},{"inputs":[],"name":"UsdnProtocolZeroTotalExpo","type":"error"},{"anonymous":false,"inputs":[],"name":"DefaultAdminDelayChangeCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint48","name":"newDelay","type":"uint48"},{"indexed":false,"internalType":"uint48","name":"effectSchedule","type":"uint48"}],"name":"DefaultAdminDelayChangeScheduled","type":"event"},{"anonymous":false,"inputs":[],"name":"DefaultAdminTransferCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"},{"indexed":false,"internalType":"uint48","name":"acceptSchedule","type":"uint48"}],"name":"DefaultAdminTransferScheduled","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"beginDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelDefaultAdminTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"newDelay","type":"uint48"}],"name":"changeDefaultAdminDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultAdminDelay","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultAdminDelayIncreaseWait","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"timestamp","type":"uint128"}],"name":"funding","outputs":[{"internalType":"int256","name":"funding_","type":"int256"},{"internalType":"int256","name":"fundingPerDay_","type":"int256"},{"internalType":"int256","name":"oldLongExpo_","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"price","type":"uint128"}],"name":"getEffectiveTickForPrice","outputs":[{"internalType":"int24","name":"tick_","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint256","name":"assetPrice","type":"uint256"},{"internalType":"uint256","name":"longTradingExpo","type":"uint256"},{"components":[{"internalType":"uint256","name":"hi","type":"uint256"},{"internalType":"uint256","name":"lo","type":"uint256"}],"internalType":"struct HugeUint.Uint512","name":"accumulator","type":"tuple"},{"internalType":"int24","name":"tickSpacing","type":"int24"}],"name":"getEffectiveTickForPrice","outputs":[{"internalType":"int24","name":"tick_","type":"int24"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint128","name":"desiredLiqPriceWithoutPenalty","type":"uint128"},{"internalType":"uint256","name":"assetPrice","type":"uint256"},{"internalType":"uint256","name":"longTradingExpo","type":"uint256"},{"components":[{"internalType":"uint256","name":"hi","type":"uint256"},{"internalType":"uint256","name":"lo","type":"uint256"}],"internalType":"struct HugeUint.Uint512","name":"accumulator","type":"tuple"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"uint24","name":"liquidationPenalty","type":"uint24"}],"name":"getLiqPriceFromDesiredLiqPrice","outputs":[{"internalType":"uint128","name":"liqPrice_","type":"uint128"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint256","name":"tickVersion","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IUsdnProtocolTypes.PositionId","name":"posId","type":"tuple"}],"name":"getLongPosition","outputs":[{"components":[{"internalType":"bool","name":"validated","type":"bool"},{"internalType":"uint40","name":"timestamp","type":"uint40"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint128","name":"totalExpo","type":"uint128"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct IUsdnProtocolTypes.Position","name":"pos_","type":"tuple"},{"internalType":"uint24","name":"liquidationPenalty_","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint256","name":"tickVersion","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IUsdnProtocolTypes.PositionId","name":"posId","type":"tuple"},{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint128","name":"timestamp","type":"uint128"}],"name":"getPositionValue","outputs":[{"internalType":"int256","name":"value_","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int24","name":"tick","type":"int24"}],"name":"getTickLiquidationPenalty","outputs":[{"internalType":"uint24","name":"liquidationPenalty_","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"depositAmount","type":"uint128"},{"internalType":"uint128","name":"longAmount","type":"uint128"},{"internalType":"uint128","name":"desiredLiqPrice","type":"uint128"},{"internalType":"bytes","name":"currentPriceData","type":"bytes"}],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IUsdn","name":"usdn","type":"address"},{"internalType":"contract IERC20Metadata","name":"sdex","type":"address"},{"internalType":"contract IERC20Metadata","name":"asset","type":"address"},{"internalType":"contract IBaseOracleMiddleware","name":"oracleMiddleware","type":"address"},{"internalType":"contract IBaseLiquidationRewardsManager","name":"liquidationRewardsManager","type":"address"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"address","name":"feeCollector","type":"address"},{"internalType":"contract IUsdnProtocolFallback","name":"protocolFallback","type":"address"}],"name":"initializeStorage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint256","name":"tickVersion","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IUsdnProtocolTypes.PositionId","name":"posId","type":"tuple"},{"internalType":"uint128","name":"amountToClose","type":"uint128"},{"internalType":"uint256","name":"userMinPrice","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address payable","name":"validator","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"currentPriceData","type":"bytes"},{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"},{"internalType":"bytes","name":"delegationSignature","type":"bytes"}],"name":"initiateClosePosition","outputs":[{"internalType":"enum IUsdnProtocolTypes.LongActionOutcome","name":"outcome_","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint256","name":"sharesOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address payable","name":"validator","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"currentPriceData","type":"bytes"},{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"}],"name":"initiateDeposit","outputs":[{"internalType":"bool","name":"success_","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"desiredLiqPrice","type":"uint128"},{"internalType":"uint128","name":"userMaxPrice","type":"uint128"},{"internalType":"uint256","name":"userMaxLeverage","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address payable","name":"validator","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"currentPriceData","type":"bytes"},{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"}],"name":"initiateOpenPosition","outputs":[{"internalType":"bool","name":"isInitiated_","type":"bool"},{"components":[{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint256","name":"tickVersion","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IUsdnProtocolTypes.PositionId","name":"posId_","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint152","name":"usdnShares","type":"uint152"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address payable","name":"validator","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"currentPriceData","type":"bytes"},{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"}],"name":"initiateWithdrawal","outputs":[{"internalType":"bool","name":"success_","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"currentPriceData","type":"bytes"}],"name":"liquidate","outputs":[{"components":[{"internalType":"uint256","name":"totalPositions","type":"uint256"},{"internalType":"uint256","name":"totalExpo","type":"uint256"},{"internalType":"int256","name":"remainingCollateral","type":"int256"},{"internalType":"uint128","name":"tickPrice","type":"uint128"},{"internalType":"uint128","name":"priceWithoutPenalty","type":"uint128"}],"internalType":"struct IUsdnProtocolTypes.LiqTickInfo[]","name":"liquidatedTicks_","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint128","name":"currentPrice","type":"uint128"},{"internalType":"uint128","name":"timestamp","type":"uint128"}],"name":"longAssetAvailableWithFunding","outputs":[{"internalType":"uint256","name":"available_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"currentPrice","type":"uint128"},{"internalType":"uint128","name":"timestamp","type":"uint128"}],"name":"longTradingExpoWithFunding","outputs":[{"internalType":"uint256","name":"expo_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minTick","outputs":[{"internalType":"int24","name":"tick_","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingDefaultAdmin","outputs":[{"internalType":"address","name":"newAdmin","type":"address"},{"internalType":"uint48","name":"schedule","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingDefaultAdminDelay","outputs":[{"internalType":"uint48","name":"newDelay","type":"uint48"},{"internalType":"uint48","name":"schedule","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollbackDefaultAdminDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint256","name":"tickVersion","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IUsdnProtocolTypes.PositionId","name":"posId","type":"tuple"},{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"bytes","name":"delegationSignature","type":"bytes"}],"name":"transferPositionOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint128","name":"currentPrice","type":"uint128"}],"name":"usdnPrice","outputs":[{"internalType":"uint256","name":"price_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"currentPrice","type":"uint128"},{"internalType":"uint128","name":"timestamp","type":"uint128"}],"name":"usdnPrice","outputs":[{"internalType":"uint256","name":"price_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"},{"internalType":"uint256","name":"maxValidations","type":"uint256"}],"name":"validateActionablePendingActions","outputs":[{"internalType":"uint256","name":"validatedActions_","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"validator","type":"address"},{"internalType":"bytes","name":"closePriceData","type":"bytes"},{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"}],"name":"validateClosePosition","outputs":[{"internalType":"enum IUsdnProtocolTypes.LongActionOutcome","name":"outcome_","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"validator","type":"address"},{"internalType":"bytes","name":"depositPriceData","type":"bytes"},{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"}],"name":"validateDeposit","outputs":[{"internalType":"bool","name":"success_","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"validator","type":"address"},{"internalType":"bytes","name":"openPriceData","type":"bytes"},{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"}],"name":"validateOpenPosition","outputs":[{"internalType":"enum IUsdnProtocolTypes.LongActionOutcome","name":"outcome_","type":"uint8"},{"components":[{"internalType":"int24","name":"tick","type":"int24"},{"internalType":"uint256","name":"tickVersion","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IUsdnProtocolTypes.PositionId","name":"posId_","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"validator","type":"address"},{"internalType":"bytes","name":"withdrawalPriceData","type":"bytes"},{"components":[{"internalType":"bytes[]","name":"priceData","type":"bytes[]"},{"internalType":"uint128[]","name":"rawIndices","type":"uint128[]"}],"internalType":"struct IUsdnProtocolTypes.PreviousActionsData","name":"previousActionsData","type":"tuple"}],"name":"validateWithdrawal","outputs":[{"internalType":"bool","name":"success_","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint128","name":"currentPrice","type":"uint128"},{"internalType":"uint128","name":"timestamp","type":"uint128"}],"name":"vaultAssetAvailableWithFunding","outputs":[{"internalType":"uint256","name":"available_","type":"uint256"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":null}