ETH Price: $3,871.38 (-1.22%)
Gas: 0.1 GWei

Contract

0x45A01E4e04F14f7A4a6702c74187c5F6222033cd
Transaction Hash
Method
Block
From
To
Add Liquidity12994462023-12-20 21:07:57351 days ago1703106477IN
Stargate Finance: Fee Library V07
0 ETH0.000094644.3
Transfer Ownersh...8890782023-11-18 0:40:47384 days ago1700268047IN
Stargate Finance: Fee Library V07
0 ETH0.000076032.6395976
White List2004912023-08-15 5:45:38479 days ago1692078338IN
Stargate Finance: Fee Library V07
0 ETH0.00005971.28259879
Set Trusted Remo...2004502023-08-15 5:37:26479 days ago1692077846IN
Stargate Finance: Fee Library V07
0 ETH0.000146211.55298113
Set Trusted Remo...2004492023-08-15 5:37:14479 days ago1692077834IN
Stargate Finance: Fee Library V07
0 ETH0.000146261.5535927
Set Trusted Remo...2004482023-08-15 5:37:02479 days ago1692077822IN
Stargate Finance: Fee Library V07
0 ETH0.000147251.56409452
Set Trusted Remo...2004472023-08-15 5:36:50479 days ago1692077810IN
Stargate Finance: Fee Library V07
0 ETH0.00014981.5911615
Set Trusted Remo...2004462023-08-15 5:36:38479 days ago1692077798IN
Stargate Finance: Fee Library V07
0 ETH0.00014981.5911615
Set Trusted Remo...2004452023-08-15 5:36:26479 days ago1692077786IN
Stargate Finance: Fee Library V07
0 ETH0.000150751.60119218
Set Trusted Remo...2004442023-08-15 5:36:14479 days ago1692077774IN
Stargate Finance: Fee Library V07
0 ETH0.000150871.60254436
Set Trusted Remo...2004432023-08-15 5:36:02479 days ago1692077762IN
Stargate Finance: Fee Library V07
0 ETH0.000154431.64037268
Set Trusted Remo...2004422023-08-15 5:35:50479 days ago1692077750IN
Stargate Finance: Fee Library V07
0 ETH0.000154431.64037268
Set Trusted Remo...2004412023-08-15 5:35:38479 days ago1692077738IN
Stargate Finance: Fee Library V07
0 ETH0.000154411.64037268
Set Trusted Remo...2004402023-08-15 5:35:26479 days ago1692077726IN
Stargate Finance: Fee Library V07
0 ETH0.000154541.64151162

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129681542024-12-06 10:46:1412 mins ago1733481974
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
129680332024-12-06 10:41:5817 mins ago1733481718
Stargate Finance: Fee Library V07
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StargateFeeLibraryV07

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, BSL 1.1 license
File 1 of 16 : StargateFeeLibraryV07.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.7.6;
pragma abicoder v2;

import "../interfaces/IStargateFeeLibrary.sol";
import "../Pool.sol";
import "../Factory.sol";
import "../interfaces/IStargateLPStaking.sol";
import "../chainlink/interfaces/AggregatorV3Interface.sol";
import "../lzApp/LzApp.sol";

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

///@notice Stargate fee library maintains the fees it costs to go from one pool to another across chains
/// The price feeds are eagerly updated by off-chain actors who watch the shouldCallUpdateTokenPrices() and call updateTokenPrices() if required
contract StargateFeeLibraryV07 is LzApp, IStargateFeeLibrary {
    using SafeMath for uint256;

    //---------------------------------------------------------------------------
    // VARIABLES

    // equilibrium func params. all in BPs * 10 ^ 2, i.e. 1 % = 10 ^ 6 units
    uint256 public constant DENOMINATOR = 1e18;
    uint256 public constant DELTA_1 = 6000 * 1e14;
    uint256 public constant DELTA_2 = 500 * 1e14;
    uint256 public constant LAMBDA_1 = 40 * 1e14;
    uint256 public constant LAMBDA_2 = 9960 * 1e14;

    // fee/reward bps
    uint256 public constant LP_FEE = 1 * 1e14;
    uint256 public constant PROTOCOL_FEE = 9 * 1e14;
    uint256 public constant PROTOCOL_FEE_FOR_SAME_TOKEN = 5 * 1e14;
    uint256 public constant EQ_REWARD_THRESHOLD = 6 * 1e14;
    uint256 public constant PROTOCOL_SUBSIDY = 3 * 1e13;

    // price and state thresholds, may be configurable in the future
    uint8 public constant PRICE_SHARED_DECIMALS = 8; // for price normalization
    uint256 public constant ONE_BPS_PRICE_CHANGE_THRESHOLD = 1 * 1e14;
    uint256 public constant PRICE_DRIFT_THRESHOLD = 10 * 1e14; // 10 bps
    uint256 public constant PRICE_DEPEG_THRESHOLD = 150 * 1e14; // 150 bps

    mapping(address => bool) public whitelist;
    mapping(uint256 => uint256) public poolIdToLpId; // poolId -> index of the pool in the lpStaking contract

    Factory public immutable factory;

    mapping(uint256 => address) public poolIdToPriceFeed; // poolId -> priceFeed
    // poolId1 -> poolId2 -> remoteChainIds, poolId1 < poolId2
    mapping(uint256 => mapping(uint256 => uint16[])) internal poolPairToRemoteChainIds;
    mapping(uint256 => uint256) public poolIdToPriceSD; // poolId -> price in shared decimals
    mapping(uint16 => bytes) public defaultAdapterParams; // for price sync, chainId -> params
    mapping(uint256 => address) public stargatePoolIdToLPStaking;

    enum PriceDeviationState {
        Normal,
        Drift,
        Depeg
    }

    event PriceUpdated(uint256 indexed poolId, uint256 priceSD);

    modifier notSamePool(uint256 _poolId1, uint256 _poolId2) {
        require(_poolId1 != _poolId2, "FeeLibrary: _poolId1 == _poolId2");
        _;
    }

    constructor(
        address _factory,
        address _endpoint
    ) LzApp(_endpoint) {
        require(_factory != address(0x0), "FeeLibrary: Factory cannot be 0x0");
        require(_endpoint != address(0x0), "FeeLibrary: Endpoint cannot be 0x0");

        factory = Factory(_factory);
    }

    // --------------------- ONLY OWNER ---------------------
    function whiteList(address _from, bool _whiteListed) external onlyOwner {
        whitelist[_from] = _whiteListed;
    }

    function setPoolToLpId(uint256 _poolId, uint256 _lpId) external onlyOwner {
        poolIdToLpId[_poolId] = _lpId;
    }

    // for those chains where to get the price from oracle and sync to other chains
    function setTokenPriceFeed(uint256 _poolId, address _priceFeedAddress) external onlyOwner {
        poolIdToPriceFeed[_poolId] = _priceFeedAddress;
    }

    function setStargatePoolIdToLPStakingAddress(uint256 _poolId, address _lpStaking) external onlyOwner {
        stargatePoolIdToLPStaking[_poolId] = _lpStaking;
    }

    function initTokenPrice(uint256 _poolId, uint256 _priceSD) external onlyOwner {
        poolIdToPriceSD[_poolId] = _priceSD;
        emit PriceUpdated(_poolId, _priceSD);
    }

    function setRemoteChains(
        uint256 _poolId1,
        uint256 _poolId2,
        uint16[] calldata _remoteChainIds
    ) external onlyOwner notSamePool(_poolId1, _poolId2) {
        if (_poolId1 < _poolId2) {
            poolPairToRemoteChainIds[_poolId1][_poolId2] = _remoteChainIds;
        } else {
            poolPairToRemoteChainIds[_poolId2][_poolId1] = _remoteChainIds;
        }
    }

    function setDefaultAdapterParams(uint16 _remoteChainId, bytes calldata _adapterParams) external onlyOwner {
        defaultAdapterParams[_remoteChainId] = _adapterParams;
    }

    // Override the renounce ownership inherited by zeppelin ownable
    function renounceOwnership() public override onlyOwner {}

    // --------------------- PUBLIC FUNCTIONS ---------------------
    ///@notice update the stored token price pair for the associated pool pair
    ///@dev anyone can update and sync price at any time even though the price is not changed
    ///@param _poolId1 one pool id of the pool pair
    ///@param _poolId2 the other pool id of the pool pair
    function updateTokenPrices(uint256 _poolId1, uint256 _poolId2) external payable notSamePool(_poolId1, _poolId2) {
        // get new prices from price feed
        uint256 newPrice1 = _getLatestPriceSDFromPriceFeed(_poolId1);
        uint256 newPrice2 = _getLatestPriceSDFromPriceFeed(_poolId2);

        // store the new prices
        poolIdToPriceSD[_poolId1] = newPrice1;
        poolIdToPriceSD[_poolId2] = newPrice2;
        emit PriceUpdated(_poolId1, newPrice1);
        emit PriceUpdated(_poolId2, newPrice2);

        // sync the prices to remote pools
        uint16[] memory remoteChainIds = getRemoteChains(_poolId1, _poolId2);
        require(remoteChainIds.length > 0, "FeeLibrary: invalid pool pair");

        bytes memory payload = abi.encode(_poolId1, newPrice1, _poolId2, newPrice2);
        for (uint256 i = 0; i < remoteChainIds.length; i++) {
            uint16 remoteChainId = remoteChainIds[i];
            address refundAddress = i == remoteChainIds.length - 1? msg.sender : address(this); // refund to msg.sender only for the last call
            _lzSend(remoteChainId, payload, payable(refundAddress), address(0), defaultAdapterParams[remoteChainId], address(this).balance);
        }
    }

    // --------------------- VIEW FUNCTIONS ---------------------
    ///@notice get the fees for a swap. typically called from the router via the pool
    function getFees(
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        uint16 _dstChainId,
        address _from,
        uint256 _amountSD
    ) external view override returns (Pool.SwapObj memory s) {
        // calculate the equilibrium reward
        bool whitelisted = whitelist[_from];
        s.eqReward = getEqReward(_srcPoolId, _amountSD, whitelisted); // protocol fee is 0 if whitelisted

        // calculate the equilibrium fee
        bool hasEqReward = s.eqReward > 0;
        uint256 protocolSubsidy;
        (s.eqFee, protocolSubsidy) = getEquilibriumFee(_srcPoolId, _dstPoolId, _dstChainId, _amountSD, whitelisted, hasEqReward);

        // calculate protocol and lp fee
        (s.protocolFee, s.lpFee) = getProtocolAndLpFee(_srcPoolId, _dstPoolId, _dstChainId, _amountSD, protocolSubsidy, whitelisted);

        // cap the reward at the sum of protocol fee and lp fee by increasing the protocol fee
        if (!whitelisted) {
            uint256 rewardCap = s.protocolFee.add(s.lpFee);
            if (s.eqReward > rewardCap) {
                uint256 diff = s.eqReward.sub(rewardCap);
                s.protocolFee = s.protocolFee.add(diff);
            }
        }

        // calculate drift fee
        uint256 driftFee = getDriftFee(_srcPoolId, _dstPoolId, _amountSD, whitelisted);
        s.protocolFee = s.protocolFee.add(driftFee);

        if (_amountSD < s.lpFee.add(s.eqFee).add(s.protocolFee)) {
            s.protocolFee = _amountSD.sub(s.lpFee).sub(s.eqFee);
        }

        return s;
    }

    ///@notice quote fee for price update and sync to remote chains
    ///@dev call this for value to attach to call to update token prices
    function quoteFeeForPriceUpdate(uint256 _poolId1, uint256 _poolId2) external view notSamePool(_poolId1, _poolId2) returns (uint256) {
        uint256 total = 0;
        uint16[] memory remoteChainIds = getRemoteChains(_poolId1, _poolId2);
        require(remoteChainIds.length > 0, "FeeLibrary: invalid pool pair");
        bytes memory payload = abi.encode(_poolId1, uint256(0), _poolId2, uint256(0)); // mock the payload
        for (uint256 i = 0; i < remoteChainIds.length; i++) {
            uint16 remoteChainId = remoteChainIds[i];
            (uint256 fee, ) = lzEndpoint.estimateFees(remoteChainId, address(this), payload, false, defaultAdapterParams[remoteChainId]);
            total = total.add(fee);
        }
        return total;
    }

    ///@notice function to check if update token prices should be called
    ///@dev typically called by an off-chain watcher and if returns true updateTokenPrices is called
    ///@param _poolId1 one pool id of the pool pair
    ///@param _poolId2 the other pool id of the pool pair
    ///@return bool true if updateTokenPrice should be called, false otherwise
    function shouldCallUpdateTokenPrices(uint256 _poolId1, uint256 _poolId2) external view notSamePool(_poolId1, _poolId2) returns (bool) {
        // current price and state
        uint256 currentPriceSD1 = poolIdToPriceSD[_poolId1];
        uint256 currentPriceSD2 = poolIdToPriceSD[_poolId2];
        (PriceDeviationState currentState, uint256 currentDiff, bool currentLt) = _getPriceDiffAndDeviationState(currentPriceSD1, currentPriceSD2);

        // new price and state
        uint256 newPriceSD1 = _getLatestPriceSDFromPriceFeed(_poolId1);
        uint256 newPriceSD2 = _getLatestPriceSDFromPriceFeed(_poolId2);
        (PriceDeviationState newState, uint256 newDiff, bool newLt) = _getPriceDiffAndDeviationState(newPriceSD1, newPriceSD2);

        // if state has changed then price update is required
        if (currentState != newState) {
            return true;
        }

        // 1. if state keeps normal, then no need to update
        // 2. if state is drift or depeg, but the token with higher price has changed, then update is required
        // 3. if state is depeg and the token with higher price has not changed, then no need to update
        if (newState == PriceDeviationState.Normal) {
            return false;
        } else if (currentLt != newLt) {
            return true;
        } else if (newState == PriceDeviationState.Depeg) {
            return false;
        }

        // if state is drift and the difference is not less than 1bps, then update is required
        uint256 diffDelta = newDiff > currentDiff ? newDiff.sub(currentDiff) : currentDiff.sub(newDiff);
        return diffDelta >= ONE_BPS_PRICE_CHANGE_THRESHOLD;
    }

    function getEqReward(
        uint256 _srcPoolId,
        uint256 _amountSD,
        bool _whitelisted
    ) public view returns (uint256) {
        Pool pool = factory.getPool(_srcPoolId);
        uint256 currentAssetSD = _getPoolBalanceSD(pool);
        uint256 lpAsset = pool.totalLiquidity();
        uint256 rewardPoolSize = pool.eqFeePool();

        if (lpAsset <= currentAssetSD) {
            return 0;
        }

        uint256 poolDeficit = lpAsset.sub(currentAssetSD);
        uint256 rate = rewardPoolSize.mul(DENOMINATOR).div(poolDeficit);

        if (rate <= EQ_REWARD_THRESHOLD && !_whitelisted) {
            return 0;
        }

        uint256 eqReward = _amountSD.mul(rate).div(DENOMINATOR);
        eqReward = eqReward > rewardPoolSize ? rewardPoolSize : eqReward;

        return eqReward;
    }

    function getEquilibriumFee(
        uint256 srcPoolId,
        uint256 dstPoolId,
        uint16 dstChainId,
        uint256 amountSD,
        bool whitelisted,
        bool hasEqReward
    ) public view returns (uint256, uint256) {
        if (whitelisted) {
            return (0, 0);
        }

        Pool.ChainPath memory chainPath = factory.getPool(srcPoolId).getChainPath(dstChainId, dstPoolId);
        uint256 idealBalance = chainPath.idealBalance;
        uint256 beforeBalance = chainPath.balance;

        require(beforeBalance >= amountSD, "FeeLibrary: not enough balance");
        uint256 afterBalance = beforeBalance.sub(amountSD);

        uint256 safeZoneMax = idealBalance.mul(DELTA_1).div(DENOMINATOR);
        uint256 safeZoneMin = idealBalance.mul(DELTA_2).div(DENOMINATOR);

        uint256 eqFee = 0;
        uint256 protocolSubsidy = 0;
        uint256 amountSD_ = amountSD; // stack too deep

        if (afterBalance >= safeZoneMax) {
            // no fee zone, protocol subsidize it.
            eqFee = amountSD_.mul(PROTOCOL_SUBSIDY).div(DENOMINATOR);
            // no subsidy if has eqReward
            if (!hasEqReward) {
                protocolSubsidy = eqFee;
            }
        } else if (afterBalance >= safeZoneMin) {
            // safe zone
            uint256 proxyBeforeBalance = beforeBalance < safeZoneMax ? beforeBalance : safeZoneMax;
            eqFee = _getTrapezoidArea(LAMBDA_1, 0, safeZoneMax, safeZoneMin, proxyBeforeBalance, afterBalance);
        } else {
            // danger zone
            if (beforeBalance >= safeZoneMin) {
                // across 2 or 3 zones
                // part 1
                uint256 proxyBeforeBalance = beforeBalance < safeZoneMax ? beforeBalance : safeZoneMax;
                eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_1, 0, safeZoneMax, safeZoneMin, proxyBeforeBalance, safeZoneMin));
                // part 2
                eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_2, LAMBDA_1, safeZoneMin, 0, safeZoneMin, afterBalance));
            } else {
                // only in danger zone
                // part 2 only
                uint256 beforeBalance_ = beforeBalance; // Stack too deep
                eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_2, LAMBDA_1, safeZoneMin, 0, beforeBalance_, afterBalance));
            }
        }
        return (eqFee, protocolSubsidy);
    }

    function getProtocolAndLpFee(
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        uint16, // _dstChainId
        uint256 _amountSD,
        uint256 _protocolSubsidy,
        bool _whitelisted
    ) public view returns (uint256, uint256) {
        if (_whitelisted) {
            return (0, 0);
        }

        uint256 protocolFeeBps = _srcPoolId == _dstPoolId ? PROTOCOL_FEE_FOR_SAME_TOKEN : PROTOCOL_FEE;
        uint256 amountSD = _amountSD; // Stack too deep
        uint256 srcPoolId = _srcPoolId;

        uint256 protocolFee = amountSD.mul(protocolFeeBps).div(DENOMINATOR).sub(_protocolSubsidy);
        uint256 lpFee = amountSD.mul(LP_FEE).div(DENOMINATOR);

        // when there are active emissions, give the lp fee to the protocol
        // lookup LPStaking[Time] address. If it
        address lpStakingAddr = stargatePoolIdToLPStaking[srcPoolId];
        if(lpStakingAddr != address(0x0)){
            IStargateLPStaking lpStaking = IStargateLPStaking(lpStakingAddr);
            (, uint256 allocPoint, , ) = lpStaking.poolInfo(poolIdToLpId[srcPoolId]);
            if (allocPoint > 0) {
                protocolFee = protocolFee.add(lpFee);
                lpFee = 0;
            }
        }

        return (protocolFee, lpFee);
    }

    function getDriftFee(
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        uint256 _amountSD,
        bool _whitelisted
    ) public view returns (uint256) {
        if (_srcPoolId == _dstPoolId) {
            return 0;
        }

        // get current prices and state
        uint256 srcPriceSD = poolIdToPriceSD[_srcPoolId];
        uint256 dstPriceSD = poolIdToPriceSD[_dstPoolId];
        (PriceDeviationState state, , bool lt) = _getPriceDiffAndDeviationState(srcPriceSD, dstPriceSD);

        // there is no drift fee if
        // 1. state is normal
        // 2. swap from high price to low price
        if (!lt || state == PriceDeviationState.Normal) {
            return 0;
        }

        require(state != PriceDeviationState.Depeg, "FeeLibrary: _srcPoolId depeg");

        // if whitelisted, then no drift fee
        if (_whitelisted) {
            return 0;
        }

        uint256 amountSDAfterFee = _amountSD.mul(srcPriceSD).div(dstPriceSD);
        return _amountSD.sub(amountSDAfterFee);
    }

    function getRemoteChains(uint256 _poolId1, uint256 _poolId2) public view returns (uint16[] memory) {
        if (_poolId1 < _poolId2) {
            return poolPairToRemoteChainIds[_poolId1][_poolId2];
        } else {
            return poolPairToRemoteChainIds[_poolId2][_poolId1];
        }
    }

    function getVersion() external pure override returns (string memory) {
        return "7.1.0";
    }

    // --------------------- INTERNAL FUNCTIONS ---------------------
    function _getTrapezoidArea(
        uint256 lambda,
        uint256 yOffset,
        uint256 xUpperBound,
        uint256 xLowerBound,
        uint256 xStart,
        uint256 xEnd
    ) internal pure returns (uint256) {
        require(xEnd >= xLowerBound && xStart <= xUpperBound, "FeeLibrary: balance out of bound");
        uint256 xBoundWidth = xUpperBound.sub(xLowerBound);

        // xStartDrift = xUpperBound.sub(xStart);
        uint256 yStart = xUpperBound.sub(xStart).mul(lambda).div(xBoundWidth).add(yOffset);

        // xEndDrift = xUpperBound.sub(xEnd)
        uint256 yEnd = xUpperBound.sub(xEnd).mul(lambda).div(xBoundWidth).add(yOffset);

        // compute the area
        uint256 deltaX = xStart.sub(xEnd);
        return yStart.add(yEnd).mul(deltaX).div(2).div(DENOMINATOR);
    }

    function _blockingLzReceive(uint16, bytes memory, uint64, bytes memory _payload) internal override {
        (uint256 poolId1, uint256 priceSD1, uint256 poolId2, uint256 priceSD2) = abi.decode(_payload, (uint256, uint256, uint256, uint256));
        poolIdToPriceSD[poolId1] = priceSD1;
        poolIdToPriceSD[poolId2] = priceSD2;
        emit PriceUpdated(poolId1, priceSD1);
        emit PriceUpdated(poolId2, priceSD2);
    }

    ///@notice does an external call to the price feed address supplied and returns the scaled price
    function _getLatestPriceSDFromPriceFeed(uint256 _poolId) internal view returns (uint256) {
        address priceFeed = poolIdToPriceFeed[_poolId];
        require(priceFeed != address(0x0), "FeeLibrary: price feed not set");

        uint8 decimals = AggregatorV3Interface(priceFeed).decimals();
        (, int256 price, , ,) = AggregatorV3Interface(priceFeed).latestRoundData();
        require(price >= 0, "FeeLibrary: price is negative");
        return _scalePrice(uint256(price), decimals);
    }

    ///@notice looks at the two prices and determines if the state of the pair is normal, depeg or drift
    function _getPriceDiffAndDeviationState(uint256 _priceSD1, uint256 _priceSD2) internal pure returns (PriceDeviationState, uint256, bool) {
        // get absolute difference between the two prices
        (uint256 diff, bool lt) = _getAbsoluteDiffAsBps(_priceSD1, _priceSD2);

        PriceDeviationState state;
        if (diff <= PRICE_DRIFT_THRESHOLD) {
            state = PriceDeviationState.Normal;
        } else if (diff >= PRICE_DEPEG_THRESHOLD) {
            state = PriceDeviationState.Depeg;
        } else {
            state = PriceDeviationState.Drift;
        }

        return (state, diff, lt);
    }

    function _scalePrice(uint256 _price, uint8 _decimals) internal pure returns (uint256) {
        if (_decimals == PRICE_SHARED_DECIMALS) {
            return _price;
        }

        uint256 rate = _scaleRate(_decimals, PRICE_SHARED_DECIMALS);
        return _decimals < PRICE_SHARED_DECIMALS ? _price.mul(rate) : _price.div(rate);
    }

    /// @notice returns the absolute difference between two numbers as bps
    /// @return the absolute difference between two numbers as bps
    /// @return true if _a < _b, false otherwise
    function _getAbsoluteDiffAsBps(uint256 _a, uint256 _b) internal pure returns (uint256, bool) {
        if (_a > _b) {
            return (_a.sub(_b).mul(DENOMINATOR).div(_a), false);
        } else if (_a == _b) {
            return (0, false);
        } else {
            return (_b.sub(_a).mul(DENOMINATOR).div(_b), true);
        }
    }

    function _scaleRate(uint8 _decimals, uint8 _sharedDecimals) internal pure returns (uint256) {
        uint256 diff = _decimals > _sharedDecimals? _decimals - _sharedDecimals : _sharedDecimals - _decimals;
        require(diff <= 20, "FeeLibrary: diff of decimals is too large");
        return 10 ** diff;
    }

    function _getPoolBalanceSD(Pool _pool) internal view returns (uint256) {
        return IERC20(_pool.token()).balanceOf(address(_pool)).div(_pool.convertRate());
    }

    receive() external payable {} // receive ETH from lz endpoint
}

File 2 of 16 : ILayerZeroEndpoint.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

import "./ILayerZeroUserApplicationConfig.sol";

interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
    // @notice send a LayerZero message to the specified address at a LayerZero endpoint.
    // @param _dstChainId - the destination chain identifier
    // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
    // @param _payload - a custom bytes payload to send to the destination contract
    // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
    // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
    // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
    function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;

    // @notice used by the messaging library to publish verified payload
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source contract (as bytes) at the source chain
    // @param _dstAddress - the address on destination chain
    // @param _nonce - the unbound message ordering nonce
    // @param _gasLimit - the gas limit for external contract execution
    // @param _payload - verified payload to send to the destination contract
    function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;

    // @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);

    // @notice get the outboundNonce from this source chain which, consequently, is always an EVM
    // @param _srcAddress - the source chain contract address
    function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);

    // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
    // @param _dstChainId - the destination chain identifier
    // @param _userApplication - the user app address on this EVM chain
    // @param _payload - the custom message to send over LayerZero
    // @param _payInZRO - if false, user app pays the protocol fee in native token
    // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
    function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);

    // @notice get this Endpoint's immutable source identifier
    function getChainId() external view returns (uint16);

    // @notice the interface to retry failed message on this Endpoint destination
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    // @param _payload - the payload to be retried
    function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;

    // @notice query if any STORED payload (message blocking) at the endpoint.
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);

    // @notice query if the _libraryAddress is valid for sending msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getSendLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the _libraryAddress is valid for receiving msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getReceiveLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the non-reentrancy guard for send() is on
    // @return true if the guard is on. false otherwise
    function isSendingPayload() external view returns (bool);

    // @notice query if the non-reentrancy guard for receive() is on
    // @return true if the guard is on. false otherwise
    function isReceivingPayload() external view returns (bool);

    // @notice get the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _userApplication - the contract address of the user application
    // @param _configType - type of configuration. every messaging library has its own convention.
    function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);

    // @notice get the send() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getSendVersion(address _userApplication) external view returns (uint16);

    // @notice get the lzReceive() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getReceiveVersion(address _userApplication) external view returns (uint16);
}

File 3 of 16 : ILayerZeroReceiver.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

interface ILayerZeroReceiver {
    // @notice LayerZero endpoint will invoke this function to deliver the message on the destination
    // @param _srcChainId - the source endpoint identifier
    // @param _srcAddress - the source sending contract address from the source chain
    // @param _nonce - the ordered message nonce
    // @param _payload - the signed payload is the UA bytes has encoded to be sent
    function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
}

File 4 of 16 : ILayerZeroUserApplicationConfig.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

interface ILayerZeroUserApplicationConfig {
    // @notice set the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _configType - type of configuration. every messaging library has its own convention.
    // @param _config - configuration in the bytes. can encode arbitrary content.
    function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;

    // @notice set the send() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setSendVersion(uint16 _version) external;

    // @notice set the lzReceive() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setReceiveVersion(uint16 _version) external;

    // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
    // @param _srcChainId - the chainId of the source chain
    // @param _srcAddress - the contract address of the source contract at the source chain
    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}

File 5 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

import "../utils/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 6 of 16 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 7 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

File 8 of 16 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 9 of 16 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 10 of 16 : Factory.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Pool.sol";

contract Factory is Ownable {
    using SafeMath for uint256;

    //---------------------------------------------------------------------------
    // VARIABLES
    mapping(uint256 => Pool) public getPool; // poolId -> PoolInfo
    address[] public allPools;
    address public immutable router;
    address public defaultFeeLibrary; // address for retrieving fee params for swaps

    //---------------------------------------------------------------------------
    // MODIFIERS
    modifier onlyRouter() {
        require(msg.sender == router, "Stargate: caller must be Router.");
        _;
    }

    constructor(address _router) {
        require(_router != address(0x0), "Stargate: _router cant be 0x0"); // 1 time only
        router = _router;
    }

    function setDefaultFeeLibrary(address _defaultFeeLibrary) external onlyOwner {
        require(_defaultFeeLibrary != address(0x0), "Stargate: fee library cant be 0x0");
        defaultFeeLibrary = _defaultFeeLibrary;
    }

    function allPoolsLength() external view returns (uint256) {
        return allPools.length;
    }

    function createPool(
        uint256 _poolId,
        address _token,
        uint8 _sharedDecimals,
        uint8 _localDecimals,
        string memory _name,
        string memory _symbol
    ) public onlyRouter returns (address poolAddress) {
        require(address(getPool[_poolId]) == address(0x0), "Stargate: Pool already created");

        Pool pool = new Pool(_poolId, router, _token, _sharedDecimals, _localDecimals, defaultFeeLibrary, _name, _symbol);
        getPool[_poolId] = pool;
        poolAddress = address(pool);
        allPools.push(poolAddress);
    }

    function renounceOwnership() public override onlyOwner {}
}

File 11 of 16 : LPTokenERC20.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.7.6;

// libraries
import "@openzeppelin/contracts/math/SafeMath.sol";

contract LPTokenERC20 {
    using SafeMath for uint256;

    //---------------------------------------------------------------------------
    // CONSTANTS
    string public name;
    string public symbol;
    bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
    // set in constructor
    bytes32 public DOMAIN_SEPARATOR;

    //---------------------------------------------------------------------------
    // VARIABLES
    uint256 public decimals;
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    mapping(address => uint256) public nonces;

    //---------------------------------------------------------------------------
    // EVENTS
    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256(bytes(name)),
                keccak256(bytes("1")),
                chainId,
                address(this)
            )
        );
    }

    function _mint(address to, uint256 value) internal {
        totalSupply = totalSupply.add(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(address(0), to, value);
    }

    function _burn(address from, uint256 value) internal {
        balanceOf[from] = balanceOf[from].sub(value);
        totalSupply = totalSupply.sub(value);
        emit Transfer(from, address(0), value);
    }

    function _approve(
        address owner,
        address spender,
        uint256 value
    ) private {
        allowance[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    function _transfer(
        address from,
        address to,
        uint256 value
    ) private {
        balanceOf[from] = balanceOf[from].sub(value);
        balanceOf[to] = balanceOf[to].add(value);
        emit Transfer(from, to, value);
    }

    function approve(address spender, uint256 value) external returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    function transfer(address to, uint256 value) external returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool) {
        if (allowance[from][msg.sender] != uint256(-1)) {
            allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
        }
        _transfer(from, to, value);
        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(msg.sender, spender, allowance[msg.sender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        require(deadline >= block.timestamp, "Bridge: EXPIRED");
        bytes32 digest = keccak256(
            abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
            )
        );
        address recoveredAddress = ecrecover(digest, v, r, s);
        require(recoveredAddress != address(0) && recoveredAddress == owner, "Bridge: INVALID_SIGNATURE");
        _approve(owner, spender, value);
    }
}

File 12 of 16 : Pool.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.7.6;
pragma abicoder v2;

// imports
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./LPTokenERC20.sol";
import "./interfaces/IStargateFeeLibrary.sol";

// libraries
import "@openzeppelin/contracts/math/SafeMath.sol";

/// Pool contracts on other chains and managed by the Stargate protocol.
contract Pool is LPTokenERC20, ReentrancyGuard {
    using SafeMath for uint256;

    //---------------------------------------------------------------------------
    // CONSTANTS
    bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));
    uint256 public constant BP_DENOMINATOR = 10000;

    //---------------------------------------------------------------------------
    // STRUCTS
    struct ChainPath {
        bool ready; // indicate if the counter chainPath has been created.
        uint16 dstChainId;
        uint256 dstPoolId;
        uint256 weight;
        uint256 balance;
        uint256 lkb;
        uint256 credits;
        uint256 idealBalance;
    }

    struct SwapObj {
        uint256 amount;
        uint256 eqFee;
        uint256 eqReward;
        uint256 lpFee;
        uint256 protocolFee;
        uint256 lkbRemove;
    }

    struct CreditObj {
        uint256 credits;
        uint256 idealBalance;
    }

    //---------------------------------------------------------------------------
    // VARIABLES

    // chainPath
    ChainPath[] public chainPaths; // list of connected chains with shared pools
    mapping(uint16 => mapping(uint256 => uint256)) public chainPathIndexLookup; // lookup for chainPath by chainId => poolId =>index

    // metadata
    uint256 public immutable poolId; // shared id between chains to represent same pool
    uint256 public sharedDecimals; // the shared decimals (lowest common decimals between chains)
    uint256 public localDecimals; // the decimals for the token
    uint256 public immutable convertRate; // the decimals for the token
    address public immutable token; // the token for the pool
    address public immutable router; // the token for the pool

    bool public stopSwap; // flag to stop swapping in extreme cases

    // Fee and Liquidity
    uint256 public totalLiquidity; // the total amount of tokens added on this side of the chain (fees + deposits - withdrawals)
    uint256 public totalWeight; // total weight for pool percentages
    uint256 public mintFeeBP; // fee basis points for the mint/deposit
    uint256 public protocolFeeBalance; // fee balance created from dao fee
    uint256 public mintFeeBalance; // fee balance created from mint fee
    uint256 public eqFeePool; // pool rewards in Shared Decimal format. indicate the total budget for reverse swap incentive
    address public feeLibrary; // address for retrieving fee params for swaps

    // Delta related
    uint256 public deltaCredit; // credits accumulated from txn
    bool public batched; // flag to indicate if we want batch processing.
    bool public defaultSwapMode; // flag for the default mode for swap
    bool public defaultLPMode; // flag for the default mode for lp
    uint256 public swapDeltaBP; // basis points of poolCredits to activate Delta in swap
    uint256 public lpDeltaBP; // basis points of poolCredits to activate Delta in liquidity events

    //---------------------------------------------------------------------------
    // EVENTS
    event Mint(address to, uint256 amountLP, uint256 amountSD, uint256 mintFeeAmountSD);
    event Burn(address from, uint256 amountLP, uint256 amountSD);
    event RedeemLocalCallback(address _to, uint256 _amountSD, uint256 _amountToMintSD);
    event Swap(
        uint16 chainId,
        uint256 dstPoolId,
        address from,
        uint256 amountSD,
        uint256 eqReward,
        uint256 eqFee,
        uint256 protocolFee,
        uint256 lpFee
    );
    event SendCredits(uint16 dstChainId, uint256 dstPoolId, uint256 credits, uint256 idealBalance);
    event RedeemRemote(uint16 chainId, uint256 dstPoolId, address from, uint256 amountLP, uint256 amountSD);
    event RedeemLocal(address from, uint256 amountLP, uint256 amountSD, uint16 chainId, uint256 dstPoolId, bytes to);
    event InstantRedeemLocal(address from, uint256 amountLP, uint256 amountSD, address to);
    event CreditChainPath(uint16 chainId, uint256 srcPoolId, uint256 amountSD, uint256 idealBalance);
    event SwapRemote(address to, uint256 amountSD, uint256 protocolFee, uint256 dstFee);
    event WithdrawRemote(uint16 srcChainId, uint256 srcPoolId, uint256 swapAmount, uint256 mintAmount);
    event ChainPathUpdate(uint16 dstChainId, uint256 dstPoolId, uint256 weight);
    event FeesUpdated(uint256 mintFeeBP);
    event FeeLibraryUpdated(address feeLibraryAddr);
    event StopSwapUpdated(bool swapStop);
    event WithdrawProtocolFeeBalance(address to, uint256 amountSD);
    event WithdrawMintFeeBalance(address to, uint256 amountSD);
    event DeltaParamUpdated(bool batched, uint256 swapDeltaBP, uint256 lpDeltaBP, bool defaultSwapMode, bool defaultLPMode);

    //---------------------------------------------------------------------------
    // MODIFIERS
    modifier onlyRouter() {
        require(msg.sender == router, "Stargate: only the router can call this method");
        _;
    }

    constructor(
        uint256 _poolId,
        address _router,
        address _token,
        uint256 _sharedDecimals,
        uint256 _localDecimals,
        address _feeLibrary,
        string memory _name,
        string memory _symbol
    ) LPTokenERC20(_name, _symbol) {
        require(_token != address(0x0), "Stargate: _token cannot be 0x0");
        require(_router != address(0x0), "Stargate: _router cannot be 0x0");
        poolId = _poolId;
        router = _router;
        token = _token;
        sharedDecimals = _sharedDecimals;
        decimals = uint8(_sharedDecimals);
        localDecimals = _localDecimals;
        convertRate = 10**(uint256(localDecimals).sub(sharedDecimals));
        totalWeight = 0;
        feeLibrary = _feeLibrary;

        //delta algo related
        batched = false;
        defaultSwapMode = true;
        defaultLPMode = true;
    }

    function getChainPathsLength() public view returns (uint256) {
        return chainPaths.length;
    }

    //---------------------------------------------------------------------------
    // LOCAL CHAIN FUNCTIONS

    function mint(address _to, uint256 _amountLD) external nonReentrant onlyRouter returns (uint256) {
        return _mintLocal(_to, _amountLD, true, true);
    }

    // Local                                    Remote
    // -------                                  ---------
    // swap             ->                      swapRemote
    function swap(
        uint16 _dstChainId,
        uint256 _dstPoolId,
        address _from,
        uint256 _amountLD,
        uint256 _minAmountLD,
        bool newLiquidity
    ) external nonReentrant onlyRouter returns (SwapObj memory) {
        require(!stopSwap, "Stargate: swap func stopped");
        ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
        require(cp.ready == true, "Stargate: counter chainPath is not ready");

        uint256 amountSD = amountLDtoSD(_amountLD);
        uint256 minAmountSD = amountLDtoSD(_minAmountLD);

        // request fee params from library
        SwapObj memory s = IStargateFeeLibrary(feeLibrary).getFees(poolId, _dstPoolId, _dstChainId, _from, amountSD);

        // equilibrium fee and reward. note eqFee/eqReward are separated from swap liquidity
        eqFeePool = eqFeePool.sub(s.eqReward);
        // update the new amount the user gets minus the fees
        s.amount = amountSD.sub(s.eqFee).sub(s.protocolFee).sub(s.lpFee);
        // users will also get the eqReward
        require(s.amount.add(s.eqReward) >= minAmountSD, "Stargate: slippage too high");

        // behaviours
        //     - protocolFee: booked, stayed and withdrawn at remote.
        //     - eqFee: booked, stayed and withdrawn at remote.
        //     - lpFee: booked and stayed at remote, can be withdrawn anywhere

        s.lkbRemove = amountSD.sub(s.lpFee).add(s.eqReward);
        // check for transfer solvency.
        require(cp.balance >= s.lkbRemove, "Stargate: dst balance too low");
        cp.balance = cp.balance.sub(s.lkbRemove);

        if (newLiquidity) {
            deltaCredit = deltaCredit.add(amountSD).add(s.eqReward);
        } else if (s.eqReward > 0) {
            deltaCredit = deltaCredit.add(s.eqReward);
        }

        // distribute credits on condition.
        if (!batched || deltaCredit >= totalLiquidity.mul(swapDeltaBP).div(BP_DENOMINATOR)) {
            _delta(defaultSwapMode);
        }

        emit Swap(_dstChainId, _dstPoolId, _from, s.amount, s.eqReward, s.eqFee, s.protocolFee, s.lpFee);
        return s;
    }

    // Local                                    Remote
    // -------                                  ---------
    // sendCredits      ->                      creditChainPath
    function sendCredits(uint16 _dstChainId, uint256 _dstPoolId) external nonReentrant onlyRouter returns (CreditObj memory c) {
        ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
        require(cp.ready == true, "Stargate: counter chainPath is not ready");
        cp.lkb = cp.lkb.add(cp.credits);
        c.idealBalance = totalLiquidity.mul(cp.weight).div(totalWeight);
        c.credits = cp.credits;
        cp.credits = 0;
        emit SendCredits(_dstChainId, _dstPoolId, c.credits, c.idealBalance);
    }

    // Local                                    Remote
    // -------                                  ---------
    // redeemRemote   ->                        swapRemote
    function redeemRemote(
        uint16 _dstChainId,
        uint256 _dstPoolId,
        address _from,
        uint256 _amountLP
    ) external nonReentrant onlyRouter {
        require(_from != address(0x0), "Stargate: _from cannot be 0x0");
        uint256 amountSD = _burnLocal(_from, _amountLP);
        //run Delta
        if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
            _delta(defaultLPMode);
        }
        uint256 amountLD = amountSDtoLD(amountSD);
        emit RedeemRemote(_dstChainId, _dstPoolId, _from, _amountLP, amountLD);
    }

    function instantRedeemLocal(
        address _from,
        uint256 _amountLP,
        address _to
    ) external nonReentrant onlyRouter returns (uint256 amountSD) {
        require(_from != address(0x0), "Stargate: _from cannot be 0x0");
        uint256 _deltaCredit = deltaCredit; // sload optimization.
        uint256 _capAmountLP = _amountSDtoLP(_deltaCredit);

        if (_amountLP > _capAmountLP) _amountLP = _capAmountLP;

        amountSD = _burnLocal(_from, _amountLP);
        deltaCredit = _deltaCredit.sub(amountSD);
        uint256 amountLD = amountSDtoLD(amountSD);
        _safeTransfer(token, _to, amountLD);
        emit InstantRedeemLocal(_from, _amountLP, amountSD, _to);
    }

    // Local                                    Remote
    // -------                                  ---------
    // redeemLocal   ->                         redeemLocalCheckOnRemote
    // redeemLocalCallback             <-
    function redeemLocal(
        address _from,
        uint256 _amountLP,
        uint16 _dstChainId,
        uint256 _dstPoolId,
        bytes calldata _to
    ) external nonReentrant onlyRouter returns (uint256 amountSD) {
        require(_from != address(0x0), "Stargate: _from cannot be 0x0");

        // safeguard.
        require(chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]].ready == true, "Stargate: counter chainPath is not ready");
        amountSD = _burnLocal(_from, _amountLP);

        // run Delta
        if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
            _delta(false);
        }
        emit RedeemLocal(_from, _amountLP, amountSD, _dstChainId, _dstPoolId, _to);
    }

    //---------------------------------------------------------------------------
    // REMOTE CHAIN FUNCTIONS

    // Local                                    Remote
    // -------                                  ---------
    // sendCredits      ->                      creditChainPath
    function creditChainPath(
        uint16 _dstChainId,
        uint256 _dstPoolId,
        CreditObj memory _c
    ) external nonReentrant onlyRouter {
        ChainPath storage cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
        cp.balance = cp.balance.add(_c.credits);
        if (cp.idealBalance != _c.idealBalance) {
            cp.idealBalance = _c.idealBalance;
        }
        emit CreditChainPath(_dstChainId, _dstPoolId, _c.credits, _c.idealBalance);
    }

    // Local                                    Remote
    // -------                                  ---------
    // swap             ->                      swapRemote
    function swapRemote(
        uint16 _srcChainId,
        uint256 _srcPoolId,
        address _to,
        SwapObj memory _s
    ) external nonReentrant onlyRouter returns (uint256 amountLD) {
        // booking lpFee
        totalLiquidity = totalLiquidity.add(_s.lpFee);
        // booking eqFee
        eqFeePool = eqFeePool.add(_s.eqFee);
        // booking stargateFee
        protocolFeeBalance = protocolFeeBalance.add(_s.protocolFee);

        // update LKB
        uint256 chainPathIndex = chainPathIndexLookup[_srcChainId][_srcPoolId];
        chainPaths[chainPathIndex].lkb = chainPaths[chainPathIndex].lkb.sub(_s.lkbRemove);

        // user receives the amount + the srcReward
        amountLD = amountSDtoLD(_s.amount.add(_s.eqReward));
        _safeTransfer(token, _to, amountLD);
        emit SwapRemote(_to, _s.amount.add(_s.eqReward), _s.protocolFee, _s.eqFee);
    }

    // Local                                    Remote
    // -------                                  ---------
    // redeemLocal   ->                         redeemLocalCheckOnRemote
    // redeemLocalCallback             <-
    function redeemLocalCallback(
        uint16 _srcChainId,
        uint256 _srcPoolId,
        address _to,
        uint256 _amountSD,
        uint256 _amountToMintSD
    ) external nonReentrant onlyRouter {
        if (_amountToMintSD > 0) {
            _mintLocal(_to, amountSDtoLD(_amountToMintSD), false, false);
        }

        ChainPath storage cp = getAndCheckCP(_srcChainId, _srcPoolId);
        cp.lkb = cp.lkb.sub(_amountSD);

        uint256 amountLD = amountSDtoLD(_amountSD);
        _safeTransfer(token, _to, amountLD);
        emit RedeemLocalCallback(_to, _amountSD, _amountToMintSD);
    }

    // Local                                    Remote
    // -------                                  ---------
    // redeemLocal(amount)   ->               redeemLocalCheckOnRemote
    // redeemLocalCallback             <-
    function redeemLocalCheckOnRemote(
        uint16 _srcChainId,
        uint256 _srcPoolId,
        uint256 _amountSD
    ) external nonReentrant onlyRouter returns (uint256 swapAmount, uint256 mintAmount) {
        ChainPath storage cp = getAndCheckCP(_srcChainId, _srcPoolId);
        if (_amountSD > cp.balance) {
            mintAmount = _amountSD - cp.balance;
            swapAmount = cp.balance;
            cp.balance = 0;
        } else {
            cp.balance = cp.balance.sub(_amountSD);
            swapAmount = _amountSD;
            mintAmount = 0;
        }
        emit WithdrawRemote(_srcChainId, _srcPoolId, swapAmount, mintAmount);
    }

    //---------------------------------------------------------------------------
    // DAO Calls
    function createChainPath(
        uint16 _dstChainId,
        uint256 _dstPoolId,
        uint256 _weight
    ) external onlyRouter {
        for (uint256 i = 0; i < chainPaths.length; ++i) {
            ChainPath memory cp = chainPaths[i];
            bool exists = cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId;
            require(!exists, "Stargate: cant createChainPath of existing dstChainId and _dstPoolId");
        }
        totalWeight = totalWeight.add(_weight);
        chainPathIndexLookup[_dstChainId][_dstPoolId] = chainPaths.length;
        chainPaths.push(ChainPath(false, _dstChainId, _dstPoolId, _weight, 0, 0, 0, 0));
        emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
    }

    function setWeightForChainPath(
        uint16 _dstChainId,
        uint256 _dstPoolId,
        uint16 _weight
    ) external onlyRouter {
        ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
        totalWeight = totalWeight.sub(cp.weight).add(_weight);
        cp.weight = _weight;
        emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
    }

    function setFee(uint256 _mintFeeBP) external onlyRouter {
        require(_mintFeeBP <= BP_DENOMINATOR, "Bridge: cum fees > 100%");
        mintFeeBP = _mintFeeBP;
        emit FeesUpdated(mintFeeBP);
    }

    function setFeeLibrary(address _feeLibraryAddr) external onlyRouter {
        require(_feeLibraryAddr != address(0x0), "Stargate: fee library cant be 0x0");
        feeLibrary = _feeLibraryAddr;
        emit FeeLibraryUpdated(_feeLibraryAddr);
    }

    function setSwapStop(bool _swapStop) external onlyRouter {
        stopSwap = _swapStop;
        emit StopSwapUpdated(_swapStop);
    }

    function setDeltaParam(
        bool _batched,
        uint256 _swapDeltaBP,
        uint256 _lpDeltaBP,
        bool _defaultSwapMode,
        bool _defaultLPMode
    ) external onlyRouter {
        require(_swapDeltaBP <= BP_DENOMINATOR && _lpDeltaBP <= BP_DENOMINATOR, "Stargate: wrong Delta param");
        batched = _batched;
        swapDeltaBP = _swapDeltaBP;
        lpDeltaBP = _lpDeltaBP;
        defaultSwapMode = _defaultSwapMode;
        defaultLPMode = _defaultLPMode;
        emit DeltaParamUpdated(_batched, _swapDeltaBP, _lpDeltaBP, _defaultSwapMode, _defaultLPMode);
    }

    function callDelta(bool _fullMode) external onlyRouter {
        _delta(_fullMode);
    }

    function activateChainPath(uint16 _dstChainId, uint256 _dstPoolId) external onlyRouter {
        ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
        require(cp.ready == false, "Stargate: chainPath is already active");
        // this func will only be called once
        cp.ready = true;
    }

    function withdrawProtocolFeeBalance(address _to) external onlyRouter {
        if (protocolFeeBalance > 0) {
            uint256 amountOfLD = amountSDtoLD(protocolFeeBalance);
            protocolFeeBalance = 0;
            _safeTransfer(token, _to, amountOfLD);
            emit WithdrawProtocolFeeBalance(_to, amountOfLD);
        }
    }

    function withdrawMintFeeBalance(address _to) external onlyRouter {
        if (mintFeeBalance > 0) {
            uint256 amountOfLD = amountSDtoLD(mintFeeBalance);
            mintFeeBalance = 0;
            _safeTransfer(token, _to, amountOfLD);
            emit WithdrawMintFeeBalance(_to, amountOfLD);
        }
    }

    //---------------------------------------------------------------------------
    // INTERNAL
    // Conversion Helpers
    //---------------------------------------------------------------------------
    function amountLPtoLD(uint256 _amountLP) external view returns (uint256) {
        return amountSDtoLD(_amountLPtoSD(_amountLP));
    }

    function _amountLPtoSD(uint256 _amountLP) internal view returns (uint256) {
        require(totalSupply > 0, "Stargate: cant convert LPtoSD when totalSupply == 0");
        return _amountLP.mul(totalLiquidity).div(totalSupply);
    }

    function _amountSDtoLP(uint256 _amountSD) internal view returns (uint256) {
        require(totalLiquidity > 0, "Stargate: cant convert SDtoLP when totalLiq == 0");
        return _amountSD.mul(totalSupply).div(totalLiquidity);
    }

    function amountSDtoLD(uint256 _amount) internal view returns (uint256) {
        return _amount.mul(convertRate);
    }

    function amountLDtoSD(uint256 _amount) internal view returns (uint256) {
        return _amount.div(convertRate);
    }

    function getAndCheckCP(uint16 _dstChainId, uint256 _dstPoolId) internal view returns (ChainPath storage) {
        require(chainPaths.length > 0, "Stargate: no chainpaths exist");
        ChainPath storage cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
        require(cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId, "Stargate: local chainPath does not exist");
        return cp;
    }

    function getChainPath(uint16 _dstChainId, uint256 _dstPoolId) external view returns (ChainPath memory) {
        ChainPath memory cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
        require(cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId, "Stargate: local chainPath does not exist");
        return cp;
    }

    function _burnLocal(address _from, uint256 _amountLP) internal returns (uint256) {
        require(totalSupply > 0, "Stargate: cant burn when totalSupply == 0");
        uint256 amountOfLPTokens = balanceOf[_from];
        require(amountOfLPTokens >= _amountLP, "Stargate: not enough LP tokens to burn");

        uint256 amountSD = _amountLP.mul(totalLiquidity).div(totalSupply);
        //subtract totalLiquidity accordingly
        totalLiquidity = totalLiquidity.sub(amountSD);

        _burn(_from, _amountLP);
        emit Burn(_from, _amountLP, amountSD);
        return amountSD;
    }

    function _delta(bool fullMode) internal {
        if (deltaCredit > 0 && totalWeight > 0) {
            uint256 cpLength = chainPaths.length;
            uint256[] memory deficit = new uint256[](cpLength);
            uint256 totalDeficit = 0;

            // algorithm steps 6-9: calculate the total and the amounts required to get to balance state
            for (uint256 i = 0; i < cpLength; ++i) {
                ChainPath storage cp = chainPaths[i];
                // (liquidity * (weight/totalWeight)) - (lkb+credits)
                uint256 balLiq = totalLiquidity.mul(cp.weight).div(totalWeight);
                uint256 currLiq = cp.lkb.add(cp.credits);
                if (balLiq > currLiq) {
                    // save gas since we know balLiq > currLiq and we know deficit[i] > 0
                    deficit[i] = balLiq - currLiq;
                    totalDeficit = totalDeficit.add(deficit[i]);
                }
            }

            // indicates how much delta credit is distributed
            uint256 spent;

            // handle credits with 2 tranches. the [ < totalDeficit] [excessCredit]
            // run full Delta, allocate all credits
            if (totalDeficit == 0) {
                // only fullMode delta will allocate excess credits
                if (fullMode && deltaCredit > 0) {
                    // credit ChainPath by weights
                    for (uint256 i = 0; i < cpLength; ++i) {
                        ChainPath storage cp = chainPaths[i];
                        // credits = credits + toBalanceChange + remaining allocation based on weight
                        uint256 amtToCredit = deltaCredit.mul(cp.weight).div(totalWeight);
                        spent = spent.add(amtToCredit);
                        cp.credits = cp.credits.add(amtToCredit);
                    }
                } // else do nth
            } else if (totalDeficit <= deltaCredit) {
                if (fullMode) {
                    // algorithm step 13: calculate amount to disperse to bring to balance state or as close as possible
                    uint256 excessCredit = deltaCredit - totalDeficit;
                    // algorithm steps 14-16: calculate credits
                    for (uint256 i = 0; i < cpLength; ++i) {
                        if (deficit[i] > 0) {
                            ChainPath storage cp = chainPaths[i];
                            // credits = credits + deficit + remaining allocation based on weight
                            uint256 amtToCredit = deficit[i].add(excessCredit.mul(cp.weight).div(totalWeight));
                            spent = spent.add(amtToCredit);
                            cp.credits = cp.credits.add(amtToCredit);
                        }
                    }
                } else {
                    // totalDeficit <= deltaCredit but not running fullMode
                    // credit chainPaths as is if any deficit, not using all deltaCredit
                    for (uint256 i = 0; i < cpLength; ++i) {
                        if (deficit[i] > 0) {
                            ChainPath storage cp = chainPaths[i];
                            uint256 amtToCredit = deficit[i];
                            spent = spent.add(amtToCredit);
                            cp.credits = cp.credits.add(amtToCredit);
                        }
                    }
                }
            } else {
                // totalDeficit > deltaCredit, fullMode or not, normalize the deficit by deltaCredit
                for (uint256 i = 0; i < cpLength; ++i) {
                    if (deficit[i] > 0) {
                        ChainPath storage cp = chainPaths[i];
                        uint256 proportionalDeficit = deficit[i].mul(deltaCredit).div(totalDeficit);
                        spent = spent.add(proportionalDeficit);
                        cp.credits = cp.credits.add(proportionalDeficit);
                    }
                }
            }

            // deduct the amount of credit sent
            deltaCredit = deltaCredit.sub(spent);
        }
    }

    function _mintLocal(
        address _to,
        uint256 _amountLD,
        bool _feesEnabled,
        bool _creditDelta
    ) internal returns (uint256 amountSD) {
        require(totalWeight > 0, "Stargate: No ChainPaths exist");
        amountSD = amountLDtoSD(_amountLD);

        uint256 mintFeeSD = 0;
        if (_feesEnabled) {
            mintFeeSD = amountSD.mul(mintFeeBP).div(BP_DENOMINATOR);
            amountSD = amountSD.sub(mintFeeSD);
            mintFeeBalance = mintFeeBalance.add(mintFeeSD);
        }

        if (_creditDelta) {
            deltaCredit = deltaCredit.add(amountSD);
        }

        uint256 amountLPTokens = amountSD;
        if (totalSupply != 0) {
            amountLPTokens = amountSD.mul(totalSupply).div(totalLiquidity);
        }
        totalLiquidity = totalLiquidity.add(amountSD);

        _mint(_to, amountLPTokens);
        emit Mint(_to, amountLPTokens, amountSD, mintFeeSD);

        // add to credits and call delta. short circuit to save gas
        if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
            _delta(defaultLPMode);
        }
    }

    function _safeTransfer(
        address _token,
        address _to,
        uint256 _value
    ) private {
        (bool success, bytes memory data) = _token.call(abi.encodeWithSelector(SELECTOR, _to, _value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "Stargate: TRANSFER_FAILED");
    }
}

File 13 of 16 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;

interface AggregatorV3Interface {
    function decimals() external view returns (uint8);

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

    function version() external view returns (uint256);

    // getRoundData and latestRoundData should both raise "No data present"
    // if they do not have data to report, instead of returning unset values
    // which could be misinterpreted as actual reported values.
    function getRoundData(uint80 _roundId)
    external
    view
    returns (
        uint80 roundId,
        int256 answer,
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    );

    function latestRoundData()
    external
    view
    returns (
        uint80 roundId,
        int256 answer,
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    );
}

File 14 of 16 : IStargateFeeLibrary.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.7.6;
pragma abicoder v2;
import "../Pool.sol";

interface IStargateFeeLibrary {
    function getFees(
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        uint16 _dstChainId,
        address _from,
        uint256 _amountSD
    ) external returns (Pool.SwapObj memory s);

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

File 15 of 16 : IStargateLPStaking.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.7.6;
pragma abicoder v2;

interface IStargateLPStaking {
    function poolInfo(uint256 _poolIndex)
        external
        view
        returns (
            address,
            uint256,
            uint256,
            uint256
        );
}

File 16 of 16 : LzApp.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@layerzerolabs/layerzero-core/contracts/interfaces/ILayerZeroReceiver.sol";
import "@layerzerolabs/layerzero-core/contracts/interfaces/ILayerZeroEndpoint.sol";
import "@layerzerolabs/layerzero-core/contracts/interfaces/ILayerZeroUserApplicationConfig.sol";

/*
 * a generic LzReceiver implementation
 */
abstract contract LzApp is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {

    ILayerZeroEndpoint public immutable lzEndpoint;
    mapping(uint16 => bytes) public trustedRemoteLookup;
    mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;
    address public precrime;

    event SetPrecrime(address precrime);
    event SetTrustedRemote(uint16 _remoteChainId, bytes _path);
    event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
    event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);

    constructor(address _endpoint) {
        lzEndpoint = ILayerZeroEndpoint(_endpoint);
    }

    function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public virtual override {
        // lzReceive must be called by the endpoint for security
        require(_msgSender() == address(lzEndpoint), "LzApp: invalid endpoint caller");

        bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];
        // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.
        require(_srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote), "LzApp: invalid source sending contract");

        _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
    }

    // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging
    function _blockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual;

    function _lzSend(uint16 _dstChainId, bytes memory _payload, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams, uint _nativeFee) internal virtual {
        bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];
        require(trustedRemote.length != 0, "LzApp: destination chain is not a trusted source");
        lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);
    }

    function _checkGasLimit(uint16 _dstChainId, uint16 _type, bytes memory _adapterParams, uint _extraGas) internal view virtual {
        uint providedGasLimit = _getGasLimit(_adapterParams);
        uint minGasLimit = minDstGasLookup[_dstChainId][_type] + _extraGas;
        require(minGasLimit > 0, "LzApp: minGasLimit not set");
        require(providedGasLimit >= minGasLimit, "LzApp: gas limit is too low");
    }

    function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) {
        require(_adapterParams.length >= 34, "LzApp: invalid adapterParams");
        assembly {
            gasLimit := mload(add(_adapterParams, 34))
        }
    }

    //---------------------------UserApplication config----------------------------------------
    function getConfig(uint16 _version, uint16 _chainId, address, uint _configType) external view returns (bytes memory) {
        return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);
    }

    // generic config for LayerZero user Application
    function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external override onlyOwner {
        lzEndpoint.setConfig(_version, _chainId, _configType, _config);
    }

    function setSendVersion(uint16 _version) external override onlyOwner {
        lzEndpoint.setSendVersion(_version);
    }

    function setReceiveVersion(uint16 _version) external override onlyOwner {
        lzEndpoint.setReceiveVersion(_version);
    }

    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {
        lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
    }

    // _path = abi.encodePacked(remoteAddress, localAddress)
    // this function set the trusted path for the cross-chain communication
    function setTrustedRemote(uint16 _srcChainId, bytes calldata _path) external onlyOwner {
        trustedRemoteLookup[_srcChainId] = _path;
        emit SetTrustedRemote(_srcChainId, _path);
    }

    function setPrecrime(address _precrime) external onlyOwner {
        precrime = _precrime;
        emit SetPrecrime(_precrime);
    }

    function setMinDstGas(uint16 _dstChainId, uint16 _packetType, uint _minGas) external onlyOwner {
        require(_minGas > 0, "LzApp: invalid minGas");
        minDstGasLookup[_dstChainId][_packetType] = _minGas;
        emit SetMinDstGas(_dstChainId, _packetType, _minGas);
    }

    //--------------------------- VIEW FUNCTION ----------------------------------------
    function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {
        bytes memory trustedSource = trustedRemoteLookup[_srcChainId];
        return keccak256(trustedSource) == keccak256(_srcAddress);
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_endpoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceSD","type":"uint256"}],"name":"PriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"_type","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"_minDstGas","type":"uint256"}],"name":"SetMinDstGas","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"precrime","type":"address"}],"name":"SetPrecrime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_path","type":"bytes"}],"name":"SetTrustedRemote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_remoteAddress","type":"bytes"}],"name":"SetTrustedRemoteAddress","type":"event"},{"inputs":[],"name":"DELTA_1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELTA_2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EQ_REWARD_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LAMBDA_1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LAMBDA_2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LP_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_BPS_PRICE_CHANGE_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_DEPEG_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_DRIFT_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_SHARED_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_FEE_FOR_SAME_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_SUBSIDY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"defaultAdapterParams","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"forceResumeReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"_configType","type":"uint256"}],"name":"getConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"uint256","name":"_amountSD","type":"uint256"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"getDriftFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_amountSD","type":"uint256"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"getEqReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"srcPoolId","type":"uint256"},{"internalType":"uint256","name":"dstPoolId","type":"uint256"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint256","name":"amountSD","type":"uint256"},{"internalType":"bool","name":"whitelisted","type":"bool"},{"internalType":"bool","name":"hasEqReward","type":"bool"}],"name":"getEquilibriumFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amountSD","type":"uint256"}],"name":"getFees","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"eqFee","type":"uint256"},{"internalType":"uint256","name":"eqReward","type":"uint256"},{"internalType":"uint256","name":"lpFee","type":"uint256"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"uint256","name":"lkbRemove","type":"uint256"}],"internalType":"struct Pool.SwapObj","name":"s","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint256","name":"_amountSD","type":"uint256"},{"internalType":"uint256","name":"_protocolSubsidy","type":"uint256"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"getProtocolAndLpFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"}],"name":"getRemoteChains","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_priceSD","type":"uint256"}],"name":"initTokenPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"isTrustedRemote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lzEndpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"minDstGasLookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIdToLpId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIdToPriceFeed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIdToPriceSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precrime","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"}],"name":"quoteFeeForPriceUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"uint256","name":"_configType","type":"uint256"},{"internalType":"bytes","name":"_config","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"internalType":"bytes","name":"_adapterParams","type":"bytes"}],"name":"setDefaultAdapterParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_packetType","type":"uint16"},{"internalType":"uint256","name":"_minGas","type":"uint256"}],"name":"setMinDstGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_lpId","type":"uint256"}],"name":"setPoolToLpId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_precrime","type":"address"}],"name":"setPrecrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"}],"name":"setReceiveVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"},{"internalType":"uint16[]","name":"_remoteChainIds","type":"uint16[]"}],"name":"setRemoteChains","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"}],"name":"setSendVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_lpStaking","type":"address"}],"name":"setStargatePoolIdToLPStakingAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_priceFeedAddress","type":"address"}],"name":"setTokenPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_path","type":"bytes"}],"name":"setTrustedRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"}],"name":"shouldCallUpdateTokenPrices","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stargatePoolIdToLPStaking","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"trustedRemoteLookup","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"}],"name":"updateTokenPrices","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"bool","name":"_whiteListed","type":"bool"}],"name":"whiteList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b50604051620044e4380380620044e483398101604081905262000034916200012e565b806000620000416200010d565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35060601b6001600160601b0319166080526001600160a01b038216620000cd5760405162461bcd60e51b8152600401620000c49062000165565b60405180910390fd5b6001600160a01b038116620000f65760405162461bcd60e51b8152600401620000c490620001a6565b5060601b6001600160601b03191660a052620001e8565b3390565b80516001600160a01b03811681146200012957600080fd5b919050565b6000806040838503121562000141578182fd5b6200014c8362000111565b91506200015c6020840162000111565b90509250929050565b60208082526021908201527f4665654c6962726172793a20466163746f72792063616e6e6f742062652030786040820152600360fc1b606082015260800190565b60208082526022908201527f4665654c6962726172793a20456e64706f696e742063616e6e6f742062652030604082015261078360f41b606082015260800190565b60805160601c60a05160601c6142a062000244600039806117095280611e2152806122e25250806109b75280610c505280610d7c52806111f452806120ad5280612368528061258c528061298f5280612edb52506142a06000f3fe6080604052600436106103535760003560e01c80637ba5c12f116101c6578063ad7bbfc9116100f7578063d2f68aec11610095578063eb8d72b71161006f578063eb8d72b714610935578063f2fde38b14610955578063f5ecbdbc14610975578063fc6834a1146109955761035a565b8063d2f68aec146108e0578063d7f6bde314610900578063df2a5b3b146109155761035a565b8063baf3292d116100d1578063baf3292d1461086b578063c45a01551461088b578063cbed8b9c146108a0578063d16baeb9146108c05761035a565b8063ad7bbfc914610816578063b353aaa714610836578063b7f5ada31461084b5761035a565b806396e03bf3116101645780639c2f2e251161013e5780639c2f2e251461079e5780639fb2663a146107be578063a1498635146107ec578063a810de6c146108015761035a565b806396e03bf31461073e578063972883c41461075e5780639b19251a1461077e5761035a565b80638cfd8f5c116101a05780638cfd8f5c146106df5780638da5cb5b146106ff578063918f867414610714578063950c8a74146107295761035a565b80637ba5c12f146106aa5780637f1c8bb7146106bf57806380651ee2146106005761035a565b80633c2c3065116102a05780635a208ba31161023e5780636ddc4561116102185780636ddc456114610635578063715018a6146106555780637533d7881461066a5780637b35c2601461068a5761035a565b80635a208ba3146105ed5780635e3f2727146106005780636548c4ac146106155761035a565b806342d65a8d1161027a57806342d65a8d14610583578063518a9f9f146105a357806352863703146105b857806358cbb8ed146105cd5761035a565b80633c2c3065146105215780633d8b38f6146105415780633dad0dd51461056e5761035a565b80630d8e6e2c1161030d5780631738fe38116102e75780631738fe38146104925780631ab62430146104a757806323daf69c146104d457806326cfac66146104f45761035a565b80630d8e6e2c1461043057806310ddb1371461045257806313c6e380146104725761035a565b80621d35671461035f578063012a1c2d14610381578063040d5835146103ac57806307e0db17146103ce578063084285da146103ee5780630b4501fd1461041b5761035a565b3661035a57005b600080fd5b34801561036b57600080fd5b5061037f61037a36600461386d565b6109b5565b005b34801561038d57600080fd5b50610396610bdb565b6040516103a3919061410b565b60405180910390f35b3480156103b857600080fd5b506103c1610be7565b6040516103a3919061413d565b3480156103da57600080fd5b5061037f6103e93660046137fe565b610bec565b3480156103fa57600080fd5b5061040e610409366004613a33565b610cd3565b6040516103a39190613db6565b34801561042757600080fd5b50610396610cee565b34801561043c57600080fd5b50610445610cf9565b6040516103a39190613e1d565b34801561045e57600080fd5b5061037f61046d3660046137fe565b610d18565b34801561047e57600080fd5b5061039661048d366004613a33565b610de4565b34801561049e57600080fd5b50610396610df6565b3480156104b357600080fd5b506104c76104c2366004613b80565b610e01565b6040516103a39190613ff6565b3480156104e057600080fd5b506103966104ef366004613a33565b610f4d565b34801561050057600080fd5b5061051461050f366004613a87565b610f5f565b6040516103a39190613dca565b34801561052d57600080fd5b5061040e61053c366004613a33565b611066565b34801561054d57600080fd5b5061056161055c36600461381a565b611081565b6040516103a39190613e12565b34801561057a57600080fd5b50610396611154565b34801561058f57600080fd5b5061037f61059e36600461381a565b611160565b3480156105af57600080fd5b50610396611275565b3480156105c457600080fd5b50610396611280565b3480156105d957600080fd5b506104456105e83660046137fe565b61128b565b61037f6105fb366004613a87565b611326565b34801561060c57600080fd5b5061039661152b565b34801561062157600080fd5b5061037f610630366004613a87565b611535565b34801561064157600080fd5b5061037f610650366004613a63565b6115a9565b34801561066157600080fd5b5061037f611639565b34801561067657600080fd5b506104456106853660046137fe565b61169d565b34801561069657600080fd5b506103966106a5366004613b48565b611704565b3480156106b657600080fd5b5061039661193f565b3480156106cb57600080fd5b5061037f6106da366004613a63565b611949565b3480156106eb57600080fd5b506103966106fa366004613905565b6119d9565b34801561070b57600080fd5b5061040e6119f6565b34801561072057600080fd5b50610396611a05565b34801561073557600080fd5b5061040e611a11565b34801561074a57600080fd5b5061037f610759366004613a87565b611a20565b34801561076a57600080fd5b50610396610779366004613c86565b611abf565b34801561078a57600080fd5b506105616107993660046136b9565b611b8f565b3480156107aa57600080fd5b5061037f6107b9366004613acb565b611ba4565b3480156107ca57600080fd5b506107de6107d9366004613c37565b611c86565b6040516103a3929190614114565b3480156107f857600080fd5b50610396611ddd565b34801561080d57600080fd5b50610396611de8565b34801561082257600080fd5b506107de610831366004613bd1565b611df3565b34801561084257600080fd5b5061040e6120ab565b34801561085757600080fd5b50610561610866366004613a87565b6120cf565b34801561087757600080fd5b5061037f6108863660046136b9565b61222a565b34801561089757600080fd5b5061040e6122e0565b3480156108ac57600080fd5b5061037f6108bb3660046139c2565b612304565b3480156108cc57600080fd5b5061037f6108db3660046136f1565b61242c565b3480156108ec57600080fd5b506103966108fb366004613a87565b6124b9565b34801561090c57600080fd5b5061039661263c565b34801561092157600080fd5b5061037f610930366004613982565b612647565b34801561094157600080fd5b5061037f61095036600461381a565b61275f565b34801561096157600080fd5b5061037f6109703660046136b9565b612851565b34801561098157600080fd5b50610445610990366004613932565b612953565b3480156109a157600080fd5b5061037f6109b036600461381a565b612acd565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166109e7612b53565b6001600160a01b031614610a42576040805162461bcd60e51b815260206004820152601e60248201527f4c7a4170703a20696e76616c696420656e64706f696e742063616c6c65720000604482015290519081900360640190fd5b61ffff8616600090815260016020818152604080842080548251600295821615610100026000190190911694909404601f810184900484028501840190925281845291830182828015610ad65780601f10610aab57610100808354040283529160200191610ad6565b820191906000526020600020905b815481529060010190602001808311610ab957829003601f168201915b50505050509050805186869050148015610af1575060008151115b8015610b215750808051906020012086866040518083838082843780830192505050925050506040518091039020145b610b5c5760405162461bcd60e51b81526004018080602001828103825260268152602001806142456026913960400191505060405180910390fd5b610bd28787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250612b5792505050565b50505050505050565b670dd280b9144a000081565b600881565b610bf4612b53565b6001600160a01b0316610c056119f6565b6001600160a01b031614610c4e576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166307e0db17826040518263ffffffff1660e01b8152600401808261ffff168152602001915050600060405180830381600087803b158015610cb857600080fd5b505af1158015610ccc573d6000803e3d6000fd5b5050505050565b6006602052600090815260409020546001600160a01b031681565b6603328b944c400081565b6040805180820190915260058152640372e312e360dc1b602082015290565b610d20612b53565b6001600160a01b0316610d316119f6565b6001600160a01b031614610d7a576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166310ddb137826040518263ffffffff1660e01b8152600401808261ffff168152602001915050600060405180830381600087803b158015610cb857600080fd5b60056020526000908152604090205481565b66354a6ba7a1800081565b610e096134d5565b6001600160a01b03831660009081526004602052604090205460ff16610e30878483611704565b6040830181905215156000610e49898989888787611df3565b60208601919091529050610e61898989888588611c86565b6060860152608085015282610ec8576000610e8d85606001518660800151612bed90919063ffffffff16565b90508085604001511115610ec6576040850151600090610ead9083612c47565b6080870151909150610ebf9082612bed565b6080870152505b505b6000610ed68a8a8887611abf565b6080860151909150610ee89082612bed565b6080860181905260208601516060870151610f0e9291610f089190612bed565b90612bed565b861015610f4057610f3a8560200151610f34876060015189612c4790919063ffffffff16565b90612c47565b60808601525b5050505095945050505050565b60086020526000908152604090205481565b606081831015610ff957600083815260076020908152604080832085845282529182902080548351818402810184019094528084529091830182828015610fed57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610fb45790505b50505050509050611060565b600082815260076020908152604080832086845282529182902080548351818402810184019094528084529091830182828015610fed576000918252602091829020805461ffff168452908202830192909160029101808411610fb4579050505050505090505b92915050565b600a602052600090815260409020546001600160a01b031681565b61ffff8316600090815260016020818152604080842080548251600295821615610100026000190190911694909404601f810184900484028501840190925281845284939290919083018282801561111a5780601f106110ef5761010080835404028352916020019161111a565b820191906000526020600020905b8154815290600101906020018083116110fd57829003601f168201915b50505050509050838360405180838380828437808301925050509250505060405180910390208180519060200120149150505b9392505050565b670853a0d2313c000081565b611168612b53565b6001600160a01b03166111796119f6565b6001600160a01b0316146111c2576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b604080516342d65a8d60e01b815261ffff85166004820190815260248201928352604482018490526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016926342d65a8d92879287928792606401848480828437600081840152601f19601f820116905080830192505050945050505050600060405180830381600087803b15801561126157600080fd5b505af1158015610bd2573d6000803e3d6000fd5b66b1a2bc2ec5000081565b6601c6bf5263400081565b60096020908152600091825260409182902080548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452909183018282801561131e5780601f106112f35761010080835404028352916020019161131e565b820191906000526020600020905b81548152906001019060200180831161130157829003601f168201915b505050505081565b8181808214156113515760405162461bcd60e51b815260040161134890613ee5565b60405180910390fd5b600061135c85612ca4565b9050600061136985612ca4565b600087815260086020526040808220859055878252908190208290555190915086906000805160206141b4833981519152906113a690859061410b565b60405180910390a2846000805160206141b4833981519152826040516113cc919061410b565b60405180910390a260006113e08787610f5f565b905060008151116114035760405162461bcd60e51b815260040161134890613f51565b60008784888560405160200161141c9493929190614122565b604051602081830303815290604052905060005b825181101561152057600083828151811061144757fe5b602002602001015190506000600185510383146114645730611466565b335b61ffff831660009081526009602090815260408083208054825160026001831615610100026000190190921691909104601f81018590048502820185019093528281529495506115169487948a9488949193919083018282801561150b5780601f106114e05761010080835404028352916020019161150b565b820191906000526020600020905b8154815290600101906020018083116114ee57829003601f168201915b505050505047612dfd565b5050600101611430565b505050505050505050565b655af3107a400081565b61153d612b53565b6001600160a01b031661154e6119f6565b6001600160a01b031614611597576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b60009182526005602052604090912055565b6115b1612b53565b6001600160a01b03166115c26119f6565b6001600160a01b03161461160b576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b6000918252600a602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b611641612b53565b6001600160a01b03166116526119f6565b6001600160a01b03161461169b576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b565b60016020818152600092835260409283902080548451600294821615610100026000190190911693909304601f810183900483028401830190945283835291929083018282801561131e5780601f106112f35761010080835404028352916020019161131e565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663068bcd8d866040518263ffffffff1660e01b8152600401611753919061410b565b60206040518083038186803b15801561176b57600080fd5b505afa15801561177f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a391906136d5565b905060006117b0826130bf565b90506000826001600160a01b03166315770f926040518163ffffffff1660e01b815260040160206040518083038186803b1580156117ed57600080fd5b505afa158015611801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118259190613a4b565b90506000836001600160a01b0316639bb811196040518163ffffffff1660e01b815260040160206040518083038186803b15801561186257600080fd5b505afa158015611876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189a9190613a4b565b90508282116118b057600094505050505061114d565b60006118bc8385612c47565b905060006118dc826118d685670de0b6b3a7640000613221565b9061327a565b9050660221b262dd800081111580156118f3575087155b15611907576000965050505050505061114d565b600061191f670de0b6b3a76400006118d68c85613221565b905083811161192e5780611930565b835b9b9a5050505050505050505050565b651b48eb57e00081565b611951612b53565b6001600160a01b03166119626119f6565b6001600160a01b0316146119ab576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b60009182526006602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b600260209081526000928352604080842090915290825290205481565b6000546001600160a01b031690565b670de0b6b3a764000081565b6003546001600160a01b031681565b611a28612b53565b6001600160a01b0316611a396119f6565b6001600160a01b031614611a82576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b600082815260086020526040908190208290555182906000805160206141b483398151915290611ab390849061410b565b60405180910390a25050565b600083851415611ad157506000611b87565b6000858152600860205260408082205486835290822054909180611af584846132e1565b9250509150801580611b1257506000826002811115611b1057fe5b145b15611b24576000945050505050611b87565b6002826002811115611b3257fe5b1415611b505760405162461bcd60e51b815260040161134890613fbf565b8515611b63576000945050505050611b87565b6000611b73846118d68a88613221565b9050611b7f8882612c47565b955050505050505b949350505050565b60046020526000908152604090205460ff1681565b611bac612b53565b6001600160a01b0316611bbd6119f6565b6001600160a01b031614611c06576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b838380821415611c285760405162461bcd60e51b815260040161134890613ee5565b84861015611c5a5760008681526007602090815260408083208884529091529020611c5490858561350b565b50611c7e565b60008581526007602090815260408083208984529091529020610bd290858561350b565b505050505050565b6000808215611c9a57506000905080611dd2565b6000878914611cb0576603328b944c4000611cb9565b6601c6bf526340005b905085896000611cd988610f34670de0b6b3a76400006118d68789613221565b90506000611cf9670de0b6b3a76400006118d686655af3107a4000613221565b6000848152600a60205260409020549091506001600160a01b03168015611dc857600084815260056020526040808220549051631526fe2760e01b81528392916001600160a01b03841691631526fe2791611d569160040161410b565b60806040518083038186803b158015611d6e57600080fd5b505afa158015611d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da69190613729565b50509150506000811115611dc557611dbe8585612bed565b9450600093505b50505b5090955093505050505b965096945050505050565b660221b262dd800081565b660e35fa931a000081565b6000808315611e0757506000905080611dd2565b60405163068bcd8d60e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063068bcd8d90611e56908c9060040161410b565b60206040518083038186803b158015611e6e57600080fd5b505afa158015611e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea691906136d5565b6001600160a01b031663159f6add888a6040518363ffffffff1660e01b8152600401611ed39291906140f7565b6101006040518083038186803b158015611eec57600080fd5b505afa158015611f00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f249190613767565b60e081015160808201519192509087811015611f525760405162461bcd60e51b815260040161134890613f88565b6000611f5e828a612c47565b90506000611f80670de0b6b3a76400006118d686670853a0d2313c0000613221565b90506000611fa1670de0b6b3a76400006118d68766b1a2bc2ec50000613221565b90506000808c848610611fda57611fca670de0b6b3a76400006118d683651b48eb57e000613221565b92508b611fd5578291505b612095565b838610612012576000858810611ff05785611ff2565b875b905061200a660e35fa931a000060008888858c613335565b935050612095565b83871061206f576000858810612028578561202a565b875b905061204c612045660e35fa931a000060008989868b613335565b8590612bed565b935061200a612045670dd280b9144a0000660e35fa931a00008860008a8d613335565b86612091612045670dd280b9144a0000660e35fa931a0000886000868d613335565b9350505b50909f909e509c50505050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008282808214156120f35760405162461bcd60e51b815260040161134890613ee5565b60008581526008602052604080822054868352908220549091808061211885856132e1565b92509250925060006121298b612ca4565b905060006121368b612ca4565b9050600080600061214785856132e1565b92509250925082600281111561215957fe5b88600281111561216557fe5b1461217d5760019c5050505050505050505050612222565b600083600281111561218b57fe5b14156121a45760009c5050505050505050505050612222565b801515861515146121c25760019c5050505050505050505050612222565b60028360028111156121d057fe5b14156121e95760009c5050505050505050505050612222565b6000878311612201576121fc8884612c47565b61220b565b61220b8389612c47565b655af3107a400011159d5050505050505050505050505b505092915050565b612232612b53565b6001600160a01b03166122436119f6565b6001600160a01b03161461228c576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b600380546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b9181900360200190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b61230c612b53565b6001600160a01b031661231d6119f6565b6001600160a01b031614612366576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cbed8b9c86868686866040518663ffffffff1660e01b8152600401808661ffff1681526020018561ffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b15801561241857600080fd5b505af1158015611520573d6000803e3d6000fd5b612434612b53565b6001600160a01b03166124456119f6565b6001600160a01b03161461248e576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b6001600160a01b03919091166000908152600460205260409020805460ff1916911515919091179055565b60008282808214156124dd5760405162461bcd60e51b815260040161134890613ee5565b6000806124ea8787610f5f565b9050600081511161250d5760405162461bcd60e51b815260040161134890613f51565b60008760008860006040516020016125289493929190614122565b604051602081830303815290604052905060005b825181101561262f57600083828151811061255357fe5b60209081029190910181015161ffff8116600090815260099092526040808320905163040a7bb160e41b81529193506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916340a7bb10916125c791869130918a91889160040161403a565b604080518083038186803b1580156125de57600080fd5b505afa1580156125f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126169190613aa8565b5090506126238682612bed565b9550505060010161253c565b5091979650505050505050565b66038d7ea4c6800081565b61264f612b53565b6001600160a01b03166126606119f6565b6001600160a01b0316146126a9576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b600081116126f6576040805162461bcd60e51b81526020600482015260156024820152744c7a4170703a20696e76616c6964206d696e47617360581b604482015290519081900360640190fd5b61ffff808416600081815260026020908152604080832094871680845294825291829020859055815192835282019290925280820183905290517f9d5c7c0b934da8fefa9c7760c98383778a12dfbfc0c3b3106518f43fb9508ac09181900360600190a1505050565b612767612b53565b6001600160a01b03166127786119f6565b6001600160a01b0316146127c1576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b61ffff831660009081526001602052604090206127df9083836135b8565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab838383604051808461ffff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b612859612b53565b6001600160a01b031661286a6119f6565b6001600160a01b0316146128b3576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b6001600160a01b0381166128f85760405162461bcd60e51b815260040180806020018281038252602681526020018061418e6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60408051633d7b2f6f60e21b815261ffff8087166004830152851660248201523060448201526064810183905290516060916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163f5ecbdbc91608480820192600092909190829003018186803b1580156129d657600080fd5b505afa1580156129ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015612a1357600080fd5b8101908080516040519392919084640100000000821115612a3357600080fd5b908301906020820185811115612a4857600080fd5b8251640100000000811182820188101715612a6257600080fd5b82525081516020918201929091019080838360005b83811015612a8f578181015183820152602001612a77565b50505050905090810190601f168015612abc5780820380516001836020036101000a031916815260200191505b506040525050509050949350505050565b612ad5612b53565b6001600160a01b0316612ae66119f6565b6001600160a01b031614612b2f576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b61ffff83166000908152600960205260409020612b4d9083836135b8565b50505050565b3390565b60008060008084806020019051810190612b719190613cc6565b60008481526008602052604080822085905583825290819020829055519397509195509350915084906000805160206141b483398151915290612bb590869061410b565b60405180910390a2816000805160206141b483398151915282604051612bdb919061410b565b60405180910390a25050505050505050565b60008282018381101561114d576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115612c9e576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000818152600660205260408120546001600160a01b031680612cd95760405162461bcd60e51b815260040161134890613f1a565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612d1457600080fd5b505afa158015612d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4c9190613d4a565b90506000826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015612d8957600080fd5b505afa158015612d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc19190613cfb565b5050509150506000811215612de85760405162461bcd60e51b815260040161134890613eae565b612df281836133d6565b93505050505b919050565b61ffff8616600090815260016020818152604080842080548251600295821615610100026000190190911694909404601f810184900484028501840190925281845291830182828015612e915780601f10612e6657610100808354040283529160200191612e91565b820191906000526020600020905b815481529060010190602001808311612e7457829003601f168201915b50505050509050805160001415612ed95760405162461bcd60e51b81526004018080602001828103825260308152602001806141d46030913960400191505060405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c58031008389848a8a8a8a6040518863ffffffff1660e01b8152600401808761ffff1681526020018060200180602001866001600160a01b03168152602001856001600160a01b0316815260200180602001848103845289818151815260200191508051906020019080838360005b83811015612f8b578181015183820152602001612f73565b50505050905090810190601f168015612fb85780820380516001836020036101000a031916815260200191505b5084810383528851815288516020918201918a019080838360005b83811015612feb578181015183820152602001612fd3565b50505050905090810190601f1680156130185780820380516001836020036101000a031916815260200191505b50848103825285518152855160209182019187019080838360005b8381101561304b578181015183820152602001613033565b50505050905090810190601f1680156130785780820380516001836020036101000a031916815260200191505b5099505050505050505050506000604051808303818588803b15801561309d57600080fd5b505af11580156130b1573d6000803e3d6000fd5b505050505050505050505050565b6000611060826001600160a01b031663feb56b156040518163ffffffff1660e01b815260040160206040518083038186803b1580156130fd57600080fd5b505afa158015613111573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131359190613a4b565b836001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561316e57600080fd5b505afa158015613182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a691906136d5565b6001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016131d19190613db6565b60206040518083038186803b1580156131e957600080fd5b505afa1580156131fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d69190613a4b565b60008261323057506000611060565b8282028284828161323d57fe5b041461114d5760405162461bcd60e51b81526004018080602001828103825260218152602001806142046021913960400191505060405180910390fd5b60008082116132d0576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816132d957fe5b049392505050565b60008060008060006132f3878761341e565b91509150600066038d7ea4c68000831161330f57506000613329565b66354a6ba7a18000831061332557506002613329565b5060015b97919650945092505050565b60008382101580156133475750848311155b6133635760405162461bcd60e51b815260040161134890613e30565b600061336f8686612c47565b9050600061338f88610f08846118d68d6133898d8c612c47565b90613221565b905060006133a989610f08856118d68e6133898e8c612c47565b905060006133b78787612c47565b9050611930670de0b6b3a76400006118d6600281856133898989612bed565b600060ff8216600814156133eb575081611060565b60006133f8836008613489565b9050600860ff8416106134145761340f848261327a565b611b87565b611b878482613221565b6000808284111561344e57613443846118d6670de0b6b3a76400006133898388612c47565b600091509150613482565b8284141561346157506000905080613482565b61347b836118d6670de0b6b3a76400006133898389612c47565b6001915091505b9250929050565b6000808260ff168460ff16116134a1578383036134a5565b8284035b60ff16905060148111156134cb5760405162461bcd60e51b815260040161134890613e65565b600a0a9392505050565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b82805482825590600052602060002090600f016010900481019282156135a85791602002820160005b8382111561357857833561ffff1683826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302613534565b80156135a65782816101000a81549061ffff0219169055600201602081600101049283019260010302613578565b505b506135b4929150613634565b5090565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826135ee57600085556135a8565b82601f106136075782800160ff198235161785556135a8565b828001600101855582156135a8579182015b828111156135a8578235825591602001919060010190613619565b5b808211156135b45760008155600101613635565b8051612df88161416f565b60008083601f840112613665578182fd5b50813567ffffffffffffffff81111561367c578182fd5b60208301915083602082850101111561348257600080fd5b8051612df88161417d565b805169ffffffffffffffffffff81168114612df857600080fd5b6000602082840312156136ca578081fd5b813561114d81614157565b6000602082840312156136e6578081fd5b815161114d81614157565b60008060408385031215613703578081fd5b823561370e81614157565b9150602083013561371e8161416f565b809150509250929050565b6000806000806080858703121561373e578182fd5b845161374981614157565b60208601516040870151606090970151919890975090945092505050565b600061010080838503121561377a578182fd5b6040519081019067ffffffffffffffff8211818310171561379757fe5b816040526137a484613649565b81526137b260208501613694565b602082015260408401516040820152606084015160608201526080840151608082015260a084015160a082015260c084015160c082015260e084015160e0820152809250505092915050565b60006020828403121561380f578081fd5b813561114d8161417d565b60008060006040848603121561382e578283fd5b83356138398161417d565b9250602084013567ffffffffffffffff811115613854578283fd5b61386086828701613654565b9497909650939450505050565b60008060008060008060808789031215613885578182fd5b86356138908161417d565b9550602087013567ffffffffffffffff808211156138ac578384fd5b6138b88a838b01613654565b90975095506040890135915080821682146138d1578384fd5b909350606088013590808211156138e6578384fd5b506138f389828a01613654565b979a9699509497509295939492505050565b60008060408385031215613917578182fd5b82356139228161417d565b9150602083013561371e8161417d565b60008060008060808587031215613947578182fd5b84356139528161417d565b935060208501356139628161417d565b9250604085013561397281614157565b9396929550929360600135925050565b600080600060608486031215613996578081fd5b83356139a18161417d565b925060208401356139b18161417d565b929592945050506040919091013590565b6000806000806000608086880312156139d9578283fd5b85356139e48161417d565b945060208601356139f48161417d565b935060408601359250606086013567ffffffffffffffff811115613a16578182fd5b613a2288828901613654565b969995985093965092949392505050565b600060208284031215613a44578081fd5b5035919050565b600060208284031215613a5c578081fd5b5051919050565b60008060408385031215613a75578182fd5b82359150602083013561371e81614157565b60008060408385031215613a99578182fd5b50508035926020909101359150565b60008060408385031215613aba578182fd5b505080516020909101519092909150565b60008060008060608587031215613ae0578182fd5b8435935060208501359250604085013567ffffffffffffffff80821115613b05578384fd5b818701915087601f830112613b18578384fd5b813581811115613b26578485fd5b8860208083028501011115613b39578485fd5b95989497505060200194505050565b600080600060608486031215613b5c578081fd5b83359250602084013591506040840135613b758161416f565b809150509250925092565b600080600080600060a08688031215613b97578283fd5b85359450602086013593506040860135613bb08161417d565b92506060860135613bc081614157565b949793965091946080013592915050565b60008060008060008060c08789031215613be9578384fd5b86359550602087013594506040870135613c028161417d565b9350606087013592506080870135613c198161416f565b915060a0870135613c298161416f565b809150509295509295509295565b60008060008060008060c08789031215613c4f578384fd5b86359550602087013594506040870135613c688161417d565b9350606087013592506080870135915060a0870135613c298161416f565b60008060008060808587031215613c9b578182fd5b8435935060208501359250604085013591506060850135613cbb8161416f565b939692955090935050565b60008060008060808587031215613cdb578182fd5b505082516020840151604085015160609095015191969095509092509050565b600080600080600060a08688031215613d12578283fd5b613d1b8661369f565b9450602086015193506040860151925060608601519150613d3e6080870161369f565b90509295509295909350565b600060208284031215613d5b578081fd5b815160ff8116811461114d578182fd5b60008151808452815b81811015613d9057602081850181015186830182015201613d74565b81811115613da15782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b81811015613e0657835161ffff1683529284019291840191600101613de6565b50909695505050505050565b901515815260200190565b60006020825261114d6020830184613d6b565b6020808252818101527f4665654c6962726172793a2062616c616e6365206f7574206f6620626f756e64604082015260600190565b60208082526029908201527f4665654c6962726172793a2064696666206f6620646563696d616c7320697320604082015268746f6f206c6172676560b81b606082015260800190565b6020808252601d908201527f4665654c6962726172793a207072696365206973206e65676174697665000000604082015260600190565b6020808252818101527f4665654c6962726172793a205f706f6f6c496431203d3d205f706f6f6c496432604082015260600190565b6020808252601e908201527f4665654c6962726172793a2070726963652066656564206e6f74207365740000604082015260600190565b6020808252601d908201527f4665654c6962726172793a20696e76616c696420706f6f6c2070616972000000604082015260600190565b6020808252601e908201527f4665654c6962726172793a206e6f7420656e6f7567682062616c616e63650000604082015260600190565b6020808252601c908201527f4665654c6962726172793a205f737263506f6f6c496420646570656700000000604082015260600190565b600060c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b600061ffff87168252602060018060a01b0387168184015260a0604084015261406660a0840187613d6b565b8515156060850152838103608085015282855460018082166000811461409357600181146140b0576140e6565b60028304607f16855260ff198316868601526040850193506140e6565b600283048086526140c08a61414b565b885b828110156140dd5781548882018a01529084019088016140c2565b87018801955050505b50919b9a5050505050505050505050565b61ffff929092168252602082015260400190565b90815260200190565b918252602082015260400190565b93845260208401929092526040830152606082015260800190565b60ff91909116815260200190565b60009081526020902090565b6001600160a01b038116811461416c57600080fd5b50565b801515811461416c57600080fd5b61ffff8116811461416c57600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373945c1c4e99aa89f648fbfe3df471b916f719e16d960fcec0737d4d56bd6968384c7a4170703a2064657374696e6174696f6e20636861696e206973206e6f742061207472757374656420736f75726365536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65724c7a4170703a20696e76616c696420736f757263652073656e64696e6720636f6e7472616374a26469706673582212200f9b52a5b9dcaae24f01cbc396fd17443442d70eec34a8d83fa292da242607f664736f6c63430007060033000000000000000000000000af54be5b6eec24d6bfacf1cce4eaf680a8239398000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7

Deployed Bytecode

0x6080604052600436106103535760003560e01c80637ba5c12f116101c6578063ad7bbfc9116100f7578063d2f68aec11610095578063eb8d72b71161006f578063eb8d72b714610935578063f2fde38b14610955578063f5ecbdbc14610975578063fc6834a1146109955761035a565b8063d2f68aec146108e0578063d7f6bde314610900578063df2a5b3b146109155761035a565b8063baf3292d116100d1578063baf3292d1461086b578063c45a01551461088b578063cbed8b9c146108a0578063d16baeb9146108c05761035a565b8063ad7bbfc914610816578063b353aaa714610836578063b7f5ada31461084b5761035a565b806396e03bf3116101645780639c2f2e251161013e5780639c2f2e251461079e5780639fb2663a146107be578063a1498635146107ec578063a810de6c146108015761035a565b806396e03bf31461073e578063972883c41461075e5780639b19251a1461077e5761035a565b80638cfd8f5c116101a05780638cfd8f5c146106df5780638da5cb5b146106ff578063918f867414610714578063950c8a74146107295761035a565b80637ba5c12f146106aa5780637f1c8bb7146106bf57806380651ee2146106005761035a565b80633c2c3065116102a05780635a208ba31161023e5780636ddc4561116102185780636ddc456114610635578063715018a6146106555780637533d7881461066a5780637b35c2601461068a5761035a565b80635a208ba3146105ed5780635e3f2727146106005780636548c4ac146106155761035a565b806342d65a8d1161027a57806342d65a8d14610583578063518a9f9f146105a357806352863703146105b857806358cbb8ed146105cd5761035a565b80633c2c3065146105215780633d8b38f6146105415780633dad0dd51461056e5761035a565b80630d8e6e2c1161030d5780631738fe38116102e75780631738fe38146104925780631ab62430146104a757806323daf69c146104d457806326cfac66146104f45761035a565b80630d8e6e2c1461043057806310ddb1371461045257806313c6e380146104725761035a565b80621d35671461035f578063012a1c2d14610381578063040d5835146103ac57806307e0db17146103ce578063084285da146103ee5780630b4501fd1461041b5761035a565b3661035a57005b600080fd5b34801561036b57600080fd5b5061037f61037a36600461386d565b6109b5565b005b34801561038d57600080fd5b50610396610bdb565b6040516103a3919061410b565b60405180910390f35b3480156103b857600080fd5b506103c1610be7565b6040516103a3919061413d565b3480156103da57600080fd5b5061037f6103e93660046137fe565b610bec565b3480156103fa57600080fd5b5061040e610409366004613a33565b610cd3565b6040516103a39190613db6565b34801561042757600080fd5b50610396610cee565b34801561043c57600080fd5b50610445610cf9565b6040516103a39190613e1d565b34801561045e57600080fd5b5061037f61046d3660046137fe565b610d18565b34801561047e57600080fd5b5061039661048d366004613a33565b610de4565b34801561049e57600080fd5b50610396610df6565b3480156104b357600080fd5b506104c76104c2366004613b80565b610e01565b6040516103a39190613ff6565b3480156104e057600080fd5b506103966104ef366004613a33565b610f4d565b34801561050057600080fd5b5061051461050f366004613a87565b610f5f565b6040516103a39190613dca565b34801561052d57600080fd5b5061040e61053c366004613a33565b611066565b34801561054d57600080fd5b5061056161055c36600461381a565b611081565b6040516103a39190613e12565b34801561057a57600080fd5b50610396611154565b34801561058f57600080fd5b5061037f61059e36600461381a565b611160565b3480156105af57600080fd5b50610396611275565b3480156105c457600080fd5b50610396611280565b3480156105d957600080fd5b506104456105e83660046137fe565b61128b565b61037f6105fb366004613a87565b611326565b34801561060c57600080fd5b5061039661152b565b34801561062157600080fd5b5061037f610630366004613a87565b611535565b34801561064157600080fd5b5061037f610650366004613a63565b6115a9565b34801561066157600080fd5b5061037f611639565b34801561067657600080fd5b506104456106853660046137fe565b61169d565b34801561069657600080fd5b506103966106a5366004613b48565b611704565b3480156106b657600080fd5b5061039661193f565b3480156106cb57600080fd5b5061037f6106da366004613a63565b611949565b3480156106eb57600080fd5b506103966106fa366004613905565b6119d9565b34801561070b57600080fd5b5061040e6119f6565b34801561072057600080fd5b50610396611a05565b34801561073557600080fd5b5061040e611a11565b34801561074a57600080fd5b5061037f610759366004613a87565b611a20565b34801561076a57600080fd5b50610396610779366004613c86565b611abf565b34801561078a57600080fd5b506105616107993660046136b9565b611b8f565b3480156107aa57600080fd5b5061037f6107b9366004613acb565b611ba4565b3480156107ca57600080fd5b506107de6107d9366004613c37565b611c86565b6040516103a3929190614114565b3480156107f857600080fd5b50610396611ddd565b34801561080d57600080fd5b50610396611de8565b34801561082257600080fd5b506107de610831366004613bd1565b611df3565b34801561084257600080fd5b5061040e6120ab565b34801561085757600080fd5b50610561610866366004613a87565b6120cf565b34801561087757600080fd5b5061037f6108863660046136b9565b61222a565b34801561089757600080fd5b5061040e6122e0565b3480156108ac57600080fd5b5061037f6108bb3660046139c2565b612304565b3480156108cc57600080fd5b5061037f6108db3660046136f1565b61242c565b3480156108ec57600080fd5b506103966108fb366004613a87565b6124b9565b34801561090c57600080fd5b5061039661263c565b34801561092157600080fd5b5061037f610930366004613982565b612647565b34801561094157600080fd5b5061037f61095036600461381a565b61275f565b34801561096157600080fd5b5061037f6109703660046136b9565b612851565b34801561098157600080fd5b50610445610990366004613932565b612953565b3480156109a157600080fd5b5061037f6109b036600461381a565b612acd565b7f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b03166109e7612b53565b6001600160a01b031614610a42576040805162461bcd60e51b815260206004820152601e60248201527f4c7a4170703a20696e76616c696420656e64706f696e742063616c6c65720000604482015290519081900360640190fd5b61ffff8616600090815260016020818152604080842080548251600295821615610100026000190190911694909404601f810184900484028501840190925281845291830182828015610ad65780601f10610aab57610100808354040283529160200191610ad6565b820191906000526020600020905b815481529060010190602001808311610ab957829003601f168201915b50505050509050805186869050148015610af1575060008151115b8015610b215750808051906020012086866040518083838082843780830192505050925050506040518091039020145b610b5c5760405162461bcd60e51b81526004018080602001828103825260268152602001806142456026913960400191505060405180910390fd5b610bd28787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250612b5792505050565b50505050505050565b670dd280b9144a000081565b600881565b610bf4612b53565b6001600160a01b0316610c056119f6565b6001600160a01b031614610c4e576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b7f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b03166307e0db17826040518263ffffffff1660e01b8152600401808261ffff168152602001915050600060405180830381600087803b158015610cb857600080fd5b505af1158015610ccc573d6000803e3d6000fd5b5050505050565b6006602052600090815260409020546001600160a01b031681565b6603328b944c400081565b6040805180820190915260058152640372e312e360dc1b602082015290565b610d20612b53565b6001600160a01b0316610d316119f6565b6001600160a01b031614610d7a576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b7f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b03166310ddb137826040518263ffffffff1660e01b8152600401808261ffff168152602001915050600060405180830381600087803b158015610cb857600080fd5b60056020526000908152604090205481565b66354a6ba7a1800081565b610e096134d5565b6001600160a01b03831660009081526004602052604090205460ff16610e30878483611704565b6040830181905215156000610e49898989888787611df3565b60208601919091529050610e61898989888588611c86565b6060860152608085015282610ec8576000610e8d85606001518660800151612bed90919063ffffffff16565b90508085604001511115610ec6576040850151600090610ead9083612c47565b6080870151909150610ebf9082612bed565b6080870152505b505b6000610ed68a8a8887611abf565b6080860151909150610ee89082612bed565b6080860181905260208601516060870151610f0e9291610f089190612bed565b90612bed565b861015610f4057610f3a8560200151610f34876060015189612c4790919063ffffffff16565b90612c47565b60808601525b5050505095945050505050565b60086020526000908152604090205481565b606081831015610ff957600083815260076020908152604080832085845282529182902080548351818402810184019094528084529091830182828015610fed57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610fb45790505b50505050509050611060565b600082815260076020908152604080832086845282529182902080548351818402810184019094528084529091830182828015610fed576000918252602091829020805461ffff168452908202830192909160029101808411610fb4579050505050505090505b92915050565b600a602052600090815260409020546001600160a01b031681565b61ffff8316600090815260016020818152604080842080548251600295821615610100026000190190911694909404601f810184900484028501840190925281845284939290919083018282801561111a5780601f106110ef5761010080835404028352916020019161111a565b820191906000526020600020905b8154815290600101906020018083116110fd57829003601f168201915b50505050509050838360405180838380828437808301925050509250505060405180910390208180519060200120149150505b9392505050565b670853a0d2313c000081565b611168612b53565b6001600160a01b03166111796119f6565b6001600160a01b0316146111c2576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b604080516342d65a8d60e01b815261ffff85166004820190815260248201928352604482018490526001600160a01b037f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd716926342d65a8d92879287928792606401848480828437600081840152601f19601f820116905080830192505050945050505050600060405180830381600087803b15801561126157600080fd5b505af1158015610bd2573d6000803e3d6000fd5b66b1a2bc2ec5000081565b6601c6bf5263400081565b60096020908152600091825260409182902080548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452909183018282801561131e5780601f106112f35761010080835404028352916020019161131e565b820191906000526020600020905b81548152906001019060200180831161130157829003601f168201915b505050505081565b8181808214156113515760405162461bcd60e51b815260040161134890613ee5565b60405180910390fd5b600061135c85612ca4565b9050600061136985612ca4565b600087815260086020526040808220859055878252908190208290555190915086906000805160206141b4833981519152906113a690859061410b565b60405180910390a2846000805160206141b4833981519152826040516113cc919061410b565b60405180910390a260006113e08787610f5f565b905060008151116114035760405162461bcd60e51b815260040161134890613f51565b60008784888560405160200161141c9493929190614122565b604051602081830303815290604052905060005b825181101561152057600083828151811061144757fe5b602002602001015190506000600185510383146114645730611466565b335b61ffff831660009081526009602090815260408083208054825160026001831615610100026000190190921691909104601f81018590048502820185019093528281529495506115169487948a9488949193919083018282801561150b5780601f106114e05761010080835404028352916020019161150b565b820191906000526020600020905b8154815290600101906020018083116114ee57829003601f168201915b505050505047612dfd565b5050600101611430565b505050505050505050565b655af3107a400081565b61153d612b53565b6001600160a01b031661154e6119f6565b6001600160a01b031614611597576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b60009182526005602052604090912055565b6115b1612b53565b6001600160a01b03166115c26119f6565b6001600160a01b03161461160b576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b6000918252600a602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b611641612b53565b6001600160a01b03166116526119f6565b6001600160a01b03161461169b576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b565b60016020818152600092835260409283902080548451600294821615610100026000190190911693909304601f810183900483028401830190945283835291929083018282801561131e5780601f106112f35761010080835404028352916020019161131e565b6000807f000000000000000000000000af54be5b6eec24d6bfacf1cce4eaf680a82393986001600160a01b031663068bcd8d866040518263ffffffff1660e01b8152600401611753919061410b565b60206040518083038186803b15801561176b57600080fd5b505afa15801561177f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117a391906136d5565b905060006117b0826130bf565b90506000826001600160a01b03166315770f926040518163ffffffff1660e01b815260040160206040518083038186803b1580156117ed57600080fd5b505afa158015611801573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118259190613a4b565b90506000836001600160a01b0316639bb811196040518163ffffffff1660e01b815260040160206040518083038186803b15801561186257600080fd5b505afa158015611876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189a9190613a4b565b90508282116118b057600094505050505061114d565b60006118bc8385612c47565b905060006118dc826118d685670de0b6b3a7640000613221565b9061327a565b9050660221b262dd800081111580156118f3575087155b15611907576000965050505050505061114d565b600061191f670de0b6b3a76400006118d68c85613221565b905083811161192e5780611930565b835b9b9a5050505050505050505050565b651b48eb57e00081565b611951612b53565b6001600160a01b03166119626119f6565b6001600160a01b0316146119ab576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b60009182526006602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b600260209081526000928352604080842090915290825290205481565b6000546001600160a01b031690565b670de0b6b3a764000081565b6003546001600160a01b031681565b611a28612b53565b6001600160a01b0316611a396119f6565b6001600160a01b031614611a82576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b600082815260086020526040908190208290555182906000805160206141b483398151915290611ab390849061410b565b60405180910390a25050565b600083851415611ad157506000611b87565b6000858152600860205260408082205486835290822054909180611af584846132e1565b9250509150801580611b1257506000826002811115611b1057fe5b145b15611b24576000945050505050611b87565b6002826002811115611b3257fe5b1415611b505760405162461bcd60e51b815260040161134890613fbf565b8515611b63576000945050505050611b87565b6000611b73846118d68a88613221565b9050611b7f8882612c47565b955050505050505b949350505050565b60046020526000908152604090205460ff1681565b611bac612b53565b6001600160a01b0316611bbd6119f6565b6001600160a01b031614611c06576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b838380821415611c285760405162461bcd60e51b815260040161134890613ee5565b84861015611c5a5760008681526007602090815260408083208884529091529020611c5490858561350b565b50611c7e565b60008581526007602090815260408083208984529091529020610bd290858561350b565b505050505050565b6000808215611c9a57506000905080611dd2565b6000878914611cb0576603328b944c4000611cb9565b6601c6bf526340005b905085896000611cd988610f34670de0b6b3a76400006118d68789613221565b90506000611cf9670de0b6b3a76400006118d686655af3107a4000613221565b6000848152600a60205260409020549091506001600160a01b03168015611dc857600084815260056020526040808220549051631526fe2760e01b81528392916001600160a01b03841691631526fe2791611d569160040161410b565b60806040518083038186803b158015611d6e57600080fd5b505afa158015611d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da69190613729565b50509150506000811115611dc557611dbe8585612bed565b9450600093505b50505b5090955093505050505b965096945050505050565b660221b262dd800081565b660e35fa931a000081565b6000808315611e0757506000905080611dd2565b60405163068bcd8d60e01b81526000906001600160a01b037f000000000000000000000000af54be5b6eec24d6bfacf1cce4eaf680a8239398169063068bcd8d90611e56908c9060040161410b565b60206040518083038186803b158015611e6e57600080fd5b505afa158015611e82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea691906136d5565b6001600160a01b031663159f6add888a6040518363ffffffff1660e01b8152600401611ed39291906140f7565b6101006040518083038186803b158015611eec57600080fd5b505afa158015611f00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f249190613767565b60e081015160808201519192509087811015611f525760405162461bcd60e51b815260040161134890613f88565b6000611f5e828a612c47565b90506000611f80670de0b6b3a76400006118d686670853a0d2313c0000613221565b90506000611fa1670de0b6b3a76400006118d68766b1a2bc2ec50000613221565b90506000808c848610611fda57611fca670de0b6b3a76400006118d683651b48eb57e000613221565b92508b611fd5578291505b612095565b838610612012576000858810611ff05785611ff2565b875b905061200a660e35fa931a000060008888858c613335565b935050612095565b83871061206f576000858810612028578561202a565b875b905061204c612045660e35fa931a000060008989868b613335565b8590612bed565b935061200a612045670dd280b9144a0000660e35fa931a00008860008a8d613335565b86612091612045670dd280b9144a0000660e35fa931a0000886000868d613335565b9350505b50909f909e509c50505050505050505050505050565b7f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd781565b60008282808214156120f35760405162461bcd60e51b815260040161134890613ee5565b60008581526008602052604080822054868352908220549091808061211885856132e1565b92509250925060006121298b612ca4565b905060006121368b612ca4565b9050600080600061214785856132e1565b92509250925082600281111561215957fe5b88600281111561216557fe5b1461217d5760019c5050505050505050505050612222565b600083600281111561218b57fe5b14156121a45760009c5050505050505050505050612222565b801515861515146121c25760019c5050505050505050505050612222565b60028360028111156121d057fe5b14156121e95760009c5050505050505050505050612222565b6000878311612201576121fc8884612c47565b61220b565b61220b8389612c47565b655af3107a400011159d5050505050505050505050505b505092915050565b612232612b53565b6001600160a01b03166122436119f6565b6001600160a01b03161461228c576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b600380546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b9181900360200190a150565b7f000000000000000000000000af54be5b6eec24d6bfacf1cce4eaf680a823939881565b61230c612b53565b6001600160a01b031661231d6119f6565b6001600160a01b031614612366576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b7f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b031663cbed8b9c86868686866040518663ffffffff1660e01b8152600401808661ffff1681526020018561ffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b15801561241857600080fd5b505af1158015611520573d6000803e3d6000fd5b612434612b53565b6001600160a01b03166124456119f6565b6001600160a01b03161461248e576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b6001600160a01b03919091166000908152600460205260409020805460ff1916911515919091179055565b60008282808214156124dd5760405162461bcd60e51b815260040161134890613ee5565b6000806124ea8787610f5f565b9050600081511161250d5760405162461bcd60e51b815260040161134890613f51565b60008760008860006040516020016125289493929190614122565b604051602081830303815290604052905060005b825181101561262f57600083828151811061255357fe5b60209081029190910181015161ffff8116600090815260099092526040808320905163040a7bb160e41b81529193506001600160a01b037f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd716916340a7bb10916125c791869130918a91889160040161403a565b604080518083038186803b1580156125de57600080fd5b505afa1580156125f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126169190613aa8565b5090506126238682612bed565b9550505060010161253c565b5091979650505050505050565b66038d7ea4c6800081565b61264f612b53565b6001600160a01b03166126606119f6565b6001600160a01b0316146126a9576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b600081116126f6576040805162461bcd60e51b81526020600482015260156024820152744c7a4170703a20696e76616c6964206d696e47617360581b604482015290519081900360640190fd5b61ffff808416600081815260026020908152604080832094871680845294825291829020859055815192835282019290925280820183905290517f9d5c7c0b934da8fefa9c7760c98383778a12dfbfc0c3b3106518f43fb9508ac09181900360600190a1505050565b612767612b53565b6001600160a01b03166127786119f6565b6001600160a01b0316146127c1576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b61ffff831660009081526001602052604090206127df9083836135b8565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab838383604051808461ffff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a1505050565b612859612b53565b6001600160a01b031661286a6119f6565b6001600160a01b0316146128b3576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b6001600160a01b0381166128f85760405162461bcd60e51b815260040180806020018281038252602681526020018061418e6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60408051633d7b2f6f60e21b815261ffff8087166004830152851660248201523060448201526064810183905290516060916001600160a01b037f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7169163f5ecbdbc91608480820192600092909190829003018186803b1580156129d657600080fd5b505afa1580156129ea573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015612a1357600080fd5b8101908080516040519392919084640100000000821115612a3357600080fd5b908301906020820185811115612a4857600080fd5b8251640100000000811182820188101715612a6257600080fd5b82525081516020918201929091019080838360005b83811015612a8f578181015183820152602001612a77565b50505050905090810190601f168015612abc5780820380516001836020036101000a031916815260200191505b506040525050509050949350505050565b612ad5612b53565b6001600160a01b0316612ae66119f6565b6001600160a01b031614612b2f576040805162461bcd60e51b81526020600482018190526024820152600080516020614225833981519152604482015290519081900360640190fd5b61ffff83166000908152600960205260409020612b4d9083836135b8565b50505050565b3390565b60008060008084806020019051810190612b719190613cc6565b60008481526008602052604080822085905583825290819020829055519397509195509350915084906000805160206141b483398151915290612bb590869061410b565b60405180910390a2816000805160206141b483398151915282604051612bdb919061410b565b60405180910390a25050505050505050565b60008282018381101561114d576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115612c9e576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000818152600660205260408120546001600160a01b031680612cd95760405162461bcd60e51b815260040161134890613f1a565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612d1457600080fd5b505afa158015612d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4c9190613d4a565b90506000826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a06040518083038186803b158015612d8957600080fd5b505afa158015612d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc19190613cfb565b5050509150506000811215612de85760405162461bcd60e51b815260040161134890613eae565b612df281836133d6565b93505050505b919050565b61ffff8616600090815260016020818152604080842080548251600295821615610100026000190190911694909404601f810184900484028501840190925281845291830182828015612e915780601f10612e6657610100808354040283529160200191612e91565b820191906000526020600020905b815481529060010190602001808311612e7457829003601f168201915b50505050509050805160001415612ed95760405162461bcd60e51b81526004018080602001828103825260308152602001806141d46030913960400191505060405180910390fd5b7f000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd76001600160a01b031663c58031008389848a8a8a8a6040518863ffffffff1660e01b8152600401808761ffff1681526020018060200180602001866001600160a01b03168152602001856001600160a01b0316815260200180602001848103845289818151815260200191508051906020019080838360005b83811015612f8b578181015183820152602001612f73565b50505050905090810190601f168015612fb85780820380516001836020036101000a031916815260200191505b5084810383528851815288516020918201918a019080838360005b83811015612feb578181015183820152602001612fd3565b50505050905090810190601f1680156130185780820380516001836020036101000a031916815260200191505b50848103825285518152855160209182019187019080838360005b8381101561304b578181015183820152602001613033565b50505050905090810190601f1680156130785780820380516001836020036101000a031916815260200191505b5099505050505050505050506000604051808303818588803b15801561309d57600080fd5b505af11580156130b1573d6000803e3d6000fd5b505050505050505050505050565b6000611060826001600160a01b031663feb56b156040518163ffffffff1660e01b815260040160206040518083038186803b1580156130fd57600080fd5b505afa158015613111573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131359190613a4b565b836001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561316e57600080fd5b505afa158015613182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a691906136d5565b6001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016131d19190613db6565b60206040518083038186803b1580156131e957600080fd5b505afa1580156131fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d69190613a4b565b60008261323057506000611060565b8282028284828161323d57fe5b041461114d5760405162461bcd60e51b81526004018080602001828103825260218152602001806142046021913960400191505060405180910390fd5b60008082116132d0576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816132d957fe5b049392505050565b60008060008060006132f3878761341e565b91509150600066038d7ea4c68000831161330f57506000613329565b66354a6ba7a18000831061332557506002613329565b5060015b97919650945092505050565b60008382101580156133475750848311155b6133635760405162461bcd60e51b815260040161134890613e30565b600061336f8686612c47565b9050600061338f88610f08846118d68d6133898d8c612c47565b90613221565b905060006133a989610f08856118d68e6133898e8c612c47565b905060006133b78787612c47565b9050611930670de0b6b3a76400006118d6600281856133898989612bed565b600060ff8216600814156133eb575081611060565b60006133f8836008613489565b9050600860ff8416106134145761340f848261327a565b611b87565b611b878482613221565b6000808284111561344e57613443846118d6670de0b6b3a76400006133898388612c47565b600091509150613482565b8284141561346157506000905080613482565b61347b836118d6670de0b6b3a76400006133898389612c47565b6001915091505b9250929050565b6000808260ff168460ff16116134a1578383036134a5565b8284035b60ff16905060148111156134cb5760405162461bcd60e51b815260040161134890613e65565b600a0a9392505050565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b82805482825590600052602060002090600f016010900481019282156135a85791602002820160005b8382111561357857833561ffff1683826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302613534565b80156135a65782816101000a81549061ffff0219169055600201602081600101049283019260010302613578565b505b506135b4929150613634565b5090565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826135ee57600085556135a8565b82601f106136075782800160ff198235161785556135a8565b828001600101855582156135a8579182015b828111156135a8578235825591602001919060010190613619565b5b808211156135b45760008155600101613635565b8051612df88161416f565b60008083601f840112613665578182fd5b50813567ffffffffffffffff81111561367c578182fd5b60208301915083602082850101111561348257600080fd5b8051612df88161417d565b805169ffffffffffffffffffff81168114612df857600080fd5b6000602082840312156136ca578081fd5b813561114d81614157565b6000602082840312156136e6578081fd5b815161114d81614157565b60008060408385031215613703578081fd5b823561370e81614157565b9150602083013561371e8161416f565b809150509250929050565b6000806000806080858703121561373e578182fd5b845161374981614157565b60208601516040870151606090970151919890975090945092505050565b600061010080838503121561377a578182fd5b6040519081019067ffffffffffffffff8211818310171561379757fe5b816040526137a484613649565b81526137b260208501613694565b602082015260408401516040820152606084015160608201526080840151608082015260a084015160a082015260c084015160c082015260e084015160e0820152809250505092915050565b60006020828403121561380f578081fd5b813561114d8161417d565b60008060006040848603121561382e578283fd5b83356138398161417d565b9250602084013567ffffffffffffffff811115613854578283fd5b61386086828701613654565b9497909650939450505050565b60008060008060008060808789031215613885578182fd5b86356138908161417d565b9550602087013567ffffffffffffffff808211156138ac578384fd5b6138b88a838b01613654565b90975095506040890135915080821682146138d1578384fd5b909350606088013590808211156138e6578384fd5b506138f389828a01613654565b979a9699509497509295939492505050565b60008060408385031215613917578182fd5b82356139228161417d565b9150602083013561371e8161417d565b60008060008060808587031215613947578182fd5b84356139528161417d565b935060208501356139628161417d565b9250604085013561397281614157565b9396929550929360600135925050565b600080600060608486031215613996578081fd5b83356139a18161417d565b925060208401356139b18161417d565b929592945050506040919091013590565b6000806000806000608086880312156139d9578283fd5b85356139e48161417d565b945060208601356139f48161417d565b935060408601359250606086013567ffffffffffffffff811115613a16578182fd5b613a2288828901613654565b969995985093965092949392505050565b600060208284031215613a44578081fd5b5035919050565b600060208284031215613a5c578081fd5b5051919050565b60008060408385031215613a75578182fd5b82359150602083013561371e81614157565b60008060408385031215613a99578182fd5b50508035926020909101359150565b60008060408385031215613aba578182fd5b505080516020909101519092909150565b60008060008060608587031215613ae0578182fd5b8435935060208501359250604085013567ffffffffffffffff80821115613b05578384fd5b818701915087601f830112613b18578384fd5b813581811115613b26578485fd5b8860208083028501011115613b39578485fd5b95989497505060200194505050565b600080600060608486031215613b5c578081fd5b83359250602084013591506040840135613b758161416f565b809150509250925092565b600080600080600060a08688031215613b97578283fd5b85359450602086013593506040860135613bb08161417d565b92506060860135613bc081614157565b949793965091946080013592915050565b60008060008060008060c08789031215613be9578384fd5b86359550602087013594506040870135613c028161417d565b9350606087013592506080870135613c198161416f565b915060a0870135613c298161416f565b809150509295509295509295565b60008060008060008060c08789031215613c4f578384fd5b86359550602087013594506040870135613c688161417d565b9350606087013592506080870135915060a0870135613c298161416f565b60008060008060808587031215613c9b578182fd5b8435935060208501359250604085013591506060850135613cbb8161416f565b939692955090935050565b60008060008060808587031215613cdb578182fd5b505082516020840151604085015160609095015191969095509092509050565b600080600080600060a08688031215613d12578283fd5b613d1b8661369f565b9450602086015193506040860151925060608601519150613d3e6080870161369f565b90509295509295909350565b600060208284031215613d5b578081fd5b815160ff8116811461114d578182fd5b60008151808452815b81811015613d9057602081850181015186830182015201613d74565b81811115613da15782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b81811015613e0657835161ffff1683529284019291840191600101613de6565b50909695505050505050565b901515815260200190565b60006020825261114d6020830184613d6b565b6020808252818101527f4665654c6962726172793a2062616c616e6365206f7574206f6620626f756e64604082015260600190565b60208082526029908201527f4665654c6962726172793a2064696666206f6620646563696d616c7320697320604082015268746f6f206c6172676560b81b606082015260800190565b6020808252601d908201527f4665654c6962726172793a207072696365206973206e65676174697665000000604082015260600190565b6020808252818101527f4665654c6962726172793a205f706f6f6c496431203d3d205f706f6f6c496432604082015260600190565b6020808252601e908201527f4665654c6962726172793a2070726963652066656564206e6f74207365740000604082015260600190565b6020808252601d908201527f4665654c6962726172793a20696e76616c696420706f6f6c2070616972000000604082015260600190565b6020808252601e908201527f4665654c6962726172793a206e6f7420656e6f7567682062616c616e63650000604082015260600190565b6020808252601c908201527f4665654c6962726172793a205f737263506f6f6c496420646570656700000000604082015260600190565b600060c082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b600061ffff87168252602060018060a01b0387168184015260a0604084015261406660a0840187613d6b565b8515156060850152838103608085015282855460018082166000811461409357600181146140b0576140e6565b60028304607f16855260ff198316868601526040850193506140e6565b600283048086526140c08a61414b565b885b828110156140dd5781548882018a01529084019088016140c2565b87018801955050505b50919b9a5050505050505050505050565b61ffff929092168252602082015260400190565b90815260200190565b918252602082015260400190565b93845260208401929092526040830152606082015260800190565b60ff91909116815260200190565b60009081526020902090565b6001600160a01b038116811461416c57600080fd5b50565b801515811461416c57600080fd5b61ffff8116811461416c57600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373945c1c4e99aa89f648fbfe3df471b916f719e16d960fcec0737d4d56bd6968384c7a4170703a2064657374696e6174696f6e20636861696e206973206e6f742061207472757374656420736f75726365536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65724c7a4170703a20696e76616c696420736f757263652073656e64696e6720636f6e7472616374a26469706673582212200f9b52a5b9dcaae24f01cbc396fd17443442d70eec34a8d83fa292da242607f664736f6c63430007060033

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

000000000000000000000000af54be5b6eec24d6bfacf1cce4eaf680a8239398000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7

-----Decoded View---------------
Arg [0] : _factory (address): 0xAF54BE5B6eEc24d6BFACf1cce4eaF680A8239398
Arg [1] : _endpoint (address): 0xb6319cC6c8c27A8F5dAF0dD3DF91EA35C4720dd7

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000af54be5b6eec24d6bfacf1cce4eaf680a8239398
Arg [1] : 000000000000000000000000b6319cc6c8c27a8f5daf0dd3df91ea35c4720dd7


Block Transaction Gas Used Reward
view all blocks sequenced

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

Validator Index Block Amount
View All Withdrawals

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

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