false
true
0

Contract Address Details

0xe4F208b73FCD06417153dA8620D805414b73A005

Contract Name
CVProtocol
Creator
0xd6db43–d657d9 at 0x750183–83ee90
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
1,052 Transactions
Transfers
1,502 Transfers
Gas Used
295,473,159
Last Balance Update
27899025
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
CVProtocol




Optimization enabled
true
Compiler version
v0.8.26+commit.8a97fa7a




Optimization runs
200
EVM Version
shanghai




Verified at
2026-07-01T16:46:53.861586Z

Constructor Arguments

00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba000000000000000000000000ff640cbd35a618df1348d861b5e47f7eab05b4220000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000077ca0bf25b19ae23474e2249ba52d1ce03760c700000000000000000000000005dd357debb23305126604d2ebc13160b513bbaca00000000000000000000000087fa4f1403a01b82cbc8e1d147f3e945679373fb000000000000000000000000472d13c2833e3e5e759b48a61a75798de12cd53f000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d90000000000000000000000000000000000000000000000000000000001e1338000000000000000000000000000000000000000000000000000000000000f406500000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000001464cef9b8b587b5a000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27000000000000000000000000f6f8db0aba00007681f8faf16a0fda1c9b030b110000000000000000000000002fa878ab3f87cc1c9737fc071108f904c0b0c95d0000000000000000000000002b591e99afe9f32eaa6214f7b7629768c40eeb3900000000000000000000000057fde0a71132198bbec939b98976993d8d89d22500000000000000000000000095b303987a60c71504d99aa1b13b4da07b0790ab000000000000000000000000c10a4ed9b4042222d69ff0b374eddd47ed90fc1f
              

CVProtocol.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {
    ICVMintable,
    IERC20,
    IReserveNFT,
    IDiamondNFT,
    IConvictionNFT,
    IScoreOracle,
    IPulseXFactory,
    IPulseXRouter,
    IPulseXPair
} from "./CVInterfaces.sol";

/// @title CVProtocol
/// @notice Mining, drip, and protocol owned liquidity for CV, wired to the live
///         pMINT Reserve, Diamond, and Conviction vaults. Audit hardened.
///
/// ============================ READ THIS FIRST ============================
/// Still requires a full external audit before mainnet. No owner, no pause, no
/// admin mint, no drain path. Rate knobs and genesis length are deploy time and
/// permanent, model them first.
///
/// Hardening in this version:
///  - refRate is a real TWAP read from the pair cumulative price. flush sizes the CV
///    mint from it and buyAndBurn sets its min out from it, so neither a flash loan nor
///    a slow repeated spot poke can move the price the protocol acts on.
///  - updateTWAP is permissionless so a keeper can keep refRate fresh in quiet periods,
///    which prevents buyAndBurn from locking up after a long idle gap.
///  - flush adds liquidity only when spot sits within FLUSH_BAND_BPS of refRate, so the
///    protocol never pairs its buffer into a pool that was pre seeded or skewed off price.
///  - drip claims use saturating subtraction, so a decrease in an external NFT
///    weight cannot underflow and lock a holder out of future claims.
///  - the rate decay is closed form by squaring, no long loop.
///  - mine pulls only the 15 percent cost, no pull and refund round trip.
///  - undistributed CV can be recycled back into the drip permissionlessly.
/// =========================================================================
contract CVProtocol {
    uint256 public constant BPS = 10_000;
    uint256 public constant MIN_RESERVE = 10_000e18;
    uint256 public constant LP_COST_BPS = 1_000; // 10% of the commit into the locked pool
    uint256 public constant BURN_COST_BPS = 500; // 5% of the commit into buy and burn
    uint256 public constant MINER_BPS = 7_000;
    uint256 public constant CONV_BPS = 4_500;
    uint256 public constant RESERVE_VAULT_BPS = 2_000;
    uint256 public constant DIAMOND_VAULT_BPS = 2_000;
    uint256 public constant LP_BPS = 1_500;
    uint8 public constant CONV_ASSETS = 7;
    uint256 public constant INFLATION_BPS = 369;
    uint256 public constant EPOCH = 1 days;
    uint256 public constant ACC = 1e18;
    uint256 public constant WAD = 1e18;
    uint256 public constant SLIPPAGE_BPS = 1_500; // 15% max slippage on buy and burn
    uint256 public constant MIN_FLUSH_INTERVAL = 1 hours; // light spam guard on flush
    uint256 public constant MIN_TWAP_WINDOW = 30 minutes; // minimum averaging window for the price
    uint256 public constant FLUSH_BAND_BPS = 1_500; // flush adds only when spot is within this of the reference

    ICVMintable public immutable cv;
    IERC20 public immutable pmint;
    IERC20 public immutable pdai;
    IReserveNFT public immutable reserveNFT;
    IDiamondNFT public immutable diamondNFT;
    IConvictionNFT public immutable convictionNFT;
    IScoreOracle public immutable score;
    IPulseXRouter public immutable router;

    uint256 public immutable genesisEnd;
    uint256 public immutable baselineNum;
    uint256 public immutable baselineDen;
    uint256 public immutable initRate;

    address[7] public convictionAssets;

    uint256 public mintRate;
    uint256 public lastEpoch;
    uint256 public epochIssued;

    uint256 public refRate; // CV per pMINT reference, the TWAP, used for flush sizing and buy and burn min out
    uint256 public lastFlushTime;

    // CV/PMINT time weighted average price observation
    uint256 public twapCumLast;
    uint32 public twapTsLast;
    bool public twapInit;

    uint256 public pmintLpBuffer;
    uint256 public pmintBurnBuffer;
    address public cvPmintPair;
    address public cvPdaiPair;

    mapping(address => uint256) public miningOwed;

    uint256[7] public accConv;
    uint256 public accReserve;
    uint256 public accDiamond;
    mapping(uint256 => uint256) public convCp;
    mapping(uint256 => uint256) public convClaimed;
    mapping(uint256 => uint256) public reserveCp;
    mapping(uint256 => uint256) public reserveClaimed;
    mapping(uint256 => uint256) public diamondCp;
    mapping(uint256 => uint256) public diamondClaimed;

    uint256 public accLp;
    uint256 public totalLp;
    mapping(address => uint256) public lpBal;
    mapping(address => uint256) public lpCp;

    uint256 public cvUndistributed;

    bool private _locked;
    modifier nonReentrant() {
        require(!_locked, "reentrant");
        _locked = true;
        _;
        _locked = false;
    }

    event Mined(address indexed miner, uint256 notional, uint256 cost, uint256 cvOut, uint256 minerShare, uint256 dripShare, uint256 rate, uint256 multBps);
    event MinerClaimed(address indexed miner, uint256 amount);
    event NftClaimed(address indexed owner, uint256 amount);
    event LpDeposited(address indexed user, uint256 amount);
    event LpWithdrawn(address indexed user, uint256 amount);
    event Flushed(uint256 pmintUsed, uint256 cvPaired, uint256 liquidity, uint256 refRate);
    event BoughtAndBurned(uint256 pmintIn, uint256 cvBurned);
    event Recycled(uint256 amount);

    constructor(
        address _cv,
        address _pmint,
        address _pdai,
        address _reserve,
        address _diamond,
        address _conviction,
        address _score,
        address _router,
        uint256 _genesisDuration,
        uint256 _baselineNum,
        uint256 _baselineDen,
        uint256 _initRate,
        address[7] memory _convictionAssets
    ) {
        require(_cv != address(0) && _pmint != address(0) && _pdai != address(0), "zero token");
        require(_reserve != address(0) && _diamond != address(0) && _conviction != address(0), "zero nft");
        require(_score != address(0) && _router != address(0), "zero dep");
        require(_baselineDen != 0 && _baselineNum <= _baselineDen, "bad baseline");
        require(_initRate > 0, "init rate");
        cv = ICVMintable(_cv);
        pmint = IERC20(_pmint);
        pdai = IERC20(_pdai);
        reserveNFT = IReserveNFT(_reserve);
        diamondNFT = IDiamondNFT(_diamond);
        convictionNFT = IConvictionNFT(_conviction);
        score = IScoreOracle(_score);
        router = IPulseXRouter(_router);
        genesisEnd = block.timestamp + _genesisDuration;
        baselineNum = _baselineNum;
        baselineDen = _baselineDen;
        initRate = _initRate;
        mintRate = _initRate;
        refRate = _initRate;
        lastEpoch = block.timestamp / EPOCH;
        for (uint256 i = 0; i < CONV_ASSETS; i++) {
            require(_convictionAssets[i] != address(0), "zero asset");
            convictionAssets[i] = _convictionAssets[i];
        }
    }

    // ================================ mining ================================

    function mine(uint256 amount, uint256[] calldata reserveIds) external nonReentrant {
        require(amount > 0, "amount=0");
        _advance();

        uint256 reserveTotal;
        uint256 prev;
        for (uint256 k = 0; k < reserveIds.length; k++) {
            uint256 id = reserveIds[k];
            require(id > prev, "ids not ascending");
            prev = id;
            require(reserveNFT.ownerOf(id) == msg.sender, "not your reserve");
            (uint256 amt, , , , , , , , , ) = reserveNFT.getReserve(id);
            reserveTotal += amt;
        }
        require(reserveTotal >= MIN_RESERVE, "need 10k reserve");

        // pull only the 15 percent cost, the miner keeps the rest, no refund round trip
        uint256 lpPart = (amount * LP_COST_BPS) / BPS;
        uint256 burnPart = (amount * BURN_COST_BPS) / BPS;
        require(pmint.transferFrom(msg.sender, address(this), lpPart + burnPart), "pmint in");
        pmintLpBuffer += lpPart;
        pmintBurnBuffer += burnPart;

        uint256 multBps = _multBps(msg.sender);
        uint256 cvOut = (((amount * mintRate) / WAD) * multBps) / 100;
        require(cvOut > 0, "cv=0");

        cv.mint(address(this), cvOut);
        epochIssued += cvOut;

        uint256 minerShare = (cvOut * MINER_BPS) / BPS;
        miningOwed[msg.sender] += minerShare;
        _distribute(cvOut - minerShare);

        emit Mined(msg.sender, amount, lpPart + burnPart, cvOut, minerShare, cvOut - minerShare, mintRate, multBps);
    }

    function claimMiner() external nonReentrant {
        uint256 owed = miningOwed[msg.sender];
        require(owed > 0, "nothing");
        miningOwed[msg.sender] = 0;
        require(cv.transfer(msg.sender, owed), "cv out");
        emit MinerClaimed(msg.sender, owed);
    }

    // =============================== rate engine ===============================

    function _advance() internal {
        uint256 nowE = block.timestamp / EPOCH;
        if (nowE == lastEpoch) return;
        if (block.timestamp >= genesisEnd) {
            uint256 supply = cv.totalSupply();
            uint256 allowance = (supply * INFLATION_BPS) / BPS / 365;
            if (allowance > 0 && epochIssued > allowance) {
                mintRate = (mintRate * allowance) / epochIssued;
            }
        }
        uint256 steps = nowE - lastEpoch;
        uint256 factorWad = (baselineNum * WAD) / baselineDen; // <= WAD
        mintRate = (mintRate * _powWad(factorWad, steps)) / WAD;
        epochIssued = 0;
        lastEpoch = nowE;
    }

    /// @dev closed form decay, base^exp in WAD by squaring, about log2(exp) steps
    function _powWad(uint256 baseWad, uint256 e) internal pure returns (uint256 r) {
        r = WAD;
        uint256 b = baseWad;
        while (e > 0) {
            if (e & 1 == 1) r = (r * b) / WAD;
            b = (b * b) / WAD;
            e >>= 1;
        }
    }

    function poke() external {
        _advance();
    }

    function _multBps(address u) internal view returns (uint256) {
        uint16 s = score.scoreOf(u);
        if (s >= 800) return 200;
        if (s >= 740) return 160;
        if (s >= 670) return 120;
        if (s >= 580) return 80;
        return 40;
    }

    function _sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a - b : 0; // saturating, never underflows on a weight decrease
    }

    // ============================= drip distribution =============================

    function _distribute(uint256 d) internal {
        uint256 used;

        uint256 convTotal = (d * CONV_BPS) / BPS;
        uint256 perAsset = convTotal / CONV_ASSETS;
        for (uint8 i = 0; i < CONV_ASSETS; i++) {
            uint256 tw = convictionNFT.getAssetConfig(convictionAssets[i]).totalCV;
            if (tw > 0) {
                accConv[i] += (perAsset * ACC) / tw;
            } else {
                cvUndistributed += perAsset;
            }
        }
        used += perAsset * CONV_ASSETS;

        uint256 rv = (d * RESERVE_VAULT_BPS) / BPS;
        uint256 twR = reserveNFT.totalCV();
        if (twR > 0) {
            accReserve += (rv * ACC) / twR;
        } else {
            cvUndistributed += rv;
        }
        used += rv;

        uint256 dv = (d * DIAMOND_VAULT_BPS) / BPS;
        uint256 twD = diamondNFT.totalCV();
        if (twD > 0) {
            accDiamond += (dv * ACC) / twD;
        } else {
            cvUndistributed += dv;
        }
        used += dv;

        uint256 lp = (d * LP_BPS) / BPS;
        if (totalLp > 0) {
            accLp += (lp * ACC) / totalLp;
        } else {
            cvUndistributed += lp;
        }
        used += lp;

        if (d > used) cvUndistributed += (d - used);
    }

    /// @notice Permissionless. Re routes trapped CV back through the drip so it is not
    ///         stuck. If a bucket is still empty it simply returns there, a no op.
    function recycleUndistributed() external nonReentrant {
        uint256 x = cvUndistributed;
        require(x > 0, "none");
        cvUndistributed = 0;
        _distribute(x);
        emit Recycled(x);
    }

    function _convIndex(address asset) internal view returns (int256) {
        for (uint256 i = 0; i < CONV_ASSETS; i++) {
            if (convictionAssets[i] == asset) return int256(i);
        }
        return -1;
    }

    function claimConviction(uint256[] calldata ids) external nonReentrant {
        uint256 total;
        for (uint256 k = 0; k < ids.length; k++) {
            uint256 id = ids[k];
            require(convictionNFT.ownerOf(id) == msg.sender, "not owner");
            (address asset, , uint128 cvw, , , , , , bool closed, , ) = convictionNFT.positions(id);
            if (closed) continue;
            int256 ix = _convIndex(asset);
            if (ix < 0) continue;
            uint256 accrued = (uint256(cvw) * accConv[uint256(ix)]) / ACC;
            uint256 owed = _sub(accrued, convCp[id]);
            convCp[id] = accrued;
            if (owed > 0) {
                convClaimed[id] += owed;
                total += owed;
            }
        }
        if (total > 0) {
            require(cv.transfer(msg.sender, total), "cv out");
            emit NftClaimed(msg.sender, total);
        }
    }

    function claimReserve(uint256[] calldata ids) external nonReentrant {
        uint256 total;
        for (uint256 k = 0; k < ids.length; k++) {
            uint256 id = ids[k];
            require(reserveNFT.ownerOf(id) == msg.sender, "not owner");
            (, uint256 cvw, , , , , , , , ) = reserveNFT.getReserve(id);
            uint256 accrued = (cvw * accReserve) / ACC;
            uint256 owed = _sub(accrued, reserveCp[id]);
            reserveCp[id] = accrued;
            if (owed > 0) {
                reserveClaimed[id] += owed;
                total += owed;
            }
        }
        if (total > 0) {
            require(cv.transfer(msg.sender, total), "cv out");
            emit NftClaimed(msg.sender, total);
        }
    }

    function claimDiamond(uint256[] calldata ids) external nonReentrant {
        uint256 total;
        for (uint256 k = 0; k < ids.length; k++) {
            uint256 id = ids[k];
            require(diamondNFT.ownerOf(id) == msg.sender, "not owner");
            (, uint128 cvw, , , , , , bool closed, ) = diamondNFT.positions(id);
            if (closed) continue;
            uint256 accrued = (uint256(cvw) * accDiamond) / ACC;
            uint256 owed = _sub(accrued, diamondCp[id]);
            diamondCp[id] = accrued;
            if (owed > 0) {
                diamondClaimed[id] += owed;
                total += owed;
            }
        }
        if (total > 0) {
            require(cv.transfer(msg.sender, total), "cv out");
            emit NftClaimed(msg.sender, total);
        }
    }

    // ---------------------------- CV/pDAI LP vault ----------------------------

    function depositLp(uint256 amount) external nonReentrant {
        require(amount > 0, "amount=0");
        address t = _lpToken();
        _settleLp(msg.sender);
        require(IERC20(t).transferFrom(msg.sender, address(this), amount), "lp in");
        lpBal[msg.sender] += amount;
        totalLp += amount;
        lpCp[msg.sender] = (lpBal[msg.sender] * accLp) / ACC;
        emit LpDeposited(msg.sender, amount);
    }

    function withdrawLp(uint256 amount) external nonReentrant {
        require(lpBal[msg.sender] >= amount, "bal");
        address t = _lpToken();
        _settleLp(msg.sender);
        lpBal[msg.sender] -= amount;
        totalLp -= amount;
        lpCp[msg.sender] = (lpBal[msg.sender] * accLp) / ACC;
        require(IERC20(t).transfer(msg.sender, amount), "lp out");
        emit LpWithdrawn(msg.sender, amount);
    }

    function claimLp() external nonReentrant {
        _settleLp(msg.sender);
        lpCp[msg.sender] = (lpBal[msg.sender] * accLp) / ACC;
    }

    function _settleLp(address u) internal {
        uint256 pend = _sub((lpBal[u] * accLp) / ACC, lpCp[u]);
        if (pend > 0) {
            lpCp[u] = (lpBal[u] * accLp) / ACC;
            require(cv.transfer(u, pend), "cv out");
        }
    }

    function _lpToken() internal returns (address) {
        if (cvPdaiPair == address(0)) {
            cvPdaiPair = IPulseXFactory(router.factory()).getPair(address(cv), address(pdai));
        }
        require(cvPdaiPair != address(0), "no cv/pdai pair");
        return cvPdaiPair;
    }

    // ============================ price, TWAP ============================

    /// @dev CV per pMINT cumulative, UQ112x112, extrapolated to now, Uniswap V2 oracle pattern
    function _cvPerPmintCum(address pair) internal view returns (uint256 cum, uint32 ts) {
        (uint112 r0, uint112 r1, uint32 tsLast) = IPulseXPair(pair).getReserves();
        bool pmintIs0 = IPulseXPair(pair).token0() == address(pmint);
        cum = pmintIs0 ? IPulseXPair(pair).price0CumulativeLast() : IPulseXPair(pair).price1CumulativeLast();
        ts = uint32(block.timestamp);
        if (r0 > 0 && r1 > 0 && tsLast != ts) {
            uint256 cvR = pmintIs0 ? uint256(r1) : uint256(r0);
            uint256 pmR = pmintIs0 ? uint256(r0) : uint256(r1);
            uint256 spotUQ = (cvR << 112) / pmR; // CV per pMINT in UQ112x112
            uint32 elapsed;
            unchecked {
                elapsed = ts - tsLast;
                cum += spotUQ * elapsed; // wraps like the pair, intended
            }
        }
    }

    /// @dev refresh refRate from the TWAP if at least one window has passed since the last observation
    function _updateRef() internal {
        address pair = cvPmintPair;
        if (pair == address(0)) {
            pair = IPulseXFactory(router.factory()).getPair(address(cv), address(pmint));
            if (pair == address(0)) return; // no pool yet, refRate stays at initRate
            cvPmintPair = pair;
        }
        (uint256 cum, uint32 ts) = _cvPerPmintCum(pair);
        if (!twapInit) {
            twapCumLast = cum;
            twapTsLast = ts;
            twapInit = true;
            return; // first observation, do not move refRate yet
        }
        uint32 elapsed;
        unchecked { elapsed = ts - twapTsLast; }
        if (elapsed < MIN_TWAP_WINDOW) return; // keep refRate until a full window builds
        uint256 avgUQ;
        unchecked { avgUQ = (cum - twapCumLast) / elapsed; }
        uint256 priceWad = (avgUQ * WAD) >> 112;
        if (priceWad > 0) refRate = priceWad;
        twapCumLast = cum;
        twapTsLast = ts;
    }

    /// @notice Permissionless. Advances the TWAP observation so refRate stays current during
    ///         quiet periods. Keepers should call this on a schedule, hourly is plenty, so buy
    ///         and burn always has a fresh reference and cannot stall after a long idle gap.
    function updateTWAP() external {
        _updateRef();
    }

    // ====================== flush: protocol owned liquidity ======================

    function flush() external nonReentrant {
        require(block.timestamp >= lastFlushTime + MIN_FLUSH_INTERVAL, "too soon");
        uint256 buf = pmintLpBuffer;
        require(buf > 0, "empty");
        pmintLpBuffer = 0;
        lastFlushTime = block.timestamp;

        _updateRef(); // refRate is the TWAP once the pool and a window exist, else initRate

        // size the CV mint from the TWAP, not raw spot, so a skewed spot cannot inflate it
        uint256 cvToPair = (buf * refRate) / WAD;
        require(cvToPair > 0, "cv pair=0");

        cv.mint(address(this), cvToPair);
        require(pmint.approve(address(router), buf), "approve pmint");
        require(cv.approve(address(router), cvToPair), "approve cv");

        // add only near the reference ratio. If the pool is skewed away from refRate, whether
        // pre seeded at launch or manipulated later, the router cannot meet these mins and the
        // add reverts, so the protocol never pairs its buffer at a bad price. On the very first
        // add into an empty pool the router uses both amounts in full, opening at refRate.
        uint256 minCv = (cvToPair * (BPS - FLUSH_BAND_BPS)) / BPS;
        uint256 minPm = (buf * (BPS - FLUSH_BAND_BPS)) / BPS;

        (uint256 usedCv, uint256 usedPm, uint256 liq) = router.addLiquidity(
            address(cv), address(pmint), cvToPair, buf, minCv, minPm, address(this), block.timestamp
        );

        if (buf > usedPm) pmintLpBuffer += (buf - usedPm);
        if (cvToPair > usedCv) cvUndistributed += (cvToPair - usedCv);
        emit Flushed(usedPm, usedCv, liq, refRate);
    }

        // ====================== buy and burn, reference anchored ======================

    function buyAndBurn() external nonReentrant {
        uint256 amountIn = pmintBurnBuffer;
        require(amountIn > 0, "empty");
        _updateRef();
        require(cvPmintPair != address(0), "no pool yet");
        pmintBurnBuffer = 0;

        address[] memory path = new address[](2);
        path[0] = address(pmint);
        path[1] = address(cv);

        // min out from the slow reference rate, not spot, so a sandwich that worsens price reverts
        uint256 expected = (amountIn * refRate) / WAD;
        uint256 minOut = (expected * (BPS - SLIPPAGE_BPS)) / BPS;

        uint256 balBefore = cv.balanceOf(address(this));
        require(pmint.approve(address(router), amountIn), "approve");
        router.swapExactTokensForTokensSupportingFeeOnTransferTokens(amountIn, minOut, path, address(this), block.timestamp);
        uint256 cvBought = cv.balanceOf(address(this)) - balBefore;
        if (cvBought > 0) cv.burn(cvBought);
        emit BoughtAndBurned(amountIn, cvBought);
    }

    // ================================== views ==================================

    function convUnclaimed(uint256 id) external view returns (uint256) {
        (address asset, , uint128 cvw, , , , , , bool closed, , ) = convictionNFT.positions(id);
        if (closed) return 0;
        int256 ix = _convIndex(asset);
        if (ix < 0) return 0;
        return _sub((uint256(cvw) * accConv[uint256(ix)]) / ACC, convCp[id]);
    }

    function reserveUnclaimed(uint256 id) external view returns (uint256) {
        (, uint256 cvw, , , , , , , , ) = reserveNFT.getReserve(id);
        return _sub((cvw * accReserve) / ACC, reserveCp[id]);
    }

    function diamondUnclaimed(uint256 id) external view returns (uint256) {
        (, uint128 cvw, , , , , , bool closed, ) = diamondNFT.positions(id);
        if (closed) return 0;
        return _sub((uint256(cvw) * accDiamond) / ACC, diamondCp[id]);
    }

    function lpPending(address u) external view returns (uint256) {
        return _sub((lpBal[u] * accLp) / ACC, lpCp[u]);
    }

    function inGenesis() external view returns (bool) {
        return block.timestamp < genesisEnd;
    }
}
        

/CVInterfaces.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// Wired to the real pMINT contracts. Addresses in CV_DEPLOY.md.

interface IERC20 {
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
    function totalSupply() external view returns (uint256);
}

interface ICVMintable is IERC20 {
    function mint(address to, uint256 amount) external;
    function burn(uint256 amount) external;
}

// pMINT Reserve. Locks pMINT. Soulbound during lock, sellable once matured.
interface IReserveNFT {
    function ownerOf(uint256 tokenId) external view returns (address);
    function getReserve(uint256 tokenId) external view returns (
        uint256 amount,
        uint256 cv,
        uint256 startTime,
        uint256 unlockTime,
        uint256 durationDays,
        uint256 amountTier,
        uint256 durationTier,
        bool matured,
        bool rewardActive,
        uint256 rewardEligibleTime
    );
    function totalCV() external view returns (uint256);
}

// Diamond vault. Locks pDAI.
interface IDiamondNFT {
    function ownerOf(uint256 tokenId) external view returns (address);
    function positions(uint256 tokenId) external view returns (
        uint128 amount,
        uint128 cv,
        uint64 startTime,
        uint64 unlockTime,
        uint32 durationDays,
        uint16 amountTier,
        uint16 durationTier,
        bool closed,
        bool activated
    );
    function totalCV() external view returns (uint256);
}

// Universal Conviction vault. Multi asset, governance can add more beyond the core set.
interface IConvictionNFT {
    struct AssetView {
        bool isApproved;
        bool isCoreAsset;
        uint256[8] amountTiers;
        uint256 minSponsorship;
        uint256 totalLocked;
        uint256 totalCV;
        uint256 positionsActive;
        uint256 positionsPending;
        uint256 positionsAllTime;
        uint256 emergencyExits;
        uint256 matureExits;
        uint256 approvedAt;
    }
    function ownerOf(uint256 tokenId) external view returns (address);
    function positions(uint256 tokenId) external view returns (
        address asset,
        uint128 amount,
        uint128 cv,
        uint64 startTime,
        uint64 unlockTime,
        uint32 durationDays,
        uint16 amountTier,
        uint16 durationTier,
        bool closed,
        bool activated,
        address referrer
    );
    function getAssetConfig(address asset) external view returns (AssetView memory);
}

// THE ONE PIECE STILL TO DECIDE. The conviction score is computed off chain by your
// worker. This is the on chain bridge the contract reads for the mining multiplier.
// It can be a signature verifier, a merkle proof checker, or a worker pushed oracle.
interface IScoreOracle {
    function scoreOf(address user) external view returns (uint16); // 300..850
}

interface IPulseXFactory {
    function getPair(address a, address b) external view returns (address);
}

interface IPulseXRouter {
    function factory() external view returns (address);
    function addLiquidity(
        address tokenA, address tokenB,
        uint256 amountADesired, uint256 amountBDesired,
        uint256 amountAMin, uint256 amountBMin,
        address to, uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn, uint256 amountOutMin,
        address[] calldata path, address to, uint256 deadline
    ) external;
    function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);
}

interface IPulseXPair {
    function token0() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint256);
    function price1CumulativeLast() external view returns (uint256);
}
          

Compiler Settings

{"viaIR":true,"remappings":[],"optimizer":{"runs":200,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"shanghai","compilationTarget":{"CVProtocol.sol":"CVProtocol"}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_cv","internalType":"address"},{"type":"address","name":"_pmint","internalType":"address"},{"type":"address","name":"_pdai","internalType":"address"},{"type":"address","name":"_reserve","internalType":"address"},{"type":"address","name":"_diamond","internalType":"address"},{"type":"address","name":"_conviction","internalType":"address"},{"type":"address","name":"_score","internalType":"address"},{"type":"address","name":"_router","internalType":"address"},{"type":"uint256","name":"_genesisDuration","internalType":"uint256"},{"type":"uint256","name":"_baselineNum","internalType":"uint256"},{"type":"uint256","name":"_baselineDen","internalType":"uint256"},{"type":"uint256","name":"_initRate","internalType":"uint256"},{"type":"address[7]","name":"_convictionAssets","internalType":"address[7]"}]},{"type":"event","name":"BoughtAndBurned","inputs":[{"type":"uint256","name":"pmintIn","internalType":"uint256","indexed":false},{"type":"uint256","name":"cvBurned","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Flushed","inputs":[{"type":"uint256","name":"pmintUsed","internalType":"uint256","indexed":false},{"type":"uint256","name":"cvPaired","internalType":"uint256","indexed":false},{"type":"uint256","name":"liquidity","internalType":"uint256","indexed":false},{"type":"uint256","name":"refRate","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LpDeposited","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LpWithdrawn","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Mined","inputs":[{"type":"address","name":"miner","internalType":"address","indexed":true},{"type":"uint256","name":"notional","internalType":"uint256","indexed":false},{"type":"uint256","name":"cost","internalType":"uint256","indexed":false},{"type":"uint256","name":"cvOut","internalType":"uint256","indexed":false},{"type":"uint256","name":"minerShare","internalType":"uint256","indexed":false},{"type":"uint256","name":"dripShare","internalType":"uint256","indexed":false},{"type":"uint256","name":"rate","internalType":"uint256","indexed":false},{"type":"uint256","name":"multBps","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MinerClaimed","inputs":[{"type":"address","name":"miner","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NftClaimed","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Recycled","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ACC","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BURN_COST_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"CONV_ASSETS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"CONV_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DIAMOND_VAULT_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"EPOCH","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"FLUSH_BAND_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"INFLATION_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"LP_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"LP_COST_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MINER_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MIN_FLUSH_INTERVAL","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MIN_RESERVE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MIN_TWAP_WINDOW","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"RESERVE_VAULT_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"SLIPPAGE_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"WAD","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accConv","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accDiamond","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accLp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accReserve","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"baselineDen","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"baselineNum","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"buyAndBurn","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimConviction","inputs":[{"type":"uint256[]","name":"ids","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimDiamond","inputs":[{"type":"uint256[]","name":"ids","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimLp","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimMiner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimReserve","inputs":[{"type":"uint256[]","name":"ids","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"convClaimed","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"convCp","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"convUnclaimed","inputs":[{"type":"uint256","name":"id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"convictionAssets","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IConvictionNFT"}],"name":"convictionNFT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ICVMintable"}],"name":"cv","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"cvPdaiPair","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"cvPmintPair","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cvUndistributed","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"depositLp","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"diamondClaimed","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"diamondCp","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IDiamondNFT"}],"name":"diamondNFT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"diamondUnclaimed","inputs":[{"type":"uint256","name":"id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"epochIssued","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"flush","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"genesisEnd","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"inGenesis","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"initRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastEpoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastFlushTime","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lpBal","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lpCp","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lpPending","inputs":[{"type":"address","name":"u","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"mine","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256[]","name":"reserveIds","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"miningOwed","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"mintRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"pdai","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"pmint","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pmintBurnBuffer","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pmintLpBuffer","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"poke","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recycleUndistributed","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"refRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"reserveClaimed","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"reserveCp","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IReserveNFT"}],"name":"reserveNFT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"reserveUnclaimed","inputs":[{"type":"uint256","name":"id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPulseXRouter"}],"name":"router","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IScoreOracle"}],"name":"score","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalLp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"twapCumLast","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"twapInit","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"twapTsLast","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateTWAP","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawLp","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]}]
              

Contract Creation Code

0x6102006040523461054f576040516144f73881900390601f8201601f19168301906001600160401b03821184831017610553578291604052833981016102608282031261054f5781809161005282610567565b61005e60208401610567565b61006a60408501610567565b61007660608601610567565b9061008360808701610567565b61008f60a08801610567565b9161009c60c08901610567565b906100a960e08a01610567565b956101008a0151976101208b015199806101408d01519c61016001519d61019f01121561054f576040519d8e60e0810190811060018060401b03821117610553578f9060405290610260810192831161054f5761018001905b828210610537575050506001600160a01b03169586151580610525575b80610513575b156104e1576001600160a01b031692831515806104cf575b806104bd575b1561048d576001600160a01b0316958615158061047b575b1561044b578a151580610441575b1561040d578b156103dc576080526001600160a01b0390811660a05290811660c05260e0919091529081166101005290811661012052610140919091521661016052429081019081106103c857610180526101a0526101c052806101e05280600755600a556201518042046008555f5b6007811015610257576001600160a01b036101f4828461057b565b511615610225576001906001600160a01b03610210828561057b565b5116828060a01b0319825416178155016101d9565b60405162461bcd60e51b815260206004820152600a6024820152691e995c9bc8185cdcd95d60b21b6044820152606490fd5b604051613f5690816105a182396080518181816105180152818161097f01528181610c36015281816115c10152818161201301528181612685015281816130b001528181613523015281816136f601526138bc015260a051818181610486015281816114aa0152818161158b015281816120bc015281816131f7015261354b015260c051818181612498015261371e015260e0518181816103cc01528181610bc30152818161143b015281816125cf0152613a170152610100518181816110a0015281816119e601528181612b7c0152613aaf01526101205181818161121c0152818161256e01528181612e97015261399e015261014051818181610b440152613e59015261016051818181610aa50152818161166001528181612089015281816134d301526136a6015261018051818181610aec015281816119730152612f7901526101a051818181611cb50152612fac01526101c0518181816124440152612ff201526101e051816111a90152f35b634e487b7160e01b5f52601160045260245ffd5b60405162461bcd60e51b8152602060048201526009602482015268696e6974207261746560b81b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b62616420626173656c696e6560a01b6044820152606490fd5b508a8a1115610169565b60405162461bcd60e51b815260206004820152600860248201526707a65726f206465760c41b6044820152606490fd5b506001600160a01b038816151561015b565b60405162461bcd60e51b81526020600482015260086024820152671e995c9bc81b999d60c21b6044820152606490fd5b506001600160a01b0386161515610143565b506001600160a01b038516151561013d565b60405162461bcd60e51b815260206004820152600a6024820152693d32b937903a37b5b2b760b11b6044820152606490fd5b506001600160a01b0383161515610125565b506001600160a01b038216151561011f565b6020809161054484610567565b815201910190610102565b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b038216820361054f57565b90600781101561058c5760051b0190565b634e487b7160e01b5f52603260045260245ffdfe6080806040526004361015610012575f80fd5b5f905f3560e01c90816303c85629146129655750806306a4c9831461294857806309dfd0e6146129245780630ed52473146124285780630eeb27c4146128fa578063141132b7146128dc57806318178358146128c2578063191a9f42146128965780631a65893b1461287a5780631abc0eda146128575780632112a3221461282f578063242c135d14612812578063249d39e9146127f65780632a9e9774146127d95780632d734380146127bc5780632e8300871461279f578063313408c91461266b57806331f4d720146127825780633f110e3d146127585780633f86079e1461273457806340ecfefb1461270c57806343c41d04146126d05780634601ed47146126b45780634707b74814612670578063504d2e9b1461266b57806350992a8b1461259d5780635474f0af14612559578063587f373f146124e35780635bcd7852146124c7578063604d7d2314612483578063613094ee14612467578063689e6f131461242d5780636a146024146124285780636b9f96ea14611f965780636da514ec14611f5957806370222cfa14611f3c57806370d079bd14611f205780637175af6214611f02578063767390ee14611ee457806377f8bb6d14610ef65780638d83f29d14611ec657806393686d4114611e9c578063959afa1514611cd85780639a67964814611c9d5780639bea590e14611c81578063a0988db414611c63578063a0dc275814611c45578063a42fefec14611c27578063a504f7e314611bb6578063a7b16e3514611996578063a9abc96e1461195b578063aa6df29914611516578063ac1e294b146114d9578063b4ce468d14611494578063b75d95c11461146a578063b8c1e7ba14610ef6578063c617f4ed14611425578063c8f10300146111cc578063c9323e3114611191578063c93d512e146110ed578063ca0dcf16146110cf578063cfdf66011461108a578063dae7292a14610efb578063df0b366714610ef6578063e174770314610ecf578063e59f345b14610e9a578063e794b39a14610e70578063ec41c6bc14610e53578063ed3ad9ac14610b73578063efedc66914610b2e578063f31bf66914610b11578063f40fbb3c14610ad4578063f887ea4014610a8f578063f899667a14610a66578063fedc6ccc146109055763ff7025d214610362575f80fd5b346109025760403660031901126109025760043560243567ffffffffffffffff81116108fe576103969036906004016129d9565b60016027546103a860ff821615612c7f565b60ff1916176027558215916103bd8315612e43565b6103c5612f67565b84918291907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169083905b8086106107685788888869021e19e0c9bab24000008810610730576103e882028281046103e81482171561071c576127109004906101f48302908382046101f414171561071c5761271090049061048160206104548484612cb7565b6040516323b872dd60e01b8152336004820152306024820152604481019190915291829081906064820190565b0381887f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19081156107115785916106d3575b50156106a3576104d081600e54612cb7565b600e556104df82600f54612cb7565b600f556104eb33613e2f565b91606461050d84670de0b6b3a764000061050760075489612b2e565b04612b2e565b0490811561067857857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610674576040516340c10f1960e01b8152306004820152602481018590529082908290604490829084905af1801561066957610650575b505061058882600954612cb7565b600955611b588202828104611b580361063c57906127106105d59204933388526012602052604088206105bc868254612cb7565b90556105d06105cb8686612cf8565b61397d565b612cb7565b916105e08183612cf8565b9160075493604051968752602087015260408601526060850152608084015260a083015260c08201527fa738e9069b8aa14d79b4dee9ff8094829c55d53112d9a1a93d74d14a0480b32360e03392a260ff196027541660275580f35b634e487b7160e01b87526011600452602487fd5b8161065a91612a0a565b61066557858761057a565b8580fd5b6040513d84823e3d90fd5b5080fd5b606460405162461bcd60e51b8152602060048201526004602482015263063763d360e41b6044820152fd5b60405162461bcd60e51b81526020600482015260086024820152673836b4b73a1034b760c11b6044820152606490fd5b90506020813d602011610709575b816106ee60209383612a0a565b81010312610705576106ff90612a89565b856104be565b8480fd5b3d91506106e1565b6040513d87823e3d90fd5b634e487b7160e01b84526011600452602484fd5b60405162461bcd60e51b815260206004820152601060248201526f6e6565642031306b207265736572766560801b6044820152606490fd5b90919293610777868387612d05565b35928311156108c557826040516331a9108f60e11b8152816004820152602081602481895afa9081156108ba578b9161087d575b50336001600160a01b039091160361084557604051906377778db360e01b8252600482015261014081602481885afa801561083a576001926107f4928c92610800575b50612cb7565b950194939291906103f8565b6108239192506101403d8111610833575b61081b8183612a0a565b810190612c28565b505050505050505050905f6107ee565b503d610811565b6040513d8c823e3d90fd5b60405162461bcd60e51b815260206004820152601060248201526f6e6f7420796f7572207265736572766560801b6044820152606490fd5b90506020813d82116108b2575b8161089760209383612a0a565b810103126108ae576108a890612d29565b5f6107ab565b8a80fd5b3d915061088a565b6040513d8d823e3d90fd5b60405162461bcd60e51b8152602060048201526011602482015270696473206e6f7420617363656e64696e6760781b6044820152606490fd5b8280fd5b80fd5b5034610902578060031936011261090257600160275461092860ff821615612c7f565b60ff191617602755338152601260205260408120548015610a3757338083526012602090815260408085208590555163a9059cbb60e01b815260048101929092526024820183905281604481866001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af18015610a2c5783906109f1575b6109b89150612d75565b6040519081527ff14b08e987df188c7676e8601bb40336ef511abfb4e9e35913f5ed9c0db0467c60203392a260ff196027541660275580f35b506020813d602011610a24575b81610a0b60209383612a0a565b810103126108fe57610a1f6109b891612a89565b6109ae565b3d91506109fe565b6040513d85823e3d90fd5b60405162461bcd60e51b81526020600482015260076024820152666e6f7468696e6760c81b6044820152606490fd5b503461090257602036600319011261090257604060209160043581528280522054604051908152f35b50346109025780600319360112610902576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461090257806003193601126109025760206040517f000000000000000000000000000000000000000000000000000000000000000042108152f35b50346109025780600319360112610902576020604051611b588152f35b50346109025780600319360112610902576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346109025760203660031901126109025760043567ffffffffffffffff811161067457610ba59036906004016129d9565b6001602754610bb760ff821615612c7f565b60ff19161760275582917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691835b818110610cdc57858580610c0b575b5060ff196027541660275580f35b60405163a9059cbb60e01b815233600482015260248101829052602081604481866001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af18015610a2c578390610ca1575b610c6f9150612d75565b6040519081527f2c3dab7c883557b1efe1614d25d4a2a2d2845836f063cce9a69f27bc757bdd1160203392a281610bfd565b506020813d602011610cd4575b81610cbb60209383612a0a565b810103126108fe57610ccf610c6f91612a89565b610c65565b3d9150610cae565b610ce7818385612d05565b356040516331a9108f60e11b8152816004820152602081602481895afa8015610e0a578890610e15575b610d2691506001600160a01b03163314612d3d565b6040516377778db360e01b81526004810182905261014081602481895afa908115610e0a57670de0b6b3a764000091610d6a918a91610de1575b50601a5490612b2e565b0490808852601e60205260408820548083115f14610dd957610d8c9083612cf8565b915b818952601e602052604089205581610dab575b5050600101610bee565b9060019296610dd1928952601f60205260408920610dca838254612cb7565b9055612cb7565b94905f610da1565b508791610d8e565b610dfa91506101403d81116108335761081b8183612a0a565b505050505050505090505f610d60565b6040513d8a823e3d90fd5b506020813d8211610e4b575b81610e2e60209383612a0a565b81010312610e4757610e42610d2691612d29565b610d11565b8780fd5b3d9150610e21565b50346109025780600319360112610902576020604051610e108152f35b50346109025760203660031901126109025760406020916004358152601f83522054604051908152f35b503461090257602036600319011261090257600435600781101561067457546040516001600160a01b03909116815260209150f35b5034610902576020366003190112610902576020610eee600435612e7a565b604051908152f35b6129bd565b5034610902576020366003190112610902576004356001602754610f2260ff821615612c7f565b60ff191617602755610f35811515612e43565b610f3d613631565b610f46336137f6565b6040516323b872dd60e01b815233600482015230602482015260448101839052906020908290606490829087906001600160a01b03165af1908115610a2c578391611050575b501561102357338252602460205260408220610fa9828254612cb7565b9055610fb781602354612cb7565b6023553382526024602052670de0b6b3a7640000610fdc604084205460225490612b2e565b04338352602560205260408320556040519081527fdae4417c25a93cfb86ce5fbbb8fc1630945b61afaeab4f29cf301b9a058ba91460203392a260ff196027541660275580f35b60405162461bcd60e51b815260206004820152600560248201526436381034b760d91b6044820152606490fd5b90506020813d602011611082575b8161106b60209383612a0a565b810103126108fe5761107c90612a89565b5f610f8c565b3d915061105e565b50346109025780600319360112610902576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346109025780600319360112610902576020600754604051908152f35b5034610902578060031936011261090257600160275461111060ff821615612c7f565b60ff19161760275560265480156111665760207f74405529d531f035eac9d9aff6843cb2a1e612e6091d8ca9a6fd666c2975daa591836026556111528161397d565b604051908152a160ff196027541660275580f35b606460405162461bcd60e51b81526020600482015260046024820152636e6f6e6560e01b6044820152fd5b503461090257806003193601126109025760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346109025760203660031901126109025760043567ffffffffffffffff8111610674576111fe9036906004016129d9565b600160275461121060ff821615612c7f565b60ff19161760275582917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691835b81811061126357858580610c0b575060ff196027541660275580f35b61126e818385612d05565b356040516331a9108f60e11b8152816004820152602081602481895afa8015610e0a5788906113eb575b6112ad91506001600160a01b03163314612d3d565b60405163133f757160e31b81526004810182905261016081602481895afa8015610e0a57889089928a916113ac575b506113a1576112ea9061394a565b8881126113a157600781101561138d57670de0b6b3a7640000916001600160801b0361131b92601301549116612b2e565b0490808852601c60205260408820548083115f146113855761133d9083612cf8565b915b818952601c60205260408920558161135e575b50506001905b01611247565b906001929661137d928952601d60205260408920610dca838254612cb7565b94905f611352565b50879161133f565b634e487b7160e01b89526032600452602489fd5b505050600190611358565b9150506113d191506101603d81116113e4575b6113c98183612a0a565b810190612daa565b505097959650505050505090915f6112dc565b503d6113bf565b506020813d821161141d575b8161140460209383612a0a565b81010312610e47576114186112ad91612d29565b611298565b3d91506113f7565b50346109025780600319360112610902576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346109025760203660031901126109025760406020916004358152601d83522054604051908152f35b50346109025780600319360112610902576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610902576020366003190112610902576004356001600160a01b03811690819003610674578160409160209352601283522054604051908152f35b5034610902578060031936011261090257600160275461153960ff821615612c7f565b60ff191617602755600f5461154f811515612cc4565b611557613184565b6010546001600160a01b0316156119285781600f5560405161157a606082612a0a565b6002815260208101604036823781517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169290156119145782825280517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169390600110156119005783604083015261271061161a670de0b6b3a7640000611614600a5489612b2e565b04612b16565b6040516370a0823160e01b815230600482015294919004602085602481895afa948515610e0a5788956118cc575b5060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016600482018190526024820189905293602090829060449082908d905af19081156118c1578991611883575b501561185457823b15610e4757604051635c11d79560e01b815260048101889052602481019190915260a06044820152925160a48401819052879493929160c4840191865b818110611832575050508491838381809430606483015242608483015203925af1908115610a2c57839161181d575b50506040516370a0823160e01b8152306004820152602081602481875afa908115610a2c5783916117e0575b509061175691612cf8565b918261179b575b507ffdb3006cb8eee4ff80ca9d86bfde362716e8f75802a29934394ae287b93d36256040848482519182526020820152a160ff196027541660275580f35b803b1561067457818091602460405180948193630852cd8d60e31b83528860048401525af18015610669571561175d57816117d591612a0a565b6108fe57825f61175d565b919250506020813d602011611815575b816117fd60209383612a0a565b81010312611811575184919061175661174b565b5f80fd5b3d91506117f0565b8161182791612a0a565b61067457815f61171f565b82516001600160a01b031684528a9750602093840193909201916001016116f0565b60405162461bcd60e51b8152602060048201526007602482015266617070726f766560c81b6044820152606490fd5b90506020813d6020116118b9575b8161189e60209383612a0a565b810103126118b5576118af90612a89565b5f6116ab565b8880fd5b3d9150611891565b6040513d8b823e3d90fd5b9094506020813d6020116118f8575b816118e860209383612a0a565b810103126118115751935f611648565b3d91506118db565b634e487b7160e01b86526032600452602486fd5b634e487b7160e01b85526032600452602485fd5b60405162461bcd60e51b815260206004820152600b60248201526a1b9bc81c1bdbdb081e595d60aa1b6044820152606490fd5b503461090257806003193601126109025760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346109025760203660031901126109025760043567ffffffffffffffff8111610674576119c89036906004016129d9565b60016027546119da60ff821615612c7f565b60ff19161760275582917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691835b818110611a2d57858580610c0b575060ff196027541660275580f35b611a38818385612d05565b356040516331a9108f60e11b8152816004820152602081602481895afa8015610e0a578890611b7c575b611a7791506001600160a01b03163314612d3d565b60405163133f757160e31b81526004810182905261012081602481895afa8015610e0a5788918991611b42575b50611b3857611ac8670de0b6b3a7640000916001600160801b03601b549116612b2e565b04908088526020805260408820548083115f14611b3057611ae99083612cf8565b915b81895260208052604089205581611b09575b50506001905b01611a11565b9060019296611b28928952602160205260408920610dca838254612cb7565b94905f611afd565b508791611aeb565b5050600190611b03565b9050611b6691506101203d8111611b75575b611b5e8183612a0a565b810190612a96565b5096505050505050905f611aa4565b503d611b54565b506020813d8211611bae575b81611b9560209383612a0a565b81010312610e4757611ba9611a7791612d29565b611a62565b3d9150611b88565b50346109025780600319360112610902576001602754611bd960ff821615612c7f565b60ff191617602755611bea336137f6565b3381526024602052670de0b6b3a7640000611c0c604083205460225490612b2e565b043382526025602052604082205560ff196027541660275580f35b50346109025780600319360112610902576020600a54604051908152f35b50346109025780600319360112610902576020604051620151808152f35b50346109025780600319360112610902576020601a54604051908152f35b5034610902578060031936011261090257611c9a613184565b80f35b503461090257806003193601126109025760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b5034610902576020366003190112610902576004356001602754611cff60ff821615612c7f565b60ff191617602755338252602460205280604083205410611e7157611d22613631565b611d2b336137f6565b338352602460205260408320611d42838254612cf8565b9055611d5082602354612cf8565b6023553383526024602052670de0b6b3a7640000611d75604085205460225490612b2e565b3380865260256020908152604080882094909304909355905163a9059cbb60e01b8152600481019190915260248101849052918290604490829087906001600160a01b03165af1908115610a2c578391611e37575b5015611e09576040519081527f44282e2a4bbb86b9f8089d1086f4e0df273054eab62cdbda18f647cfd22a1eff60203392a260ff196027541660275580f35b60405162461bcd60e51b81526020600482015260066024820152651b1c081bdd5d60d21b6044820152606490fd5b90506020813d602011611e69575b81611e5260209383612a0a565b810103126108fe57611e6390612a89565b5f611dca565b3d9150611e45565b60405162461bcd60e51b815260206004820152600360248201526218985b60ea1b6044820152606490fd5b50346109025760203660031901126109025760406020916004358152601e83522054604051908152f35b50346109025780600319360112610902576020600b54604051908152f35b50346109025780600319360112610902576020600c54604051908152f35b50346109025780600319360112610902576020600954604051908152f35b5034610902578060031936011261090257602060405160078152f35b503461090257806003193601126109025760206040516111948152f35b5034610902576020366003190112610902576004356001600160a01b03811690819003610674578160409160209352602483522054604051908152f35b5034611811575f366003190112611811576001602754611fb960ff821615612c7f565b60ff191617602755600b54610e1081018091116124145742106123e457600e54611fe4811515612cc4565b5f600e5542600b55611ff4613184565b670de0b6b3a7640000612009600a5483612b2e565b049081156123b3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b15611811576040516340c10f1960e01b8152306004820152602481018490525f8160448183875af180156123a857612393575b5060405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483018190526024830184905293917f0000000000000000000000000000000000000000000000000000000000000000909116906020816044818a865af1908115612319578791612359575b50156123245760405163095ea7b360e01b81526001600160a01b0385166004820152602481018690526020816044818a875af19081156123195787916122db575b50156122a9576101046060928761271061215189612b16565b049661271061215f88612b16565b04604051988996879562e8e33760e81b8752600487015260248601528a6044860152886064860152608485015260a48401523060c48401524260e48401525af1801561229e57849185938692612254575b5090827fde8bddcf06ffae09e386175c662c7c92a86de098e74fe7b096b32c841d12343495858481608098979611612235575b5050818111612216575b5050600a5491604051938452602084015260408301526060820152a160ff196027541660275580f35b61222b9161222391612cf8565b602654612cb7565b602655815f6121ed565b61224a9161224291612cf8565b600e54612cb7565b600e55845f6121e3565b92509250506060813d606011612296575b8161227260609383612a0a565b8101031261229257805160208201516040909201519192909190826121b0565b8380fd5b3d9150612265565b6040513d86823e3d90fd5b60405162461bcd60e51b815260206004820152600a60248201526930b8383937bb329031bb60b11b6044820152606490fd5b90506020813d602011612311575b816122f660209383612a0a565b8101031261230d5761230790612a89565b5f612138565b8680fd5b3d91506122e9565b6040513d89823e3d90fd5b60405162461bcd60e51b815260206004820152600d60248201526c185c1c1c9bdd99481c1b5a5b9d609a1b6044820152606490fd5b90506020813d60201161238b575b8161237460209383612a0a565b8101031261230d5761238590612a89565b5f6120f7565b3d9150612367565b6123a09194505f90612a0a565b5f925f612071565b6040513d5f823e3d90fd5b60405162461bcd60e51b81526020600482015260096024820152680637620706169723d360bc1b6044820152606490fd5b60405162461bcd60e51b81526020600482015260086024820152673a37b79039b7b7b760c11b6044820152606490fd5b634e487b7160e01b5f52601160045260245ffd5b61297f565b34611811575f3660031901126118115760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34611811575f3660031901126118115760206040516101718152f35b34611811575f366003190112611811576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34611811575f3660031901126118115760206040516103e88152f35b34611811576020366003190112611811576004356001600160a01b0381169081900361181157805f526024602052670de0b6b3a764000061252b60405f205460225490612b2e565b04905f52602560205260405f2054908181115f1461254f57602091610eee91612cf8565b505060205f610eee565b34611811575f366003190112611811576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34611811576020366003190112611811576040516377778db360e01b81526004803590820181905290610140816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156123a857670de0b6b3a76400009161261e915f916126425750601a5490612b2e565b04905f52601e60205260405f2054908181115f1461254f57602091610eee91612cf8565b61265b91506101403d81116108335761081b8183612a0a565b5050505050505050905084610d60565b6129a1565b34611811575f366003190112611811576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34611811575f3660031901126118115760206040516101f48152f35b34611811576020366003190112611811576004356001600160a01b03811690819003611811575f526025602052602060405f2054604051908152f35b34611811575f366003190112611811576010546040516001600160a01b039091168152602090f35b34611811575f36600319011261181157602060ff600d54821c166040519015158152f35b34611811576020366003190112611811576004355f526021602052602060405f2054604051908152f35b34611811575f366003190112611811576020602254604051908152f35b34611811575f366003190112611811576020600e54604051908152f35b34611811575f366003190112611811576020602654604051908152f35b34611811575f366003190112611811576020600f54604051908152f35b34611811575f3660031901126118115760206040516127108152f35b34611811575f366003190112611811576020602354604051908152f35b34611811575f366003190112611811576011546040516001600160a01b039091168152602090f35b34611811575f36600319011261181157602063ffffffff600d5416604051908152f35b34611811575f3660031901126118115760206040516107088152f35b346118115760203660031901126118115760043560078110156118115760209060130154604051908152f35b34611811575f366003190112611811576128da612f67565b005b34611811576020366003190112611811576020610eee600435612b5f565b34611811576020366003190112611811576004355f52601c602052602060405f2054604051908152f35b34611811575f36600319011261181157602060405169021e19e0c9bab24000008152f35b34611811575f366003190112611811576020600854604051908152f35b34611811575f36600319011261181157602090601b548152f35b34611811575f366003190112611811576020604051670de0b6b3a76400008152f35b34611811575f3660031901126118115760206040516107d08152f35b34611811575f3660031901126118115760206040516105dc8152f35b9181601f840112156118115782359167ffffffffffffffff8311611811576020808501948460051b01011161181157565b90601f8019910116810190811067ffffffffffffffff821117612a2c57604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160801b038216820361181157565b519067ffffffffffffffff8216820361181157565b519063ffffffff8216820361181157565b519061ffff8216820361181157565b5190811515820361181157565b908161012091031261181157612aab81612a40565b91612ab860208301612a40565b91612ac560408201612a54565b91612ad260608301612a54565b91612adf60808201612a69565b91612aec60a08301612a7a565b91612af960c08201612a7a565b91612b13610100612b0c60e08501612a89565b9301612a89565b90565b90612134820291808304612134149015171561241457565b8181029291811591840414171561241457565b8115612b4b570490565b634e487b7160e01b5f52601260045260245ffd5b60405163133f757160e31b815260048101829052610120816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156123a8575f915f91612bfe575b50612bf857612bd9670de0b6b3a7640000916001600160801b03601b549116612b2e565b04905f526020805260405f20548082115f14612bf857612b1391612cf8565b50505f90565b9050612c1991506101203d8111611b7557611b5e8183612a0a565b5096505050505050905f612bb5565b9190826101409103126118115781519160208101519160408201519160608101519160808201519160a08101519160c082015191612c6860e08201612a89565b91610120612c796101008401612a89565b92015190565b15612c8657565b60405162461bcd60e51b81526020600482015260096024820152681c99595b9d1c985b9d60ba1b6044820152606490fd5b9190820180921161241457565b15612ccb57565b60405162461bcd60e51b8152602060048201526005602482015264656d70747960d81b6044820152606490fd5b9190820391821161241457565b9190811015612d155760051b0190565b634e487b7160e01b5f52603260045260245ffd5b51906001600160a01b038216820361181157565b15612d4457565b60405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b6044820152606490fd5b15612d7c57565b60405162461bcd60e51b815260206004820152600660248201526518dd881bdd5d60d21b6044820152606490fd5b908161016091031261181157612dbf81612d29565b91612dcc60208301612a40565b91612dd960408201612a40565b91612de660608301612a54565b91612df360808201612a54565b91612e0060a08301612a69565b91612e0d60c08201612a7a565b91612e1a60e08301612a7a565b91612e286101008201612a89565b91612b13610140612e3c6101208501612a89565b9301612d29565b15612e4a57565b60405162461bcd60e51b81526020600482015260086024820152670616d6f756e743d360c41b6044820152606490fd5b60405163133f757160e31b815260048101829052610160816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156123a8575f905f925f91612f38575b50612f3157612ee09061394a565b5f8112612f31576007811015612d1557670de0b6b3a7640000916001600160801b03612f1192601301549116612b2e565b04905f52601c60205260405f20548082115f14612bf857612b1391612cf8565b5050505f90565b915050612f5491506101603d81116113e4576113c98183612a0a565b505097959650505050505090915f612ed2565b620151804204600854808214613180577f000000000000000000000000000000000000000000000000000000000000000042101561309a575b612faa9082612cf8565b7f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000810290808204670de0b6b3a7640000149015171561241457613017907f000000000000000000000000000000000000000000000000000000000000000090612b41565b600754670de0b6b3a7640000929091815b61304e575050670de0b6b3a76400009161304191612b2e565b046007555f600955600855565b600180831614613078575b61306c81670de0b6b3a764000092612b2e565b049060011c9081613028565b9261306c670de0b6b3a7640000613090868294612b2e565b0494915050613059565b6040516318160ddd60e01b8152906020826004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9182156123a8575f9261314c575b5061017182029180830461017114901517156124145761016d612710612faa93040480151580613141575b613120575b509050612fa0565b61312f61313891600754612b2e565b60095490612b41565b6007555f613118565b508060095411613113565b9091506020813d602011613178575b8161316860209383612a0a565b810103126118115751905f6130e8565b3d915061315b565b5050565b6010546001600160a01b0381169081156134bc575b50604051630240bc6b60e21b81526001600160a01b039190911690606081600481855afa9182156123a8575f925f925f91613463575b50604051630dfe168160e01b8152602081600481865afa9081156123a8575f91613424575b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169116149160049060209084156133c957604051635909c0d560e01b815292839182905afa9081156123a8575f91613397575b50905b81926001600160701b0363ffffffff4216961680151580613385575b80613375575b61331d575b505050509050600d5460ff8160201c16156133035750600d549063ffffffff80831684031661070881106132fd576132b990600c548303612b41565b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156124145760701c806132f4575b50600c5563ffffffff191617600d55565b600a555f6132e3565b50505050565b6401000000009291600c5564ffffffffff19161717600d55565b61334d92945063ffffffff9395825f1461336e576001600160701b038116925b1561335d5750905b60701b612b41565b918403160201805f80808061327d565b6001600160701b0391501690613345565b819261333d565b508663ffffffff84161415613278565b506001600160701b0386161515613272565b90506020813d6020116133c1575b816133b260209383612a0a565b8101031261181157515f613253565b3d91506133a5565b604051635a3d549360e01b815292839182905afa9081156123a8575f916133f2575b5090613256565b90506020813d60201161341c575b8161340d60209383612a0a565b8101031261181157515f6133eb565b3d9150613400565b90506020813d60201161345b575b8161343f60209383612a0a565b81010312611811576020613454600492612d29565b91506131f4565b3d9150613432565b93505090506060823d6060116134b4575b8161348160609383612a0a565b810103126118115761349282613f0c565b906134ab60406134a460208601613f0c565b9401612a69565b9192915f6131cf565b3d9150613474565b60405163c45a015560e01b815291506020826004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9182156123a8575f926135f5575b5060405163e6a4390560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152909260209184916044918391165afa9182156123a8575f926135b9575b506001600160a01b0382169081156135b4576001600160a01b031916176010555f613199565b505050565b9091506020813d6020116135ed575b816135d560209383612a0a565b81010312611811576135e690612d29565b905f61358e565b3d91506135c8565b9091506020813d602011613629575b8161361160209383612a0a565b810103126118115761362290612d29565b905f61350b565b3d9150613604565b6011546001600160a01b03811615613691575b506011546001600160a01b0316801561365a5790565b60405162461bcd60e51b815260206004820152600f60248201526e37379031bb17b83230b4903830b4b960891b6044820152606490fd5b60405163c45a015560e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156123a8575f916137bc575b5060405163e6a4390560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152909160209183916044918391165afa9081156123a8575f91613782575b506001600160a01b03166001600160a01b031991909116176011555f613644565b90506020813d6020116137b4575b8161379d60209383612a0a565b81010312611811576137ae90612d29565b5f613761565b3d9150613790565b90506020813d6020116137ee575b816137d760209383612a0a565b81010312611811576137e890612d29565b5f6136de565b3d91506137ca565b60018060a01b03811690815f52602460205260405f205490670de0b6b3a76400006138246022548094612b2e565b04835f52602560205260405f20548082115f146139415761384491612cf8565b905b816138515750505050565b83670de0b6b3a76400006138756020956138b7975f526024875260405f2054612b2e565b5f9283526025865260409283902091900490555163a9059cbb60e01b81526001600160a01b039091166004820152602481019190915291829081906044820190565b03815f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156123a8575f90613906575b6138fd9150612d75565b5f8080806132fd565b506020813d602011613939575b8161392060209383612a0a565b81010312611811576139346138fd91612a89565b6138f3565b3d9150613913565b50505f90613846565b5f5b60078110156139765780546001600160a01b038381169116146139715760010161394c565b905090565b50505f1990565b611194810281159082810461119414821715612414576007612710909104047f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165f5b600760ff821610613c57575050600781029080820460071490151715612414576107d083028381046107d01483171561241457604051636c5e3b8360e11b8152612710909104916020826004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9182156123a8575f92613c23575b50828215613c1157670de0b6b3a76400000290838204670de0b6b3a7640000148415171561241457613a90613a88613a98948694612b41565b601a54612cb7565b601a55612cb7565b604051636c5e3b8360e11b815291906020836004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9283156123a8575f93613bdd575b508215613bcc57670de0b6b3a7640000820292828404670de0b6b3a7640000148315171561241457613b1f613b2791613b2f95612b41565b601b54612cb7565b601b55612cb7565b906105dc8302908382046105dc141715612414576023546127109091049015613bb457670de0b6b3a7640000810291818304670de0b6b3a7640000148215171561241457613b8e613b86613b969460235490612b41565b602254612cb7565b602255612cb7565b90818111613ba2575050565b613baf9161222391612cf8565b602655565b613b9691613bc482602654612cb7565b602655612cb7565b613b2f9250613bc482602654612cb7565b9092506020813d602011613c09575b81613bf960209383612a0a565b810103126118115751915f613ae7565b3d9150613bec565b90613a989250613bc482602654612cb7565b9091506020813d602011613c4f575b81613c3f60209383612a0a565b810103126118115751905f613a4f565b3d9150613c32565b6007811015612d15578054604051636ec3ab6760e01b81526001600160a01b03909116600482015261026081602481865afa80156123a8575f90613d04575b60a0015190508015613cea57670de0b6b3a7640000840291848304670de0b6b3a7640000148515171561241457613cd160019260ff94612b41565b613ce082601301918254612cb7565b90555b01166139c8565b50600160ff91613cfc85602654612cb7565b602655613ce3565b506102603d8111613e28575b613d1a8183612a0a565b810190610260818303126118115760405191610180830183811067ffffffffffffffff821117612a2c57604052613d5082612a89565b8352613d5e60208301612a89565b602084015280605f8301121561181157604051610100810181811067ffffffffffffffff821117612a2c576040528061014084019283116118115760408401905b838210613e1857505091610240918493604060a09601525160608401526101608101516080840152610180810151848401526101a081015160c08401526101c081015160e08401526101e08101516101008401526102008101516101208401526102208101516101408401520151610160820152613c96565b8151815260209182019101613d9f565b503d613d10565b60405163099d7a2b60e11b81526001600160a01b03918216600482015290602090829060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa80156123a8575f90613ed1575b61ffff915016610320811015613ecb576102e4811015613ec55761029e811015613ebf576102441115613eba57602890565b605090565b50607890565b5060a090565b5060c890565b506020813d602011613f04575b81613eeb60209383612a0a565b8101031261181157613eff61ffff91612a7a565b613e88565b3d9150613ede565b51906001600160701b03821682036118115756fea26469706673582212204742a772dcad095a4870607075735df197e3b54b7b0ea7729d10be0250cd013764736f6c634300081a003300000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba000000000000000000000000ff640cbd35a618df1348d861b5e47f7eab05b4220000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000077ca0bf25b19ae23474e2249ba52d1ce03760c700000000000000000000000005dd357debb23305126604d2ebc13160b513bbaca00000000000000000000000087fa4f1403a01b82cbc8e1d147f3e945679373fb000000000000000000000000472d13c2833e3e5e759b48a61a75798de12cd53f000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d90000000000000000000000000000000000000000000000000000000001e1338000000000000000000000000000000000000000000000000000000000000f406500000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000001464cef9b8b587b5a000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27000000000000000000000000f6f8db0aba00007681f8faf16a0fda1c9b030b110000000000000000000000002fa878ab3f87cc1c9737fc071108f904c0b0c95d0000000000000000000000002b591e99afe9f32eaa6214f7b7629768c40eeb3900000000000000000000000057fde0a71132198bbec939b98976993d8d89d22500000000000000000000000095b303987a60c71504d99aa1b13b4da07b0790ab000000000000000000000000c10a4ed9b4042222d69ff0b374eddd47ed90fc1f

Deployed ByteCode

0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816303c85629146129655750806306a4c9831461294857806309dfd0e6146129245780630ed52473146124285780630eeb27c4146128fa578063141132b7146128dc57806318178358146128c2578063191a9f42146128965780631a65893b1461287a5780631abc0eda146128575780632112a3221461282f578063242c135d14612812578063249d39e9146127f65780632a9e9774146127d95780632d734380146127bc5780632e8300871461279f578063313408c91461266b57806331f4d720146127825780633f110e3d146127585780633f86079e1461273457806340ecfefb1461270c57806343c41d04146126d05780634601ed47146126b45780634707b74814612670578063504d2e9b1461266b57806350992a8b1461259d5780635474f0af14612559578063587f373f146124e35780635bcd7852146124c7578063604d7d2314612483578063613094ee14612467578063689e6f131461242d5780636a146024146124285780636b9f96ea14611f965780636da514ec14611f5957806370222cfa14611f3c57806370d079bd14611f205780637175af6214611f02578063767390ee14611ee457806377f8bb6d14610ef65780638d83f29d14611ec657806393686d4114611e9c578063959afa1514611cd85780639a67964814611c9d5780639bea590e14611c81578063a0988db414611c63578063a0dc275814611c45578063a42fefec14611c27578063a504f7e314611bb6578063a7b16e3514611996578063a9abc96e1461195b578063aa6df29914611516578063ac1e294b146114d9578063b4ce468d14611494578063b75d95c11461146a578063b8c1e7ba14610ef6578063c617f4ed14611425578063c8f10300146111cc578063c9323e3114611191578063c93d512e146110ed578063ca0dcf16146110cf578063cfdf66011461108a578063dae7292a14610efb578063df0b366714610ef6578063e174770314610ecf578063e59f345b14610e9a578063e794b39a14610e70578063ec41c6bc14610e53578063ed3ad9ac14610b73578063efedc66914610b2e578063f31bf66914610b11578063f40fbb3c14610ad4578063f887ea4014610a8f578063f899667a14610a66578063fedc6ccc146109055763ff7025d214610362575f80fd5b346109025760403660031901126109025760043560243567ffffffffffffffff81116108fe576103969036906004016129d9565b60016027546103a860ff821615612c7f565b60ff1916176027558215916103bd8315612e43565b6103c5612f67565b84918291907f00000000000000000000000077ca0bf25b19ae23474e2249ba52d1ce03760c706001600160a01b03169083905b8086106107685788888869021e19e0c9bab24000008810610730576103e882028281046103e81482171561071c576127109004906101f48302908382046101f414171561071c5761271090049061048160206104548484612cb7565b6040516323b872dd60e01b8152336004820152306024820152604481019190915291829081906064820190565b0381887f000000000000000000000000ff640cbd35a618df1348d861b5e47f7eab05b4226001600160a01b03165af19081156107115785916106d3575b50156106a3576104d081600e54612cb7565b600e556104df82600f54612cb7565b600f556104eb33613e2f565b91606461050d84670de0b6b3a764000061050760075489612b2e565b04612b2e565b0490811561067857857f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba6001600160a01b0316803b15610674576040516340c10f1960e01b8152306004820152602481018590529082908290604490829084905af1801561066957610650575b505061058882600954612cb7565b600955611b588202828104611b580361063c57906127106105d59204933388526012602052604088206105bc868254612cb7565b90556105d06105cb8686612cf8565b61397d565b612cb7565b916105e08183612cf8565b9160075493604051968752602087015260408601526060850152608084015260a083015260c08201527fa738e9069b8aa14d79b4dee9ff8094829c55d53112d9a1a93d74d14a0480b32360e03392a260ff196027541660275580f35b634e487b7160e01b87526011600452602487fd5b8161065a91612a0a565b61066557858761057a565b8580fd5b6040513d84823e3d90fd5b5080fd5b606460405162461bcd60e51b8152602060048201526004602482015263063763d360e41b6044820152fd5b60405162461bcd60e51b81526020600482015260086024820152673836b4b73a1034b760c11b6044820152606490fd5b90506020813d602011610709575b816106ee60209383612a0a565b81010312610705576106ff90612a89565b856104be565b8480fd5b3d91506106e1565b6040513d87823e3d90fd5b634e487b7160e01b84526011600452602484fd5b60405162461bcd60e51b815260206004820152601060248201526f6e6565642031306b207265736572766560801b6044820152606490fd5b90919293610777868387612d05565b35928311156108c557826040516331a9108f60e11b8152816004820152602081602481895afa9081156108ba578b9161087d575b50336001600160a01b039091160361084557604051906377778db360e01b8252600482015261014081602481885afa801561083a576001926107f4928c92610800575b50612cb7565b950194939291906103f8565b6108239192506101403d8111610833575b61081b8183612a0a565b810190612c28565b505050505050505050905f6107ee565b503d610811565b6040513d8c823e3d90fd5b60405162461bcd60e51b815260206004820152601060248201526f6e6f7420796f7572207265736572766560801b6044820152606490fd5b90506020813d82116108b2575b8161089760209383612a0a565b810103126108ae576108a890612d29565b5f6107ab565b8a80fd5b3d915061088a565b6040513d8d823e3d90fd5b60405162461bcd60e51b8152602060048201526011602482015270696473206e6f7420617363656e64696e6760781b6044820152606490fd5b8280fd5b80fd5b5034610902578060031936011261090257600160275461092860ff821615612c7f565b60ff191617602755338152601260205260408120548015610a3757338083526012602090815260408085208590555163a9059cbb60e01b815260048101929092526024820183905281604481866001600160a01b037f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba165af18015610a2c5783906109f1575b6109b89150612d75565b6040519081527ff14b08e987df188c7676e8601bb40336ef511abfb4e9e35913f5ed9c0db0467c60203392a260ff196027541660275580f35b506020813d602011610a24575b81610a0b60209383612a0a565b810103126108fe57610a1f6109b891612a89565b6109ae565b3d91506109fe565b6040513d85823e3d90fd5b60405162461bcd60e51b81526020600482015260076024820152666e6f7468696e6760c81b6044820152606490fd5b503461090257602036600319011261090257604060209160043581528280522054604051908152f35b50346109025780600319360112610902576040517f000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d96001600160a01b03168152602090f35b503461090257806003193601126109025760206040517f000000000000000000000000000000000000000000000000000000006c25285f42108152f35b50346109025780600319360112610902576020604051611b588152f35b50346109025780600319360112610902576040517f000000000000000000000000472d13c2833e3e5e759b48a61a75798de12cd53f6001600160a01b03168152602090f35b50346109025760203660031901126109025760043567ffffffffffffffff811161067457610ba59036906004016129d9565b6001602754610bb760ff821615612c7f565b60ff19161760275582917f00000000000000000000000077ca0bf25b19ae23474e2249ba52d1ce03760c706001600160a01b031691835b818110610cdc57858580610c0b575b5060ff196027541660275580f35b60405163a9059cbb60e01b815233600482015260248101829052602081604481866001600160a01b037f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba165af18015610a2c578390610ca1575b610c6f9150612d75565b6040519081527f2c3dab7c883557b1efe1614d25d4a2a2d2845836f063cce9a69f27bc757bdd1160203392a281610bfd565b506020813d602011610cd4575b81610cbb60209383612a0a565b810103126108fe57610ccf610c6f91612a89565b610c65565b3d9150610cae565b610ce7818385612d05565b356040516331a9108f60e11b8152816004820152602081602481895afa8015610e0a578890610e15575b610d2691506001600160a01b03163314612d3d565b6040516377778db360e01b81526004810182905261014081602481895afa908115610e0a57670de0b6b3a764000091610d6a918a91610de1575b50601a5490612b2e565b0490808852601e60205260408820548083115f14610dd957610d8c9083612cf8565b915b818952601e602052604089205581610dab575b5050600101610bee565b9060019296610dd1928952601f60205260408920610dca838254612cb7565b9055612cb7565b94905f610da1565b508791610d8e565b610dfa91506101403d81116108335761081b8183612a0a565b505050505050505090505f610d60565b6040513d8a823e3d90fd5b506020813d8211610e4b575b81610e2e60209383612a0a565b81010312610e4757610e42610d2691612d29565b610d11565b8780fd5b3d9150610e21565b50346109025780600319360112610902576020604051610e108152f35b50346109025760203660031901126109025760406020916004358152601f83522054604051908152f35b503461090257602036600319011261090257600435600781101561067457546040516001600160a01b03909116815260209150f35b5034610902576020366003190112610902576020610eee600435612e7a565b604051908152f35b6129bd565b5034610902576020366003190112610902576004356001602754610f2260ff821615612c7f565b60ff191617602755610f35811515612e43565b610f3d613631565b610f46336137f6565b6040516323b872dd60e01b815233600482015230602482015260448101839052906020908290606490829087906001600160a01b03165af1908115610a2c578391611050575b501561102357338252602460205260408220610fa9828254612cb7565b9055610fb781602354612cb7565b6023553382526024602052670de0b6b3a7640000610fdc604084205460225490612b2e565b04338352602560205260408320556040519081527fdae4417c25a93cfb86ce5fbbb8fc1630945b61afaeab4f29cf301b9a058ba91460203392a260ff196027541660275580f35b60405162461bcd60e51b815260206004820152600560248201526436381034b760d91b6044820152606490fd5b90506020813d602011611082575b8161106b60209383612a0a565b810103126108fe5761107c90612a89565b5f610f8c565b3d915061105e565b50346109025780600319360112610902576040517f0000000000000000000000005dd357debb23305126604d2ebc13160b513bbaca6001600160a01b03168152602090f35b50346109025780600319360112610902576020600754604051908152f35b5034610902578060031936011261090257600160275461111060ff821615612c7f565b60ff19161760275560265480156111665760207f74405529d531f035eac9d9aff6843cb2a1e612e6091d8ca9a6fd666c2975daa591836026556111528161397d565b604051908152a160ff196027541660275580f35b606460405162461bcd60e51b81526020600482015260046024820152636e6f6e6560e01b6044820152fd5b503461090257806003193601126109025760206040517f000000000000000000000000000000000000000000000001464cef9b8b587b5a8152f35b50346109025760203660031901126109025760043567ffffffffffffffff8111610674576111fe9036906004016129d9565b600160275461121060ff821615612c7f565b60ff19161760275582917f00000000000000000000000087fa4f1403a01b82cbc8e1d147f3e945679373fb6001600160a01b031691835b81811061126357858580610c0b575060ff196027541660275580f35b61126e818385612d05565b356040516331a9108f60e11b8152816004820152602081602481895afa8015610e0a5788906113eb575b6112ad91506001600160a01b03163314612d3d565b60405163133f757160e31b81526004810182905261016081602481895afa8015610e0a57889089928a916113ac575b506113a1576112ea9061394a565b8881126113a157600781101561138d57670de0b6b3a7640000916001600160801b0361131b92601301549116612b2e565b0490808852601c60205260408820548083115f146113855761133d9083612cf8565b915b818952601c60205260408920558161135e575b50506001905b01611247565b906001929661137d928952601d60205260408920610dca838254612cb7565b94905f611352565b50879161133f565b634e487b7160e01b89526032600452602489fd5b505050600190611358565b9150506113d191506101603d81116113e4575b6113c98183612a0a565b810190612daa565b505097959650505050505090915f6112dc565b503d6113bf565b506020813d821161141d575b8161140460209383612a0a565b81010312610e47576114186112ad91612d29565b611298565b3d91506113f7565b50346109025780600319360112610902576040517f00000000000000000000000077ca0bf25b19ae23474e2249ba52d1ce03760c706001600160a01b03168152602090f35b50346109025760203660031901126109025760406020916004358152601d83522054604051908152f35b50346109025780600319360112610902576040517f000000000000000000000000ff640cbd35a618df1348d861b5e47f7eab05b4226001600160a01b03168152602090f35b5034610902576020366003190112610902576004356001600160a01b03811690819003610674578160409160209352601283522054604051908152f35b5034610902578060031936011261090257600160275461153960ff821615612c7f565b60ff191617602755600f5461154f811515612cc4565b611557613184565b6010546001600160a01b0316156119285781600f5560405161157a606082612a0a565b6002815260208101604036823781517f000000000000000000000000ff640cbd35a618df1348d861b5e47f7eab05b4226001600160a01b03169290156119145782825280517f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba6001600160a01b03169390600110156119005783604083015261271061161a670de0b6b3a7640000611614600a5489612b2e565b04612b16565b6040516370a0823160e01b815230600482015294919004602085602481895afa948515610e0a5788956118cc575b5060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d916600482018190526024820189905293602090829060449082908d905af19081156118c1578991611883575b501561185457823b15610e4757604051635c11d79560e01b815260048101889052602481019190915260a06044820152925160a48401819052879493929160c4840191865b818110611832575050508491838381809430606483015242608483015203925af1908115610a2c57839161181d575b50506040516370a0823160e01b8152306004820152602081602481875afa908115610a2c5783916117e0575b509061175691612cf8565b918261179b575b507ffdb3006cb8eee4ff80ca9d86bfde362716e8f75802a29934394ae287b93d36256040848482519182526020820152a160ff196027541660275580f35b803b1561067457818091602460405180948193630852cd8d60e31b83528860048401525af18015610669571561175d57816117d591612a0a565b6108fe57825f61175d565b919250506020813d602011611815575b816117fd60209383612a0a565b81010312611811575184919061175661174b565b5f80fd5b3d91506117f0565b8161182791612a0a565b61067457815f61171f565b82516001600160a01b031684528a9750602093840193909201916001016116f0565b60405162461bcd60e51b8152602060048201526007602482015266617070726f766560c81b6044820152606490fd5b90506020813d6020116118b9575b8161189e60209383612a0a565b810103126118b5576118af90612a89565b5f6116ab565b8880fd5b3d9150611891565b6040513d8b823e3d90fd5b9094506020813d6020116118f8575b816118e860209383612a0a565b810103126118115751935f611648565b3d91506118db565b634e487b7160e01b86526032600452602486fd5b634e487b7160e01b85526032600452602485fd5b60405162461bcd60e51b815260206004820152600b60248201526a1b9bc81c1bdbdb081e595d60aa1b6044820152606490fd5b503461090257806003193601126109025760206040517f000000000000000000000000000000000000000000000000000000006c25285f8152f35b50346109025760203660031901126109025760043567ffffffffffffffff8111610674576119c89036906004016129d9565b60016027546119da60ff821615612c7f565b60ff19161760275582917f0000000000000000000000005dd357debb23305126604d2ebc13160b513bbaca6001600160a01b031691835b818110611a2d57858580610c0b575060ff196027541660275580f35b611a38818385612d05565b356040516331a9108f60e11b8152816004820152602081602481895afa8015610e0a578890611b7c575b611a7791506001600160a01b03163314612d3d565b60405163133f757160e31b81526004810182905261012081602481895afa8015610e0a5788918991611b42575b50611b3857611ac8670de0b6b3a7640000916001600160801b03601b549116612b2e565b04908088526020805260408820548083115f14611b3057611ae99083612cf8565b915b81895260208052604089205581611b09575b50506001905b01611a11565b9060019296611b28928952602160205260408920610dca838254612cb7565b94905f611afd565b508791611aeb565b5050600190611b03565b9050611b6691506101203d8111611b75575b611b5e8183612a0a565b810190612a96565b5096505050505050905f611aa4565b503d611b54565b506020813d8211611bae575b81611b9560209383612a0a565b81010312610e4757611ba9611a7791612d29565b611a62565b3d9150611b88565b50346109025780600319360112610902576001602754611bd960ff821615612c7f565b60ff191617602755611bea336137f6565b3381526024602052670de0b6b3a7640000611c0c604083205460225490612b2e565b043382526025602052604082205560ff196027541660275580f35b50346109025780600319360112610902576020600a54604051908152f35b50346109025780600319360112610902576020604051620151808152f35b50346109025780600319360112610902576020601a54604051908152f35b5034610902578060031936011261090257611c9a613184565b80f35b503461090257806003193601126109025760206040517f00000000000000000000000000000000000000000000000000000000000f40658152f35b5034610902576020366003190112610902576004356001602754611cff60ff821615612c7f565b60ff191617602755338252602460205280604083205410611e7157611d22613631565b611d2b336137f6565b338352602460205260408320611d42838254612cf8565b9055611d5082602354612cf8565b6023553383526024602052670de0b6b3a7640000611d75604085205460225490612b2e565b3380865260256020908152604080882094909304909355905163a9059cbb60e01b8152600481019190915260248101849052918290604490829087906001600160a01b03165af1908115610a2c578391611e37575b5015611e09576040519081527f44282e2a4bbb86b9f8089d1086f4e0df273054eab62cdbda18f647cfd22a1eff60203392a260ff196027541660275580f35b60405162461bcd60e51b81526020600482015260066024820152651b1c081bdd5d60d21b6044820152606490fd5b90506020813d602011611e69575b81611e5260209383612a0a565b810103126108fe57611e6390612a89565b5f611dca565b3d9150611e45565b60405162461bcd60e51b815260206004820152600360248201526218985b60ea1b6044820152606490fd5b50346109025760203660031901126109025760406020916004358152601e83522054604051908152f35b50346109025780600319360112610902576020600b54604051908152f35b50346109025780600319360112610902576020600c54604051908152f35b50346109025780600319360112610902576020600954604051908152f35b5034610902578060031936011261090257602060405160078152f35b503461090257806003193601126109025760206040516111948152f35b5034610902576020366003190112610902576004356001600160a01b03811690819003610674578160409160209352602483522054604051908152f35b5034611811575f366003190112611811576001602754611fb960ff821615612c7f565b60ff191617602755600b54610e1081018091116124145742106123e457600e54611fe4811515612cc4565b5f600e5542600b55611ff4613184565b670de0b6b3a7640000612009600a5483612b2e565b049081156123b3577f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba6001600160a01b031690813b15611811576040516340c10f1960e01b8152306004820152602481018490525f8160448183875af180156123a857612393575b5060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d98116600483018190526024830184905293917f000000000000000000000000ff640cbd35a618df1348d861b5e47f7eab05b422909116906020816044818a865af1908115612319578791612359575b50156123245760405163095ea7b360e01b81526001600160a01b0385166004820152602481018690526020816044818a875af19081156123195787916122db575b50156122a9576101046060928761271061215189612b16565b049661271061215f88612b16565b04604051988996879562e8e33760e81b8752600487015260248601528a6044860152886064860152608485015260a48401523060c48401524260e48401525af1801561229e57849185938692612254575b5090827fde8bddcf06ffae09e386175c662c7c92a86de098e74fe7b096b32c841d12343495858481608098979611612235575b5050818111612216575b5050600a5491604051938452602084015260408301526060820152a160ff196027541660275580f35b61222b9161222391612cf8565b602654612cb7565b602655815f6121ed565b61224a9161224291612cf8565b600e54612cb7565b600e55845f6121e3565b92509250506060813d606011612296575b8161227260609383612a0a565b8101031261229257805160208201516040909201519192909190826121b0565b8380fd5b3d9150612265565b6040513d86823e3d90fd5b60405162461bcd60e51b815260206004820152600a60248201526930b8383937bb329031bb60b11b6044820152606490fd5b90506020813d602011612311575b816122f660209383612a0a565b8101031261230d5761230790612a89565b5f612138565b8680fd5b3d91506122e9565b6040513d89823e3d90fd5b60405162461bcd60e51b815260206004820152600d60248201526c185c1c1c9bdd99481c1b5a5b9d609a1b6044820152606490fd5b90506020813d60201161238b575b8161237460209383612a0a565b8101031261230d5761238590612a89565b5f6120f7565b3d9150612367565b6123a09194505f90612a0a565b5f925f612071565b6040513d5f823e3d90fd5b60405162461bcd60e51b81526020600482015260096024820152680637620706169723d360bc1b6044820152606490fd5b60405162461bcd60e51b81526020600482015260086024820152673a37b79039b7b7b760c11b6044820152606490fd5b634e487b7160e01b5f52601160045260245ffd5b61297f565b34611811575f3660031901126118115760206040517f00000000000000000000000000000000000000000000000000000000000f42408152f35b34611811575f3660031901126118115760206040516101718152f35b34611811575f366003190112611811576040517f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f6001600160a01b03168152602090f35b34611811575f3660031901126118115760206040516103e88152f35b34611811576020366003190112611811576004356001600160a01b0381169081900361181157805f526024602052670de0b6b3a764000061252b60405f205460225490612b2e565b04905f52602560205260405f2054908181115f1461254f57602091610eee91612cf8565b505060205f610eee565b34611811575f366003190112611811576040517f00000000000000000000000087fa4f1403a01b82cbc8e1d147f3e945679373fb6001600160a01b03168152602090f35b34611811576020366003190112611811576040516377778db360e01b81526004803590820181905290610140816024817f00000000000000000000000077ca0bf25b19ae23474e2249ba52d1ce03760c706001600160a01b03165afa9081156123a857670de0b6b3a76400009161261e915f916126425750601a5490612b2e565b04905f52601e60205260405f2054908181115f1461254f57602091610eee91612cf8565b61265b91506101403d81116108335761081b8183612a0a565b5050505050505050905084610d60565b6129a1565b34611811575f366003190112611811576040517f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba6001600160a01b03168152602090f35b34611811575f3660031901126118115760206040516101f48152f35b34611811576020366003190112611811576004356001600160a01b03811690819003611811575f526025602052602060405f2054604051908152f35b34611811575f366003190112611811576010546040516001600160a01b039091168152602090f35b34611811575f36600319011261181157602060ff600d54821c166040519015158152f35b34611811576020366003190112611811576004355f526021602052602060405f2054604051908152f35b34611811575f366003190112611811576020602254604051908152f35b34611811575f366003190112611811576020600e54604051908152f35b34611811575f366003190112611811576020602654604051908152f35b34611811575f366003190112611811576020600f54604051908152f35b34611811575f3660031901126118115760206040516127108152f35b34611811575f366003190112611811576020602354604051908152f35b34611811575f366003190112611811576011546040516001600160a01b039091168152602090f35b34611811575f36600319011261181157602063ffffffff600d5416604051908152f35b34611811575f3660031901126118115760206040516107088152f35b346118115760203660031901126118115760043560078110156118115760209060130154604051908152f35b34611811575f366003190112611811576128da612f67565b005b34611811576020366003190112611811576020610eee600435612b5f565b34611811576020366003190112611811576004355f52601c602052602060405f2054604051908152f35b34611811575f36600319011261181157602060405169021e19e0c9bab24000008152f35b34611811575f366003190112611811576020600854604051908152f35b34611811575f36600319011261181157602090601b548152f35b34611811575f366003190112611811576020604051670de0b6b3a76400008152f35b34611811575f3660031901126118115760206040516107d08152f35b34611811575f3660031901126118115760206040516105dc8152f35b9181601f840112156118115782359167ffffffffffffffff8311611811576020808501948460051b01011161181157565b90601f8019910116810190811067ffffffffffffffff821117612a2c57604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160801b038216820361181157565b519067ffffffffffffffff8216820361181157565b519063ffffffff8216820361181157565b519061ffff8216820361181157565b5190811515820361181157565b908161012091031261181157612aab81612a40565b91612ab860208301612a40565b91612ac560408201612a54565b91612ad260608301612a54565b91612adf60808201612a69565b91612aec60a08301612a7a565b91612af960c08201612a7a565b91612b13610100612b0c60e08501612a89565b9301612a89565b90565b90612134820291808304612134149015171561241457565b8181029291811591840414171561241457565b8115612b4b570490565b634e487b7160e01b5f52601260045260245ffd5b60405163133f757160e31b815260048101829052610120816024817f0000000000000000000000005dd357debb23305126604d2ebc13160b513bbaca6001600160a01b03165afa80156123a8575f915f91612bfe575b50612bf857612bd9670de0b6b3a7640000916001600160801b03601b549116612b2e565b04905f526020805260405f20548082115f14612bf857612b1391612cf8565b50505f90565b9050612c1991506101203d8111611b7557611b5e8183612a0a565b5096505050505050905f612bb5565b9190826101409103126118115781519160208101519160408201519160608101519160808201519160a08101519160c082015191612c6860e08201612a89565b91610120612c796101008401612a89565b92015190565b15612c8657565b60405162461bcd60e51b81526020600482015260096024820152681c99595b9d1c985b9d60ba1b6044820152606490fd5b9190820180921161241457565b15612ccb57565b60405162461bcd60e51b8152602060048201526005602482015264656d70747960d81b6044820152606490fd5b9190820391821161241457565b9190811015612d155760051b0190565b634e487b7160e01b5f52603260045260245ffd5b51906001600160a01b038216820361181157565b15612d4457565b60405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b6044820152606490fd5b15612d7c57565b60405162461bcd60e51b815260206004820152600660248201526518dd881bdd5d60d21b6044820152606490fd5b908161016091031261181157612dbf81612d29565b91612dcc60208301612a40565b91612dd960408201612a40565b91612de660608301612a54565b91612df360808201612a54565b91612e0060a08301612a69565b91612e0d60c08201612a7a565b91612e1a60e08301612a7a565b91612e286101008201612a89565b91612b13610140612e3c6101208501612a89565b9301612d29565b15612e4a57565b60405162461bcd60e51b81526020600482015260086024820152670616d6f756e743d360c41b6044820152606490fd5b60405163133f757160e31b815260048101829052610160816024817f00000000000000000000000087fa4f1403a01b82cbc8e1d147f3e945679373fb6001600160a01b03165afa80156123a8575f905f925f91612f38575b50612f3157612ee09061394a565b5f8112612f31576007811015612d1557670de0b6b3a7640000916001600160801b03612f1192601301549116612b2e565b04905f52601c60205260405f20548082115f14612bf857612b1391612cf8565b5050505f90565b915050612f5491506101603d81116113e4576113c98183612a0a565b505097959650505050505090915f612ed2565b620151804204600854808214613180577f000000000000000000000000000000000000000000000000000000006c25285f42101561309a575b612faa9082612cf8565b7f00000000000000000000000000000000000000000000000000000000000f4065670de0b6b3a7640000810290808204670de0b6b3a7640000149015171561241457613017907f00000000000000000000000000000000000000000000000000000000000f424090612b41565b600754670de0b6b3a7640000929091815b61304e575050670de0b6b3a76400009161304191612b2e565b046007555f600955600855565b600180831614613078575b61306c81670de0b6b3a764000092612b2e565b049060011c9081613028565b9261306c670de0b6b3a7640000613090868294612b2e565b0494915050613059565b6040516318160ddd60e01b8152906020826004817f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba6001600160a01b03165afa9182156123a8575f9261314c575b5061017182029180830461017114901517156124145761016d612710612faa93040480151580613141575b613120575b509050612fa0565b61312f61313891600754612b2e565b60095490612b41565b6007555f613118565b508060095411613113565b9091506020813d602011613178575b8161316860209383612a0a565b810103126118115751905f6130e8565b3d915061315b565b5050565b6010546001600160a01b0381169081156134bc575b50604051630240bc6b60e21b81526001600160a01b039190911690606081600481855afa9182156123a8575f925f925f91613463575b50604051630dfe168160e01b8152602081600481865afa9081156123a8575f91613424575b507f000000000000000000000000ff640cbd35a618df1348d861b5e47f7eab05b4226001600160a01b039081169116149160049060209084156133c957604051635909c0d560e01b815292839182905afa9081156123a8575f91613397575b50905b81926001600160701b0363ffffffff4216961680151580613385575b80613375575b61331d575b505050509050600d5460ff8160201c16156133035750600d549063ffffffff80831684031661070881106132fd576132b990600c548303612b41565b670de0b6b3a7640000810290808204670de0b6b3a764000014901517156124145760701c806132f4575b50600c5563ffffffff191617600d55565b600a555f6132e3565b50505050565b6401000000009291600c5564ffffffffff19161717600d55565b61334d92945063ffffffff9395825f1461336e576001600160701b038116925b1561335d5750905b60701b612b41565b918403160201805f80808061327d565b6001600160701b0391501690613345565b819261333d565b508663ffffffff84161415613278565b506001600160701b0386161515613272565b90506020813d6020116133c1575b816133b260209383612a0a565b8101031261181157515f613253565b3d91506133a5565b604051635a3d549360e01b815292839182905afa9081156123a8575f916133f2575b5090613256565b90506020813d60201161341c575b8161340d60209383612a0a565b8101031261181157515f6133eb565b3d9150613400565b90506020813d60201161345b575b8161343f60209383612a0a565b81010312611811576020613454600492612d29565b91506131f4565b3d9150613432565b93505090506060823d6060116134b4575b8161348160609383612a0a565b810103126118115761349282613f0c565b906134ab60406134a460208601613f0c565b9401612a69565b9192915f6131cf565b3d9150613474565b60405163c45a015560e01b815291506020826004817f000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d96001600160a01b03165afa9182156123a8575f926135f5575b5060405163e6a4390560e01b81526001600160a01b037f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba811660048301527f000000000000000000000000ff640cbd35a618df1348d861b5e47f7eab05b42281166024830152909260209184916044918391165afa9182156123a8575f926135b9575b506001600160a01b0382169081156135b4576001600160a01b031916176010555f613199565b505050565b9091506020813d6020116135ed575b816135d560209383612a0a565b81010312611811576135e690612d29565b905f61358e565b3d91506135c8565b9091506020813d602011613629575b8161361160209383612a0a565b810103126118115761362290612d29565b905f61350b565b3d9150613604565b6011546001600160a01b03811615613691575b506011546001600160a01b0316801561365a5790565b60405162461bcd60e51b815260206004820152600f60248201526e37379031bb17b83230b4903830b4b960891b6044820152606490fd5b60405163c45a015560e01b81526020816004817f000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d96001600160a01b03165afa9081156123a8575f916137bc575b5060405163e6a4390560e01b81526001600160a01b037f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba811660048301527f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f81166024830152909160209183916044918391165afa9081156123a8575f91613782575b506001600160a01b03166001600160a01b031991909116176011555f613644565b90506020813d6020116137b4575b8161379d60209383612a0a565b81010312611811576137ae90612d29565b5f613761565b3d9150613790565b90506020813d6020116137ee575b816137d760209383612a0a565b81010312611811576137e890612d29565b5f6136de565b3d91506137ca565b60018060a01b03811690815f52602460205260405f205490670de0b6b3a76400006138246022548094612b2e565b04835f52602560205260405f20548082115f146139415761384491612cf8565b905b816138515750505050565b83670de0b6b3a76400006138756020956138b7975f526024875260405f2054612b2e565b5f9283526025865260409283902091900490555163a9059cbb60e01b81526001600160a01b039091166004820152602481019190915291829081906044820190565b03815f7f00000000000000000000000083c8b596b0825326707f5bc88e2bd2a052d3ffba6001600160a01b03165af180156123a8575f90613906575b6138fd9150612d75565b5f8080806132fd565b506020813d602011613939575b8161392060209383612a0a565b81010312611811576139346138fd91612a89565b6138f3565b3d9150613913565b50505f90613846565b5f5b60078110156139765780546001600160a01b038381169116146139715760010161394c565b905090565b50505f1990565b611194810281159082810461119414821715612414576007612710909104047f00000000000000000000000087fa4f1403a01b82cbc8e1d147f3e945679373fb6001600160a01b03165f5b600760ff821610613c57575050600781029080820460071490151715612414576107d083028381046107d01483171561241457604051636c5e3b8360e11b8152612710909104916020826004817f00000000000000000000000077ca0bf25b19ae23474e2249ba52d1ce03760c706001600160a01b03165afa9182156123a8575f92613c23575b50828215613c1157670de0b6b3a76400000290838204670de0b6b3a7640000148415171561241457613a90613a88613a98948694612b41565b601a54612cb7565b601a55612cb7565b604051636c5e3b8360e11b815291906020836004817f0000000000000000000000005dd357debb23305126604d2ebc13160b513bbaca6001600160a01b03165afa9283156123a8575f93613bdd575b508215613bcc57670de0b6b3a7640000820292828404670de0b6b3a7640000148315171561241457613b1f613b2791613b2f95612b41565b601b54612cb7565b601b55612cb7565b906105dc8302908382046105dc141715612414576023546127109091049015613bb457670de0b6b3a7640000810291818304670de0b6b3a7640000148215171561241457613b8e613b86613b969460235490612b41565b602254612cb7565b602255612cb7565b90818111613ba2575050565b613baf9161222391612cf8565b602655565b613b9691613bc482602654612cb7565b602655612cb7565b613b2f9250613bc482602654612cb7565b9092506020813d602011613c09575b81613bf960209383612a0a565b810103126118115751915f613ae7565b3d9150613bec565b90613a989250613bc482602654612cb7565b9091506020813d602011613c4f575b81613c3f60209383612a0a565b810103126118115751905f613a4f565b3d9150613c32565b6007811015612d15578054604051636ec3ab6760e01b81526001600160a01b03909116600482015261026081602481865afa80156123a8575f90613d04575b60a0015190508015613cea57670de0b6b3a7640000840291848304670de0b6b3a7640000148515171561241457613cd160019260ff94612b41565b613ce082601301918254612cb7565b90555b01166139c8565b50600160ff91613cfc85602654612cb7565b602655613ce3565b506102603d8111613e28575b613d1a8183612a0a565b810190610260818303126118115760405191610180830183811067ffffffffffffffff821117612a2c57604052613d5082612a89565b8352613d5e60208301612a89565b602084015280605f8301121561181157604051610100810181811067ffffffffffffffff821117612a2c576040528061014084019283116118115760408401905b838210613e1857505091610240918493604060a09601525160608401526101608101516080840152610180810151848401526101a081015160c08401526101c081015160e08401526101e08101516101008401526102008101516101208401526102208101516101408401520151610160820152613c96565b8151815260209182019101613d9f565b503d613d10565b60405163099d7a2b60e11b81526001600160a01b03918216600482015290602090829060249082907f000000000000000000000000472d13c2833e3e5e759b48a61a75798de12cd53f165afa80156123a8575f90613ed1575b61ffff915016610320811015613ecb576102e4811015613ec55761029e811015613ebf576102441115613eba57602890565b605090565b50607890565b5060a090565b5060c890565b506020813d602011613f04575b81613eeb60209383612a0a565b8101031261181157613eff61ffff91612a7a565b613e88565b3d9150613ede565b51906001600160701b03821682036118115756fea26469706673582212204742a772dcad095a4870607075735df197e3b54b7b0ea7729d10be0250cd013764736f6c634300081a0033