ETH Price: $2,819.28 (+4.63%)

Contract

0xed8B26D99834540C5013701bB3715faFD39993Ba
 
Transaction Hash
Method
Block
From
To
Withdraw From SP218292542025-02-12 8:34:475 days ago1739349287IN
0xed8B26D9...FD39993Ba
0 ETH0.000115880.81781482
Provide To SP218059322025-02-09 2:20:118 days ago1739067611IN
0xed8B26D9...FD39993Ba
0 ETH0.000210080.84308389
Provide To SP217779452025-02-05 4:35:4712 days ago1738730147IN
0xed8B26D9...FD39993Ba
0 ETH0.00028771.15453392
Provide To SP217578332025-02-02 9:08:1115 days ago1738487291IN
0xed8B26D9...FD39993Ba
0 ETH0.000650562.56141613
Withdraw From SP217543982025-02-01 21:36:5915 days ago1738445819IN
0xed8B26D9...FD39993Ba
0 ETH0.000375762.65077781
Withdraw From SP217279692025-01-29 5:02:3519 days ago1738126955IN
0xed8B26D9...FD39993Ba
0 ETH0.000331871.6
Provide To SP216866512025-01-23 10:39:4725 days ago1737628787IN
0xed8B26D9...FD39993Ba
0 ETH0.001707786.41309539
Withdraw From SP216723972025-01-21 10:54:2327 days ago1737456863IN
0xed8B26D9...FD39993Ba
0 ETH0.0023957912.58831617
Provide To SP216527542025-01-18 17:05:2329 days ago1737219923IN
0xed8B26D9...FD39993Ba
0 ETH0.0068854327.62496382
Withdraw From SP216241182025-01-14 17:07:2333 days ago1736874443IN
0xed8B26D9...FD39993Ba
0 ETH0.001795514.40799417
Withdraw From SP216179882025-01-13 20:35:3534 days ago1736800535IN
0xed8B26D9...FD39993Ba
0 ETH0.001044916.46529223
Withdraw From SP215940342025-01-10 12:19:5938 days ago1736511599IN
0xed8B26D9...FD39993Ba
0 ETH0.000703344.96253433
Withdraw From SP215938122025-01-10 11:35:2338 days ago1736508923IN
0xed8B26D9...FD39993Ba
0 ETH0.000845715.96751971
Withdraw From SP215928882025-01-10 8:28:5938 days ago1736497739IN
0xed8B26D9...FD39993Ba
0 ETH0.000732475.16802962
Provide To SP215919442025-01-10 5:19:2338 days ago1736486363IN
0xed8B26D9...FD39993Ba
0 ETH0.000761993.28272053
Withdraw From SP215879102025-01-09 15:47:4738 days ago1736437667IN
0xed8B26D9...FD39993Ba
0 ETH0.0016123811.37735668
Provide To SP215870092025-01-09 12:45:5939 days ago1736426759IN
0xed8B26D9...FD39993Ba
0 ETH0.001392315.58692532
Provide To SP215797182025-01-08 12:20:3540 days ago1736338835IN
0xed8B26D9...FD39993Ba
0 ETH0.001248665.0105032
Provide To SP215786752025-01-08 8:51:2340 days ago1736326283IN
0xed8B26D9...FD39993Ba
0 ETH0.001770067.10271871
Withdraw From SP215742932025-01-07 18:09:5940 days ago1736273399IN
0xed8B26D9...FD39993Ba
0 ETH0.0022154711.76373894
Claim Collateral...215692272025-01-07 1:12:4741 days ago1736212367IN
0xed8B26D9...FD39993Ba
0 ETH0.001255.99933096
Withdraw From SP215657662025-01-06 13:37:4742 days ago1736170667IN
0xed8B26D9...FD39993Ba
0 ETH0.001242059.96589254
Claim Reward215637542025-01-06 6:52:2342 days ago1736146343IN
0xed8B26D9...FD39993Ba
0 ETH0.001350885.74397403
Provide To SP215628752025-01-06 3:54:4742 days ago1736135687IN
0xed8B26D9...FD39993Ba
0 ETH0.000822975.73413359
Withdraw From SP215438772025-01-03 12:12:2345 days ago1735906343IN
0xed8B26D9...FD39993Ba
0 ETH0.001271359.27716381
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StabilityPool

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, MIT license
File 1 of 11 : StabilityPool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import "SafeERC20.sol";
import "IERC20.sol";
import "PrismaOwnable.sol";
import "SystemStart.sol";
import "PrismaMath.sol";
import "IDebtToken.sol";
import "IVault.sol";

/**
    @title Prisma Stability Pool
    @notice Based on Liquity's `StabilityPool`
            https://github.com/liquity/dev/blob/main/packages/contracts/contracts/StabilityPool.sol

            Prisma's implementation is modified to support multiple collaterals. Deposits into
            the stability pool may be used to liquidate any supported collateral type.
 */
contract StabilityPool is PrismaOwnable, SystemStart {
    using SafeERC20 for IERC20;

    uint256 public constant DECIMAL_PRECISION = 1e18;
    uint128 public constant SUNSET_DURATION = 180 days;
    uint256 constant REWARD_DURATION = 1 weeks;

    uint256 public constant emissionId = 0;

    IDebtToken public immutable debtToken;
    IPrismaVault public immutable vault;
    address public immutable factory;
    address public immutable liquidationManager;

    uint128 public rewardRate;
    uint32 public lastUpdate;
    uint32 public periodFinish;

    mapping(IERC20 collateral => uint256 index) public indexByCollateral;
    IERC20[] public collateralTokens;

    // Tracker for Debt held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.
    uint256 internal totalDebtTokenDeposits;

    mapping(address => AccountDeposit) public accountDeposits; // depositor address -> initial deposit
    mapping(address => Snapshots) public depositSnapshots; // depositor address -> snapshots struct

    // index values are mapped against the values within `collateralTokens`
    mapping(address => uint256[256]) public depositSums; // depositor address -> sums

    mapping(address depositor => uint80[256] gains) public collateralGainsByDepositor;

    mapping(address depositor => uint256 rewards) private storedPendingReward;

    /*  Product 'P': Running product by which to multiply an initial deposit, in order to find the current compounded deposit,
     * after a series of liquidations have occurred, each of which cancel some debt with the deposit.
     *
     * During its lifetime, a deposit's value evolves from d_t to d_t * P / P_t , where P_t
     * is the snapshot of P taken at the instant the deposit was made. 18-digit decimal.
     */
    uint256 public P = DECIMAL_PRECISION;

    uint256 public constant SCALE_FACTOR = 1e9;

    // Each time the scale of P shifts by SCALE_FACTOR, the scale is incremented by 1
    uint128 public currentScale;

    // With each offset that fully empties the Pool, the epoch is incremented by 1
    uint128 public currentEpoch;

    /* collateral Gain sum 'S': During its lifetime, each deposit d_t earns a collateral gain of ( d_t * [S - S_t] )/P_t, where S_t
     * is the depositor's snapshot of S taken at the time t when the deposit was made.
     *
     * The 'S' sums are stored in a nested mapping (epoch => scale => sum):
     *
     * - The inner mapping records the sum S at different scales
     * - The outer mapping records the (scale => sum) mappings, for different epochs.
     */

    // index values are mapped against the values within `collateralTokens`
    mapping(uint128 => mapping(uint128 => uint256[256])) public epochToScaleToSums;

    /*
     * Similarly, the sum 'G' is used to calculate Prisma gains. During it's lifetime, each deposit d_t earns a Prisma gain of
     *  ( 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.
     *
     *  Prisma reward events occur are triggered by depositor operations (new deposit, topup, withdrawal), and liquidations.
     *  In each case, the Prisma reward is issued (i.e. G is updated), before other state changes are made.
     */
    mapping(uint128 => mapping(uint128 => uint256)) public epochToScaleToG;

    // Error tracker for the error correction in the Prisma issuance calculation
    uint256 public lastPrismaError;
    // Error trackers for the error correction in the offset calculation
    uint256 public lastCollateralError_Offset;
    uint256 public lastDebtLossError_Offset;

    mapping(uint16 => SunsetIndex) _sunsetIndexes;
    Queue queue;

    struct AccountDeposit {
        uint128 amount;
        uint128 timestamp; // timestamp of the last deposit
    }

    struct Snapshots {
        uint256 P;
        uint256 G;
        uint128 scale;
        uint128 epoch;
    }

    struct SunsetIndex {
        uint128 idx;
        uint128 expiry;
    }
    struct Queue {
        uint16 firstSunsetIndexKey;
        uint16 nextSunsetIndexKey;
    }

    event StabilityPoolDebtBalanceUpdated(uint256 _newBalance);

    event P_Updated(uint256 _P);
    event S_Updated(uint256 idx, uint256 _S, uint128 _epoch, uint128 _scale);
    event G_Updated(uint256 _G, uint128 _epoch, uint128 _scale);
    event EpochUpdated(uint128 _currentEpoch);
    event ScaleUpdated(uint128 _currentScale);

    event DepositSnapshotUpdated(address indexed _depositor, uint256 _P, uint256 _G);
    event UserDepositChanged(address indexed _depositor, uint256 _newDeposit);

    event CollateralGainWithdrawn(address indexed _depositor, uint256[] _collateral);
    event CollateralOverwritten(IERC20 oldCollateral, IERC20 newCollateral);

    event RewardClaimed(address indexed account, address indexed recipient, uint256 claimed);

    constructor(
        address _prismaCore,
        IDebtToken _debtTokenAddress,
        IPrismaVault _vault,
        address _factory,
        address _liquidationManager
    ) PrismaOwnable(_prismaCore) SystemStart(_prismaCore) {
        debtToken = _debtTokenAddress;
        vault = _vault;
        factory = _factory;
        liquidationManager = _liquidationManager;
        periodFinish = uint32(block.timestamp - 1);
    }

    function enableCollateral(IERC20 _collateral) external {
        require(msg.sender == factory, "Not factory");
        uint256 length = collateralTokens.length;
        bool collateralEnabled;
        for (uint256 i = 0; i < length; i++) {
            if (collateralTokens[i] == _collateral) {
                collateralEnabled = true;
                break;
            }
        }
        if (!collateralEnabled) {
            Queue memory queueCached = queue;
            if (queueCached.nextSunsetIndexKey > queueCached.firstSunsetIndexKey) {
                SunsetIndex memory sIdx = _sunsetIndexes[queueCached.firstSunsetIndexKey];
                if (sIdx.expiry < block.timestamp) {
                    delete _sunsetIndexes[queue.firstSunsetIndexKey++];
                    _overwriteCollateral(_collateral, sIdx.idx);
                    return;
                }
            }
            collateralTokens.push(_collateral);
            indexByCollateral[_collateral] = collateralTokens.length;
        } else {
            // revert if the factory is trying to deploy a new TM with a sunset collateral
            require(indexByCollateral[_collateral] > 0, "Collateral is sunsetting");
        }
    }

    function _overwriteCollateral(IERC20 _newCollateral, uint256 idx) internal {
        require(indexByCollateral[_newCollateral] == 0, "Collateral must be sunset");
        uint256 length = collateralTokens.length;
        require(idx < length, "Index too large");
        uint256 externalLoopEnd = currentEpoch;
        uint256 internalLoopEnd = currentScale;
        for (uint128 i; i <= externalLoopEnd; ) {
            for (uint128 j; j <= internalLoopEnd; ) {
                epochToScaleToSums[i][j][idx] = 0;
                unchecked {
                    ++j;
                }
            }
            unchecked {
                ++i;
            }
        }
        indexByCollateral[_newCollateral] = idx + 1;
        emit CollateralOverwritten(collateralTokens[idx], _newCollateral);
        collateralTokens[idx] = _newCollateral;
    }

    /**
     * @notice Starts sunsetting a collateral
     *         During sunsetting liquidated collateral handoff to the SP will revert
        @dev IMPORTANT: When sunsetting a collateral, `TroveManager.startSunset`
                        should be called on all TM linked to that collateral
        @param collateral Collateral to sunset

     */
    function startCollateralSunset(IERC20 collateral) external onlyOwner {
        require(indexByCollateral[collateral] > 0, "Collateral already sunsetting");
        _sunsetIndexes[queue.nextSunsetIndexKey++] = SunsetIndex(
            uint128(indexByCollateral[collateral] - 1),
            uint128(block.timestamp + SUNSET_DURATION)
        );
        delete indexByCollateral[collateral]; //This will prevent calls to the SP in case of liquidations
    }

    function getTotalDebtTokenDeposits() external view returns (uint256) {
        return totalDebtTokenDeposits;
    }

    // --- External Depositor Functions ---

    /*  provideToSP():
     *
     * - Triggers a Prisma issuance, based on time passed since the last issuance. The Prisma issuance is shared between *all* depositors and front ends
     * - Tags the deposit with the provided front end tag param, if it's a new deposit
     * - Sends depositor's accumulated gains (Prisma, collateral) to depositor
     * - Sends the tagged front end's accumulated Prisma gains to the tagged front end
     * - Increases deposit and tagged front end's stake, and takes new snapshots for each.
     */
    function provideToSP(uint256 _amount) external {
        require(!PRISMA_CORE.paused(), "Deposits are paused");
        require(_amount > 0, "StabilityPool: Amount must be non-zero");

        _triggerRewardIssuance();

        _accrueDepositorCollateralGain(msg.sender);

        uint256 compoundedDebtDeposit = getCompoundedDebtDeposit(msg.sender);

        _accrueRewards(msg.sender);

        debtToken.sendToSP(msg.sender, _amount);
        uint256 newTotalDebtTokenDeposits = totalDebtTokenDeposits + _amount;
        totalDebtTokenDeposits = newTotalDebtTokenDeposits;
        emit StabilityPoolDebtBalanceUpdated(newTotalDebtTokenDeposits);

        uint256 newDeposit = compoundedDebtDeposit + _amount;
        accountDeposits[msg.sender] = AccountDeposit({
            amount: uint128(newDeposit),
            timestamp: uint128(block.timestamp)
        });

        _updateSnapshots(msg.sender, newDeposit);
        emit UserDepositChanged(msg.sender, newDeposit);
    }

    /*  withdrawFromSP():
     *
     * - Triggers a Prisma issuance, based on time passed since the last issuance. The Prisma issuance is shared between *all* depositors and front ends
     * - Removes the deposit's front end tag if it is a full withdrawal
     * - Sends all depositor's accumulated gains (Prisma, collateral) to depositor
     * - Sends the tagged front end's accumulated Prisma gains to the tagged front end
     * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.
     *
     * If _amount > userDeposit, the user withdraws all of their compounded deposit.
     */
    function withdrawFromSP(uint256 _amount) external {
        uint256 initialDeposit = accountDeposits[msg.sender].amount;
        uint128 depositTimestamp = accountDeposits[msg.sender].timestamp;
        require(initialDeposit > 0, "StabilityPool: User must have a non-zero deposit");
        require(depositTimestamp < block.timestamp, "!Deposit and withdraw same block");

        _triggerRewardIssuance();

        _accrueDepositorCollateralGain(msg.sender);

        uint256 compoundedDebtDeposit = getCompoundedDebtDeposit(msg.sender);
        uint256 debtToWithdraw = PrismaMath._min(_amount, compoundedDebtDeposit);

        _accrueRewards(msg.sender);

        if (debtToWithdraw > 0) {
            debtToken.returnFromPool(address(this), msg.sender, debtToWithdraw);
            _decreaseDebt(debtToWithdraw);
        }

        // Update deposit
        uint256 newDeposit = compoundedDebtDeposit - debtToWithdraw;
        accountDeposits[msg.sender] = AccountDeposit({ amount: uint128(newDeposit), timestamp: depositTimestamp });

        _updateSnapshots(msg.sender, newDeposit);
        emit UserDepositChanged(msg.sender, newDeposit);
    }

    // --- Prisma issuance functions ---

    function _triggerRewardIssuance() internal {
        _updateG(_vestedEmissions());

        uint256 _periodFinish = periodFinish;
        uint256 lastUpdateWeek = (_periodFinish - startTime) / 1 weeks;
        // If the last claim was a week earlier we reclaim
        if (getWeek() >= lastUpdateWeek) {
            uint256 amount = vault.allocateNewEmissions(emissionId);
            if (amount > 0) {
                // If the previous period is not finished we combine new and pending old rewards
                if (block.timestamp < _periodFinish) {
                    uint256 remaining = _periodFinish - block.timestamp;
                    amount += remaining * rewardRate;
                }
                rewardRate = uint128(amount / REWARD_DURATION);
                periodFinish = uint32(block.timestamp + REWARD_DURATION);
            }
        }
        lastUpdate = uint32(block.timestamp);
    }

    function _vestedEmissions() internal view returns (uint256) {
        uint256 updated = periodFinish;
        // Period is not ended we max at current timestamp
        if (updated > block.timestamp) updated = block.timestamp;
        // if the last update was after the current update time it means all rewards have been vested already
        uint256 lastUpdateCached = lastUpdate;
        if (lastUpdateCached >= updated) return 0; //Nothing to claim
        uint256 duration = updated - lastUpdateCached;
        return duration * rewardRate;
    }

    function _updateG(uint256 _prismaIssuance) internal {
        uint256 totalDebt = totalDebtTokenDeposits; // cached to save an SLOAD
        /*
         * When total deposits is 0, G is not updated. In this case, the Prisma issued can not be obtained by later
         * depositors - it is missed out on, and remains in the balanceof the Treasury contract.
         *
         */
        if (totalDebt == 0 || _prismaIssuance == 0) {
            return;
        }

        uint256 prismaPerUnitStaked;
        prismaPerUnitStaked = _computePrismaPerUnitStaked(_prismaIssuance, totalDebt);
        uint128 currentEpochCached = currentEpoch;
        uint128 currentScaleCached = currentScale;
        uint256 marginalPrismaGain = prismaPerUnitStaked * P;
        uint256 newG = epochToScaleToG[currentEpochCached][currentScaleCached] + marginalPrismaGain;
        epochToScaleToG[currentEpochCached][currentScaleCached] = newG;

        emit G_Updated(newG, currentEpochCached, currentScaleCached);
    }

    function _computePrismaPerUnitStaked(
        uint256 _prismaIssuance,
        uint256 _totalDebtTokenDeposits
    ) internal returns (uint256) {
        /*
         * Calculate the Prisma-per-unit staked.  Division uses a "feedback" error correction, to keep the
         * cumulative error low in the running total G:
         *
         * 1) Form a numerator which compensates for the floor division error that occurred the last time this
         * function was called.
         * 2) Calculate "per-unit-staked" ratio.
         * 3) Multiply the ratio back by its denominator, to reveal the current floor division error.
         * 4) Store this error for use in the next correction when this function is called.
         * 5) Note: static analysis tools complain about this "division before multiplication", however, it is intended.
         */
        uint256 prismaNumerator = (_prismaIssuance * DECIMAL_PRECISION) + lastPrismaError;

        uint256 prismaPerUnitStaked = prismaNumerator / _totalDebtTokenDeposits;
        lastPrismaError = prismaNumerator - (prismaPerUnitStaked * _totalDebtTokenDeposits);

        return prismaPerUnitStaked;
    }

    // --- Liquidation functions ---

    /*
     * Cancels out the specified debt against the Debt contained in the Stability Pool (as far as possible)
     */
    function offset(IERC20 collateral, uint256 _debtToOffset, uint256 _collToAdd) external virtual {
        _offset(collateral, _debtToOffset, _collToAdd);
    }

    function _offset(IERC20 collateral, uint256 _debtToOffset, uint256 _collToAdd) internal {
        require(msg.sender == liquidationManager, "StabilityPool: Caller is not Liquidation Manager");
        uint256 idx = indexByCollateral[collateral];
        idx -= 1;

        uint256 totalDebt = totalDebtTokenDeposits; // cached to save an SLOAD
        if (totalDebt == 0 || _debtToOffset == 0) {
            return;
        }

        _triggerRewardIssuance();

        (uint256 collateralGainPerUnitStaked, uint256 debtLossPerUnitStaked) = _computeRewardsPerUnitStaked(
            _collToAdd,
            _debtToOffset,
            totalDebt
        );

        _updateRewardSumAndProduct(collateralGainPerUnitStaked, debtLossPerUnitStaked, idx); // updates S and P

        // Cancel the liquidated Debt debt with the Debt in the stability pool
        _decreaseDebt(_debtToOffset);
    }

    // --- Offset helper functions ---

    function _computeRewardsPerUnitStaked(
        uint256 _collToAdd,
        uint256 _debtToOffset,
        uint256 _totalDebtTokenDeposits
    ) internal returns (uint256 collateralGainPerUnitStaked, uint256 debtLossPerUnitStaked) {
        /*
         * Compute the Debt and collateral rewards. Uses a "feedback" error correction, to keep
         * the cumulative error in the P and S state variables low:
         *
         * 1) Form numerators which compensate for the floor division errors that occurred the last time this
         * function was called.
         * 2) Calculate "per-unit-staked" ratios.
         * 3) Multiply each ratio back by its denominator, to reveal the current floor division error.
         * 4) Store these errors for use in the next correction when this function is called.
         * 5) Note: static analysis tools complain about this "division before multiplication", however, it is intended.
         */
        uint256 collateralNumerator = (_collToAdd * DECIMAL_PRECISION) + lastCollateralError_Offset;

        if (_debtToOffset == _totalDebtTokenDeposits) {
            debtLossPerUnitStaked = DECIMAL_PRECISION; // When the Pool depletes to 0, so does each deposit
            lastDebtLossError_Offset = 0;
        } else {
            uint256 debtLossNumerator = (_debtToOffset * DECIMAL_PRECISION) - lastDebtLossError_Offset;
            /*
             * Add 1 to make error in quotient positive. We want "slightly too much" Debt loss,
             * which ensures the error in any given compoundedDebtDeposit favors the Stability Pool.
             */
            debtLossPerUnitStaked = (debtLossNumerator / _totalDebtTokenDeposits) + 1;
            lastDebtLossError_Offset = (debtLossPerUnitStaked * _totalDebtTokenDeposits) - debtLossNumerator;
        }

        collateralGainPerUnitStaked = collateralNumerator / _totalDebtTokenDeposits;
        lastCollateralError_Offset = collateralNumerator - (collateralGainPerUnitStaked * _totalDebtTokenDeposits);

        return (collateralGainPerUnitStaked, debtLossPerUnitStaked);
    }

    // Update the Stability Pool reward sum S and product P
    function _updateRewardSumAndProduct(
        uint256 _collateralGainPerUnitStaked,
        uint256 _debtLossPerUnitStaked,
        uint256 idx
    ) internal {
        uint256 currentP = P;
        uint256 newP;

        /*
         * The newProductFactor is the factor by which to change all deposits, due to the depletion of Stability Pool Debt in the liquidation.
         * We make the product factor 0 if there was a pool-emptying. Otherwise, it is (1 - DebtLossPerUnitStaked)
         */
        uint256 newProductFactor = uint256(DECIMAL_PRECISION) - _debtLossPerUnitStaked;

        uint128 currentScaleCached = currentScale;
        uint128 currentEpochCached = currentEpoch;
        uint256 currentS = epochToScaleToSums[currentEpochCached][currentScaleCached][idx];

        /*
         * Calculate the new S first, before we update P.
         * The collateral gain for any given depositor from a liquidation depends on the value of their deposit
         * (and the value of totalDeposits) prior to the Stability being depleted by the debt in the liquidation.
         *
         * Since S corresponds to collateral gain, and P to deposit loss, we update S first.
         */
        uint256 marginalCollateralGain = _collateralGainPerUnitStaked * currentP;
        uint256 newS = currentS + marginalCollateralGain;
        epochToScaleToSums[currentEpochCached][currentScaleCached][idx] = newS;
        emit S_Updated(idx, newS, currentEpochCached, currentScaleCached);

        // If the Stability Pool was emptied, increment the epoch, and reset the scale and product P
        if (newProductFactor == 0) {
            currentEpoch = currentEpochCached + 1;
            emit EpochUpdated(currentEpoch);
            currentScale = 0;
            emit ScaleUpdated(currentScale);
            newP = DECIMAL_PRECISION;

            // If multiplying P by a non-zero product factor would reduce P below the scale boundary, increment the scale
        } else if ((currentP * newProductFactor) / DECIMAL_PRECISION < SCALE_FACTOR) {
            newP = (currentP * newProductFactor * SCALE_FACTOR) / DECIMAL_PRECISION;
            currentScale = currentScaleCached + 1;
            emit ScaleUpdated(currentScale);
        } else {
            newP = (currentP * newProductFactor) / DECIMAL_PRECISION;
        }

        require(newP > 0, "NewP");
        P = newP;
        emit P_Updated(newP);
    }

    function _decreaseDebt(uint256 _amount) internal {
        uint256 newTotalDebtTokenDeposits = totalDebtTokenDeposits - _amount;
        totalDebtTokenDeposits = newTotalDebtTokenDeposits;
        emit StabilityPoolDebtBalanceUpdated(newTotalDebtTokenDeposits);
    }

    // --- Reward calculator functions for depositor and front end ---

    /* Calculates the collateral gain earned by the deposit since its last snapshots were taken.
     * Given by the formula:  E = d0 * (S - S(0))/P(0)
     * where S(0) and P(0) are the depositor's snapshots of the sum S and product P, respectively.
     * d0 is the last recorded deposit value.
     */
    function getDepositorCollateralGain(address _depositor) external view returns (uint256[] memory collateralGains) {
        collateralGains = new uint256[](collateralTokens.length);

        uint256 P_Snapshot = depositSnapshots[_depositor].P;
        if (P_Snapshot == 0) return collateralGains;
        uint80[256] storage depositorGains = collateralGainsByDepositor[_depositor];
        uint256 initialDeposit = accountDeposits[_depositor].amount;
        uint128 epochSnapshot = depositSnapshots[_depositor].epoch;
        uint128 scaleSnapshot = depositSnapshots[_depositor].scale;
        uint256[256] storage sums = epochToScaleToSums[epochSnapshot][scaleSnapshot];
        uint256[256] storage nextSums = epochToScaleToSums[epochSnapshot][scaleSnapshot + 1];
        uint256[256] storage depSums = depositSums[_depositor];

        for (uint256 i = 0; i < collateralGains.length; i++) {
            collateralGains[i] = depositorGains[i];
            if (sums[i] == 0) continue; // Collateral was overwritten or not gains
            uint256 firstPortion = sums[i] - depSums[i];
            uint256 secondPortion = nextSums[i] / SCALE_FACTOR;
            collateralGains[i] += (initialDeposit * (firstPortion + secondPortion)) / P_Snapshot / DECIMAL_PRECISION;
        }
        return collateralGains;
    }

    function _accrueDepositorCollateralGain(address _depositor) private returns (bool hasGains) {
        uint80[256] storage depositorGains = collateralGainsByDepositor[_depositor];
        uint256 collaterals = collateralTokens.length;
        uint256 initialDeposit = accountDeposits[_depositor].amount;
        hasGains = false;
        if (initialDeposit == 0) {
            return hasGains;
        }

        uint128 epochSnapshot = depositSnapshots[_depositor].epoch;
        uint128 scaleSnapshot = depositSnapshots[_depositor].scale;
        uint256 P_Snapshot = depositSnapshots[_depositor].P;

        uint256[256] storage sums = epochToScaleToSums[epochSnapshot][scaleSnapshot];
        uint256[256] storage nextSums = epochToScaleToSums[epochSnapshot][scaleSnapshot + 1];
        uint256[256] storage depSums = depositSums[_depositor];

        for (uint256 i = 0; i < collaterals; i++) {
            if (sums[i] == 0) continue; // Collateral was overwritten or not gains
            hasGains = true;
            uint256 firstPortion = sums[i] - depSums[i];
            uint256 secondPortion = nextSums[i] / SCALE_FACTOR;
            depositorGains[i] += uint80(
                (initialDeposit * (firstPortion + secondPortion)) / P_Snapshot / DECIMAL_PRECISION
            );
        }
        return (hasGains);
    }

    /*
     * Calculate the Prisma gain earned by a deposit since its last snapshots were taken.
     * Given by the formula:  Prisma = d0 * (G - G(0))/P(0)
     * where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively.
     * d0 is the last recorded deposit value.
     */
    function claimableReward(address _depositor) external view returns (uint256) {
        uint256 totalDebt = totalDebtTokenDeposits;
        uint256 initialDeposit = accountDeposits[_depositor].amount;

        if (totalDebt == 0 || initialDeposit == 0) {
            return 0;
        }
        uint256 prismaNumerator = (_vestedEmissions() * DECIMAL_PRECISION) + lastPrismaError;
        uint256 prismaPerUnitStaked = prismaNumerator / totalDebt;
        uint256 marginalPrismaGain = prismaPerUnitStaked * P;

        Snapshots memory snapshots = depositSnapshots[_depositor];
        uint128 epochSnapshot = snapshots.epoch;
        uint128 scaleSnapshot = snapshots.scale;
        uint256 firstPortion;
        uint256 secondPortion;
        if (scaleSnapshot == currentScale) {
            firstPortion = epochToScaleToG[epochSnapshot][scaleSnapshot] - snapshots.G + marginalPrismaGain;
            secondPortion = epochToScaleToG[epochSnapshot][scaleSnapshot + 1] / SCALE_FACTOR;
        } else {
            firstPortion = epochToScaleToG[epochSnapshot][scaleSnapshot] - snapshots.G;
            secondPortion = (epochToScaleToG[epochSnapshot][scaleSnapshot + 1] + marginalPrismaGain) / SCALE_FACTOR;
        }

        return (initialDeposit * (firstPortion + secondPortion)) / snapshots.P / DECIMAL_PRECISION;
    }

    function _claimableReward(address _depositor) private view returns (uint256) {
        uint256 initialDeposit = accountDeposits[_depositor].amount;
        if (initialDeposit == 0) {
            return 0;
        }

        Snapshots memory snapshots = depositSnapshots[_depositor];

        return _getPrismaGainFromSnapshots(initialDeposit, snapshots);
    }

    function _getPrismaGainFromSnapshots(
        uint256 initialStake,
        Snapshots memory snapshots
    ) internal view returns (uint256) {
        /*
         * Grab the sum 'G' from the epoch at which the stake was made. The Prisma gain may span up to one scale change.
         * If it does, the second portion of the Prisma gain is scaled by 1e9.
         * If the gain spans no scale change, the second portion will be 0.
         */
        uint128 epochSnapshot = snapshots.epoch;
        uint128 scaleSnapshot = snapshots.scale;
        uint256 G_Snapshot = snapshots.G;
        uint256 P_Snapshot = snapshots.P;

        uint256 firstPortion = epochToScaleToG[epochSnapshot][scaleSnapshot] - G_Snapshot;
        uint256 secondPortion = epochToScaleToG[epochSnapshot][scaleSnapshot + 1] / SCALE_FACTOR;

        uint256 prismaGain = (initialStake * (firstPortion + secondPortion)) / P_Snapshot / DECIMAL_PRECISION;

        return prismaGain;
    }

    // --- Compounded deposit and compounded front end stake ---

    /*
     * Return the user's compounded deposit. Given by the formula:  d = d0 * P/P(0)
     * where P(0) is the depositor's snapshot of the product P, taken when they last updated their deposit.
     */
    function getCompoundedDebtDeposit(address _depositor) public view returns (uint256) {
        uint256 initialDeposit = accountDeposits[_depositor].amount;
        if (initialDeposit == 0) {
            return 0;
        }

        Snapshots memory snapshots = depositSnapshots[_depositor];

        uint256 compoundedDeposit = _getCompoundedStakeFromSnapshots(initialDeposit, snapshots);
        return compoundedDeposit;
    }

    // Internal function, used to calculcate compounded deposits and compounded front end stakes.
    function _getCompoundedStakeFromSnapshots(
        uint256 initialStake,
        Snapshots memory snapshots
    ) internal view returns (uint256) {
        uint256 snapshot_P = snapshots.P;
        uint128 scaleSnapshot = snapshots.scale;
        uint128 epochSnapshot = snapshots.epoch;

        // If stake was made before a pool-emptying event, then it has been fully cancelled with debt -- so, return 0
        if (epochSnapshot < currentEpoch) {
            return 0;
        }

        uint256 compoundedStake;
        uint128 scaleDiff = currentScale - scaleSnapshot;

        /* Compute the compounded stake. If a scale change in P was made during the stake's lifetime,
         * account for it. If more than one scale change was made, then the stake has decreased by a factor of
         * at least 1e-9 -- so return 0.
         */
        if (scaleDiff == 0) {
            compoundedStake = (initialStake * P) / snapshot_P;
        } else if (scaleDiff == 1) {
            compoundedStake = (initialStake * P) / snapshot_P / SCALE_FACTOR;
        } else {
            // if scaleDiff >= 2
            compoundedStake = 0;
        }

        /*
         * If compounded deposit is less than a billionth of the initial deposit, return 0.
         *
         * NOTE: originally, this line was in place to stop rounding errors making the deposit too large. However, the error
         * corrections should ensure the error in P "favors the Pool", i.e. any given compounded deposit should slightly less
         * than it's theoretical value.
         *
         * Thus it's unclear whether this line is still really needed.
         */
        if (compoundedStake < initialStake / 1e9) {
            return 0;
        }

        return compoundedStake;
    }

    // --- Sender functions for Debt deposit, collateral gains and Prisma gains ---
    function claimCollateralGains(address recipient, uint256[] calldata collateralIndexes) external virtual {
        _claimCollateralGains(recipient, collateralIndexes);
    }

    function _claimCollateralGains(address recipient, uint256[] calldata collateralIndexes) internal {
        uint256 loopEnd = collateralIndexes.length;
        uint256[] memory collateralGains = new uint256[](collateralTokens.length);

        uint80[256] storage depositorGains = collateralGainsByDepositor[msg.sender];
        for (uint256 i; i < loopEnd; ) {
            uint256 collateralIndex = collateralIndexes[i];
            uint256 gains = depositorGains[collateralIndex];
            if (gains > 0) {
                collateralGains[collateralIndex] = gains;
                depositorGains[collateralIndex] = 0;
                collateralTokens[collateralIndex].safeTransfer(recipient, gains);
            }
            unchecked {
                ++i;
            }
        }
        emit CollateralGainWithdrawn(msg.sender, collateralGains);
    }

    // --- Stability Pool Deposit Functionality ---

    function _updateSnapshots(address _depositor, uint256 _newValue) internal {
        uint256 length;
        if (_newValue == 0) {
            delete depositSnapshots[_depositor];

            length = collateralTokens.length;
            for (uint256 i = 0; i < length; i++) {
                depositSums[_depositor][i] = 0;
            }
            emit DepositSnapshotUpdated(_depositor, 0, 0);
            return;
        }
        uint128 currentScaleCached = currentScale;
        uint128 currentEpochCached = currentEpoch;
        uint256 currentP = P;

        // Get S and G for the current epoch and current scale
        uint256[256] storage currentS = epochToScaleToSums[currentEpochCached][currentScaleCached];
        uint256 currentG = epochToScaleToG[currentEpochCached][currentScaleCached];

        // Record new snapshots of the latest running product P, sum S, and sum G, for the depositor
        depositSnapshots[_depositor].P = currentP;
        depositSnapshots[_depositor].G = currentG;
        depositSnapshots[_depositor].scale = currentScaleCached;
        depositSnapshots[_depositor].epoch = currentEpochCached;

        length = collateralTokens.length;
        for (uint256 i = 0; i < length; i++) {
            depositSums[_depositor][i] = currentS[i];
        }

        emit DepositSnapshotUpdated(_depositor, currentP, currentG);
    }

    //This assumes the snapshot gets updated in the caller
    function _accrueRewards(address _depositor) internal {
        uint256 amount = _claimableReward(_depositor);
        storedPendingReward[_depositor] = storedPendingReward[_depositor] + amount;
    }

    function claimReward(address recipient) external returns (uint256 amount) {
        amount = _claimReward(msg.sender);
        if (amount > 0) {
            vault.transferAllocatedTokens(msg.sender, recipient, amount);
        }
        emit RewardClaimed(msg.sender, recipient, amount);
        return amount;
    }

    function vaultClaimReward(address claimant, address) external returns (uint256 amount) {
        require(msg.sender == address(vault));

        return _claimReward(claimant);
    }

    function _claimReward(address account) internal returns (uint256 amount) {
        uint256 initialDeposit = accountDeposits[account].amount;

        if (initialDeposit > 0) {
            uint128 depositTimestamp = accountDeposits[account].timestamp;
            _triggerRewardIssuance();
            bool hasGains = _accrueDepositorCollateralGain(account);

            uint256 compoundedDebtDeposit = getCompoundedDebtDeposit(account);
            uint256 debtLoss = initialDeposit - compoundedDebtDeposit;

            amount = _claimableReward(account);
            // we update only if the snapshot has changed
            if (debtLoss > 0 || hasGains || amount > 0) {
                // Update deposit
                uint256 newDeposit = compoundedDebtDeposit;
                accountDeposits[account] = AccountDeposit({ amount: uint128(newDeposit), timestamp: depositTimestamp });
                _updateSnapshots(account, newDeposit);
            }
        }
        uint256 pending = storedPendingReward[account];
        if (pending > 0) {
            amount += pending;
            storedPendingReward[account] = 0;
        }
        return amount;
    }
}

File 2 of 11 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "IERC20.sol";
import "draft-IERC20Permit.sol";
import "Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 3 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 4 of 11 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 5 of 11 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 6 of 11 : PrismaOwnable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import "IPrismaCore.sol";

/**
    @title Prisma Ownable
    @notice Contracts inheriting `PrismaOwnable` have the same owner as `PrismaCore`.
            The ownership cannot be independently modified or renounced.
 */
contract PrismaOwnable {
    IPrismaCore public immutable PRISMA_CORE;

    constructor(address _prismaCore) {
        PRISMA_CORE = IPrismaCore(_prismaCore);
    }

    modifier onlyOwner() {
        require(msg.sender == PRISMA_CORE.owner(), "Only owner");
        _;
    }

    function owner() public view returns (address) {
        return PRISMA_CORE.owner();
    }

    function guardian() public view returns (address) {
        return PRISMA_CORE.guardian();
    }
}

File 7 of 11 : IPrismaCore.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IPrismaCore {
    event FeeReceiverSet(address feeReceiver);
    event GuardianSet(address guardian);
    event NewOwnerAccepted(address oldOwner, address owner);
    event NewOwnerCommitted(address owner, address pendingOwner, uint256 deadline);
    event NewOwnerRevoked(address owner, address revokedOwner);
    event Paused();
    event PriceFeedSet(address priceFeed);
    event Unpaused();

    function acceptTransferOwnership() external;

    function commitTransferOwnership(address newOwner) external;

    function revokeTransferOwnership() external;

    function setFeeReceiver(address _feeReceiver) external;

    function setGuardian(address _guardian) external;

    function setPaused(bool _paused) external;

    function setPriceFeed(address _priceFeed) external;

    function OWNERSHIP_TRANSFER_DELAY() external view returns (uint256);

    function feeReceiver() external view returns (address);

    function guardian() external view returns (address);

    function owner() external view returns (address);

    function ownershipTransferDeadline() external view returns (uint256);

    function paused() external view returns (bool);

    function pendingOwner() external view returns (address);

    function priceFeed() external view returns (address);

    function startTime() external view returns (uint256);
}

File 8 of 11 : SystemStart.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import "IPrismaCore.sol";

/**
    @title Prisma System Start Time
    @dev Provides a unified `startTime` and `getWeek`, used for emissions.
 */
contract SystemStart {
    uint256 immutable startTime;

    constructor(address prismaCore) {
        startTime = IPrismaCore(prismaCore).startTime();
    }

    function getWeek() public view returns (uint256 week) {
        return (block.timestamp - startTime) / 1 weeks;
    }
}

File 9 of 11 : PrismaMath.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

library PrismaMath {
    uint256 internal constant DECIMAL_PRECISION = 1e18;

    /* Precision for Nominal ICR (independent of price). Rationale for the value:
     *
     * - Making it “too high” could lead to overflows.
     * - Making it “too low” could lead to an ICR equal to zero, due to truncation from Solidity floor division.
     *
     * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39,
     * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.
     *
     */
    uint256 internal constant NICR_PRECISION = 1e20;

    function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a < _b) ? _a : _b;
    }

    function _max(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a >= _b) ? _a : _b;
    }

    /*
     * Multiply two decimal numbers and use normal rounding rules:
     * -round product up if 19'th mantissa digit >= 5
     * -round product down if 19'th mantissa digit < 5
     *
     * Used only inside the exponentiation, _decPow().
     */
    function decMul(uint256 x, uint256 y) internal pure returns (uint256 decProd) {
        uint256 prod_xy = x * y;

        decProd = (prod_xy + (DECIMAL_PRECISION / 2)) / DECIMAL_PRECISION;
    }

    /*
     * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.
     *
     * Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity.
     *
     * Called by two functions that represent time in units of minutes:
     * 1) TroveManager._calcDecayedBaseRate
     * 2) CommunityIssuance._getCumulativeIssuanceFraction
     *
     * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals
     * "minutes in 1000 years": 60 * 24 * 365 * 1000
     *
     * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be
     * negligibly different from just passing the cap, since:
     *
     * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years
     * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible
     */
    function _decPow(uint256 _base, uint256 _minutes) internal pure returns (uint256) {
        if (_minutes > 525600000) {
            _minutes = 525600000;
        } // cap to avoid overflow

        if (_minutes == 0) {
            return DECIMAL_PRECISION;
        }

        uint256 y = DECIMAL_PRECISION;
        uint256 x = _base;
        uint256 n = _minutes;

        // Exponentiation-by-squaring
        while (n > 1) {
            if (n % 2 == 0) {
                x = decMul(x, x);
                n = n / 2;
            } else {
                // if (n % 2 != 0)
                y = decMul(x, y);
                x = decMul(x, x);
                n = (n - 1) / 2;
            }
        }

        return decMul(x, y);
    }

    function _getAbsoluteDifference(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a >= _b) ? _a - _b : _b - _a;
    }

    function _computeNominalCR(uint256 _coll, uint256 _debt) internal pure returns (uint256) {
        if (_debt > 0) {
            return (_coll * NICR_PRECISION) / _debt;
        }
        // Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR.
        else {
            // if (_debt == 0)
            return 2 ** 256 - 1;
        }
    }

    function _computeCR(uint256 _coll, uint256 _debt, uint256 _price) internal pure returns (uint256) {
        if (_debt > 0) {
            uint256 newCollRatio = (_coll * _price) / _debt;

            return newCollRatio;
        }
        // Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR.
        else {
            // if (_debt == 0)
            return 2 ** 256 - 1;
        }
    }

    function _computeCR(uint256 _coll, uint256 _debt) internal pure returns (uint256) {
        if (_debt > 0) {
            uint256 newCollRatio = (_coll) / _debt;

            return newCollRatio;
        }
        // Return the maximal value for uint256 if the Trove has a debt of 0. Represents "infinite" CR.
        else {
            // if (_debt == 0)
            return 2 ** 256 - 1;
        }
    }
}

File 10 of 11 : IDebtToken.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IDebtToken {
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event ReceiveFromChain(uint16 indexed _srcChainId, address indexed _to, uint256 _amount);
    event RetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash);
    event SendToChain(uint16 indexed _dstChainId, address indexed _from, bytes _toAddress, uint256 _amount);
    event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint256 _minDstGas);
    event SetPrecrime(address precrime);
    event SetTrustedRemote(uint16 _remoteChainId, bytes _path);
    event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
    event SetUseCustomAdapterParams(bool _useCustomAdapterParams);
    event Transfer(address indexed from, address indexed to, uint256 value);

    function approve(address spender, uint256 amount) external returns (bool);

    function burn(address _account, uint256 _amount) external;

    function burnWithGasCompensation(address _account, uint256 _amount) external returns (bool);

    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    function enableTroveManager(address _troveManager) external;

    function flashLoan(address receiver, address token, uint256 amount, bytes calldata data) external returns (bool);

    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;

    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);

    function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;

    function mint(address _account, uint256 _amount) external;

    function mintWithGasCompensation(address _account, uint256 _amount) external returns (bool);

    function nonblockingLzReceive(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        uint64 _nonce,
        bytes calldata _payload
    ) external;

    function permit(
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    function renounceOwnership() external;

    function returnFromPool(address _poolAddress, address _receiver, uint256 _amount) external;

    function sendToSP(address _sender, uint256 _amount) external;

    function setConfig(uint16 _version, uint16 _chainId, uint256 _configType, bytes calldata _config) external;

    function setMinDstGas(uint16 _dstChainId, uint16 _packetType, uint256 _minGas) external;

    function setPayloadSizeLimit(uint16 _dstChainId, uint256 _size) external;

    function setPrecrime(address _precrime) external;

    function setReceiveVersion(uint16 _version) external;

    function setSendVersion(uint16 _version) external;

    function setTrustedRemote(uint16 _srcChainId, bytes calldata _path) external;

    function setTrustedRemoteAddress(uint16 _remoteChainId, bytes calldata _remoteAddress) external;

    function setUseCustomAdapterParams(bool _useCustomAdapterParams) external;

    function transfer(address recipient, uint256 amount) external returns (bool);

    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    function transferOwnership(address newOwner) external;

    function retryMessage(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        uint64 _nonce,
        bytes calldata _payload
    ) external payable;

    function sendFrom(
        address _from,
        uint16 _dstChainId,
        bytes calldata _toAddress,
        uint256 _amount,
        address _refundAddress,
        address _zroPaymentAddress,
        bytes calldata _adapterParams
    ) external payable;

    function DEBT_GAS_COMPENSATION() external view returns (uint256);

    function DEFAULT_PAYLOAD_SIZE_LIMIT() external view returns (uint256);

    function FLASH_LOAN_FEE() external view returns (uint256);

    function NO_EXTRA_GAS() external view returns (uint256);

    function PT_SEND() external view returns (uint16);

    function allowance(address owner, address spender) external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function borrowerOperationsAddress() external view returns (address);

    function circulatingSupply() external view returns (uint256);

    function decimals() external view returns (uint8);

    function domainSeparator() external view returns (bytes32);

    function estimateSendFee(
        uint16 _dstChainId,
        bytes calldata _toAddress,
        uint256 _amount,
        bool _useZro,
        bytes calldata _adapterParams
    ) external view returns (uint256 nativeFee, uint256 zroFee);

    function factory() external view returns (address);

    function failedMessages(uint16, bytes calldata, uint64) external view returns (bytes32);

    function flashFee(address token, uint256 amount) external view returns (uint256);

    function gasPool() external view returns (address);

    function getConfig(
        uint16 _version,
        uint16 _chainId,
        address,
        uint256 _configType
    ) external view returns (bytes memory);

    function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory);

    function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);

    function lzEndpoint() external view returns (address);

    function maxFlashLoan(address token) external view returns (uint256);

    function minDstGasLookup(uint16, uint16) external view returns (uint256);

    function name() external view returns (string memory);

    function nonces(address owner) external view returns (uint256);

    function owner() external view returns (address);

    function payloadSizeLimitLookup(uint16) external view returns (uint256);

    function permitTypeHash() external view returns (bytes32);

    function precrime() external view returns (address);

    function stabilityPoolAddress() external view returns (address);

    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    function symbol() external view returns (string memory);

    function token() external view returns (address);

    function totalSupply() external view returns (uint256);

    function troveManager(address) external view returns (bool);

    function trustedRemoteLookup(uint16) external view returns (bytes memory);

    function useCustomAdapterParams() external view returns (bool);

    function version() external view returns (string memory);
}

File 11 of 11 : IVault.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IPrismaVault {
    struct InitialAllowance {
        address receiver;
        uint256 amount;
    }

    event BoostCalculatorSet(address boostCalculator);
    event BoostDelegationSet(address indexed boostDelegate, bool isEnabled, uint256 feePct, address callback);
    event EmissionScheduleSet(address emissionScheduler);
    event IncreasedAllocation(address indexed receiver, uint256 increasedAmount);
    event NewReceiverRegistered(address receiver, uint256 id);
    event ReceiverIsActiveStatusModified(uint256 indexed id, bool isActive);
    event UnallocatedSupplyIncreased(uint256 increasedAmount, uint256 unallocatedTotal);
    event UnallocatedSupplyReduced(uint256 reducedAmount, uint256 unallocatedTotal);

    function allocateNewEmissions(uint256 id) external returns (uint256);

    function batchClaimRewards(
        address receiver,
        address boostDelegate,
        address[] calldata rewardContracts,
        uint256 maxFeePct
    ) external returns (bool);

    function increaseUnallocatedSupply(uint256 amount) external returns (bool);

    function registerReceiver(address receiver, uint256 count) external returns (bool);

    function setBoostCalculator(address _boostCalculator) external returns (bool);

    function setBoostDelegationParams(bool isEnabled, uint256 feePct, address callback) external returns (bool);

    function setEmissionSchedule(address _emissionSchedule) external returns (bool);

    function setInitialParameters(
        address _emissionSchedule,
        address _boostCalculator,
        uint256 totalSupply,
        uint64 initialLockWeeks,
        uint128[] calldata _fixedInitialAmounts,
        InitialAllowance[] calldata initialAllowances
    ) external;

    function setReceiverIsActive(uint256 id, bool isActive) external returns (bool);

    function transferAllocatedTokens(address claimant, address receiver, uint256 amount) external returns (bool);

    function transferTokens(address token, address receiver, uint256 amount) external returns (bool);

    function PRISMA_CORE() external view returns (address);

    function allocated(address) external view returns (uint256);

    function boostCalculator() external view returns (address);

    function boostDelegation(address) external view returns (bool isEnabled, uint16 feePct, address callback);

    function claimableRewardAfterBoost(
        address account,
        address receiver,
        address boostDelegate,
        address rewardContract
    ) external view returns (uint256 adjustedAmount, uint256 feeToDelegate);

    function emissionSchedule() external view returns (address);

    function getClaimableWithBoost(address claimant) external view returns (uint256 maxBoosted, uint256 boosted);

    function getWeek() external view returns (uint256 week);

    function guardian() external view returns (address);

    function idToReceiver(uint256) external view returns (address account, bool isActive);

    function lockWeeks() external view returns (uint64);

    function locker() external view returns (address);

    function owner() external view returns (address);

    function claimableBoostDelegationFees(address claimant) external view returns (uint256 amount);

    function prismaToken() external view returns (address);

    function receiverUpdatedWeek(uint256) external view returns (uint16);

    function totalUpdateWeek() external view returns (uint64);

    function unallocatedTotal() external view returns (uint128);

    function voter() external view returns (address);

    function weeklyEmissions(uint256) external view returns (uint128);
}

Settings
{
  "evmVersion": "paris",
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "libraries": {
    "StabilityPool.sol": {}
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_prismaCore","type":"address"},{"internalType":"contract IDebtToken","name":"_debtTokenAddress","type":"address"},{"internalType":"contract IPrismaVault","name":"_vault","type":"address"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_liquidationManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_depositor","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"_collateral","type":"uint256[]"}],"name":"CollateralGainWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"oldCollateral","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"newCollateral","type":"address"}],"name":"CollateralOverwritten","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"_P","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_G","type":"uint256"}],"name":"DepositSnapshotUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"_currentEpoch","type":"uint128"}],"name":"EpochUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_G","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"_epoch","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"_scale","type":"uint128"}],"name":"G_Updated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_P","type":"uint256"}],"name":"P_Updated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimed","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"idx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_S","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"_epoch","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"_scale","type":"uint128"}],"name":"S_Updated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"_currentScale","type":"uint128"}],"name":"ScaleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newBalance","type":"uint256"}],"name":"StabilityPoolDebtBalanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"_newDeposit","type":"uint256"}],"name":"UserDepositChanged","type":"event"},{"inputs":[],"name":"DECIMAL_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"P","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRISMA_CORE","outputs":[{"internalType":"contract IPrismaCore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALE_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUNSET_DURATION","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountDeposits","outputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"timestamp","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"collateralIndexes","type":"uint256[]"}],"name":"claimCollateralGains","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"claimReward","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_depositor","type":"address"}],"name":"claimableReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"collateralGainsByDepositor","outputs":[{"internalType":"uint80","name":"gains","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"collateralTokens","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentEpoch","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentScale","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtToken","outputs":[{"internalType":"contract IDebtToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"depositSnapshots","outputs":[{"internalType":"uint256","name":"P","type":"uint256"},{"internalType":"uint256","name":"G","type":"uint256"},{"internalType":"uint128","name":"scale","type":"uint128"},{"internalType":"uint128","name":"epoch","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"depositSums","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emissionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_collateral","type":"address"}],"name":"enableCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"}],"name":"epochToScaleToG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochToScaleToSums","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_depositor","type":"address"}],"name":"getCompoundedDebtDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_depositor","type":"address"}],"name":"getDepositorCollateralGain","outputs":[{"internalType":"uint256[]","name":"collateralGains","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDebtTokenDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWeek","outputs":[{"internalType":"uint256","name":"week","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"collateral","type":"address"}],"name":"indexByCollateral","outputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastCollateralError_Offset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastDebtLossError_Offset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPrismaError","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"collateral","type":"address"},{"internalType":"uint256","name":"_debtToOffset","type":"uint256"},{"internalType":"uint256","name":"_collToAdd","type":"uint256"}],"name":"offset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodFinish","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"provideToSP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"collateral","type":"address"}],"name":"startCollateralSunset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IPrismaVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"claimant","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"vaultClaimReward","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawFromSP","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610140604052670de0b6b3a76400006009553480156200001e57600080fd5b50604051620036e4380380620036e483398101604081905262000041916200012a565b6001600160a01b0385166080819052604080516378e9792560e01b815290518792916378e979259160048083019260209291908290030181865afa1580156200008e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000b49190620001aa565b60a052506001600160a01b0380851660c05283811660e05282811661010052811661012052620000e6600142620001c4565b600060146101000a81548163ffffffff021916908363ffffffff1602179055505050505050620001ec565b6001600160a01b03811681146200012757600080fd5b50565b600080600080600060a086880312156200014357600080fd5b8551620001508162000111565b6020870151909550620001638162000111565b6040870151909450620001768162000111565b6060870151909350620001898162000111565b60808701519092506200019c8162000111565b809150509295509295909350565b600060208284031215620001bd57600080fd5b5051919050565b81810381811115620001e657634e487b7160e01b600052601160045260246000fd5b92915050565b60805160a05160c05160e05161010051610120516134546200029060003960008181610311015261256301526000818161057101526106d60152600081816106830152818161149d015281816118b20152611b7901526000818161065c01528181610d0f01526112810152600081816113cf0152611b21015260008181610598015281816109b0015281816110890152818161111b015261140201526134546000f3fe608060405234801561001057600080fd5b50600436106102525760003560e01c806386da082411610146578063ce4b5bbe116100c3578063e666673311610087578063e666673314610607578063e95034251461061a578063ebe2b12b1461062d578063f058203814610644578063f8d8989814610657578063fbfa77cf1461067e57600080fd5b8063ce4b5bbe146105ba578063d279c191146105c5578063d5f195fe146105d8578063d7936b7e146105eb578063db03fdaa146105f457600080fd5b8063a4e59ac81161010a578063a4e59ac814610523578063a7528a0314610536578063c046371114610540578063c45a01551461056c578063cc9641a81461059357600080fd5b806386da082414610489578063874d6d81146104fb5780638b8fbd92146105035780638da5cb5b1461050c578063a20baee61461051457600080fd5b8063452a9320116101d457806378c77a241161019857806378c77a24146103db5780637b0a47ee146103ee57806381bafb311461040157806382e0a5741461040a578063835dada01461043557600080fd5b8063452a932014610366578063476363711461036e5780635383dfcb146103765780635e3078ec1461039657806376671808146103a957600080fd5b8063172c48c71161021b578063172c48c7146102ce57806319f27b3b146102f95780631ef3a04c1461030c5780632e54bf9514610333578063307d36121461034657600080fd5b8062ba85b51461025757806309e2acb0146102735780630d9a6b351461028657806311be0de51461028e5780631500d2c3146102a3575b600080fd5b610260600e5481565b6040519081526020015b60405180910390f35b610260610281366004612fe3565b6106a5565b600354610260565b6102a161029c36600461300f565b6106cb565b005b6102b66102b1366004612fe3565b610941565b6040516001600160501b03909116815260200161026a565b6102e16102dc366004613033565b610984565b6040516001600160a01b03909116815260200161026a565b6102a161030736600461300f565b6109ae565b6102e17f000000000000000000000000000000000000000000000000000000000000000081565b6102a1610341366004613033565b610bcf565b61035961035436600461300f565b610e13565b60405161026a919061304c565b6102e1611085565b610260600081565b61026061038436600461300f565b60016020526000908152604090205481565b6102a16103a4366004613090565b61110e565b600a546103c390600160801b90046001600160801b031681565b6040516001600160801b03909116815260200161026a565b6102a16103e9366004613033565b611119565b6000546103c3906001600160801b031681565b610260600f5481565b610260610418366004613134565b600c60209081526000928352604080842090915290825290205481565b61046961044336600461300f565b6004602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161026a565b6104cc61049736600461300f565b6005602052600090815260409020805460018201546002909201549091906001600160801b0380821691600160801b90041684565b6040805194855260208501939093526001600160801b039182169284019290925216606082015260800161026a565b6102606113c4565b61026060095481565b6102e16113fe565b610260670de0b6b3a764000081565b600a546103c3906001600160801b031681565b6103c362ed4e0081565b60005461055790600160801b900463ffffffff1681565b60405163ffffffff909116815260200161026a565b6102e17f000000000000000000000000000000000000000000000000000000000000000081565b6102e17f000000000000000000000000000000000000000000000000000000000000000081565b610260633b9aca0081565b6102606105d336600461300f565b61145e565b6102606105e636600461300f565b611551565b610260600d5481565b610260610602366004613167565b6115ed565b6102a16106153660046131a3565b611620565b61026061062836600461300f565b61162b565b60005461055790600160a01b900463ffffffff1681565b6102606106523660046131d8565b6118a5565b6102e17f000000000000000000000000000000000000000000000000000000000000000081565b6102e17f000000000000000000000000000000000000000000000000000000000000000081565b60066020528160005260406000208161010081106106c257600080fd5b01549150829050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107365760405162461bcd60e51b815260206004820152600b60248201526a4e6f7420666163746f727960a81b60448201526064015b60405180910390fd5b6002546000805b8281101561079757836001600160a01b03166002828154811061076257610762613211565b6000918252602090912001546001600160a01b0316036107855760019150610797565b8061078f8161323d565b91505061073d565b50806108d7576040805180820190915260115461ffff808216808452620100009092041660208301819052111561087357805161ffff166000908152601060209081526040918290208251808401909352546001600160801b038082168452600160801b90910416908201819052421115610871576011805460109160009161ffff16908261082583613256565b82546101009290920a61ffff8181021990931691831602179091551681526020810191909152604001600090812055805161086a9086906001600160801b03166118ee565b5050505050565b505b5060028054600180820183557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180546001600160a01b0319166001600160a01b03871690811790915591546000928352602091909152604090912055505050565b6001600160a01b03831660009081526001602052604090205461093c5760405162461bcd60e51b815260206004820152601860248201527f436f6c6c61746572616c2069732073756e73657474696e670000000000000000604482015260640161072d565b505050565b600760205281600052604060002081610100811061095e57600080fd5b60039182820401919006600a02915091509054906101000a90046001600160501b031681565b6002818154811061099457600080fd5b6000918252602090912001546001600160a01b0316905081565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a309190613277565b6001600160a01b0316336001600160a01b031614610a7d5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b604482015260640161072d565b6001600160a01b038116600090815260016020526040902054610ae25760405162461bcd60e51b815260206004820152601d60248201527f436f6c6c61746572616c20616c72656164792073756e73657474696e67000000604482015260640161072d565b60405180604001604052806001806000856001600160a01b03166001600160a01b0316815260200190815260200160002054610b1e9190613294565b6001600160801b03168152602001610b3962ed4e00426132a7565b6001600160801b031690526011805460109160009162010000900461ffff16906002610b6483613256565b825461ffff9182166101009390930a928302928202191691909117909155168152602080820192909252604090810160009081208451948401516001600160801b03908116600160801b029516949094179093556001600160a01b0390931682526001905290812055565b336000908152600460205260409020546001600160801b0380821691600160801b90041681610c595760405162461bcd60e51b815260206004820152603060248201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060448201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606482015260840161072d565b42816001600160801b031610610cb15760405162461bcd60e51b815260206004820181905260248201527f214465706f73697420616e642077697468647261772073616d6520626c6f636b604482015260640161072d565b610cb9611af6565b610cc233611cb0565b506000610cce33611551565b90506000610cdc8583611ecc565b9050610ce733611ee2565b8015610d7c57604051631062c15f60e11b8152306004820152336024820152604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906320c582be90606401600060405180830381600087803b158015610d5b57600080fd5b505af1158015610d6f573d6000803e3d6000fd5b50505050610d7c81611f34565b6000610d888284613294565b6040805180820182526001600160801b03808416825287811660208084019182523360008181526004909252949020925190518216600160801b029116179055909150610dd59082611f83565b60405181815233907fbce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c9906020015b60405180910390a2505050505050565b60025460609067ffffffffffffffff811115610e3157610e316132ba565b604051908082528060200260200182016040528015610e5a578160200160208202803683370190505b506001600160a01b038316600090815260056020526040812054919250819003610e845750919050565b6001600160a01b0383166000908152600760209081526040808320600483528184205460058452828520600201546001600160801b03600160801b82048116808852600b808852868920938316808a52848952968920828a5297529396921694929392919081610ef58560016132d0565b6001600160801b03168152602080820192909252604090810160009081206001600160a01b038d16825260069093529081209192505b89518110156110775787816101008110610f4757610f47613211565b60039182820401919006600a029054906101000a90046001600160501b03166001600160501b03168a8281518110610f8157610f81613211565b60200260200101818152505083816101008110610fa057610fa0613211565b01541561106557600082826101008110610fbc57610fbc613211565b015485836101008110610fd157610fd1613211565b0154610fdd9190613294565b90506000633b9aca0085846101008110610ff957610ff9613211565b015461100591906132f7565b9050670de0b6b3a76400008b61101b83856132a7565b611025908c613319565b61102f91906132f7565b61103991906132f7565b8c848151811061104b5761104b613211565b6020026020010181815161105f91906132a7565b90525050505b8061106f8161323d565b915050610f2b565b505050505050505050919050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111099190613277565b905090565b61093c838383612173565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611177573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119b9190613330565b156111de5760405162461bcd60e51b815260206004820152601360248201527211195c1bdcda5d1cc8185c99481c185d5cd959606a1b604482015260640161072d565b6000811161123d5760405162461bcd60e51b815260206004820152602660248201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6044820152656e2d7a65726f60d01b606482015260840161072d565b611245611af6565b61124e33611cb0565b50600061125a33611551565b905061126533611ee2565b60405163e75b3ae760e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e75b3ae790604401600060405180830381600087803b1580156112cd57600080fd5b505af11580156112e1573d6000803e3d6000fd5b505050506000826003546112f591906132a7565b60038190556040518181529091507f5c1eb83edfbe7709b9a63e8c7e294df8731e15bc212a85bf6e95cb906600bcbb9060200160405180910390a1600061133c84846132a7565b6040805180820182526001600160801b03808416825242811660208084019182523360008181526004909252949020925190518216600160801b0291161790559091506113899082611f83565b60405181815233907fbce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c99060200160405180910390a250505050565b600062093a806113f47f000000000000000000000000000000000000000000000000000000000000000042613294565b61110991906132f7565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110e5573d6000803e3d6000fd5b600061146933612318565b9050801561150c576040516335e97f1f60e11b81523360048201526001600160a01b038381166024830152604482018390527f00000000000000000000000000000000000000000000000000000000000000001690636bd2fe3e906064016020604051808303816000875af11580156114e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150a9190613330565b505b6040518181526001600160a01b0383169033907f0aa4d283470c904c551d18bb894d37e17674920f3261a7f854be501e25f421b79060200160405180910390a3919050565b6001600160a01b0381166000908152600460205260408120546001600160801b03168082036115835750600092915050565b6001600160a01b0383166000908152600560209081526040808320815160808101835281548152600182015493810193909352600201546001600160801b0380821692840192909252600160801b9004166060820152906115e4838361246b565b95945050505050565b600b60205282600052604060002060205281600052604060002081610100811061161657600080fd5b0154925083915050565b61093c838383612558565b6003546001600160a01b0382166000908152600460205260408120549091906001600160801b031681158061165e575080155b1561166d575060009392505050565b6000600d54670de0b6b3a7640000611683612664565b61168d9190613319565b61169791906132a7565b905060006116a584836132f7565b90506000600954826116b79190613319565b6001600160a01b0388166000908152600560209081526040808320815160808101835281548152600182015493810193909352600201546001600160801b03808216928401839052600160801b909104811660608401819052600a5495965092949293919282911683036117c5576020808601516001600160801b038087166000908152600c8452604080822092881682529190935290912054879161175c91613294565b61176691906132a7565b6001600160801b0385166000908152600c60205260408120919350633b9aca0091906117938660016132d0565b6001600160801b03166001600160801b03168152602001908152602001600020546117be91906132f7565b9050611861565b6020808601516001600160801b038087166000908152600c84526040808220928816825291909352909120546117fb9190613294565b6001600160801b0385166000908152600c60205260408120919350633b9aca009188916118298760016132d0565b6001600160801b03166001600160801b031681526020019081526020016000205461185491906132a7565b61185e91906132f7565b90505b8451670de0b6b3a76400009061187783856132a7565b611881908c613319565b61188b91906132f7565b61189591906132f7565b9c9b505050505050505050505050565b6000336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146118dc57600080fd5b6118e583612318565b90505b92915050565b6001600160a01b038216600090815260016020526040902054156119545760405162461bcd60e51b815260206004820152601960248201527f436f6c6c61746572616c206d7573742062652073756e73657400000000000000604482015260640161072d565b6002548082106119985760405162461bcd60e51b815260206004820152600f60248201526e496e64657820746f6f206c6172676560881b604482015260640161072d565b600a546001600160801b03600160801b82048116911660005b82816001600160801b031611611a205760005b82816001600160801b031611611a17576001600160801b038083166000908152600b602090815260408083209385168352929052908120876101008110611a0d57611a0d613211565b01556001016119c4565b506001016119b1565b50611a2c8460016132a7565b6001600160a01b038616600090815260016020526040902055600280547f9e147d339c63698deb55c3d0d44ed3eba29bac2a068a88c4bc5bde17d6331e19919086908110611a7c57611a7c613211565b60009182526020918290200154604080516001600160a01b039283168152918916928201929092520160405180910390a18460028581548110611ac157611ac1613211565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505050505050565b611b06611b01612664565b6126cd565b60008054600160a01b900463ffffffff169062093a80611b467f000000000000000000000000000000000000000000000000000000000000000084613294565b611b5091906132f7565b905080611b5b6113c4565b10611c8e5760405163378cbf7560e01b8152600060048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063378cbf75906024016020604051808303816000875af1158015611bca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bee9190613352565b90508015611c8c5782421015611c31576000611c0a4285613294565b600054909150611c23906001600160801b031682613319565b611c2d90836132a7565b9150505b611c3e62093a80826132f7565b600080546001600160801b0319166001600160801b0392909216919091179055611c6b62093a80426132a7565b600060146101000a81548163ffffffff021916908363ffffffff1602179055505b505b50506000805463ffffffff60801b1916600160801b4263ffffffff1602179055565b6001600160a01b03811660009081526007602090815260408083206002546004909352908320549091906001600160801b0316808403611cf257505050919050565b6001600160a01b0385166000908152600560209081526040808320600281015490546001600160801b03600160801b83048116808752600b80875285882092909416808852828752948720818852939095529394929390929081611d578660016132d0565b6001600160801b03168152602080820192909252604090810160009081206001600160a01b038e16825260069093529081209192505b88811015611ebd5783816101008110611da857611da8613211565b015415611eab5760019a50600082826101008110611dc857611dc8613211565b015485836101008110611ddd57611ddd613211565b0154611de99190613294565b90506000633b9aca0085846101008110611e0557611e05613211565b0154611e1191906132f7565b9050670de0b6b3a764000087611e2783856132a7565b611e31908d613319565b611e3b91906132f7565b611e4591906132f7565b8c846101008110611e5857611e58613211565b60039182820401919006600a028282829054906101000a90046001600160501b0316611e84919061336b565b92506101000a8154816001600160501b0302191690836001600160501b0316021790555050505b80611eb58161323d565b915050611d8d565b50505050505050505050919050565b6000818310611edb57816118e5565b5090919050565b6000611eed826127c9565b6001600160a01b038316600090815260086020526040902054909150611f149082906132a7565b6001600160a01b0390921660009081526008602052604090209190915550565b600081600354611f449190613294565b60038190556040518181529091507f5c1eb83edfbe7709b9a63e8c7e294df8731e15bc212a85bf6e95cb906600bcbb9060200160405180910390a15050565b60008160000361204b57506001600160a01b038216600090815260056020526040812081815560018101829055600290810182905554905b81811015612001576001600160a01b0384166000908152600660205260408120826101008110611fed57611fed613211565b015580611ff98161323d565b915050611fbb565b5060408051600080825260208201526001600160a01b038516917fc48943df4095f4f20d171fd2872eafdc0eed4d9014ac3672f3bde7fd425449d5910160405180910390a2505050565b50600a546009546001600160801b03600160801b80840482166000818152600b6020908152604080832095909716808352948152868220838352600c82528783208684528252878320546001600160a01b038b1684526005909252968220868155600181018290559383028517600294850155925495939491939192905b8681101561212457828161010081106120e4576120e4613211565b01546001600160a01b038a16600090815260066020526040902082610100811061211057612110613211565b01558061211c8161323d565b9150506120c9565b5060408051848152602081018390526001600160a01b038a16917fc48943df4095f4f20d171fd2872eafdc0eed4d9014ac3672f3bde7fd425449d5910160405180910390a25050505050505050565b600254819060009067ffffffffffffffff811115612193576121936132ba565b6040519080825280602002602001820160405280156121bc578160200160208202803683370190505b503360009081526007602052604081209192505b838110156122de5760008686838181106121ec576121ec613211565b90506020020135905060008382610100811061220a5761220a613211565b60039182820401919006600a029054906101000a90046001600160501b03166001600160501b0316905060008111156122d4578085838151811061225057612250613211565b60200260200101818152505060008483610100811061227157612271613211565b60039182820401919006600a026101000a8154816001600160501b0302191690836001600160501b031602179055506122d48982600285815481106122b8576122b8613211565b6000918252602090912001546001600160a01b03169190612866565b50506001016121d0565b50336001600160a01b03167faecf5c2e84838a7ed87234d73965fc51f96b87b4c957f03bf22cfeb618c9aae183604051610e03919061304c565b6001600160a01b0381166000908152600460205260408120546001600160801b0316801561241f576001600160a01b038316600090815260046020526040902054600160801b90046001600160801b0316612371611af6565b600061237c85611cb0565b9050600061238986611551565b905060006123978286613294565b90506123a2876127c9565b955060008111806123b05750825b806123bb5750600086115b1561241a576040805180820182526001600160801b03808516825286811660208084019182526001600160a01b038c166000908152600490915293909320915192518116600160801b029216919091179055816124188882611f83565b505b505050505b6001600160a01b03831660009081526008602052604090205480156124645761244881846132a7565b6001600160a01b03851660009081526008602052604081205592505b5050919050565b805160408201516060830151600a546000939291906001600160801b03600160801b909104811690821610156124a757600093505050506118e8565b600a5460009081906124c39085906001600160801b031661338b565b9050806001600160801b03166000036124f65784600954896124e59190613319565b6124ef91906132f7565b915061252a565b806001600160801b031660010361252557633b9aca00856009548a61251b9190613319565b6124e591906132f7565b600091505b612538633b9aca00896132f7565b82101561254d576000955050505050506118e8565b509695505050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146125e95760405162461bcd60e51b815260206004820152603060248201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204c697160448201526f3ab4b230ba34b7b71026b0b730b3b2b960811b606482015260840161072d565b6001600160a01b038316600090815260016020819052604090912054906126109082613294565b600354909150801580612621575083155b1561262d575050505050565b612635611af6565b6000806126438587856128b8565b9150915061265282828661297d565b61265b86611f34565b50505050505050565b60008054600160a01b900463ffffffff16428111156126805750425b600054600160801b900463ffffffff168181106126a05760009250505090565b60006126ac8284613294565b6000549091506126c5906001600160801b031682613319565b935050505090565b6003548015806126db575081155b156126e4575050565b60006126f08383612c9f565b600a546009549192506001600160801b03600160801b820481169291169060009061271b9085613319565b6001600160801b038085166000908152600c60209081526040808320938716835292905290812054919250906127529083906132a7565b6001600160801b038581166000818152600c60209081526040808320948916808452948252918290208590558151858152908101929092528101919091529091507f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb649689060600160405180910390a150505050505050565b6001600160a01b0381166000908152600460205260408120546001600160801b03168082036127fb5750600092915050565b6001600160a01b038316600090815260056020908152604091829020825160808101845281548152600182015492810192909252600201546001600160801b0380821693830193909352600160801b9004909116606082015261285e8282612cf2565b949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261093c908490612dd6565b6000806000600e54670de0b6b3a7640000876128d49190613319565b6128de91906132a7565b90508385036128fc576000600f55670de0b6b3a76400009150612951565b600f54600090612914670de0b6b3a764000088613319565b61291e9190613294565b905061292a85826132f7565b6129359060016132a7565b9250806129428685613319565b61294c9190613294565b600f55505b61295b84826132f7565b92506129678484613319565b6129719082613294565b600e5550935093915050565b60095460008061299585670de0b6b3a7640000613294565b600a546001600160801b03600160801b820481166000818152600b602090815260408083209490951680835293905292832093945090929091908761010081106129e1576129e1613211565b0154905060006129f1878b613319565b905060006129ff82846132a7565b6001600160801b038086166000908152600b60209081526040808320938a1683529290522090915081908a6101008110612a3b57612a3b613211565b0155604080518a8152602081018390526001600160801b03868116828401528716606082015290517fe150473acddd94d1c6add794bd840c8d3e297dc3e50d863b56c0fba04d0d02479181900360800190a185600003612b4957612aa08460016132d0565b600a80546001600160801b03908116600160801b93821684021791829055604051929091041681527fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d9060200160405180910390a1600a80546001600160801b0319169055604051600081527f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9060200160405180910390a1670de0b6b3a76400009650612c21565b633b9aca00670de0b6b3a7640000612b61888b613319565b612b6b91906132f7565b1015612c0157670de0b6b3a7640000633b9aca00612b89888b613319565b612b939190613319565b612b9d91906132f7565b9650612baa8560016132d0565b600a80546001600160801b0319166001600160801b039290921691821790556040519081527f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9060200160405180910390a1612c21565b670de0b6b3a7640000612c14878a613319565b612c1e91906132f7565b96505b60008711612c5a5760405162461bcd60e51b815260040161072d9060208082526004908201526304e6577560e41b604082015260600190565b60098790556040518781527fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9060200160405180910390a15050505050505050505050565b600080600d54670de0b6b3a764000085612cb99190613319565b612cc391906132a7565b90506000612cd184836132f7565b9050612cdd8482613319565b612ce79083613294565b600d55949350505050565b606081015160408083015160208085015185516001600160801b038087166000908152600c8552868120918616815293529382205491949390918590612d39908490613294565b6001600160801b0386166000908152600c6020526040812091925090633b9aca009082612d678860016132d0565b6001600160801b03166001600160801b0316815260200190815260200160002054612d9291906132f7565b90506000670de0b6b3a764000084612daa84866132a7565b612db4908d613319565b612dbe91906132f7565b612dc891906132f7565b9a9950505050505050505050565b6000612e2b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612ea89092919063ffffffff16565b80519091501561093c5780806020019051810190612e499190613330565b61093c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161072d565b606061285e848460008585600080866001600160a01b03168587604051612ecf91906133cf565b60006040518083038185875af1925050503d8060008114612f0c576040519150601f19603f3d011682016040523d82523d6000602084013e612f11565b606091505b5091509150612f2287838387612f2d565b979650505050505050565b60608315612f9c578251600003612f95576001600160a01b0385163b612f955760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161072d565b508161285e565b61285e8383815115612fb15781518083602001fd5b8060405162461bcd60e51b815260040161072d91906133eb565b6001600160a01b0381168114612fe057600080fd5b50565b60008060408385031215612ff657600080fd5b823561300181612fcb565b946020939093013593505050565b60006020828403121561302157600080fd5b813561302c81612fcb565b9392505050565b60006020828403121561304557600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b8181101561308457835183529284019291840191600101613068565b50909695505050505050565b6000806000604084860312156130a557600080fd5b83356130b081612fcb565b9250602084013567ffffffffffffffff808211156130cd57600080fd5b818601915086601f8301126130e157600080fd5b8135818111156130f057600080fd5b8760208260051b850101111561310557600080fd5b6020830194508093505050509250925092565b80356001600160801b038116811461312f57600080fd5b919050565b6000806040838503121561314757600080fd5b61315083613118565b915061315e60208401613118565b90509250929050565b60008060006060848603121561317c57600080fd5b61318584613118565b925061319360208501613118565b9150604084013590509250925092565b6000806000606084860312156131b857600080fd5b83356131c381612fcb565b95602085013595506040909401359392505050565b600080604083850312156131eb57600080fd5b82356131f681612fcb565b9150602083013561320681612fcb565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161324f5761324f613227565b5060010190565b600061ffff80831681810361326d5761326d613227565b6001019392505050565b60006020828403121561328957600080fd5b815161302c81612fcb565b818103818111156118e8576118e8613227565b808201808211156118e8576118e8613227565b634e487b7160e01b600052604160045260246000fd5b6001600160801b038181168382160190808211156132f0576132f0613227565b5092915050565b60008261331457634e487b7160e01b600052601260045260246000fd5b500490565b80820281158282048414176118e8576118e8613227565b60006020828403121561334257600080fd5b8151801515811461302c57600080fd5b60006020828403121561336457600080fd5b5051919050565b6001600160501b038181168382160190808211156132f0576132f0613227565b6001600160801b038281168282160390808211156132f0576132f0613227565b60005b838110156133c65781810151838201526020016133ae565b50506000910152565b600082516133e18184602087016133ab565b9190910192915050565b602081526000825180602084015261340a8160408501602087016133ab565b601f01601f1916919091016040019291505056fea2646970667358221220a6b414ff3abbf71aa38488f4215b453604386370247c248fe9244c5ea26a787964736f6c634300081300330000000000000000000000005d17ea085f2ff5da3e6979d5d26f1dbab664ccf80000000000000000000000004591dbff62656e7859afe5e45f6f47d3669fbb2800000000000000000000000006bdf212c290473dcacea9793890c5024c7eb02c00000000000000000000000070b66e20766b775b2e9ce5b718bbd285af59b7e10000000000000000000000005de309dfd7f94e9e2a18cb6ba61ca305abf8e9e2

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102525760003560e01c806386da082411610146578063ce4b5bbe116100c3578063e666673311610087578063e666673314610607578063e95034251461061a578063ebe2b12b1461062d578063f058203814610644578063f8d8989814610657578063fbfa77cf1461067e57600080fd5b8063ce4b5bbe146105ba578063d279c191146105c5578063d5f195fe146105d8578063d7936b7e146105eb578063db03fdaa146105f457600080fd5b8063a4e59ac81161010a578063a4e59ac814610523578063a7528a0314610536578063c046371114610540578063c45a01551461056c578063cc9641a81461059357600080fd5b806386da082414610489578063874d6d81146104fb5780638b8fbd92146105035780638da5cb5b1461050c578063a20baee61461051457600080fd5b8063452a9320116101d457806378c77a241161019857806378c77a24146103db5780637b0a47ee146103ee57806381bafb311461040157806382e0a5741461040a578063835dada01461043557600080fd5b8063452a932014610366578063476363711461036e5780635383dfcb146103765780635e3078ec1461039657806376671808146103a957600080fd5b8063172c48c71161021b578063172c48c7146102ce57806319f27b3b146102f95780631ef3a04c1461030c5780632e54bf9514610333578063307d36121461034657600080fd5b8062ba85b51461025757806309e2acb0146102735780630d9a6b351461028657806311be0de51461028e5780631500d2c3146102a3575b600080fd5b610260600e5481565b6040519081526020015b60405180910390f35b610260610281366004612fe3565b6106a5565b600354610260565b6102a161029c36600461300f565b6106cb565b005b6102b66102b1366004612fe3565b610941565b6040516001600160501b03909116815260200161026a565b6102e16102dc366004613033565b610984565b6040516001600160a01b03909116815260200161026a565b6102a161030736600461300f565b6109ae565b6102e17f0000000000000000000000005de309dfd7f94e9e2a18cb6ba61ca305abf8e9e281565b6102a1610341366004613033565b610bcf565b61035961035436600461300f565b610e13565b60405161026a919061304c565b6102e1611085565b610260600081565b61026061038436600461300f565b60016020526000908152604090205481565b6102a16103a4366004613090565b61110e565b600a546103c390600160801b90046001600160801b031681565b6040516001600160801b03909116815260200161026a565b6102a16103e9366004613033565b611119565b6000546103c3906001600160801b031681565b610260600f5481565b610260610418366004613134565b600c60209081526000928352604080842090915290825290205481565b61046961044336600461300f565b6004602052600090815260409020546001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161026a565b6104cc61049736600461300f565b6005602052600090815260409020805460018201546002909201549091906001600160801b0380821691600160801b90041684565b6040805194855260208501939093526001600160801b039182169284019290925216606082015260800161026a565b6102606113c4565b61026060095481565b6102e16113fe565b610260670de0b6b3a764000081565b600a546103c3906001600160801b031681565b6103c362ed4e0081565b60005461055790600160801b900463ffffffff1681565b60405163ffffffff909116815260200161026a565b6102e17f00000000000000000000000070b66e20766b775b2e9ce5b718bbd285af59b7e181565b6102e17f0000000000000000000000005d17ea085f2ff5da3e6979d5d26f1dbab664ccf881565b610260633b9aca0081565b6102606105d336600461300f565b61145e565b6102606105e636600461300f565b611551565b610260600d5481565b610260610602366004613167565b6115ed565b6102a16106153660046131a3565b611620565b61026061062836600461300f565b61162b565b60005461055790600160a01b900463ffffffff1681565b6102606106523660046131d8565b6118a5565b6102e17f0000000000000000000000004591dbff62656e7859afe5e45f6f47d3669fbb2881565b6102e17f00000000000000000000000006bdf212c290473dcacea9793890c5024c7eb02c81565b60066020528160005260406000208161010081106106c257600080fd5b01549150829050565b336001600160a01b037f00000000000000000000000070b66e20766b775b2e9ce5b718bbd285af59b7e116146107365760405162461bcd60e51b815260206004820152600b60248201526a4e6f7420666163746f727960a81b60448201526064015b60405180910390fd5b6002546000805b8281101561079757836001600160a01b03166002828154811061076257610762613211565b6000918252602090912001546001600160a01b0316036107855760019150610797565b8061078f8161323d565b91505061073d565b50806108d7576040805180820190915260115461ffff808216808452620100009092041660208301819052111561087357805161ffff166000908152601060209081526040918290208251808401909352546001600160801b038082168452600160801b90910416908201819052421115610871576011805460109160009161ffff16908261082583613256565b82546101009290920a61ffff8181021990931691831602179091551681526020810191909152604001600090812055805161086a9086906001600160801b03166118ee565b5050505050565b505b5060028054600180820183557f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180546001600160a01b0319166001600160a01b03871690811790915591546000928352602091909152604090912055505050565b6001600160a01b03831660009081526001602052604090205461093c5760405162461bcd60e51b815260206004820152601860248201527f436f6c6c61746572616c2069732073756e73657474696e670000000000000000604482015260640161072d565b505050565b600760205281600052604060002081610100811061095e57600080fd5b60039182820401919006600a02915091509054906101000a90046001600160501b031681565b6002818154811061099457600080fd5b6000918252602090912001546001600160a01b0316905081565b7f0000000000000000000000005d17ea085f2ff5da3e6979d5d26f1dbab664ccf86001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a309190613277565b6001600160a01b0316336001600160a01b031614610a7d5760405162461bcd60e51b815260206004820152600a60248201526927b7363c9037bbb732b960b11b604482015260640161072d565b6001600160a01b038116600090815260016020526040902054610ae25760405162461bcd60e51b815260206004820152601d60248201527f436f6c6c61746572616c20616c72656164792073756e73657474696e67000000604482015260640161072d565b60405180604001604052806001806000856001600160a01b03166001600160a01b0316815260200190815260200160002054610b1e9190613294565b6001600160801b03168152602001610b3962ed4e00426132a7565b6001600160801b031690526011805460109160009162010000900461ffff16906002610b6483613256565b825461ffff9182166101009390930a928302928202191691909117909155168152602080820192909252604090810160009081208451948401516001600160801b03908116600160801b029516949094179093556001600160a01b0390931682526001905290812055565b336000908152600460205260409020546001600160801b0380821691600160801b90041681610c595760405162461bcd60e51b815260206004820152603060248201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060448201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606482015260840161072d565b42816001600160801b031610610cb15760405162461bcd60e51b815260206004820181905260248201527f214465706f73697420616e642077697468647261772073616d6520626c6f636b604482015260640161072d565b610cb9611af6565b610cc233611cb0565b506000610cce33611551565b90506000610cdc8583611ecc565b9050610ce733611ee2565b8015610d7c57604051631062c15f60e11b8152306004820152336024820152604481018290527f0000000000000000000000004591dbff62656e7859afe5e45f6f47d3669fbb286001600160a01b0316906320c582be90606401600060405180830381600087803b158015610d5b57600080fd5b505af1158015610d6f573d6000803e3d6000fd5b50505050610d7c81611f34565b6000610d888284613294565b6040805180820182526001600160801b03808416825287811660208084019182523360008181526004909252949020925190518216600160801b029116179055909150610dd59082611f83565b60405181815233907fbce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c9906020015b60405180910390a2505050505050565b60025460609067ffffffffffffffff811115610e3157610e316132ba565b604051908082528060200260200182016040528015610e5a578160200160208202803683370190505b506001600160a01b038316600090815260056020526040812054919250819003610e845750919050565b6001600160a01b0383166000908152600760209081526040808320600483528184205460058452828520600201546001600160801b03600160801b82048116808852600b808852868920938316808a52848952968920828a5297529396921694929392919081610ef58560016132d0565b6001600160801b03168152602080820192909252604090810160009081206001600160a01b038d16825260069093529081209192505b89518110156110775787816101008110610f4757610f47613211565b60039182820401919006600a029054906101000a90046001600160501b03166001600160501b03168a8281518110610f8157610f81613211565b60200260200101818152505083816101008110610fa057610fa0613211565b01541561106557600082826101008110610fbc57610fbc613211565b015485836101008110610fd157610fd1613211565b0154610fdd9190613294565b90506000633b9aca0085846101008110610ff957610ff9613211565b015461100591906132f7565b9050670de0b6b3a76400008b61101b83856132a7565b611025908c613319565b61102f91906132f7565b61103991906132f7565b8c848151811061104b5761104b613211565b6020026020010181815161105f91906132a7565b90525050505b8061106f8161323d565b915050610f2b565b505050505050505050919050565b60007f0000000000000000000000005d17ea085f2ff5da3e6979d5d26f1dbab664ccf86001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111099190613277565b905090565b61093c838383612173565b7f0000000000000000000000005d17ea085f2ff5da3e6979d5d26f1dbab664ccf86001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611177573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119b9190613330565b156111de5760405162461bcd60e51b815260206004820152601360248201527211195c1bdcda5d1cc8185c99481c185d5cd959606a1b604482015260640161072d565b6000811161123d5760405162461bcd60e51b815260206004820152602660248201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6044820152656e2d7a65726f60d01b606482015260840161072d565b611245611af6565b61124e33611cb0565b50600061125a33611551565b905061126533611ee2565b60405163e75b3ae760e01b8152336004820152602481018390527f0000000000000000000000004591dbff62656e7859afe5e45f6f47d3669fbb286001600160a01b03169063e75b3ae790604401600060405180830381600087803b1580156112cd57600080fd5b505af11580156112e1573d6000803e3d6000fd5b505050506000826003546112f591906132a7565b60038190556040518181529091507f5c1eb83edfbe7709b9a63e8c7e294df8731e15bc212a85bf6e95cb906600bcbb9060200160405180910390a1600061133c84846132a7565b6040805180820182526001600160801b03808416825242811660208084019182523360008181526004909252949020925190518216600160801b0291161790559091506113899082611f83565b60405181815233907fbce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c99060200160405180910390a250505050565b600062093a806113f47f0000000000000000000000000000000000000000000000000000000064d4288042613294565b61110991906132f7565b60007f0000000000000000000000005d17ea085f2ff5da3e6979d5d26f1dbab664ccf86001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110e5573d6000803e3d6000fd5b600061146933612318565b9050801561150c576040516335e97f1f60e11b81523360048201526001600160a01b038381166024830152604482018390527f00000000000000000000000006bdf212c290473dcacea9793890c5024c7eb02c1690636bd2fe3e906064016020604051808303816000875af11580156114e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150a9190613330565b505b6040518181526001600160a01b0383169033907f0aa4d283470c904c551d18bb894d37e17674920f3261a7f854be501e25f421b79060200160405180910390a3919050565b6001600160a01b0381166000908152600460205260408120546001600160801b03168082036115835750600092915050565b6001600160a01b0383166000908152600560209081526040808320815160808101835281548152600182015493810193909352600201546001600160801b0380821692840192909252600160801b9004166060820152906115e4838361246b565b95945050505050565b600b60205282600052604060002060205281600052604060002081610100811061161657600080fd5b0154925083915050565b61093c838383612558565b6003546001600160a01b0382166000908152600460205260408120549091906001600160801b031681158061165e575080155b1561166d575060009392505050565b6000600d54670de0b6b3a7640000611683612664565b61168d9190613319565b61169791906132a7565b905060006116a584836132f7565b90506000600954826116b79190613319565b6001600160a01b0388166000908152600560209081526040808320815160808101835281548152600182015493810193909352600201546001600160801b03808216928401839052600160801b909104811660608401819052600a5495965092949293919282911683036117c5576020808601516001600160801b038087166000908152600c8452604080822092881682529190935290912054879161175c91613294565b61176691906132a7565b6001600160801b0385166000908152600c60205260408120919350633b9aca0091906117938660016132d0565b6001600160801b03166001600160801b03168152602001908152602001600020546117be91906132f7565b9050611861565b6020808601516001600160801b038087166000908152600c84526040808220928816825291909352909120546117fb9190613294565b6001600160801b0385166000908152600c60205260408120919350633b9aca009188916118298760016132d0565b6001600160801b03166001600160801b031681526020019081526020016000205461185491906132a7565b61185e91906132f7565b90505b8451670de0b6b3a76400009061187783856132a7565b611881908c613319565b61188b91906132f7565b61189591906132f7565b9c9b505050505050505050505050565b6000336001600160a01b037f00000000000000000000000006bdf212c290473dcacea9793890c5024c7eb02c16146118dc57600080fd5b6118e583612318565b90505b92915050565b6001600160a01b038216600090815260016020526040902054156119545760405162461bcd60e51b815260206004820152601960248201527f436f6c6c61746572616c206d7573742062652073756e73657400000000000000604482015260640161072d565b6002548082106119985760405162461bcd60e51b815260206004820152600f60248201526e496e64657820746f6f206c6172676560881b604482015260640161072d565b600a546001600160801b03600160801b82048116911660005b82816001600160801b031611611a205760005b82816001600160801b031611611a17576001600160801b038083166000908152600b602090815260408083209385168352929052908120876101008110611a0d57611a0d613211565b01556001016119c4565b506001016119b1565b50611a2c8460016132a7565b6001600160a01b038616600090815260016020526040902055600280547f9e147d339c63698deb55c3d0d44ed3eba29bac2a068a88c4bc5bde17d6331e19919086908110611a7c57611a7c613211565b60009182526020918290200154604080516001600160a01b039283168152918916928201929092520160405180910390a18460028581548110611ac157611ac1613211565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505050505050565b611b06611b01612664565b6126cd565b60008054600160a01b900463ffffffff169062093a80611b467f0000000000000000000000000000000000000000000000000000000064d4288084613294565b611b5091906132f7565b905080611b5b6113c4565b10611c8e5760405163378cbf7560e01b8152600060048201819052907f00000000000000000000000006bdf212c290473dcacea9793890c5024c7eb02c6001600160a01b03169063378cbf75906024016020604051808303816000875af1158015611bca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bee9190613352565b90508015611c8c5782421015611c31576000611c0a4285613294565b600054909150611c23906001600160801b031682613319565b611c2d90836132a7565b9150505b611c3e62093a80826132f7565b600080546001600160801b0319166001600160801b0392909216919091179055611c6b62093a80426132a7565b600060146101000a81548163ffffffff021916908363ffffffff1602179055505b505b50506000805463ffffffff60801b1916600160801b4263ffffffff1602179055565b6001600160a01b03811660009081526007602090815260408083206002546004909352908320549091906001600160801b0316808403611cf257505050919050565b6001600160a01b0385166000908152600560209081526040808320600281015490546001600160801b03600160801b83048116808752600b80875285882092909416808852828752948720818852939095529394929390929081611d578660016132d0565b6001600160801b03168152602080820192909252604090810160009081206001600160a01b038e16825260069093529081209192505b88811015611ebd5783816101008110611da857611da8613211565b015415611eab5760019a50600082826101008110611dc857611dc8613211565b015485836101008110611ddd57611ddd613211565b0154611de99190613294565b90506000633b9aca0085846101008110611e0557611e05613211565b0154611e1191906132f7565b9050670de0b6b3a764000087611e2783856132a7565b611e31908d613319565b611e3b91906132f7565b611e4591906132f7565b8c846101008110611e5857611e58613211565b60039182820401919006600a028282829054906101000a90046001600160501b0316611e84919061336b565b92506101000a8154816001600160501b0302191690836001600160501b0316021790555050505b80611eb58161323d565b915050611d8d565b50505050505050505050919050565b6000818310611edb57816118e5565b5090919050565b6000611eed826127c9565b6001600160a01b038316600090815260086020526040902054909150611f149082906132a7565b6001600160a01b0390921660009081526008602052604090209190915550565b600081600354611f449190613294565b60038190556040518181529091507f5c1eb83edfbe7709b9a63e8c7e294df8731e15bc212a85bf6e95cb906600bcbb9060200160405180910390a15050565b60008160000361204b57506001600160a01b038216600090815260056020526040812081815560018101829055600290810182905554905b81811015612001576001600160a01b0384166000908152600660205260408120826101008110611fed57611fed613211565b015580611ff98161323d565b915050611fbb565b5060408051600080825260208201526001600160a01b038516917fc48943df4095f4f20d171fd2872eafdc0eed4d9014ac3672f3bde7fd425449d5910160405180910390a2505050565b50600a546009546001600160801b03600160801b80840482166000818152600b6020908152604080832095909716808352948152868220838352600c82528783208684528252878320546001600160a01b038b1684526005909252968220868155600181018290559383028517600294850155925495939491939192905b8681101561212457828161010081106120e4576120e4613211565b01546001600160a01b038a16600090815260066020526040902082610100811061211057612110613211565b01558061211c8161323d565b9150506120c9565b5060408051848152602081018390526001600160a01b038a16917fc48943df4095f4f20d171fd2872eafdc0eed4d9014ac3672f3bde7fd425449d5910160405180910390a25050505050505050565b600254819060009067ffffffffffffffff811115612193576121936132ba565b6040519080825280602002602001820160405280156121bc578160200160208202803683370190505b503360009081526007602052604081209192505b838110156122de5760008686838181106121ec576121ec613211565b90506020020135905060008382610100811061220a5761220a613211565b60039182820401919006600a029054906101000a90046001600160501b03166001600160501b0316905060008111156122d4578085838151811061225057612250613211565b60200260200101818152505060008483610100811061227157612271613211565b60039182820401919006600a026101000a8154816001600160501b0302191690836001600160501b031602179055506122d48982600285815481106122b8576122b8613211565b6000918252602090912001546001600160a01b03169190612866565b50506001016121d0565b50336001600160a01b03167faecf5c2e84838a7ed87234d73965fc51f96b87b4c957f03bf22cfeb618c9aae183604051610e03919061304c565b6001600160a01b0381166000908152600460205260408120546001600160801b0316801561241f576001600160a01b038316600090815260046020526040902054600160801b90046001600160801b0316612371611af6565b600061237c85611cb0565b9050600061238986611551565b905060006123978286613294565b90506123a2876127c9565b955060008111806123b05750825b806123bb5750600086115b1561241a576040805180820182526001600160801b03808516825286811660208084019182526001600160a01b038c166000908152600490915293909320915192518116600160801b029216919091179055816124188882611f83565b505b505050505b6001600160a01b03831660009081526008602052604090205480156124645761244881846132a7565b6001600160a01b03851660009081526008602052604081205592505b5050919050565b805160408201516060830151600a546000939291906001600160801b03600160801b909104811690821610156124a757600093505050506118e8565b600a5460009081906124c39085906001600160801b031661338b565b9050806001600160801b03166000036124f65784600954896124e59190613319565b6124ef91906132f7565b915061252a565b806001600160801b031660010361252557633b9aca00856009548a61251b9190613319565b6124e591906132f7565b600091505b612538633b9aca00896132f7565b82101561254d576000955050505050506118e8565b509695505050505050565b336001600160a01b037f0000000000000000000000005de309dfd7f94e9e2a18cb6ba61ca305abf8e9e216146125e95760405162461bcd60e51b815260206004820152603060248201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204c697160448201526f3ab4b230ba34b7b71026b0b730b3b2b960811b606482015260840161072d565b6001600160a01b038316600090815260016020819052604090912054906126109082613294565b600354909150801580612621575083155b1561262d575050505050565b612635611af6565b6000806126438587856128b8565b9150915061265282828661297d565b61265b86611f34565b50505050505050565b60008054600160a01b900463ffffffff16428111156126805750425b600054600160801b900463ffffffff168181106126a05760009250505090565b60006126ac8284613294565b6000549091506126c5906001600160801b031682613319565b935050505090565b6003548015806126db575081155b156126e4575050565b60006126f08383612c9f565b600a546009549192506001600160801b03600160801b820481169291169060009061271b9085613319565b6001600160801b038085166000908152600c60209081526040808320938716835292905290812054919250906127529083906132a7565b6001600160801b038581166000818152600c60209081526040808320948916808452948252918290208590558151858152908101929092528101919091529091507f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb649689060600160405180910390a150505050505050565b6001600160a01b0381166000908152600460205260408120546001600160801b03168082036127fb5750600092915050565b6001600160a01b038316600090815260056020908152604091829020825160808101845281548152600182015492810192909252600201546001600160801b0380821693830193909352600160801b9004909116606082015261285e8282612cf2565b949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261093c908490612dd6565b6000806000600e54670de0b6b3a7640000876128d49190613319565b6128de91906132a7565b90508385036128fc576000600f55670de0b6b3a76400009150612951565b600f54600090612914670de0b6b3a764000088613319565b61291e9190613294565b905061292a85826132f7565b6129359060016132a7565b9250806129428685613319565b61294c9190613294565b600f55505b61295b84826132f7565b92506129678484613319565b6129719082613294565b600e5550935093915050565b60095460008061299585670de0b6b3a7640000613294565b600a546001600160801b03600160801b820481166000818152600b602090815260408083209490951680835293905292832093945090929091908761010081106129e1576129e1613211565b0154905060006129f1878b613319565b905060006129ff82846132a7565b6001600160801b038086166000908152600b60209081526040808320938a1683529290522090915081908a6101008110612a3b57612a3b613211565b0155604080518a8152602081018390526001600160801b03868116828401528716606082015290517fe150473acddd94d1c6add794bd840c8d3e297dc3e50d863b56c0fba04d0d02479181900360800190a185600003612b4957612aa08460016132d0565b600a80546001600160801b03908116600160801b93821684021791829055604051929091041681527fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d9060200160405180910390a1600a80546001600160801b0319169055604051600081527f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9060200160405180910390a1670de0b6b3a76400009650612c21565b633b9aca00670de0b6b3a7640000612b61888b613319565b612b6b91906132f7565b1015612c0157670de0b6b3a7640000633b9aca00612b89888b613319565b612b939190613319565b612b9d91906132f7565b9650612baa8560016132d0565b600a80546001600160801b0319166001600160801b039290921691821790556040519081527f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9060200160405180910390a1612c21565b670de0b6b3a7640000612c14878a613319565b612c1e91906132f7565b96505b60008711612c5a5760405162461bcd60e51b815260040161072d9060208082526004908201526304e6577560e41b604082015260600190565b60098790556040518781527fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9060200160405180910390a15050505050505050505050565b600080600d54670de0b6b3a764000085612cb99190613319565b612cc391906132a7565b90506000612cd184836132f7565b9050612cdd8482613319565b612ce79083613294565b600d55949350505050565b606081015160408083015160208085015185516001600160801b038087166000908152600c8552868120918616815293529382205491949390918590612d39908490613294565b6001600160801b0386166000908152600c6020526040812091925090633b9aca009082612d678860016132d0565b6001600160801b03166001600160801b0316815260200190815260200160002054612d9291906132f7565b90506000670de0b6b3a764000084612daa84866132a7565b612db4908d613319565b612dbe91906132f7565b612dc891906132f7565b9a9950505050505050505050565b6000612e2b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612ea89092919063ffffffff16565b80519091501561093c5780806020019051810190612e499190613330565b61093c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161072d565b606061285e848460008585600080866001600160a01b03168587604051612ecf91906133cf565b60006040518083038185875af1925050503d8060008114612f0c576040519150601f19603f3d011682016040523d82523d6000602084013e612f11565b606091505b5091509150612f2287838387612f2d565b979650505050505050565b60608315612f9c578251600003612f95576001600160a01b0385163b612f955760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161072d565b508161285e565b61285e8383815115612fb15781518083602001fd5b8060405162461bcd60e51b815260040161072d91906133eb565b6001600160a01b0381168114612fe057600080fd5b50565b60008060408385031215612ff657600080fd5b823561300181612fcb565b946020939093013593505050565b60006020828403121561302157600080fd5b813561302c81612fcb565b9392505050565b60006020828403121561304557600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b8181101561308457835183529284019291840191600101613068565b50909695505050505050565b6000806000604084860312156130a557600080fd5b83356130b081612fcb565b9250602084013567ffffffffffffffff808211156130cd57600080fd5b818601915086601f8301126130e157600080fd5b8135818111156130f057600080fd5b8760208260051b850101111561310557600080fd5b6020830194508093505050509250925092565b80356001600160801b038116811461312f57600080fd5b919050565b6000806040838503121561314757600080fd5b61315083613118565b915061315e60208401613118565b90509250929050565b60008060006060848603121561317c57600080fd5b61318584613118565b925061319360208501613118565b9150604084013590509250925092565b6000806000606084860312156131b857600080fd5b83356131c381612fcb565b95602085013595506040909401359392505050565b600080604083850312156131eb57600080fd5b82356131f681612fcb565b9150602083013561320681612fcb565b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161324f5761324f613227565b5060010190565b600061ffff80831681810361326d5761326d613227565b6001019392505050565b60006020828403121561328957600080fd5b815161302c81612fcb565b818103818111156118e8576118e8613227565b808201808211156118e8576118e8613227565b634e487b7160e01b600052604160045260246000fd5b6001600160801b038181168382160190808211156132f0576132f0613227565b5092915050565b60008261331457634e487b7160e01b600052601260045260246000fd5b500490565b80820281158282048414176118e8576118e8613227565b60006020828403121561334257600080fd5b8151801515811461302c57600080fd5b60006020828403121561336457600080fd5b5051919050565b6001600160501b038181168382160190808211156132f0576132f0613227565b6001600160801b038281168282160390808211156132f0576132f0613227565b60005b838110156133c65781810151838201526020016133ae565b50506000910152565b600082516133e18184602087016133ab565b9190910192915050565b602081526000825180602084015261340a8160408501602087016133ab565b601f01601f1916919091016040019291505056fea2646970667358221220a6b414ff3abbf71aa38488f4215b453604386370247c248fe9244c5ea26a787964736f6c63430008130033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000005d17ea085f2ff5da3e6979d5d26f1dbab664ccf80000000000000000000000004591dbff62656e7859afe5e45f6f47d3669fbb2800000000000000000000000006bdf212c290473dcacea9793890c5024c7eb02c00000000000000000000000070b66e20766b775b2e9ce5b718bbd285af59b7e10000000000000000000000005de309dfd7f94e9e2a18cb6ba61ca305abf8e9e2

-----Decoded View---------------
Arg [0] : _prismaCore (address): 0x5d17eA085F2FF5da3e6979D5d26F1dBaB664ccf8
Arg [1] : _debtTokenAddress (address): 0x4591DBfF62656E7859Afe5e45f6f47D3669fBB28
Arg [2] : _vault (address): 0x06bDF212C290473dCACea9793890C5024c7Eb02c
Arg [3] : _factory (address): 0x70b66E20766b775B2E9cE5B718bbD285Af59b7E1
Arg [4] : _liquidationManager (address): 0x5de309dfd7f94e9e2A18Cb6bA61CA305aBF8e9E2

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000005d17ea085f2ff5da3e6979d5d26f1dbab664ccf8
Arg [1] : 0000000000000000000000004591dbff62656e7859afe5e45f6f47d3669fbb28
Arg [2] : 00000000000000000000000006bdf212c290473dcacea9793890c5024c7eb02c
Arg [3] : 00000000000000000000000070b66e20766b775b2e9ce5b718bbd285af59b7e1
Arg [4] : 0000000000000000000000005de309dfd7f94e9e2a18cb6ba61ca305abf8e9e2


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.