{"ok":true,"contract":{"address":"0xdff76acd594101fb5e9fae176aedb21a7a1fe39f","contract_name":"StabilityPool","deployed":"1699791002","fund":"0","fund_usd":"0.00000000","native_balance":"0","network":"polygon","first_seen":"1780728093","verified":true,"is_proxy":false,"implementation_address":null,"proxy_contract_name":"StabilityPool","implementation_contract_name":null,"deploy_tx_hash":"0xd7259bc49cd467ea8a140d45c9b08d4c15600827b938aa1f350a2fd233d3942f","deployer_address":"0x109861a2a539ddb151ee591588a14cf86309e4e5","deploy_block_number":"49852713","deployed_at_timestamp":"1699791002","deployed_at":"2023-11-12T12:10:02.000Z","confidence":"precise","fetched_at":"2026-06-06T06:40:48.162Z","source_code":"// File: contracts/StabilityPool.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n// import openzeppelin reentrancy guard\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"./utils/constants.sol\";\nimport \"./utils/BONQMath.sol\";\nimport \"./interfaces/IVaultFactory.sol\";\nimport \"./interfaces/IMintableToken.sol\";\nimport \"./interfaces/IVault.sol\";\nimport \"./interfaces/ILiquidationRouter.sol\";\n\n/// @title is used to liquidate vaults and reward depositors with collateral redeemed\ncontract StabilityPool is Ownable, ReentrancyGuard, Constants {\n    using BONQMath for uint256;\n    using SafeERC20 for IERC20;\n\n    struct TokenToS {\n        address tokenAddress;\n        uint256 S_value;\n    }\n\n    struct TokenToUint256 {\n        address tokenAddress;\n        uint256 value;\n    }\n\n    struct Snapshots {\n        TokenToS[] tokenToSArray;\n        uint256 P;\n        uint256 G;\n        uint128 scale;\n        uint128 epoch;\n    }\n\n    IVaultFactory public factory;\n    IMintableToken public immutable stableCoin;\n\n    IERC20 public immutable a3aToken;\n\n    uint256 public totalDeposit;\n\n    mapping(address => uint256) public collateralToLastErrorOffset;\n    uint256 public lastStableCoinLossErrorOffset;\n\n    mapping(address => uint256) public deposits;\n    mapping(address => Snapshots) public depositSnapshots; // depositor address -> snapshots struct\n\n    uint256 public a3aPerMinute;\n    uint256 public totalA3ARewardsLeft;\n    uint256 public latestA3ARewardTime;\n    // Error tracker for the error correction in the A3A redistribution calculation\n    uint256 public lastA3AError;\n    /*  Product 'P': Running product by which to multiply an initial deposit, in order to find the current compounded deposit,\n     * after a series of liquidations have occurred, each of which cancel some StableCoin debt with the deposit.\n     *\n     * During its lifetime, a deposit's value evolves from d_t to d_t * P / P_t , where P_t\n     * is the snapshot of P taken at the instant the deposit was made. 18-digit decimal.\n     */\n    uint256 public P;\n\n    uint256 public constant SCALE_FACTOR = 1e9;\n\n    uint256 public constant SECONDS_IN_ONE_MINUTE = 60;\n\n    // Each time the scale of P shifts by SCALE_FACTOR, the scale is incremented by 1\n    uint128 public currentScale;\n\n    // With each offset that fully empties the Pool, the epoch is incremented by 1\n    uint128 public currentEpoch;\n\n    /* Collateral Gain sum 'S': During its lifetime, each deposit d_t earns an Collateral gain of ( d_t * [S - S_t] )/P_t, where S_t\n     * is the depositor's snapshot of S taken at the time t when the deposit was made.\n     *\n     * The 'S' sums are stored in a nested mapping (epoch => scale => sum):\n     *\n     * - The inner mapping records the sum S at different scales\n     * - The outer mapping records the (scale => sum) mappings, for different epochs.\n     */\n    mapping(uint128 => mapping(uint128 => TokenToS[])) public epochToScaleToTokenToSum;\n\n    /*\n     * Similarly, the sum 'G' is used to calculate A3A gains. During it's lifetime, each deposit d_t earns a A3A gain of\n     *  ( d_t * [G - G_t] )/P_t, where G_t is the depositor's snapshot of G taken at time t when  the deposit was made.\n     *\n     *  A3A reward events occur are triggered by depositor operations (new deposit, topup, withdrawal), and liquidations.\n     *  In each case, the A3A reward is issued (i.e. G is updated), before other state changes are made.\n     */\n    mapping(uint128 => mapping(uint128 => uint256)) public epochToScaleToG;\n\n    event Deposit(address _contributor, uint256 _amount);\n    event TotalDepositUpdated(uint256 _newValue);\n    event Withdraw(address _contributor, uint256 _amount);\n\n    // solhint-disable-next-line event-name-camelcase\n    event A3ARewardRedeemed(address _contributor, uint256 _amount);\n    event A3ARewardIssue(uint256 issuance, uint256 _totalA3ARewardsLeft);\n    event A3APerMinuteUpdated(uint256 _newAmount);\n    event TotalA3ARewardsUpdated(uint256 _newAmount);\n    // solhint-disable-next-line event-name-camelcase\n    event CollateralRewardRedeemed(address _contributor, address _tokenAddress, uint256 _amount);\n    event DepositSnapshotUpdated(address indexed _depositor, uint256 _P, uint256 _G, uint256 _newDepositValue);\n\n    /* solhint-disable event-name-camelcase */\n    event P_Updated(uint256 _P);\n    event S_Updated(address _tokenAddress, uint256 _S, uint128 _epoch, uint128 _scale);\n    event G_Updated(uint256 _G, uint128 _epoch, uint128 _scale);\n    /* solhint-disable event-name-camelcase */\n    event EpochUpdated(uint128 _currentEpoch);\n    event ScaleUpdated(uint128 _currentScale);\n\n    constructor(address _factory, address _a3aToken) {\n        require(_factory != address(0x0), \"factory-is-0\");\n        require(_a3aToken != address(0x0), \"a3a-is-0\");\n        factory = IVaultFactory(_factory);\n        stableCoin = IMintableToken(address(IVaultFactory(_factory).stable()));\n        a3aToken = IERC20(_a3aToken);\n        P = DECIMAL_PRECISION;\n    }\n\n    /// @dev to deposit StableCoin into StabilityPool this must be protected against a reentrant attack from the arbitrage\n    /// @param  _amount amount to deposit\n    function deposit(uint256 _amount) public nonReentrant {\n        // address depositor = msg.sender;\n        require(_amount > 0, \"amount-is-0\");\n\n        stableCoin.transferFrom(msg.sender, address(this), _amount);\n        uint256 initialDeposit = deposits[msg.sender];\n        _redeemReward();\n\n        Snapshots memory snapshots = depositSnapshots[msg.sender];\n\n        uint256 compoundedDeposit = _getCompoundedDepositFromSnapshots(initialDeposit, snapshots);\n        // uint256 newValue = compoundedDeposit + _amount;\n        uint256 newTotalDeposit = totalDeposit + _amount;\n        totalDeposit = newTotalDeposit;\n\n        _updateDepositAndSnapshots(msg.sender, compoundedDeposit + _amount);\n\n        emit Deposit(msg.sender, _amount);\n        emit TotalDepositUpdated(newTotalDeposit);\n    }\n\n    /// @dev to withdraw StableCoin that was not spent if this function is called in a reentrantway during arbitrage  it\n    /// @dev would skew the token allocation and must be protected against\n    /// @param  _amount amount to withdraw\n    function withdraw(uint256 _amount) public nonReentrant {\n        uint256 contributorDeposit = deposits[msg.sender];\n        require(_amount > 0, \"amount-is-0\");\n        require(contributorDeposit > 0, \"deposit-is-0\");\n        _redeemReward();\n\n        Snapshots memory snapshots = depositSnapshots[msg.sender];\n\n        uint256 compoundedDeposit = _getCompoundedDepositFromSnapshots(contributorDeposit, snapshots);\n        uint256 calculatedAmount = compoundedDeposit.min(_amount);\n\n        uint256 newValue = compoundedDeposit - calculatedAmount;\n\n        totalDeposit = totalDeposit - calculatedAmount;\n\n        _updateDepositAndSnapshots(msg.sender, newValue);\n\n        stableCoin.transfer(msg.sender, calculatedAmount);\n        emit Withdraw(msg.sender, calculatedAmount);\n        emit TotalDepositUpdated(totalDeposit);\n    }\n\n    /// @dev to withdraw collateral rewards earned after liquidations\n    /// @dev this function does not provide an opportunity for a reentrancy attack\n    function redeemReward() external {\n        Snapshots memory snapshots = depositSnapshots[msg.sender];\n        uint256 contributorDeposit = deposits[msg.sender];\n\n        uint256 compoundedDeposit = _getCompoundedDepositFromSnapshots(contributorDeposit, snapshots);\n        _redeemReward();\n        _updateDepositAndSnapshots(msg.sender, compoundedDeposit);\n    }\n\n    function setVaultFactory(address _factory) external onlyOwner {\n        require(_factory != address(0x0), \"factory-is-0\");\n        factory = IVaultFactory(_factory);\n    }\n\n    /// @dev liquidates vault, must be called from that vault\n    /// @dev this function does not provide an opportunity for a reentrancy attack even though it would make the arbitrage\n    /// @dev fail because of the lowering of the stablecoin balance\n    /// @notice must be called by the valid vault\n    function liquidate() external {\n        require(msg.sender == factory.liquidationRouter(), \"not-liquidation-router\");\n        IVaultFactory factory_cached = factory;\n\n        ILiquidationRouter _liquidationRouter = ILiquidationRouter(factory_cached.liquidationRouter());\n        uint256 _underWaterDebt = _liquidationRouter.underWaterDebt();\n        address[] memory _collaterals = _liquidationRouter.collaterals();\n        uint256 _collateralCount = _collaterals.length;\n\n        uint256 totalStableCoin = totalDeposit; // cached to save an SLOAD\n\n        for (uint256 i; i < _collateralCount; i++) {\n            IERC20 _collateralToken = IERC20(_collaterals[i]);\n            uint256 _collateralAmount = _liquidationRouter.collateral(address(_collateralToken));\n            _collateralToken.safeTransferFrom(address(_liquidationRouter), address(this), _collateralAmount);\n\n            (uint256 collateralGainPerUnitStaked, uint256 stableCoinLossPerUnitStaked) = _computeRewardsPerUnitStaked(\n                address(_collateralToken),\n                _collateralAmount,\n                _underWaterDebt,\n                totalStableCoin\n            );\n\n            _updateRewardSumAndProduct(address(_collateralToken), collateralGainPerUnitStaked, stableCoinLossPerUnitStaked);\n        }\n\n        _triggerA3Adistribution();\n\n        stableCoin.burn(_underWaterDebt);\n        uint256 newTotalDeposit = totalStableCoin - _underWaterDebt;\n        totalDeposit = newTotalDeposit;\n        emit TotalDepositUpdated(newTotalDeposit);\n        //factory_cached.emitLiquidationEvent(address(collateralToken), msg.sender, address(this), vaultCollateral);\n    }\n\n    /// @dev gets current deposit of msg.sender\n    function getWithdrawableDeposit(address staker) public view returns (uint256) {\n        uint256 initialDeposit = deposits[staker];\n        Snapshots memory snapshots = depositSnapshots[staker];\n        return _getCompoundedDepositFromSnapshots(initialDeposit, snapshots);\n    }\n\n    /// @dev gets collateral reward of msg.sender\n    /// @param _token collateral token address\n    function getCollateralReward(address _token, address _depositor) external view returns (uint256) {\n        Snapshots memory _snapshots = depositSnapshots[_depositor];\n        uint256 _initialDeposit = deposits[_depositor];\n\n        uint128 epochSnapshot = _snapshots.epoch;\n        uint128 scaleSnapshot = _snapshots.scale;\n\n        TokenToS[] memory tokensToSum_cached = epochToScaleToTokenToSum[epochSnapshot][scaleSnapshot];\n        uint256 tokenArrayLength = tokensToSum_cached.length;\n\n        TokenToS memory cachedS;\n        for (uint128 i = 0; i < tokenArrayLength; i++) {\n            TokenToS memory S = tokensToSum_cached[i];\n            if (S.tokenAddress == _token) {\n                cachedS = S;\n                break;\n            }\n        }\n        if (cachedS.tokenAddress == address(0)) return 0;\n        uint256 relatedSValue_snapshot;\n        for (uint128 i = 0; i < _snapshots.tokenToSArray.length; i++) {\n            TokenToS memory S_snapsot = _snapshots.tokenToSArray[i];\n            if (S_snapsot.tokenAddress == _token) {\n                relatedSValue_snapshot = S_snapsot.S_value;\n                break;\n            }\n        }\n        TokenToS[] memory nextTokensToSum_cached = epochToScaleToTokenToSum[epochSnapshot][scaleSnapshot + 1];\n        uint256 nextScaleS;\n        for (uint128 i = 0; i < nextTokensToSum_cached.length; i++) {\n            TokenToS memory nextScaleTokenToS = nextTokensToSum_cached[i];\n            if (nextScaleTokenToS.tokenAddress == _token) {\n                nextScaleS = nextScaleTokenToS.S_value;\n                break;\n            }\n        }\n\n        uint256 P_Snapshot = _snapshots.P;\n\n        uint256 collateralGain = _getCollateralGainFromSnapshots(\n            _initialDeposit,\n            cachedS.S_value,\n            nextScaleS,\n            relatedSValue_snapshot,\n            P_Snapshot\n        );\n\n        return collateralGain;\n    }\n\n    /// @dev gets A3A reward of _depositor\n    /// @param _depositor user address\n    function getDepositorA3AGain(address _depositor) external view returns (uint256) {\n        uint256 totalA3ARewardsLeft_cached = totalA3ARewardsLeft;\n        uint256 totalStableCoin = totalDeposit;\n        if (totalA3ARewardsLeft_cached == 0 || a3aPerMinute == 0 || totalStableCoin == 0) {\n            return 0;\n        }\n\n        uint256 _a3aIssuance = a3aPerMinute * ((block.timestamp - latestA3ARewardTime) / SECONDS_IN_ONE_MINUTE);\n        if (totalA3ARewardsLeft_cached < _a3aIssuance) {\n            _a3aIssuance = totalA3ARewardsLeft_cached;\n        }\n\n        uint256 a3aGain = (_a3aIssuance * DECIMAL_PRECISION + lastA3AError) / totalStableCoin;\n        uint256 marginalA3AGain = a3aGain * P;\n\n        return _getDepositorA3AGain(_depositor, marginalA3AGain);\n    }\n\n    /// @dev sets amount of A3A per minute for rewards\n    function setA3APerMinute(uint256 _a3aPerMinute) external onlyOwner {\n        _triggerA3Adistribution();\n        a3aPerMinute = _a3aPerMinute;\n        emit A3APerMinuteUpdated(a3aPerMinute);\n    }\n\n    /// @dev sets total amount of A3A to be rewarded (pays per minute until reaches the amount rewarded)\n    function setA3AAmountForRewards() external onlyOwner {\n        _triggerA3Adistribution();\n        totalA3ARewardsLeft = a3aToken.balanceOf(address(this));\n        emit TotalA3ARewardsUpdated(totalA3ARewardsLeft);\n    }\n\n    function _redeemReward() private {\n        _redeemCollateralReward();\n        _triggerA3Adistribution();\n        _redeemA3AReward();\n    }\n\n    function _redeemCollateralReward() internal {\n        address depositor = msg.sender;\n        TokenToUint256[] memory depositorCollateralGains = _getDepositorCollateralGains(depositor);\n        _sendCollateralRewardsToDepositor(depositorCollateralGains);\n    }\n\n    function _redeemA3AReward() internal {\n        address depositor = msg.sender;\n        uint256 depositorA3AGain = _getDepositorA3AGain(depositor, 0);\n        _sendA3ARewardsToDepositor(depositorA3AGain);\n        emit A3ARewardRedeemed(depositor, depositorA3AGain);\n    }\n\n    /// @dev updates user deposit snapshot data for new deposit value\n    function _updateDepositAndSnapshots(address _depositor, uint256 _newValue) private {\n        deposits[_depositor] = _newValue;\n        if (_newValue == 0) {\n            delete depositSnapshots[_depositor];\n            emit DepositSnapshotUpdated(_depositor, 0, 0, 0);\n            return;\n        }\n        uint128 cachedEpoch = currentEpoch;\n        uint128 cachedScale = currentScale;\n        TokenToS[] storage cachedTokenToSArray = epochToScaleToTokenToSum[cachedEpoch][cachedScale]; // TODO: maybe remove and read twice?\n        uint256 cachedP = P;\n        uint256 cachedG = epochToScaleToG[cachedEpoch][cachedScale];\n\n        depositSnapshots[_depositor].tokenToSArray = cachedTokenToSArray; // TODO\n        depositSnapshots[_depositor].P = cachedP;\n        depositSnapshots[_depositor].G = cachedG;\n        depositSnapshots[_depositor].scale = cachedScale;\n        depositSnapshots[_depositor].epoch = cachedEpoch;\n        emit DepositSnapshotUpdated(_depositor, cachedP, cachedG, _newValue);\n    }\n\n    function _updateRewardSumAndProduct(\n        address _collateralTokenAddress,\n        uint256 _collateralGainPerUnitStaked,\n        uint256 _stableCoinLossPerUnitStaked\n    ) internal {\n        assert(_stableCoinLossPerUnitStaked <= DECIMAL_PRECISION);\n\n        uint128 currentScaleCached = currentScale;\n        uint128 currentEpochCached = currentEpoch;\n        uint256 currentS;\n        uint256 currentSIndex;\n        bool _found;\n        TokenToS[] memory currentTokenToSArray = epochToScaleToTokenToSum[currentEpochCached][currentScaleCached];\n        for (uint128 i = 0; i < currentTokenToSArray.length; i++) {\n            if (currentTokenToSArray[i].tokenAddress == _collateralTokenAddress) {\n                currentS = currentTokenToSArray[i].S_value;\n                currentSIndex = i;\n                _found = true;\n            }\n        }\n        /*\n         * Calculate the new S first, before we update P.\n         * The Collateral gain for any given depositor from a liquidation depends on the value of their deposit\n         * (and the value of totalDeposits) prior to the Stability being depleted by the debt in the liquidation.\n         *\n         * Since S corresponds to Collateral gain, and P to deposit loss, we update S first.\n         */\n        uint256 marginalCollateralGain = _collateralGainPerUnitStaked * P;\n        uint256 newS = currentS + marginalCollateralGain;\n        if (currentTokenToSArray.length == 0 || !_found) {\n            TokenToS memory tokenToS;\n            tokenToS.S_value = newS;\n            tokenToS.tokenAddress = _collateralTokenAddress;\n            epochToScaleToTokenToSum[currentEpochCached][currentScaleCached].push() = tokenToS;\n        } else {\n            epochToScaleToTokenToSum[currentEpochCached][currentScaleCached][currentSIndex].S_value = newS;\n        }\n        emit S_Updated(_collateralTokenAddress, newS, currentEpochCached, currentScaleCached);\n        _updateP(_stableCoinLossPerUnitStaked, true);\n    }\n\n    function _updateP(uint256 _stableCoinChangePerUnitStaked, bool loss) internal {\n        /*\n         * The newProductFactor is the factor by which to change all deposits, due to the depletion of Stability Pool StableCoin in the liquidation.\n         * We make the product factor 0 if there was a pool-emptying. Otherwise, it is (1 - StableCoinLossPerUnitStaked)\n         */\n        uint256 newProductFactor;\n        if (loss) {\n            newProductFactor = uint256(DECIMAL_PRECISION - _stableCoinChangePerUnitStaked);\n        } else {\n            newProductFactor = uint256(DECIMAL_PRECISION + _stableCoinChangePerUnitStaked);\n        }\n        uint256 currentP = P;\n        uint256 newP;\n        // If the Stability Pool was emptied, increment the epoch, and reset the scale and product P\n        if (newProductFactor == 0) {\n            currentEpoch += 1;\n            emit EpochUpdated(currentEpoch);\n            currentScale = 0;\n            emit ScaleUpdated(0);\n            newP = DECIMAL_PRECISION;\n\n            // If multiplying P by a non-zero product factor would reduce P below the scale boundary, increment the scale\n        } else if ((currentP * newProductFactor) / DECIMAL_PRECISION < SCALE_FACTOR) {\n            newP = (currentP * newProductFactor * SCALE_FACTOR) / DECIMAL_PRECISION;\n            currentScale += 1;\n            emit ScaleUpdated(currentScale);\n        } else {\n            newP = (currentP * newProductFactor) / DECIMAL_PRECISION;\n        }\n\n        assert(newP > 0);\n        P = newP;\n\n        emit P_Updated(newP);\n    }\n\n    /// @dev updates G when new A3A amount is issued\n    /// @param _a3aIssuance new A3A issuance amount\n    function _updateG(uint256 _a3aIssuance) internal {\n        uint256 totalStableCoin = totalDeposit; // cached to save an SLOAD\n        /*\n         * When total deposits is 0, G is not updated. In this case, the A3A issued can not be obtained by later\n         * depositors - it is missed out on, and remains in the balanceof the Stability Pool.\n         *\n         */\n        if (totalStableCoin == 0 || _a3aIssuance == 0) {\n            return;\n        }\n\n        uint256 a3aPerUnitStaked;\n        a3aPerUnitStaked = _computeA3APerUnitStaked(_a3aIssuance, totalStableCoin);\n\n        uint256 marginalA3AGain = a3aPerUnitStaked * P;\n        uint128 currentEpoch_cached = currentEpoch;\n        uint128 currentScale_cached = currentScale;\n\n        uint256 newEpochToScaleToG = epochToScaleToG[currentEpoch_cached][currentScale_cached] + marginalA3AGain;\n        epochToScaleToG[currentEpoch_cached][currentScale_cached] = newEpochToScaleToG;\n\n        emit G_Updated(newEpochToScaleToG, currentEpoch_cached, currentScale_cached);\n    }\n\n    function _getDepositorCollateralGains(address _depositor) internal view returns (TokenToUint256[] memory) {\n        uint256 initialDeposit = deposits[_depositor];\n        if (initialDeposit == 0) {\n            TokenToUint256[] memory x;\n            return x;\n        }\n\n        Snapshots memory snapshots = depositSnapshots[_depositor];\n\n        TokenToUint256[] memory gainPerCollateralArray = _getCollateralGainsArrayFromSnapshots(initialDeposit, snapshots);\n        return gainPerCollateralArray;\n    }\n\n    function _getCollateralGainsArrayFromSnapshots(\n        uint256 _initialDeposit,\n        Snapshots memory _snapshots\n    ) internal view returns (TokenToUint256[] memory) {\n        /*\n         * Grab the sum 'S' from the epoch at which the stake was made. The Collateral gain may span up to one scale change.\n         * If it does, the second portion of the Collateral gain is scaled by 1e9.\n         * If the gain spans no scale change, the second portion will be 0.\n         */\n        uint128 epochSnapshot = _snapshots.epoch;\n        uint128 scaleSnapshot = _snapshots.scale;\n        TokenToS[] memory tokensToSum_cached = epochToScaleToTokenToSum[epochSnapshot][scaleSnapshot];\n        uint256 tokenArrayLength = tokensToSum_cached.length;\n        TokenToUint256[] memory CollateralGainsArray = new TokenToUint256[](tokenArrayLength);\n        for (uint128 i = 0; i < tokenArrayLength; i++) {\n            TokenToS memory S = tokensToSum_cached[i];\n            uint256 relatedS_snapshot;\n            for (uint128 j = 0; j < _snapshots.tokenToSArray.length; j++) {\n                TokenToS memory S_snapsot = _snapshots.tokenToSArray[j];\n                if (S_snapsot.tokenAddress == S.tokenAddress) {\n                    relatedS_snapshot = S_snapsot.S_value;\n                    break;\n                }\n            }\n            TokenToS[] memory nextTokensToSum_cached = epochToScaleToTokenToSum[epochSnapshot][scaleSnapshot + 1];\n            uint256 nextScaleS;\n            for (uint128 j = 0; j < nextTokensToSum_cached.length; j++) {\n                TokenToS memory nextScaleTokenToS = nextTokensToSum_cached[j];\n                if (nextScaleTokenToS.tokenAddress == S.tokenAddress) {\n                    nextScaleS = nextScaleTokenToS.S_value;\n                    break;\n                }\n            }\n            uint256 P_Snapshot = _snapshots.P;\n\n            CollateralGainsArray[i].value = _getCollateralGainFromSnapshots(\n                _initialDeposit,\n                S.S_value,\n                nextScaleS,\n                relatedS_snapshot,\n                P_Snapshot\n            );\n            CollateralGainsArray[i].tokenAddress = S.tokenAddress;\n        }\n\n        return CollateralGainsArray;\n    }\n\n    function _getCollateralGainFromSnapshots(\n        uint256 initialDeposit,\n        uint256 S,\n        uint256 nextScaleS,\n        uint256 S_Snapshot,\n        uint256 P_Snapshot\n    ) internal pure returns (uint256) {\n        uint256 firstPortion = S - S_Snapshot;\n        uint256 secondPortion = nextScaleS / SCALE_FACTOR;\n        uint256 collateralGain = (initialDeposit * (firstPortion + secondPortion)) / P_Snapshot / DECIMAL_PRECISION;\n\n        return collateralGain;\n    }\n\n    function _getDepositorA3AGain(address _depositor, uint256 _marginalA3AGain) internal view returns (uint256) {\n        uint256 initialDeposit = deposits[_depositor];\n        if (initialDeposit == 0) {\n            return 0;\n        }\n        Snapshots memory _snapshots = depositSnapshots[_depositor];\n        /*\n         * Grab the sum 'G' from the epoch at which the stake was made. The A3A gain may span up to one scale change.\n         * If it does, the second portion of the A3A gain is scaled by 1e9.\n         * If the gain spans no scale change, the second portion will be 0.\n         */\n        uint256 firstEpochPortion = epochToScaleToG[_snapshots.epoch][_snapshots.scale];\n        uint256 secondEpochPortion = epochToScaleToG[_snapshots.epoch][_snapshots.scale + 1];\n        if (_snapshots.epoch == currentEpoch) {\n            if (_snapshots.scale == currentScale) firstEpochPortion += _marginalA3AGain;\n            if (_snapshots.scale + 1 == currentScale) secondEpochPortion += _marginalA3AGain;\n        }\n        uint256 gainPortions = firstEpochPortion - _snapshots.G + secondEpochPortion / SCALE_FACTOR;\n\n        return (initialDeposit * (gainPortions)) / _snapshots.P / DECIMAL_PRECISION;\n    }\n\n    /// @dev gets compounded deposit of the user\n    function _getCompoundedDepositFromSnapshots(\n        uint256 _initialStake,\n        Snapshots memory _snapshots\n    ) internal view returns (uint256) {\n        uint256 snapshot_P = _snapshots.P;\n\n        // If stake was made before a pool-emptying event, then it has been fully cancelled with debt -- so, return 0\n        if (_snapshots.epoch < currentEpoch) {\n            return 0;\n        }\n\n        uint256 compoundedStake;\n        uint128 scaleDiff = currentScale - _snapshots.scale;\n\n        /* Compute the compounded stake. If a scale change in P was made during the stake's lifetime,\n         * account for it. If more than one scale change was made, then the stake has decreased by a factor of\n         * at least 1e-9 -- so return 0.\n         */\n        uint256 calculatedSnapshotP = snapshot_P == 0 ? DECIMAL_PRECISION : snapshot_P;\n        if (scaleDiff == 0) {\n            compoundedStake = (_initialStake * P) / calculatedSnapshotP;\n        } else if (scaleDiff == 1) {\n            compoundedStake = (_initialStake * P) / calculatedSnapshotP / SCALE_FACTOR;\n        } else {\n            // if scaleDiff >= 2\n            compoundedStake = 0;\n        }\n\n        /*\n         * If compounded deposit is less than a billionth of the initial deposit, return 0.\n         *\n         * NOTE: originally, this line was in place to stop rounding errors making the deposit too large. However, the error\n         * corrections should ensure the error in P \"favors the Pool\", i.e. any given compounded deposit should slightly less\n         * than it's theoretical value.\n         *\n         * Thus it's unclear whether this line is still really needed.\n         */\n        if (compoundedStake < _initialStake / 1e9) {\n            return 0;\n        }\n\n        return compoundedStake;\n    }\n\n    /// @dev Compute the StableCoin and Collateral rewards. Uses a \"feedback\" error correction, to keep\n    /// the cumulative error in the P and S state variables low:s\n    function _computeRewardsPerUnitStaked(\n        address _collateralTokenAddress,\n        uint256 _collToAdd,\n        uint256 _debtToOffset,\n        uint256 _totalStableCoinDeposits\n    ) internal returns (uint256 collateralGainPerUnitStaked, uint256 stableCoinLossPerUnitStaked) {\n        /*\n         * Compute the StableCoin and Collateral rewards. Uses a \"feedback\" error correction, to keep\n         * the cumulative error in the P and S state variables low:\n         *\n         * 1) Form numerators which compensate for the floor division errors that occurred the last time this\n         * function was called.\n         * 2) Calculate \"per-unit-staked\" ratios.\n         * 3) Multiply each ratio back by its denominator, to reveal the current floor division error.\n         * 4) Store these errors for use in the next correction when this function is called.\n         * 5) Note: static analysis tools complain about this \"division before multiplication\", however, it is intended.\n         */\n        uint256 collateralNumerator = _collToAdd * DECIMAL_PRECISION + collateralToLastErrorOffset[_collateralTokenAddress];\n\n        assert(_debtToOffset <= _totalStableCoinDeposits);\n        if (_debtToOffset == _totalStableCoinDeposits) {\n            stableCoinLossPerUnitStaked = DECIMAL_PRECISION; // When the Pool depletes to 0, so does each deposit\n            lastStableCoinLossErrorOffset = 0;\n        } else {\n            uint256 stableCoinLossNumerator = _debtToOffset * DECIMAL_PRECISION - lastStableCoinLossErrorOffset;\n            /*\n             * Add 1 to make error in quotient positive. We want \"slightly too much\" StableCoin loss,\n             * which ensures the error in any given compoundedStableCoinDeposit favors the Stability Pool.\n             */\n            stableCoinLossPerUnitStaked = stableCoinLossNumerator / _totalStableCoinDeposits + 1;\n            lastStableCoinLossErrorOffset = stableCoinLossPerUnitStaked * _totalStableCoinDeposits - stableCoinLossNumerator;\n        }\n\n        collateralGainPerUnitStaked = (_totalStableCoinDeposits != 0) ? collateralNumerator / _totalStableCoinDeposits : 0;\n        collateralToLastErrorOffset[_collateralTokenAddress] =\n            collateralNumerator -\n            collateralGainPerUnitStaked *\n            _totalStableCoinDeposits;\n\n        return (collateralGainPerUnitStaked, stableCoinLossPerUnitStaked);\n    }\n\n    /// @dev distributes A3A per minutes that was not spent yet\n    function _triggerA3Adistribution() internal {\n        uint256 issuance = _issueA3ARewards();\n        _updateG(issuance);\n    }\n\n    function _issueA3ARewards() internal returns (uint256) {\n        uint256 newA3ARewardTime = block.timestamp;\n        uint256 totalA3ARewardsLeft_cached = totalA3ARewardsLeft;\n        if (totalA3ARewardsLeft_cached == 0 || a3aPerMinute == 0 || totalDeposit == 0) {\n            latestA3ARewardTime = newA3ARewardTime;\n            return 0;\n        }\n\n        uint256 timePassedInMinutes = (newA3ARewardTime - latestA3ARewardTime) / SECONDS_IN_ONE_MINUTE;\n        uint256 issuance = a3aPerMinute * timePassedInMinutes;\n        if (totalA3ARewardsLeft_cached < issuance) {\n            issuance = totalA3ARewardsLeft_cached; // event will capture that 0 tokens left\n        }\n        uint256 newTotalA3ARewardsLeft = totalA3ARewardsLeft_cached - issuance;\n        totalA3ARewardsLeft = newTotalA3ARewardsLeft;\n        latestA3ARewardTime = newA3ARewardTime;\n\n        emit A3ARewardIssue(issuance, newTotalA3ARewardsLeft);\n\n        return issuance;\n    }\n\n    function _computeA3APerUnitStaked(uint256 _a3aIssuance, uint256 _totalStableCoinDeposits) internal returns (uint256) {\n        /*\n         * Calculate the A3A-per-unit staked.  Division uses a \"feedback\" error correction, to keep the\n         * cumulative error low in the running total G:\n         *\n         * 1) Form a numerator which compensates for the floor division error that occurred the last time this\n         * function was called.\n         * 2) Calculate \"per-unit-staked\" ratio.\n         * 3) Multiply the ratio back by its denominator, to reveal the current floor division error.\n         * 4) Store this error for use in the next correction when this function is called.\n         * 5) Note: static analysis tools complain about this \"division before multiplication\", however, it is intended.\n         */\n        uint256 a3aNumerator = _a3aIssuance * DECIMAL_PRECISION + lastA3AError;\n\n        uint256 a3aPerUnitStaked = a3aNumerator / _totalStableCoinDeposits;\n        lastA3AError = a3aNumerator - (a3aPerUnitStaked * _totalStableCoinDeposits);\n\n        return a3aPerUnitStaked;\n    }\n\n    /// @dev transfers collateral rewards tokens precalculated to the depositor\n    function _sendCollateralRewardsToDepositor(TokenToUint256[] memory _depositorCollateralGains) internal {\n        for (uint256 i = 0; i < _depositorCollateralGains.length; i++) {\n            if (_depositorCollateralGains[i].value == 0) {\n                continue;\n            }\n            IERC20 collateralToken = IERC20(_depositorCollateralGains[i].tokenAddress);\n            collateralToken.safeTransfer(msg.sender, _depositorCollateralGains[i].value);\n            emit CollateralRewardRedeemed(\n                msg.sender,\n                _depositorCollateralGains[i].tokenAddress,\n                _depositorCollateralGains[i].value\n            );\n        }\n    }\n\n    /// @dev transfers A3A amount to the user\n    function _sendA3ARewardsToDepositor(uint256 _a3aGain) internal {\n        a3aToken.transfer(msg.sender, _a3aGain);\n    }\n}\n\n\n// File: contracts/utils/BONQMath.sol\n// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.4;\n\nlibrary BONQMath {\n  uint256 public constant DECIMAL_PRECISION = 1e18;\n  uint256 public constant MAX_INT = 2**256 - 1;\n\n  uint256 public constant MINUTE_DECAY_FACTOR = 999037758833783000;\n\n  /// @dev return the smaller of two numbers\n  function min(uint256 a, uint256 b) internal pure returns (uint256) {\n    return a < b ? a : b;\n  }\n\n  /// @dev return the bigger of two numbers\n  function max(uint256 a, uint256 b) internal pure returns (uint256) {\n    return a > b ? a : b;\n  }\n\n  /**\n   * @dev Multiply two decimal numbers and use normal rounding rules:\n   *  -round product up if 19'th mantissa digit >= 5\n   *  -round product down if 19'th mantissa digit < 5\n   *\n   * Used only inside the exponentiation, _decPow().\n   */\n  function decMul(uint256 x, uint256 y) internal pure returns (uint256 decProd) {\n    uint256 prod_xy = x * y;\n\n    decProd = (prod_xy + (DECIMAL_PRECISION / 2)) / DECIMAL_PRECISION;\n  }\n\n  /**\n   * @dev Exponentiation function for 18-digit decimal base, and integer exponent n.\n   *\n   * Uses the efficient \"exponentiation by squaring\" algorithm. O(log(n)) complexity.\n   *\n   * Called by function that represent time in units of minutes:\n   * 1) IFeeRecipient.calcDecayedBaseRate\n   *\n   * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\n   * \"minutes in 1000 years\": 60 * 24 * 365 * 1000\n   *\n   * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\n   * negligibly different from just passing the cap, since:\n   * @param _base number to exponentially increase\n   * @param _minutes power in minutes passed\n   */\n  function _decPow(uint256 _base, uint256 _minutes) internal pure returns (uint256) {\n    if (_minutes > 525600000) {\n      _minutes = 525600000;\n    } // cap to avoid overflow\n\n    if (_minutes == 0) {\n      return DECIMAL_PRECISION;\n    }\n\n    uint256 y = DECIMAL_PRECISION;\n    uint256 x = _base;\n    uint256 n = _minutes;\n\n    // Exponentiation-by-squaring\n    while (n > 1) {\n      if (n % 2 == 0) {\n        x = decMul(x, x);\n        n = n / 2;\n      } else {\n        // if (n % 2 != 0)\n        y = decMul(x, y);\n        x = decMul(x, x);\n        n = (n - 1) / 2;\n      }\n    }\n\n    return decMul(x, y);\n  }\n}\n\n\n// File: contracts/utils/constants.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ncontract Constants {\n  uint256 public constant DECIMAL_PRECISION = 1e18;\n  uint256 public constant LIQUIDATION_RESERVE = 1e18;\n  uint256 public constant MAX_INT = 2**256 - 1;\n\n  uint256 public constant PERCENT = (DECIMAL_PRECISION * 1) / 100; // 1%\n  uint256 public constant PERCENT10 = PERCENT * 10; // 10%\n  uint256 public constant PERCENT_05 = PERCENT / 2; // 0.5%\n\n  uint256 public constant MAX_BORROWING_RATE = (DECIMAL_PRECISION * 5) / 100; // 5%\n  uint256 public constant MAX_REDEMPTION_RATE = (DECIMAL_PRECISION * 1) / 100; // 1%\n\n}\n\n\n// File: contracts/interfaces/IVault.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IVault {\n    function vaultOwner() external view returns (address);\n    function debt() external view returns (uint256);\n    function transferVaultOwnership(address _newOwner) external;\n    function setName(string memory _name) external;\n    function containsCollateral(address _collateral) external view returns (bool);\n    function collateralsLength() external view returns (uint256);\n    function collateralAt(uint256 _index) external view returns (address);\n    function collaterals() external view returns (address[] memory);\n    function collateral(address _collateral) external view returns (uint256);\n    function factory() external view returns (address);\n    function addCollateral(address _collateral, uint256 _amount) external;\n    function removeCollateral(address _collateral, uint256 _amount, address _to) external;\n    function addBadDebt(uint256 _amount) external;\n    function borrowable() external view returns (uint256 _maxBorrowable, uint256 _borrowable);\n    function borrow(uint256 _amount) external;\n    function repay(uint256 _amount) external;\n    function calcRedeem(\n        address _collateral,\n        uint256 _collateralAmount\n    ) external view returns (uint256 _stableAmountNeeded, uint256 _redemptionFee);\n    function redeem(\n        address _collateral,\n        uint256 _collateralAmount\n    ) external returns (uint256 _debtRepaid, uint256 _feeCollected);\n    function healthFactor(bool _useMlr) external view returns (uint256 _healthFactor);\n    function newHealthFactor(uint256 _newDebt, bool _useMlr) external view returns (uint256 _newHealthFactor);\n    function borrowableWithDiff(\n        address _collateral,\n        uint256 _diffAmount,\n        bool _isAdd,\n        bool _useMlr\n    ) external view returns (uint256 _maxBorrowable, uint256 _borrowable);\n    function liquidate() external returns (uint256 _forgivenDebt);\n}\n\n\n// File: contracts/interfaces/IOwnable.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IOwnable {\n  /**\n   * @dev Returns the address of the current owner.\n   */\n  function owner() external view returns (address);\n\n  /**\n   * @dev Transfers ownership of the contract to a new account (`newOwner`).\n   * Can only be called by the current owner.\n   */\n  function transferOwnership(address newOwner) external;\n}\n\n\n// File: contracts/interfaces/IVaultFactory.sol\n// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.4;\n\ninterface IVaultFactory {\n    event NewVault(address indexed vault, string name, address indexed owner);\n    event PriceFeedUpdated(address indexed priceFeed);\n\n    function setPriceFeed(address _priceFeed) external;\n    function vaultCount() external view returns (uint256);\n    function lastVault() external view returns (address);\n    function firstVault() external view returns (address);\n    function nextVault(address _vault) external view returns (address);\n    function prevVault(address _vault) external view returns (address);\n    function liquidationRouter() external view returns (address);\n    function MAX_TOKENS_PER_VAULT() external view returns (uint256);\n    function priceFeed() external view returns (address);\n    function transferVaultOwnership(address _vault, address _newOwner) external;\n    function createVault(string memory _name) external returns (address);\n    function addCollateralNative(address _vault) external payable;\n    function removeCollateralNative(address _vault, uint256 _amount, address _to) external;\n    function addCollateral(address _vault, address _collateral, uint256 _amount) external;\n    function removeCollateral(address _vault, address _collateral, uint256 _amount, address _to) external;\n    function borrow(address _vault, uint256 _amount, address _to) external;\n    function distributeBadDebt(address _vault, uint256 _amount) external;\n    function closeVault(address _vault) external;\n    function repay(address _vault, uint256 _amount) external;\n    function redeem(address _vault, address _collateral, uint256 _collateralAmount, address _to) external;\n    function liquidate(address _vault) external;\n    function isLiquidatable(address _vault) external view returns (bool);\n    function isReedemable(address _vault, address _collateral) external view returns (bool);\n    function containsVault(address _vault) external view returns (bool);\n    function stable() external view returns (address);\n    function isCollateralSupported(address _collateral) external view returns (bool);\n    function vaultsByOwnerLength(address _owner) external view returns (uint256);\n}\n\n\n\n// File: contracts/interfaces/IMintableToken.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"./IOwnable.sol\";\n\ninterface IMintableToken is IERC20, IOwnable {\n  function mint(address recipient, uint256 amount) external;\n\n  function burn(uint256 amount) external;\n\n  function name() external view returns (string memory);\n\n  function symbol() external view returns (string memory);\n\n  function approve(address spender, uint256 amount) external override returns (bool);\n}\n\n\n// File: @openzeppelin/contracts/utils/Address.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n\n\n// File: @openzeppelin/contracts/utils/Context.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n\n\n// File: @openzeppelin/contracts/access/Ownable.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n\n\n// File: contracts/interfaces/ILiquidationRouter.sol\n//SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface ILiquidationRouter {\n    function addSeizedCollateral(address _collateral, uint256 _amount) external;\n\n    function addUnderWaterDebt(address _vault, uint256 _amount) external;\n\n    function removeUnderWaterDebt(uint256 _amount) external;\n\n    function underWaterDebt() external view returns (uint256);\n\n    function collaterals() external view returns (address[] memory);\n\n    function collateral(address _collateral) external view returns (uint256);\n\n    function tryLiquidate() external;\n\n    function stabilityPool() external view returns (address);\n    function auctionManager() external view returns (address);\n    function lastResortLiquidation() external view returns (address);\n    function distributeBadDebt(address _vault, uint256 _amount) external;\n    function transferOwnership(address newOwner) external;\n}\n\n\n// File: @openzeppelin/contracts/token/ERC20/IERC20.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\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 amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` 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 amount) 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 `amount` as the allowance of `spender` over the 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 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` 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 amount) external returns (bool);\n}\n\n\n// File: @openzeppelin/contracts/security/ReentrancyGuard.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // 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\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n}\n\n\n// File: @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to\n     * 0 before setting it to a non-zero value.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n    }\n}\n\n\n// File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 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 */\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    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}","source_code_hash":null,"compiler_version":"0.8.19+commit.7dd6d404","optimization_used":"1","runs":1000,"abi":"[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_factory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_a3aToken\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"name\":\"A3APerMinuteUpdated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_newAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"A3ARewardIssue\",\"type\":\"event\",\"inputs\":[{\"name\":\"issuance\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"_totalA3ARewardsLeft\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"A3ARewardRedeemed\",\"type\":\"event\",\"inputs\":[{\"name\":\"_contributor\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"_amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"CollateralRewardRedeemed\",\"type\":\"event\",\"inputs\":[{\"name\":\"_contributor\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"_tokenAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"_amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"Deposit\",\"type\":\"event\",\"inputs\":[{\"name\":\"_contributor\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"_amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"DepositSnapshotUpdated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_depositor\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"_P\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"_G\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"_newDepositValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"EpochUpdated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_currentEpoch\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"name\":\"G_Updated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_G\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"_epoch\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"},{\"name\":\"_scale\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"name\":\"OwnershipTransferred\",\"type\":\"event\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"name\":\"P_Updated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_P\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"S_Updated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_tokenAddress\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"_S\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"_epoch\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"},{\"name\":\"_scale\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"name\":\"ScaleUpdated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_currentScale\",\"type\":\"uint128\",\"indexed\":false,\"internalType\":\"uint128\"}],\"anonymous\":false},{\"name\":\"TotalA3ARewardsUpdated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_newAmount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"TotalDepositUpdated\",\"type\":\"event\",\"inputs\":[{\"name\":\"_newValue\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"Withdraw\",\"type\":\"event\",\"inputs\":[{\"name\":\"_contributor\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"_amount\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"name\":\"DECIMAL_PRECISION\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"LIQUIDATION_RESERVE\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"MAX_BORROWING_RATE\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"MAX_INT\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"MAX_REDEMPTION_RATE\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"P\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"PERCENT\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"PERCENT10\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"PERCENT_05\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"SCALE_FACTOR\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"SECONDS_IN_ONE_MINUTE\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"a3aPerMinute\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"a3aToken\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contract IERC20\"}],\"stateMutability\":\"view\"},{\"name\":\"collateralToLastErrorOffset\",\"type\":\"function\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"currentEpoch\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"name\":\"currentScale\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"name\":\"deposit\",\"type\":\"function\",\"inputs\":[{\"name\":\"_amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"name\":\"depositSnapshots\",\"type\":\"function\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"P\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"G\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"scale\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"epoch\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"stateMutability\":\"view\"},{\"name\":\"deposits\",\"type\":\"function\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"epochToScaleToG\",\"type\":\"function\",\"inputs\":[{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"epochToScaleToTokenToSum\",\"type\":\"function\",\"inputs\":[{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"tokenAddress\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"S_value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"factory\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contract IVaultFactory\"}],\"stateMutability\":\"view\"},{\"name\":\"getCollateralReward\",\"type\":\"function\",\"inputs\":[{\"name\":\"_token\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_depositor\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"getDepositorA3AGain\",\"type\":\"function\",\"inputs\":[{\"name\":\"_depositor\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"getWithdrawableDeposit\",\"type\":\"function\",\"inputs\":[{\"name\":\"staker\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"lastA3AError\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"lastStableCoinLossErrorOffset\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"latestA3ARewardTime\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"liquidate\",\"type\":\"function\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"name\":\"owner\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"name\":\"redeemReward\",\"type\":\"function\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"name\":\"renounceOwnership\",\"type\":\"function\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"name\":\"setA3AAmountForRewards\",\"type\":\"function\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"name\":\"setA3APerMinute\",\"type\":\"function\",\"inputs\":[{\"name\":\"_a3aPerMinute\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"name\":\"setVaultFactory\",\"type\":\"function\",\"inputs\":[{\"name\":\"_factory\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"name\":\"stableCoin\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contract IMintableToken\"}],\"stateMutability\":\"view\"},{\"name\":\"totalA3ARewardsLeft\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"totalDeposit\",\"type\":\"function\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"name\":\"transferOwnership\",\"type\":\"function\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"name\":\"withdraw\",\"type\":\"function\",\"inputs\":[{\"name\":\"_amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"}]","contract_file_name":"contracts/StabilityPool.sol","compiler_type":"Solidity","evm_version":"paris","constructor_arguments":null,"library":null,"license_type":null,"critical_count":0,"high_count":0,"medium_count":0,"low_count":0,"informational_count":0,"audit_status":"completed","audit_completed_at":"1780733255417","erc20_balances":[]}}