false
true
0

Contract Address Details

0xF5D0140B4d53c9476DC1488BC6d8597d7393f074

Token
Degen Protocol GOAT (GOAT)
Creator
0x907adc–a27cfa at 0x26de6b–a288c5
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
16,755 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26317884
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
GoatToken




Optimization enabled
false
Compiler version
v0.8.17+commit.8df45f5f




EVM Version
default




Verified at
2023-10-17T00:20:54.520564Z

Constructor Arguments

0x000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27

Arg [0] (address) : 0xa1077a294dde1b09bb078844df40758a5d0f9a27

              

GoatToken.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IWPLS.sol";

import "./SafeERC20.sol";

import "./ReentrancyGuard.sol";

contract GoatToken is IERC20, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    IERC20 public immutable WPLS;
    IWPLS public immutable WRAP;

    // token data
    string private constant _name = "Degen Protocol GOAT";
    string private constant _symbol = "GOAT";
    uint8 private constant _decimals = 18;
    uint256 private constant precision = 10**18;

    uint256  private _total_users;
    uint256  private _total_txs;
    uint256 private _totalSupply;

    // storage
    struct User {
        uint256 lastEntryPrice; // Ratio at time of last deposit
        uint256 deposited;  // Deposited WPLS, from minting
        uint256 withdrawn;  // Withdrawn WPLS, from redemptions
    }

    // balances
    mapping (address => User) private _stats;
    mapping (address => uint8) private _users;
    mapping (address => uint256) private _balances;
    mapping (address => mapping (address => uint256)) private _allowances;

    
    // 5% mint and redeem Fees
    uint256 public mintFee = 95000;            
    uint256 public sellFee = 95000;            
    uint256 private constant feeDenominator = 10**5;

    // Events
    
    event Burn(address from, uint256 amountBurned);
    event GarbageCollected(uint256 amountBurned);
    
    event Minted(address recipient, uint256 amountTKN);
    event Redeemed(address seller, uint256 amountTKN, uint256 amountBASE);
    event PriceChange(uint256 previousPrice, uint256 currentPrice, uint256 totalSupply);

    ////////////////////////////
    // CONSTRUCTOR & FALLBACK //
    ////////////////////////////

    constructor(address _base) {
        WPLS = IERC20(address(_base));
        WRAP = IWPLS(address(_base));
    }

    // WPLS sent to this contract gets converted into WPLS
    // Then, WPLS is deposited and token is returned to the sender
    receive () external payable {
        address sender = msg.sender;
        uint256 amount = msg.value;
        
        WRAP.deposit{value: amount}();

        _checkGarbageCollector(address(this));

        _mintWithBacking(amount, sender);
    }

    ////////////////////
    // VIEW FUNCTIONS //
    ////////////////////

    // Token Name
    function name() public pure override returns (string memory) {
        return _name;
    }

    // Token Ticker Symbol
    function symbol() public pure override returns (string memory) {
        return _symbol;
    }

    // Tokens decimals
    function decimals() public pure override returns (uint8) {
        return _decimals;
    }

    // Returns the total number of tokens in existence
    function totalSupply() external view override returns (uint256) { 
        return _totalSupply; 
    }

    // Returns the number of tokens owned by `account`
    function balanceOf(address account) public view override returns (uint256) { 
        return _balances[account]; 
    }

    // Returns the number of tokens `spender` can transfer from `holder`
    function allowance(address holder, address spender) external view override returns (uint256) { 
        return _allowances[holder][spender]; 
    }

    // Returns the amount of token given numtokens of WPLS; accounting for fees
    function estimateMinted(uint256 numTokens) public view returns (uint256) {
        uint balance = underlyingBalance();
        return _totalSupply == 0 ? numTokens.mul(mintFee).div(feeDenominator) : _totalSupply.mul(numTokens).div(balance).mul(mintFee).div(feeDenominator);
    }

    // Returns the amount of WPLS given numtokens of token
    function estimateRedeemed(uint256 numTokens) public view returns (uint256) {
        return amountOut(numTokens.mul(sellFee).div(feeDenominator));
    }

    // Amount Of Underlying To Receive For `numTokens` of token
    function amountOut(uint256 numTokens) public view returns (uint256) {
        return _calculatePrice().mul(numTokens).div(precision);
    }

    // Returns the value of `holder`'s holdings
    function getValueOfHoldings(address holder) public view returns(uint256) {
        return amountOut(_balances[holder]);
    }

    // Underlying WPLS balance
    function underlyingBalance() public view returns (uint256) {
        return WPLS.balanceOf(address(this));
    }

    // Price Of token in WPLS
    function calculatePrice() public view returns (uint256) {
        return _calculatePrice();
    }

    // Returns basic contract stats
    function getInfo() public view returns(uint256 users, uint256 txs, uint256 underlyingSupply, uint256 supply, uint256 price){
        users = _total_users;
        txs = _total_txs;
        underlyingSupply = underlyingBalance();
        supply = _totalSupply;
        price = _calculatePrice();
    }

    // Last price a user minted at
    function getLastEntryOf(address user) public view returns (uint256) {
        return _stats[user].lastEntryPrice;
    }

    // Total WPLS deposited
    function getDepositedOf(address user) public view returns (uint256) {
        return _stats[user].deposited;
    }

    // Total WPLS withdrawn
    function getWithdrawnOf(address user) public view returns (uint256) {
        return _stats[user].withdrawn;
    }

    // Calculate tokens required to redeem for exact WPLS amount
    function calculateTokensForExactWPLS(uint256 _amountOut) public view returns (uint256 _amountIn) {
        require(_amountOut > 0, "WPLS amount must be greater than 0");

        _amountIn = _amountOut.mul(precision).div(_calculatePrice()).mul(feeDenominator).div(sellFee);
    }

    /////////////////////
    // WRITE FUNCTIONS //
    /////////////////////

    // Mint token Tokens For `recipient` By Depositing WPLS Into The Contract
    function mintWithBacking(uint256 numTokens, address recipient) external nonReentrant returns (uint256) {
        _checkGarbageCollector(address(this));
        return _mintWithBacking(numTokens, recipient);
    }

    // Burns Sender's token Tokens and redeems their value in WPLS
    function redeem(uint256 tokenAmount) external nonReentrant returns (uint256) {
        return _sell(msg.sender, tokenAmount, msg.sender);
    }
    
    // Burns Sender's token Tokens and redeems their value in WPLS for `recipient`
    function redeemTo(uint256 tokenAmount, address recipient) external nonReentrant returns (uint256) {
        return _sell(msg.sender, tokenAmount, recipient);
    }
    
    // Allows A User To Erase Their Holdings From Supply - DOES NOT REDEEM UNDERLYING ASSET FOR USER
    function burn(uint256 amount) external nonReentrant {
        uint256 bal = _balances[msg.sender];
        require(bal >= amount && bal > 0, 'Zero Holdings');

        uint256 oldPrice = _calculatePrice();

        _burn(msg.sender, amount);
        _requirePriceRises(oldPrice);

        emit Burn(msg.sender, amount);
    }

    // Approves `spender` to transfer `amount` tokens from caller
    function approve(address spender, uint256 amount) public override returns (bool) {
        _allowances[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }
  
    // Transfer Function
    function transfer(address recipient, uint256 amount) external override nonReentrant returns (bool) {
        return _transferFrom(msg.sender, recipient, amount);
    }

    // Transfer Function
    function transferFrom(address sender, address recipient, uint256 amount) external override nonReentrant returns (bool) {
        _allowances[sender][msg.sender] = _allowances[sender][msg.sender].sub(amount, 'Insufficient Allowance');
        return _transferFrom(sender, recipient, amount);
    }

    ////////////////////////
    // INTERNAL FUNCTIONS //
    ////////////////////////

    // Internal Transfer
    function _transferFrom(address sender, address recipient, uint256 amount) internal returns (bool) {
        require(recipient != address(0) && sender != address(0), "Transfer To Zero");
        require(amount > 0, "Transfer Amt Zero");

        uint256 oldPrice = _calculatePrice();

        _balances[sender] = _balances[sender].sub(amount, "Insufficient Balance");
        _balances[recipient] = _balances[recipient].add(amount);

        _requirePriceRises(oldPrice);
        _total_txs += 1;

        emit Transfer(sender, recipient, amount);
        return true;
    }

    // Stake Tokens and Deposits token in Sender's Address, Must Have Prior Approval For WPLS
    function _mintWithBacking(uint256 amount, address recipient) internal returns (uint256) {
        uint256 userTokenBalance = WPLS.balanceOf(msg.sender);
        require(userTokenBalance > 0 && amount <= userTokenBalance, 'Insufficient Balance');

        uint256 oldPrice = _calculatePrice();
        uint256 amountUnderlying = underlyingBalance();
        uint256 received = _transferIn(amount);

        _stats[msg.sender].lastEntryPrice = oldPrice;
        _stats[msg.sender].deposited = _stats[msg.sender].deposited.add(amount);

        return _mintTo(recipient, received, amountUnderlying, oldPrice);
    }
    
    // Burns token Tokens And Deposits WPLS Tokens into Recipients's Address
    function _sell(address seller, uint256 tokenAmount, address recipient) internal returns (uint256) {
        require(tokenAmount > 0 && _balances[seller] >= tokenAmount);
        require(seller != address(0) && recipient != address(0));

        uint256 oldPrice = _calculatePrice();
        uint256 tokensToSwap = tokenAmount.mul(sellFee).div(feeDenominator);
        uint256 amountUnderlyingAsset = amountOut(tokensToSwap);

        _burn(seller, tokenAmount);

        require(WPLS.transfer(recipient, amountUnderlyingAsset), 'Underlying Transfer Failure');

        _requirePriceRises(oldPrice);
        _total_txs += 1;

        _stats[recipient].withdrawn = _stats[recipient].withdrawn.add(amountUnderlyingAsset);

        emit Redeemed(seller, tokenAmount, amountUnderlyingAsset);
        return amountUnderlyingAsset;
    }

    // Handles Minting Logic To Create New token
    function _mintTo(address recipient, uint256 received, uint256 totalBacking, uint256 oldPrice) private returns(uint256) {
        uint256 tokensToMintNoTax = _totalSupply == 0 ? received : _totalSupply.mul(received).div(totalBacking);
        uint256 tokensToMint = tokensToMintNoTax.mul(mintFee).div(feeDenominator);
        
        require(tokensToMint > 0, 'Zero Amount');

        _mint(recipient, tokensToMint);
        _requirePriceRises(oldPrice);

        _total_txs += 1;

        // differentiate purchase
        emit Minted(recipient, tokensToMint);
        return tokensToMint;
    }

    // Requires The Price Of token To Rise For The Transaction To Conclude
    function _requirePriceRises(uint256 oldPrice) internal {
        uint256 newPrice = _calculatePrice();
        require(newPrice >= oldPrice, 'Price Cannot Fall');
        emit PriceChange(oldPrice, newPrice, _totalSupply);
    }

    // Transfers `desiredAmount` of `token` in and verifies the transaction success
    function _transferIn(uint256 desiredAmount) internal returns (uint256) {
        uint256 balBefore = underlyingBalance();
        require(WPLS.transferFrom(msg.sender, address(this), desiredAmount), 'Failure Transfer From');
        uint256 balAfter = underlyingBalance();
        require(balAfter > balBefore, 'Zero Received');
        return balAfter - balBefore;
    }
    
    // Mints Tokens to the Receivers Address
    function _mint(address receiver, uint amount) private {

        if (_users[receiver] == 0){
            _users[receiver] = 1;
            _total_users += 1;
        }
        
        _balances[receiver] = _balances[receiver].add(amount);
        _totalSupply = _totalSupply.add(amount);
        emit Transfer(address(0), receiver, amount);
    }
    
    // Burns `amount` of tokens from `account`
    function _burn(address account, uint amount) private {
        _balances[account] = _balances[account].sub(amount, 'Insufficient Balance');
        _totalSupply = _totalSupply.sub(amount, 'Negative Supply');
        emit Transfer(account, address(0), amount);
    }

    // Make Sure there's no Native Tokens in contract
    function _checkGarbageCollector(address burnLocation) internal {
        uint256 bal = _balances[burnLocation];
        if (bal > 10**3) {
            uint256 oldPrice = _calculatePrice();
            _burn(burnLocation, bal);

            emit GarbageCollected(bal);
            emit PriceChange(oldPrice, _calculatePrice(), _totalSupply);
        }
    }

    // Returns the Current Price of 1 Token
    function _calculatePrice() internal view returns (uint256) {
        return _totalSupply == 0 ? 10**18 : (underlyingBalance().mul(precision)).div(_totalSupply);
    }
}
        

Migrations.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract Migrations {
  address public owner = msg.sender;
  uint public last_completed_migration;

  modifier restricted() {
    require(
      msg.sender == owner,
      "This function is restricted to the contract's owner"
    );
    _;
  }

  function setCompleted(uint completed) public restricted {
    last_completed_migration = completed;
  }
}
          

Ownable.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./Context.sol";

abstract contract Ownable is Context {

    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    modifier isRunning() {
        require(_paused == false, "Function unavailable because contract is paused");
        _;
    }

    bool private _paused;

    address private _owner;
    address private _previousOwner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event RunStatusUpdated(bool indexed paused);

    constructor() {
        address msgSender = _msgSender();
        _owner = msgSender;
        _paused = false;
        emit RunStatusUpdated(_paused);
        emit OwnershipTransferred(address(0), msgSender);
    }

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

    function isPaused() public view returns (bool) {
        return _paused;
    }

    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }

    function updateRunStatus(bool paused) public virtual onlyOwner {
        emit RunStatusUpdated(paused);
        _paused = paused;
    }
}
          

YieldEngine.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IGOAT.sol";
import "./IERC20.sol";
import "./ITreasury.sol";
import "./ISponsorData.sol";
import "./IYieldEngine.sol";
import "./IReferralData.sol";
import "./IReferralReport.sol";
import "./ISwapRouter02.sol";

import "./SafeMath.sol";
import "./TransferHelper.sol";

import "./Whitelist.sol";

contract YieldEngine is Whitelist, IYieldEngine {
    using SafeMath for uint256;

    IERC20 public immutable dai;
    IGOAT public immutable goat;

    address public WPLS;
    address public bufferPool;
    address public goatPen;

    bool public forceLiquidity = true;

    ISwapRouter02 public swapRouter;
    IReferralData public referralData;
    ISponsorData public sponsorData;

    event UpdateCollateralRouter(address indexed addr);
    event NewSponsorship(address indexed from, address indexed to, uint256 amount);

    event UpdateReferralData(address indexed addr);
    event UpdateSponsorData(address indexed addr);
    event UpdateForceLiquidity(bool value, bool new_value);

    event debugEvent(uint256 value0, uint256 value1);

    /* ========== INITIALIZER ========== */

    constructor(
        address _swapRouter,
        address _goat,
        address _dai,
        address _weth, 
        address _goatPen,
        address _bufferPool
    ) Ownable() {
        goat = IGOAT(_goat);
        dai = IERC20(_dai);

        swapRouter = ISwapRouter02(_swapRouter);
        goatPen = _goatPen;
        bufferPool = _bufferPool;

        WPLS = _weth;
    }

    //@dev Update the referral data for partner rewards
    function updateReferralData(address referralDataAddress) external onlyOwner {
        require(referralDataAddress != address(0), "Require valid non-zero addresses");
        referralData = IReferralData(referralDataAddress);
        emit UpdateReferralData(referralDataAddress);
    }

    //@dev Update the sponsor data used to distribute gifted / rewarded bonds
    function updateSponsorData(address sponsorDataAddress) external onlyOwner {
        require(sponsorDataAddress != address(0), "Require valid non-zero addresses");
        sponsorData = ISponsorData(sponsorDataAddress);
        emit UpdateSponsorData(sponsorDataAddress);
    }

    //@dev Forces the yield engine to topoff liquidity in the collateral buffer on every tx
    //a test harness
    function updateForceLiquidity(bool _force) external onlyOwner {
        emit UpdateForceLiquidity(forceLiquidity, _force);
        forceLiquidity = _force;
    }

    //@dev Update Core collateral liquidity can move from one contract location to another across major PCS releases
    function updateCollateralRouter(address _router) public onlyOwner {
        require(_router != address(0), "Router must be set");
        swapRouter = ISwapRouter02(_router);
        emit UpdateCollateralRouter(_router);
    }

    /********** Whitelisted Fuctions **************************************************/

    //@dev Claim and payout using the reserve
    //Sender must implement IReferralReport to succeed
    function sendPayoutTo(address _recipient, uint256 _daiAmountOut) external onlyWhitelisted returns (uint yieldAmount) {
        if (_daiAmountOut == 0) {
            return 0;
        }

        // CollateralBuffer should be large enough to support daily yield
        uint256 onePercentOfTheBufferPool = dai.balanceOf(bufferPool) / 100;

        // Debugging
        emit debugEvent(_daiAmountOut, onePercentOfTheBufferPool);

        //if yield is greater than 1% of the buffer pool, liquidate GOAT to DAI
        if (_daiAmountOut > onePercentOfTheBufferPool || forceLiquidity) {

            // 110% of the requested amount
            uint256 _thisMuch = (_daiAmountOut * 110 / 100);

            // Redeem GOAT and buy DAI for the buffer pool
            topUpBufferPool(_thisMuch);
            
            // The end user balance will only go down by the delivered amount, the buffer will never be overrun
            _daiAmountOut = _daiAmountOut.min(dai.balanceOf(bufferPool));  
        }

        //Calculate user referral rewards
        uint _referrals = _daiAmountOut / 100;
        
        //Add referral bonus for referrer, 1%
        processReferralBonus(_recipient, _referrals, msg.sender);

        // Send _daiAmountOut of DAI from the buffer pool to the _recipient
        ITreasury(bufferPool).withdrawTo(_recipient, _daiAmountOut); 
            
        return _daiAmountOut;
    }

    /********** Internal Fuctions **************************************************/

    //@dev Add referral bonus if applicable
    function processReferralBonus(address _user, uint256 _amount, address referral_report) private {
        address _referrer = referralData.referrerOf(_user);

        //Need to have an upline
        if (_referrer == address(0)) {
            return;
        }

        //partners split 50/50
        uint256 _share = _amount.div(2);

        //We operate side effect free and just add to pending sponsorships
        sponsorData.add(_referrer, _share);
        sponsorData.add(_user, _share);

        //Report the reward distribution to the caller
        IReferralReport report = IReferralReport(referral_report);
        report.reward_distribution(_referrer, _user, _share, _share);

        emit NewSponsorship(_user, _referrer, _share);
        emit NewSponsorship(_referrer, _user, _share);
    }

    //@dev release GOAT from the GOAT Pen and swap the resulting WPLS for DAI, into the Buffer Pool
    function topUpBufferPool(uint256 _thisMuch) private {
    
        // Path for WPLS to DAI
        address[] memory WPLSToDAIPath = new address[](2);
        WPLSToDAIPath[0] = WPLS;
        WPLSToDAIPath[1] = address(dai);

        // Path for DAI to WPLS
        address[] memory daiToWPLSPath = new address[](2);
        daiToWPLSPath[0] = address(dai);
        daiToWPLSPath[1] = WPLS;

        // Step 1: Find out how much WPLS is required to get _thisMuch DAI
        uint256[] memory amounts = swapRouter.getAmountsOut(_thisMuch, daiToWPLSPath);

        // Step 2: Calculate how many GOAT tokens are needed to redeem, to receive that amount of WPLS

        // Get the last element which is the WPLS amount
        uint256 wplsAmount = amounts[1];

        // Calculate the GOAT amount needed to redeem.
        uint256 goatAmount = goat.calculateTokensForExactWPLS(wplsAmount);

        // Step 3: Withdraw required GOAT from GOAT Treasury
        ITreasury(goatPen).withdrawTo(address(this), goatAmount);

        // Step 4: Redeem required GOAT
        uint256 wplsFromRedeemingGOAT = goat.redeem(goatAmount);
        
        // Step 5: Approve WPLS to swap
        TransferHelper.safeApprove(WPLS, address(swapRouter), wplsFromRedeemingGOAT, 'approve');

        // Swap WPLS for DAI
        swapRouter.swapExactTokensForTokens(wplsFromRedeemingGOAT, 0, WPLSToDAIPath, bufferPool, block.timestamp);
    }
}
          

SignedMath.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

library SignedMath {
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    function average(int256 a, int256 b) internal pure returns (int256) {
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            return uint256(n >= 0 ? n : -n);
        }
    }
}
          

Address.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

library Address {
    function isContract(address account) internal view returns (bool) {
        uint256 size;
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            if (returndata.length > 0) {
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}
          

IGOAT.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IERC20.sol";

interface IGOAT is IERC20 {
    function mintWithBacking(uint256 numTokens, address recipient) external returns (uint256);
    function redeem(uint256 tokenAmount) external returns (uint256);
    function redeemTo(uint256 tokenAmount, address recipient) external returns (uint256);
    
    function calculateTokensForExactWPLS(uint256 amount) external view returns (uint256);

    function estimateMinted(uint256 numTokens) external view returns (uint256);
    function estimateRedeemed(uint256 numTokens) external view returns (uint256);

    function getValueOfHoldings(address holder) external view returns(uint256);
}
          

ERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IERC20.sol";

import "./SafeMath.sol";

import "./Context.sol";

contract ERC20 is Context, IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    constructor (string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _decimals = 18;
    }

    function name() public view virtual returns (string memory) {
        return _name;
    }

    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    function decimals() public view virtual returns (uint8) {
        return _decimals;
    }

    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

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

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

    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function _setupDecimals(uint8 decimals_) internal virtual {
        _decimals = decimals_;
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
          

Strings.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./Math.sol";
import "./SignedMath.sol";

library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}
          

GoatFeeder.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IGOAT.sol";
import "./IERC20.sol";
import "./ITreasury.sol";
import "./ISponsorData.sol";
import "./IYieldEngine.sol";
import "./IReferralReport.sol";
import "./ISwapRouter02.sol";

import "./SafeMath.sol";

import "./Whitelist.sol";
import "./TransferHelper.sol";
import "./ReentrancyGuard.sol";



struct FuturesUser {
    bool exists; // has the user joined
    uint deposits; // total inbound deposits
    uint compound_deposits; // compound deposit; not fresh capital 
    uint current_balance; // current balance
    uint payouts;  // total yield payouts across all farms
    uint rewards; // partner rewards
    uint last_time; // last interaction
}

struct FuturesGlobals {
    uint256  total_users;
    uint256  total_deposited;
    uint256  total_compound_deposited;
    uint256  total_claimed;
    uint256  total_rewards;
    uint256  total_txs;
    uint256  current_balance;
}

contract FuturesVault is Whitelist {
    mapping(address => FuturesUser) private users; //Asset -> User

    FuturesGlobals private globals;

    mapping (address => Sponsorship) private sponsorships;

    constructor() Ownable() {}

    //@dev Get User info
    function getUser(address _user) external view returns (FuturesUser memory) {
        return users[_user];
    }

    //@dev Get FuturesGlobal info
    function getGlobals() external view returns (FuturesGlobals memory) {
        return globals;
    }

    //@dev Get Sponsorship info
    function getSponsorship(address _user) external view returns (Sponsorship memory) {
        return sponsorships[_user];
    }

    //@dev commit User Info
    function commitUser(address _user, FuturesUser memory _user_data)  onlyWhitelisted isRunning external {
        users[_user].exists = _user_data.exists; 
        users[_user].deposits = _user_data.deposits; 
        users[_user].compound_deposits = _user_data.compound_deposits;  
        users[_user].current_balance = _user_data.current_balance; 
        users[_user].payouts = _user_data.payouts;  
        users[_user].rewards = _user_data.rewards; 
        users[_user].last_time = _user_data.last_time;
    }

    //@dev commit Globals Info
    function commitGlobals(FuturesGlobals memory _globals) onlyWhitelisted isRunning external {
        globals.total_users = _globals.total_users;
        globals.total_deposited = _globals.total_deposited;
        globals.total_compound_deposited = _globals.total_compound_deposited;
        globals.total_claimed = _globals.total_claimed;
        globals.total_rewards = _globals.total_rewards;
        globals.total_txs = _globals.total_txs;
        globals.current_balance = _globals.current_balance ;
    }
}

contract FuturesEngine is Ownable, IReferralReport {
    using SafeMath for uint256;

    //Financial Model
    uint256 public constant referenceApr = 182.5e18; //0.5% daily
    uint256 public constant maxBalance = 1000000e18; //1M
    uint256 public constant minimumDeposit = 200e18; //200+ deposits; will compound available rewards
    uint256 public constant maxAvailable = 50000e18; //50K max claim daily, 10 days missed claims 
    uint256 public constant maxPayouts = (maxBalance * 5e18) / 2e18; //2.5M

    
    //Immutable long term network contracts
    ISwapRouter02 public immutable swapRouter;
    ITreasury public immutable bufferPool;
    ITreasury public immutable goatPen;
    IERC20 public immutable dai;
    IGOAT public goat;
    
    //Updatable components
    IYieldEngine public yieldEngine;
    FuturesVault public vault;
    ISponsorData public sponsors;

    address public wpls;
    address[] public pathDaiToPls;

    bool public enforceMinimum = false;

    //events
    event Deposit(address indexed user, uint256 amount);
    event CompoundDeposit(address indexed user, uint256 amount);
    event Claim(address indexed user, uint256 amount);
    event Transfer(address indexed user, address indexed new_user, uint256 current_balance);
    event RewardDistribution(address referrer, address user, uint referrer_reward, uint user_reward);
    event UpdateYieldEngine(address prev_engine, address engine);
    event UpdateVault(address prev_vault, address vault);
    event UpdateEnforceMinimum(bool prev_value, bool value);

    constructor(
        address _router, 
        address _dai, 
        address _goatPen,
        address _bufferPool,
        address _sponsorData
    ) Ownable() {

        dai = IERC20(_dai);

        swapRouter = ISwapRouter02(_router);

        goatPen = ITreasury(_goatPen);
        bufferPool = ITreasury(_bufferPool);

        sponsors = ISponsorData(_sponsorData);
    }

    ////////////////////
    // View Functions //
    ////////////////////

    //@dev Returns tax bracket and adjusted amount based on the bracket 
    function available(address _user) public view returns (uint256 _limiterRate, uint256 _adjustedAmount) {

        //Load data
        FuturesUser memory userData = vault.getUser(_user);

        //calculate gross available
        uint256 share;

        if(userData.current_balance > 0) {
            //Using 1e18 we capture all significant digits when calculating available divs
            share = userData.current_balance //payout is asymptotic and uses the current balance
                    * referenceApr //convert to daily apr
                    / (365 * 100e18)
                    / 24 hours; //divide the profit by payout rate and seconds in the day;
            _adjustedAmount = share * block.timestamp.safeSub(userData.last_time);

            _adjustedAmount = maxAvailable.min(_adjustedAmount); //minimize red candles

        }

        //apply compound rate limiter
        uint256 _comp_surplus = userData.compound_deposits.safeSub(userData.deposits);

        if (_comp_surplus < 50000e18){
            _limiterRate = 0;
        } else if ( 50000e18 <= _comp_surplus && _comp_surplus < 250000e18 ){
            _limiterRate = 10;
        } else if ( 250000e18 <= _comp_surplus && _comp_surplus < 500000e18 ){
            _limiterRate = 15;
        } else if ( 500000e18 <= _comp_surplus && _comp_surplus < 750000e18 ){
            _limiterRate = 25;
        } else if ( 750000e18 <= _comp_surplus && _comp_surplus < 1000000e18 ){
            _limiterRate = 35;
        } else if (_comp_surplus >= 1000000e18 ){
            _limiterRate = 50;
        }

        _adjustedAmount = _adjustedAmount * (100 - _limiterRate) / 100;


        // payout greater than the balance just pay the balance
        if(_adjustedAmount > userData.current_balance) {
            _adjustedAmount = userData.current_balance;
        }

    }

    //@dev Get User info
    function getUser(address _user) external view returns (FuturesUser memory) {
        return vault.getUser(_user);
    }

    //@dev Get contract snapshot
    function getInfo() external view returns (FuturesGlobals memory) {
        return vault.getGlobals();
    }

    ////////////////////
    // User Functions //
    ////////////////////

    //@dev Deposit DAI
    function deposit(uint _amount) isRunning nonReentrant external {
        
        //Only the key holder can invest their funds
        address _user = msg.sender;

        FuturesUser memory userData = vault.getUser(_user);
        FuturesGlobals memory globalsData = vault.getGlobals();
        Sponsorship memory sponsorData = sponsors.getSponsorship(_user);
        
        require(_amount >= minimumDeposit || enforceMinimum == false, "amount less than minimum deposit");
        require(userData.current_balance + _amount <= maxBalance, "max balance exceeded" );
        require(userData.payouts <= maxPayouts, "max payouts exceeded");

        uint _share = _amount / 100;
        uint _daiToSwapForWplsSoWeCanMintGOAT; 
        uint _daiToPutInTheBufferPool;
        
        //90% goes directly to the treasury
        _daiToSwapForWplsSoWeCanMintGOAT = _share * 90;
        _daiToPutInTheBufferPool = _amount - _daiToSwapForWplsSoWeCanMintGOAT;

        //Transfer 10% to Bufferpool, 90% to this contract
        TransferHelper.safeTransferFrom(address(dai), _user, address(bufferPool), _daiToPutInTheBufferPool, 'Depot: deposit, transfer to buffer');
        TransferHelper.safeTransferFrom(address(dai), _user, address(this), _daiToSwapForWplsSoWeCanMintGOAT, 'Depot: deposit, transfer to buffer');

        // Approve swap router to spend this contract's DAI, and GOAT to spend WPLS
        TransferHelper.safeApprove(address(wpls), address(goat), type(uint256).max, "Deposit: Cannot approve");
        TransferHelper.safeApprove(address(dai), address(swapRouter), type(uint256).max, "Deposit: Cannot approve");

        // Swap 90% of DAI into WPLS via swap
        uint256[] memory amountsOut = swapRouter.swapExactTokensForTokens(_daiToSwapForWplsSoWeCanMintGOAT, 0, pathDaiToPls, address(this), block.timestamp + 3 minutes);

        // Mint GOAT with resulting amount of WPLS from swap, into the GOAT Pen
        goat.mintWithBacking(amountsOut[1], address(goatPen));

        //update user stats
        if (userData.exists == false) {

            //attempt to migrate user
            userData.exists = true;
            globalsData.total_users += 1;  

            //commit updates
            vault.commitUser(_user, userData);
            vault.commitGlobals(globalsData);
        }

        //if user has an existing balance see if we have to claim yield before proceeding
        //optimistically claim yield before reset
        //if there is a balance we potentially have yield
        if (userData.current_balance > 0){
            _compoundFor(_user);

            //reload user data after a mutable function
            userData = vault.getUser(_user); 
            globalsData = vault.getGlobals();
        }

        //If we have a pending sponsorship let's settle
        if (sponsorData.pending > 0) {
            _amount += sponsorData.pending; //add pending sponsorship
            sponsors.settle(_user);
        }

        //update user
        userData.deposits += _amount;
        userData.last_time = block.timestamp;
        userData.current_balance += _amount;

        globalsData.total_deposited += _amount; 
        globalsData.current_balance += _amount;
        globalsData.total_txs += 1;

        //commit updates
        vault.commitUser(_user, userData);
        vault.commitGlobals(globalsData);

        //events
        emit Deposit(_user, _amount);
    }

    //@dev Claims earned interest for the caller
    function claim() nonReentrant external returns (bool success){
        
        address _user = msg.sender; //Only the owner of funds can claim funds
        FuturesUser memory userData = vault.getUser(_user);

        //checks
        require(userData.exists, "User is not registered");
        require(userData.current_balance > 0, "balance is required to earn yield");

        success = _claimFor(_user);
    }

    //@dev Transfer account to another wallet address
    function transfer(address _newUser) nonReentrant external  {

        address _user = msg.sender;

        FuturesUser memory userData = vault.getUser(_user);
        FuturesUser memory newData =  vault.getUser(_newUser);
        FuturesGlobals memory globalsData = vault.getGlobals();

        //Only the owner can transfer
        require(userData.exists, "user must exists");
        require(newData.exists == false && _newUser != address(0), "new address must not exist");

        //Transfer
        newData.exists = true;
        newData.deposits = userData.deposits;
        newData.current_balance = userData.current_balance;
        newData.payouts = userData.payouts;
        newData.compound_deposits = userData.compound_deposits;
        newData.rewards = userData.rewards;
        newData.last_time = userData.last_time; 

        //Zero out old account
        userData.exists = true; //once an account is created source streams are only counted once
        userData.deposits = 0;
        userData.current_balance = 0;
        userData.compound_deposits = 0;
        userData.payouts = 0;
        userData.rewards = 0;
        userData.last_time = 0;

        //house keeping
        globalsData.total_txs += 1;

        //commit
        vault.commitUser(_user, userData);
        vault.commitUser(_newUser, newData);
        vault.commitGlobals(globalsData);

        //log
        emit Transfer(_user, _newUser, newData.current_balance);

    }

    //////////////////////////
    // RESTRICTED FUNCTIONS //
    //////////////////////////

    //@dev Implements the IReferralReport interface which is called by the FarmEngine yield function back to the caller
    function reward_distribution(address _referrer, address _user, uint _referrer_reward, uint _user_reward) external {
        
        //checks 
        require(msg.sender == address(yieldEngine), "caller must be registered yield engine");
        require(_referrer != address(0) && _user != address(0), "non-zero addresses required");

        //Load data
        FuturesUser memory userData = vault.getUser(_user);
        FuturesUser memory referrerData =  vault.getUser(_referrer);
        FuturesGlobals memory globalsData = vault.getGlobals();
         
        //track exclusive rewards which are paid out via Stampede airdrops
        referrerData.rewards += _referrer_reward;
        userData.rewards += _user_reward;

        //track total rewards
        globalsData.total_rewards += _referrer_reward + _user_reward;

        //commit updates
        vault.commitUser(_user, userData);
        vault.commitUser(_referrer, referrerData);
        vault.commitGlobals(globalsData);

        emit RewardDistribution(_referrer, _user, _referrer_reward, _user_reward);
    }

    /////////////////////
    // ADMIN FUNCTIONS //
    /////////////////////

    //@dev Set goat token
    function setGoat(address _goat) external onlyOwner {
        require(_goat != address(0), "goat must be non-zero");
        goat = IGOAT(_goat);
    }

    //@dev Set WPLS token
    function setWPLS(address _wpls) external onlyOwner {
        require(_wpls != address(0), "WPLS must be non-zero");
        wpls = _wpls;
    }

    //@dev Set swap path
    function setSwapPath(address[] memory path) external onlyOwner {
        pathDaiToPls = path;
    }

    //@dev Update enforce minimum
    function updateEnforceMinimum(bool _enforceMinimum) external onlyOwner {
        
        emit UpdateEnforceMinimum(enforceMinimum, _enforceMinimum);

        enforceMinimum = _enforceMinimum;
    }

    //@dev Update the FuturesVault
    function updateFuturesVault(address _vault) external onlyOwner {
        require(_vault != address(0), "vault must be non-zero");

        emit UpdateVault(address(vault), _vault);

        vault = FuturesVault(_vault);
    }

    //@dev Update the farm engine which is used for quotes, yield calculations / distribution
    function updateYieldEngine(address _engine) external onlyOwner {
        require(_engine != address(0), "engine must be non-zero");

        emit UpdateYieldEngine(address(yieldEngine), _engine);

        yieldEngine = IYieldEngine(_engine);
    }

    ////////////////////////
    // Internal Functions //
    ////////////////////////

    function _claimFor(address _recipient) private returns (bool success) {

        FuturesUser memory userData = vault.getUser(_recipient);
        FuturesGlobals memory globalsData = vault.getGlobals();
        
        //get available
        (, uint256 _daiAmountOut) = available(_recipient);

        // payout remaining allowable divs if exceeds
        if(userData.payouts + _daiAmountOut > maxPayouts) {
            _daiAmountOut = maxPayouts.safeSub(userData.payouts);
            _daiAmountOut = _daiAmountOut.min(userData.current_balance);  //withdraw up to the current balance
        }

        //attempt to payout yield and update stats;
        if (_daiAmountOut > 0) {

            //transfer amount to user; mutable
            _daiAmountOut = yieldEngine.sendPayoutTo(_recipient, _daiAmountOut);

            //reload data after a mutable function
            userData = vault.getUser(_recipient);
            globalsData = vault.getGlobals();
        
            if (_daiAmountOut > 0) { //second check with delivered yield
                //user stats
                userData.payouts += _daiAmountOut;
                userData.current_balance = userData.current_balance.safeSub(_daiAmountOut);
                userData.last_time = block.timestamp;

                //total stats
                globalsData.total_claimed += _daiAmountOut;
                globalsData.total_txs += 1;
                globalsData.current_balance = globalsData.current_balance.safeSub(_daiAmountOut);

                //commit updates
                vault.commitUser(_recipient, userData);
                vault.commitGlobals(globalsData);

                //log events
                emit Claim(_recipient, _daiAmountOut);

                return true;
            }
        } 

        //default
        return false;
    } 

    function _compoundFor(address _user) private returns (bool success) {

        FuturesUser memory userData = vault.getUser(_user);
        FuturesGlobals memory globalsData = vault.getGlobals();
        
        //get available
        ( , uint256 _amount) = available(_user);

        // payout remaining allowable divs if exceeds
        if(userData.payouts + _amount > maxPayouts) {
            _amount = maxPayouts.safeSub(userData.payouts);
        }

        //attempt to compound yield and update stats;
        if (_amount > 0) {

            //user stats
            userData.deposits += 0; //compounding is not a deposit; here for clarity
            userData.compound_deposits += _amount;
            userData.payouts += _amount;
            userData.current_balance += _amount; 
            userData.last_time = block.timestamp;

            //total stats
            globalsData.total_deposited += 0; //compounding  doesn't move the needle; here for clarity
            globalsData.total_compound_deposited += _amount;
            globalsData.total_claimed += _amount;
            globalsData.current_balance += _amount;
            globalsData.total_txs += 1;
            
            //commit updates
            vault.commitUser(_user, userData);
            vault.commitGlobals(globalsData);

            //log events
            emit Claim(_user, _amount);
            emit CompoundDeposit(_user, _amount);

            return true;

        } else {
            //do nothing upon failure
            return false;
        }
    }
}
          

SafeERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IERC20.sol";

import "./Address.sol";
import "./SafeMath.sol";

library SafeERC20 {
    using Address for address;
    using SafeMath for uint256;

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

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

    function safeApprove(IERC20 token, address spender, uint256 value) internal {        
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

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

Whitelist.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./Ownable.sol";

contract Whitelist is Ownable {
    mapping(address => bool) public whitelist;

    event WhitelistedAddressAdded(address addr);
    event WhitelistedAddressRemoved(address addr);

    modifier onlyWhitelisted() {
        require(whitelist[msg.sender], "not whitelisted");
        _;
    }

    function addAddressToWhitelist(address addr) public onlyOwner returns (bool success) {
        if (!whitelist[addr]) {
            whitelist[addr] = true;
            emit WhitelistedAddressAdded(addr);
            success = true;
        }
    }

    function addAddressesToWhitelist(address[] memory addrs) public onlyOwner returns (bool success) {
        for (uint256 i = 0; i < addrs.length; i++) {
            if (addAddressToWhitelist(addrs[i])) {
                success = true;
            }
        }
    }

    function removeAddressFromWhitelist(address addr) public onlyOwner returns (bool success) {
        if (whitelist[addr]) {
            whitelist[addr] = false;
            emit WhitelistedAddressRemoved(addr);
            success = true;
        }
    }

    function removeAddressesFromWhitelist(address[] memory addrs) public onlyOwner returns (bool success) {
        for (uint256 i = 0; i < addrs.length; i++) {
            if (removeAddressFromWhitelist(addrs[i])) {
                success = true;
            }
        }
    }
}
          

IReferralData.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IReferralData {
    function referrerOf(address participant) external view returns (address);
}
          

SponsorData.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./SafeMath.sol";

import "./Whitelist.sol";
import "./ReentrancyGuard.sol";

contract SponsorData is Whitelist {
    using SafeMath for uint256;

    struct Sponsorship {
        uint256 pending;
        uint256 total;
    }

    mapping(address => Sponsorship) public users;

    uint256 public total_sponsored;

    constructor() Ownable() {}

    function getSponsorship(address _user) external view returns (Sponsorship memory) {
        return users[_user];
    }

    function add(address _user, uint256 _amount) external onlyWhitelisted {
        users[_user].pending += _amount;
        users[_user].total += _amount;
        total_sponsored += _amount;
    }

    function settle(address _user) external onlyWhitelisted {
        users[_user].pending = 0;
    }
}
          

ISwapRouter02.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./ISwapRouter01.sol";

interface ISwapRouter02 is ISwapRouter01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns (uint amountETH);
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external;
}
          

FuturesVault.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./Whitelist.sol";

contract FuturesVault is Whitelist {

    struct FuturesUser {
        bool exists; // has the user joined
        uint deposits; // total inbound deposits
        uint compound_deposits; // compound deposit; not fresh capital 
        uint current_balance; // current balance
        uint payouts;  // total yield payouts across all farms
        uint rewards; // partner rewards
        uint last_time; // last interaction
    }

    struct FuturesGlobals {
        uint256  total_users;
        uint256  total_deposited;
        uint256  total_compound_deposited;
        uint256  total_claimed;
        uint256  total_rewards;
        uint256  total_txs;
        uint256  current_balance;
    }

    mapping(address => FuturesUser) private users; //Asset -> User

    FuturesGlobals private globals;

    constructor() Ownable() {}

    //@dev Get User info
    function getUser(address _user) external view returns (FuturesUser memory) {
        return users[_user];
    }

    //@dev Get FuturesGlobal info
    function getGlobals() external view returns (FuturesGlobals memory) {
        return globals;
    }

    //@dev commit User Info
    function commitUser(address _user, FuturesUser memory _user_data)  onlyWhitelisted isRunning external {
        users[_user].exists = _user_data.exists; 
        users[_user].deposits = _user_data.deposits; 
        users[_user].compound_deposits = _user_data.compound_deposits;  
        users[_user].current_balance = _user_data.current_balance; 
        users[_user].payouts = _user_data.payouts;  
        users[_user].rewards = _user_data.rewards; 
        users[_user].last_time = _user_data.last_time;
    }

    //@dev commit Globals Info
    function commitGlobals(FuturesGlobals memory _globals) onlyWhitelisted isRunning external {
        globals.total_users = _globals.total_users;
        globals.total_deposited = _globals.total_deposited;
        globals.total_compound_deposited = _globals.total_compound_deposited;
        globals.total_claimed = _globals.total_claimed;
        globals.total_rewards = _globals.total_rewards;
        globals.total_txs = _globals.total_txs;
        globals.current_balance = _globals.current_balance ;
    }
}
          

ISwapFactory.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface ISwapFactory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint) external view returns (address pair);
    function allPairsLength() external view returns (uint);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}
          

IYieldEngine.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IYieldEngine {
    function sendPayoutTo(address _user, uint256 _amount) external returns (uint256  yieldAmount);
}
          

ReentrancyGuard.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;
    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}
          

ReferralData.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract ReferralData {
    event onReferralUpdate(address indexed participant, address indexed referrer);

    mapping(address => address) private referrals;
    mapping(address => uint256) private refCounts;

    ///@dev Updated the referrer of the participant
    function updateReferral(address referrer) public {
        //non-zero, no self, no duplicate
        require(referrer != address(0) && referrer != msg.sender && referrals[msg.sender] != referrer, "INVALID ADDRESS");

        address prevReferrer = referrals[msg.sender];

        //decrement previous referrer
        if (prevReferrer != address(0)) {
            if (refCounts[prevReferrer] > 0) {
                refCounts[prevReferrer] = refCounts[prevReferrer] - 1;
            }
        }
        //increment new referrer
        refCounts[referrer] = refCounts[referrer] + 1;

        //update to new
        referrals[msg.sender] = referrer;
        emit onReferralUpdate(msg.sender, referrer);
    }

    ///@dev Return the referral of the sender
    function myReferrer() public view returns (address) {
        return referrerOf(msg.sender);
    }

    //@dev Return true if referrer of user is sender
    function isMyReferral(address _user) public view returns (bool) {
        return referrerOf(_user) == msg.sender;
    }

    //@dev Return true if user has a referrer
    function hasReferrer(address _user) public view returns (bool) {
        return referrerOf(_user) != address(0);
    }

    ///@dev Return the referral of a participant
    function referrerOf(address participant) public view returns (address) {
        return referrals[participant];
    }

    ///@dev Return the referral count of a participant
    function referralCountOf(address _user) public view returns (uint256) {
        return refCounts[_user];
    }
}
          

ITreasury.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface ITreasury {
    function getBalance() external view returns (uint256);

    function withdraw(uint256 tokenAmount) external;
    function withdrawTo(address _to, uint256 _amount) external;
}
          

IERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function symbol() external view returns(string memory);
    function name() external view returns(string memory);

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

    function decimals() external view returns (uint8);

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

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
          

TransferHelper.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IERC20.sol";

library TransferHelper {
    function safeTransferFrom(address token, address from, address to, uint256 value, string memory notes) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), string.concat('STF', notes));
    }

    function safeTransfer(address token, address to, uint256 value, string memory notes) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), string.concat('ST', notes));
    }

    function safeApprove(address token, address to, uint256 value, string memory notes) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), string.concat('SA', notes));
    }

    function safeTransferETH(address to, uint256 value, string memory notes) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, string.concat('STE', notes));
    }
}
          

Counters.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

library Counters {
    struct Counter {
        uint256 _value;
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}
          

ISwapRouter01.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface ISwapRouter01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
          

IWPLS.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IERC20.sol";

interface IWPLS is IERC20 {
    function deposit() external payable;
    function transfer(address to, uint256 value) external returns (bool);
    function withdraw(uint256) external;
}
          

SafeMath.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;
        return c;
    }

    function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b > a) {
            return 0;
        } else {
            return a - b;
        }
    }

    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;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }

    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}
          

Math.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }

    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}
          

Treasury.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/*
                                          ,ooooooooooo,
                                       ,;OOOOOOOOOOOOOOo,
                                    ,ooOOOOOOOOOOOOOOOOOo;,,,,
                                ,ooooOOOOOOOOOOOOOOOOOOOOooo(@`,
                     _  __   __;oooooo OOOOOOOOOOO; ;@@@@@@@o;@@`,
            _______/@@@@@@@@@)ooOOOOOO) oOOOOOOOOOo; ;o@@@@@o;@@@:
           /######)@@@@@@@@@@( _______ ( oOOOOOOOOOOo o@@@@@@`@@@`;
          <######)@@@@@@@@@@@@(######/  `,;;;  oOOOOOo @@@@@@o,\@@;
               `\@@@@@@@@@@@@(######/ oO (@@@@\ oOOOOO;@@@@@@@, \@`,
                ))@@@@@@@@@@(       oOOOo@@@@@@: ;;oo,`o@@@@@;   (@)
                )  `@@@@@@@( (  ooOOOOOoo:@@@@@: ,' /###o@@@@;
                ( (0)     (0) ) ooooooo /@@@@@/,`  :####o@@@@;
                 )           ( `'`'`'`'/@@@@@/     /###/:@@@@;
                  `,       ,'     /###/@@@@@/     :###; :@@@@@;
                    \_`_'_/      /###/@@@@/       :###; :@@@@@;
                     ~~~~~      ;###;@@@@/        :##;  `:@@@@;
                                ;###;@@@@;       /  /    :@@@;
                               /~~~~;@@@@;      `-^-'    /   \
                               `-^--;@@@@/               `-^--'
                                    :~~~~:
                                    \/\_/

        Degen Protocol GOAT
        Single Asset Silo - v1.0.0
*/

import "./IERC20.sol";

import "./Whitelist.sol";

contract Treasury is Whitelist {

    IERC20 public token;

    string public label;

    constructor(address token_addr, string memory _label) {
        token = IERC20(token_addr);
        label = _label;
    }

    function getBalance() external view returns (uint256) {
        return token.balanceOf(address(this));
    }

    function withdraw(uint256 _amount) external onlyWhitelisted {
        require(token.transfer(_msgSender(), _amount));
    }

    function withdrawTo(address _to, uint256 _amount) external onlyWhitelisted {
        require(token.transfer(_to, _amount));
    }
}
          

IWhitelist.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IWhitelist {
    function addAddressToWhitelist(address addr) external returns (bool success);
    function addAddressesToWhitelist(address[] memory addrs) external returns (bool success);
    function removeAddressFromWhitelist(address addr) external returns (bool success);
    function removeAddressesFromWhitelist(address[] memory addrs) external returns (bool success);
}
          

IReferralReport.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IReferralReport {
    function reward_distribution(address _referrer, address _user, uint _referrer_reward, uint _user_reward) external;
}
          

Context.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./ReentrancyGuard.sol";

abstract contract Context is ReentrancyGuard {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this;
        return msg.data;
    }
}
          

ISponsorData.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

struct Sponsorship {
    uint256 pending;
    uint256 total;
}

interface ISponsorData {
    function add(address _user, uint256 _amount) external;
    function settle(address _user) external;
    function getSponsorship(address _user) external view returns (Sponsorship memory);
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_base","internalType":"address"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Burn","inputs":[{"type":"address","name":"from","internalType":"address","indexed":false},{"type":"uint256","name":"amountBurned","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GarbageCollected","inputs":[{"type":"uint256","name":"amountBurned","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Minted","inputs":[{"type":"address","name":"recipient","internalType":"address","indexed":false},{"type":"uint256","name":"amountTKN","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PriceChange","inputs":[{"type":"uint256","name":"previousPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"currentPrice","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalSupply","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Redeemed","inputs":[{"type":"address","name":"seller","internalType":"address","indexed":false},{"type":"uint256","name":"amountTKN","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountBASE","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"WPLS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IWPLS"}],"name":"WRAP","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"holder","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"amountOut","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burn","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calculatePrice","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_amountIn","internalType":"uint256"}],"name":"calculateTokensForExactWPLS","inputs":[{"type":"uint256","name":"_amountOut","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"estimateMinted","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"estimateRedeemed","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getDepositedOf","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"users","internalType":"uint256"},{"type":"uint256","name":"txs","internalType":"uint256"},{"type":"uint256","name":"underlyingSupply","internalType":"uint256"},{"type":"uint256","name":"supply","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"}],"name":"getInfo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getLastEntryOf","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getValueOfHoldings","inputs":[{"type":"address","name":"holder","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getWithdrawnOf","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"mintFee","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"mintWithBacking","inputs":[{"type":"uint256","name":"numTokens","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"redeem","inputs":[{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"redeemTo","inputs":[{"type":"uint256","name":"tokenAmount","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"sellFee","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"underlyingBalance","inputs":[]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

Verify & Publish
0x60c060405262017318600855620173186009553480156200001f57600080fd5b50604051620033a5380380620033a5833981810160405281019062000045919062000126565b60016000819055508073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505062000158565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620000ee82620000c1565b9050919050565b6200010081620000e1565b81146200010c57600080fd5b50565b6000815190506200012081620000f5565b92915050565b6000602082840312156200013f576200013e620000bc565b5b60006200014f848285016200010f565b91505092915050565b60805160a051613204620001a1600039600081816101cb01526112370152600081816109240152818161107b01528181611628015281816118360152611ff601526132046000f3fe6080604052600436106101ba5760003560e01c80636ba56b38116100ec578063d348b4091161008a578063e8bba4f611610064578063e8bba4f614610758578063ec58890914610795578063ed13b253146107d2578063ef8ef56f1461080f5761025f565b8063d348b409146106b3578063db006a75146106de578063dd62ed3e1461071b5761025f565b80637314f109116100c65780637314f109146105d157806375fe9fba1461060e57806395d89b411461064b578063a9059cbb146106765761025f565b80636ba56b381461052c5780636cba38841461056957806370a08231146105945761025f565b80632b14ca561161015957806352c08bb41161013357806352c08bb41461045857806359356c5c146104955780635a9b0b89146104c05780636b014f83146104ef5761025f565b80632b14ca56146103d9578063313ce5671461040457806342966c681461042f5761025f565b806313966db51161019557806313966db51461030957806318160ddd146103345780631f02a29c1461035f57806323b872dd1461039c5761025f565b806246516b1461026457806306fdde03146102a1578063095ea7b3146102cc5761025f565b3661025f57600033905060003490507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561023157600080fd5b505af1158015610245573d6000803e3d6000fd5b50505050506102533061083a565b61025d818361091f565b005b600080fd5b34801561027057600080fd5b5061028b60048036038101906102869190612545565b610b2c565b604051610298919061258b565b60405180910390f35b3480156102ad57600080fd5b506102b6610b78565b6040516102c39190612636565b60405180910390f35b3480156102d857600080fd5b506102f360048036038101906102ee9190612684565b610bb5565b60405161030091906126df565b60405180910390f35b34801561031557600080fd5b5061031e610ca7565b60405161032b919061258b565b60405180910390f35b34801561034057600080fd5b50610349610cad565b604051610356919061258b565b60405180910390f35b34801561036b57600080fd5b5061038660048036038101906103819190612545565b610cb7565b604051610393919061258b565b60405180910390f35b3480156103a857600080fd5b506103c360048036038101906103be91906126fa565b610d08565b6040516103d091906126df565b60405180910390f35b3480156103e557600080fd5b506103ee610eb9565b6040516103fb919061258b565b60405180910390f35b34801561041057600080fd5b50610419610ebf565b6040516104269190612769565b60405180910390f35b34801561043b57600080fd5b5061045660048036038101906104519190612784565b610ec8565b005b34801561046457600080fd5b5061047f600480360381019061047a91906127b1565b61100d565b60405161048c919061258b565b60405180910390f35b3480156104a157600080fd5b506104aa611077565b6040516104b7919061258b565b60405180910390f35b3480156104cc57600080fd5b506104d5611118565b6040516104e69594939291906127f1565b60405180910390f35b3480156104fb57600080fd5b5061051660048036038101906105119190612784565b61114a565b604051610523919061258b565b60405180910390f35b34801561053857600080fd5b50610553600480360381019061054e9190612545565b6111e9565b604051610560919061258b565b60405180910390f35b34801561057557600080fd5b5061057e611235565b60405161058b91906128a3565b60405180910390f35b3480156105a057600080fd5b506105bb60048036038101906105b69190612545565b611259565b6040516105c8919061258b565b60405180910390f35b3480156105dd57600080fd5b506105f860048036038101906105f391906127b1565b6112a2565b604051610605919061258b565b60405180910390f35b34801561061a57600080fd5b5061063560048036038101906106309190612784565b611314565b604051610642919061258b565b60405180910390f35b34801561065757600080fd5b50610660611351565b60405161066d9190612636565b60405180910390f35b34801561068257600080fd5b5061069d60048036038101906106989190612684565b61138e565b6040516106aa91906126df565b60405180910390f35b3480156106bf57600080fd5b506106c86113f8565b6040516106d5919061258b565b60405180910390f35b3480156106ea57600080fd5b5061070560048036038101906107009190612784565b611407565b604051610712919061258b565b60405180910390f35b34801561072757600080fd5b50610742600480360381019061073d91906128be565b611470565b60405161074f919061258b565b60405180910390f35b34801561076457600080fd5b5061077f600480360381019061077a9190612545565b6114f7565b60405161078c919061258b565b60405180910390f35b3480156107a157600080fd5b506107bc60048036038101906107b79190612784565b611543565b6040516107c9919061258b565b60405180910390f35b3480156107de57600080fd5b506107f960048036038101906107f49190612784565b6115eb565b604051610806919061258b565b60405180910390f35b34801561081b57600080fd5b50610824611626565b604051610831919061291f565b60405180910390f35b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506103e881111561091b57600061089261164a565b905061089e838361169f565b7f8a1c945864c85a9dee42b8734075761f7a16095a8384ab751f2417c5767e227e826040516108cd919061258b565b60405180910390a17f046aa811b2923fd55b4ca06375b4045117d4584c66fc40880a8ab8ee32d88ed1816108ff61164a565b6003546040516109119392919061293a565b60405180910390a1505b5050565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b815260040161097b9190612980565b602060405180830381865afa158015610998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bc91906129b0565b90506000811180156109ce5750808411155b610a0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0490612a29565b60405180910390fd5b6000610a1761164a565b90506000610a23611077565b90506000610a3087611827565b905082600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550610ace87600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015461197690919063ffffffff16565b600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550610b20868284866119d4565b94505050505092915050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b60606040518060400160405280601381526020017f446567656e2050726f746f636f6c20474f415400000000000000000000000000815250905090565b600081600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610c95919061258b565b60405180910390a36001905092915050565b60085481565b6000600354905090565b6000610d01600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611314565b9050919050565b6000600260005403610d4f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d4690612a95565b60405180910390fd5b6002600081905550610e1d826040518060400160405280601681526020017f496e73756666696369656e7420416c6c6f77616e636500000000000000000000815250600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610ea8848484611b59565b905060016000819055509392505050565b60095481565b60006012905090565b600260005403610f0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0490612a95565b60405180910390fd5b60026000819055506000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110158015610f695750600081115b610fa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9f90612b01565b60405180910390fd5b6000610fb261164a565b9050610fbe338461169f565b610fc781611e47565b7fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca53384604051610ff8929190612b21565b60405180910390a15050600160008190555050565b6000600260005403611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161104b90612a95565b60405180910390fd5b6002600081905550611067338484611ed7565b9050600160008190555092915050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016110d29190612980565b602060405180830381865afa1580156110ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111391906129b0565b905090565b600080600080600060015494506002549350611132611077565b9250600354915061114161164a565b90509091929394565b600080611155611077565b90506000600354146111b6576111b1620186a06111a360085461119585611187896003546121d790919063ffffffff16565b61225190919063ffffffff16565b6121d790919063ffffffff16565b61225190919063ffffffff16565b6111e1565b6111e0620186a06111d2600854866121d790919063ffffffff16565b61225190919063ffffffff16565b5b915050919050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201549050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60006002600054036112e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e090612a95565b60405180910390fd5b60026000819055506112fa3061083a565b611304838361091f565b9050600160008190555092915050565b600061134a670de0b6b3a764000061133c8461132e61164a565b6121d790919063ffffffff16565b61225190919063ffffffff16565b9050919050565b60606040518060400160405280600481526020017f474f415400000000000000000000000000000000000000000000000000000000815250905090565b60006002600054036113d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113cc90612a95565b60405180910390fd5b60026000819055506113e8338484611b59565b9050600160008190555092915050565b600061140261164a565b905090565b600060026000540361144e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144590612a95565b60405180910390fd5b6002600081905550611461338333611ed7565b90506001600081905550919050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101549050919050565b6000808211611587576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161157e90612bbc565b60405180910390fd5b6115e46009546115d6620186a06115c861159f61164a565b6115ba670de0b6b3a7640000896121d790919063ffffffff16565b61225190919063ffffffff16565b6121d790919063ffffffff16565b61225190919063ffffffff16565b9050919050565b600061161f61161a620186a061160c600954866121d790919063ffffffff16565b61225190919063ffffffff16565b611314565b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080600354146116905761168b60035461167d670de0b6b3a764000061166f611077565b6121d790919063ffffffff16565b61225190919063ffffffff16565b61169a565b670de0b6b3a76400005b905090565b611728816040518060400160405280601481526020017f496e73756666696369656e742042616c616e6365000000000000000000000000815250600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506117b7816040518060400160405280600f81526020017f4e6567617469766520537570706c790000000000000000000000000000000000815250600354611af59092919063ffffffff16565b600381905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161181b919061258b565b60405180910390a35050565b600080611832611077565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b815260040161189193929190612bdc565b6020604051808303816000875af11580156118b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d49190612c3f565b611913576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161190a90612cb8565b60405180910390fd5b600061191d611077565b9050818111611961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195890612d24565b60405180910390fd5b818161196d9190612d73565b92505050919050565b60008082846119859190612da7565b9050838110156119ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119c190612e27565b60405180910390fd5b8091505092915050565b600080600060035414611a0d57611a08846119fa876003546121d790919063ffffffff16565b61225190919063ffffffff16565b611a0f565b845b90506000611a3d620186a0611a2f600854856121d790919063ffffffff16565b61225190919063ffffffff16565b905060008111611a82576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a7990612e93565b60405180910390fd5b611a8c878261229b565b611a9584611e47565b600160026000828254611aa89190612da7565b925050819055507f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe8782604051611ae0929190612b21565b60405180910390a18092505050949350505050565b6000838311158290611b3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b349190612636565b60405180910390fd5b5060008385611b4c9190612d73565b9050809150509392505050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015611bc45750600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614155b611c03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bfa90612eff565b60405180910390fd5b60008211611c46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c3d90612f6b565b60405180910390fd5b6000611c5061164a565b9050611cdb836040518060400160405280601481526020017f496e73756666696369656e742042616c616e6365000000000000000000000000815250600660008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611d7083600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461197690919063ffffffff16565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611dbc81611e47565b600160026000828254611dcf9190612da7565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051611e33919061258b565b60405180910390a360019150509392505050565b6000611e5161164a565b905081811015611e96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e8d90612fd7565b60405180910390fd5b7f046aa811b2923fd55b4ca06375b4045117d4584c66fc40880a8ab8ee32d88ed18282600354604051611ecb9392919061293a565b60405180910390a15050565b60008083118015611f27575082600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b611f3057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015611f9a5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611fa357600080fd5b6000611fad61164a565b90506000611fdb620186a0611fcd600954886121d790919063ffffffff16565b61225190919063ffffffff16565b90506000611fe882611314565b9050611ff4878761169f565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb86836040518363ffffffff1660e01b815260040161204f929190612b21565b6020604051808303816000875af115801561206e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120929190612c3f565b6120d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c890613043565b60405180910390fd5b6120da83611e47565b6001600260008282546120ed9190612da7565b9250508190555061214981600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206002015461197690919063ffffffff16565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201819055507ff3a670cd3af7d64b488926880889d08a8585a138ff455227af6737339a1ec2628787836040516121c293929190613063565b60405180910390a18093505050509392505050565b60008083036121e9576000905061224b565b600082846121f7919061309a565b9050828482612206919061310b565b14612246576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161223d906131ae565b60405180910390fd5b809150505b92915050565b600061229383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061247f565b905092915050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1660ff1603612365576001600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600180600082825461235d9190612da7565b925050819055505b6123b781600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461197690919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061240f8160035461197690919063ffffffff16565b6003819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612473919061258b565b60405180910390a35050565b600080831182906124c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124bd9190612636565b60405180910390fd5b50600083856124d5919061310b565b9050809150509392505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612512826124e7565b9050919050565b61252281612507565b811461252d57600080fd5b50565b60008135905061253f81612519565b92915050565b60006020828403121561255b5761255a6124e2565b5b600061256984828501612530565b91505092915050565b6000819050919050565b61258581612572565b82525050565b60006020820190506125a0600083018461257c565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156125e05780820151818401526020810190506125c5565b60008484015250505050565b6000601f19601f8301169050919050565b6000612608826125a6565b61261281856125b1565b93506126228185602086016125c2565b61262b816125ec565b840191505092915050565b6000602082019050818103600083015261265081846125fd565b905092915050565b61266181612572565b811461266c57600080fd5b50565b60008135905061267e81612658565b92915050565b6000806040838503121561269b5761269a6124e2565b5b60006126a985828601612530565b92505060206126ba8582860161266f565b9150509250929050565b60008115159050919050565b6126d9816126c4565b82525050565b60006020820190506126f460008301846126d0565b92915050565b600080600060608486031215612713576127126124e2565b5b600061272186828701612530565b935050602061273286828701612530565b92505060406127438682870161266f565b9150509250925092565b600060ff82169050919050565b6127638161274d565b82525050565b600060208201905061277e600083018461275a565b92915050565b60006020828403121561279a576127996124e2565b5b60006127a88482850161266f565b91505092915050565b600080604083850312156127c8576127c76124e2565b5b60006127d68582860161266f565b92505060206127e785828601612530565b9150509250929050565b600060a082019050612806600083018861257c565b612813602083018761257c565b612820604083018661257c565b61282d606083018561257c565b61283a608083018461257c565b9695505050505050565b6000819050919050565b600061286961286461285f846124e7565b612844565b6124e7565b9050919050565b600061287b8261284e565b9050919050565b600061288d82612870565b9050919050565b61289d81612882565b82525050565b60006020820190506128b86000830184612894565b92915050565b600080604083850312156128d5576128d46124e2565b5b60006128e385828601612530565b92505060206128f485828601612530565b9150509250929050565b600061290982612870565b9050919050565b612919816128fe565b82525050565b60006020820190506129346000830184612910565b92915050565b600060608201905061294f600083018661257c565b61295c602083018561257c565b612969604083018461257c565b949350505050565b61297a81612507565b82525050565b60006020820190506129956000830184612971565b92915050565b6000815190506129aa81612658565b92915050565b6000602082840312156129c6576129c56124e2565b5b60006129d48482850161299b565b91505092915050565b7f496e73756666696369656e742042616c616e6365000000000000000000000000600082015250565b6000612a136014836125b1565b9150612a1e826129dd565b602082019050919050565b60006020820190508181036000830152612a4281612a06565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000612a7f601f836125b1565b9150612a8a82612a49565b602082019050919050565b60006020820190508181036000830152612aae81612a72565b9050919050565b7f5a65726f20486f6c64696e677300000000000000000000000000000000000000600082015250565b6000612aeb600d836125b1565b9150612af682612ab5565b602082019050919050565b60006020820190508181036000830152612b1a81612ade565b9050919050565b6000604082019050612b366000830185612971565b612b43602083018461257c565b9392505050565b7f57504c5320616d6f756e74206d7573742062652067726561746572207468616e60008201527f2030000000000000000000000000000000000000000000000000000000000000602082015250565b6000612ba66022836125b1565b9150612bb182612b4a565b604082019050919050565b60006020820190508181036000830152612bd581612b99565b9050919050565b6000606082019050612bf16000830186612971565b612bfe6020830185612971565b612c0b604083018461257c565b949350505050565b612c1c816126c4565b8114612c2757600080fd5b50565b600081519050612c3981612c13565b92915050565b600060208284031215612c5557612c546124e2565b5b6000612c6384828501612c2a565b91505092915050565b7f4661696c757265205472616e736665722046726f6d0000000000000000000000600082015250565b6000612ca26015836125b1565b9150612cad82612c6c565b602082019050919050565b60006020820190508181036000830152612cd181612c95565b9050919050565b7f5a65726f20526563656976656400000000000000000000000000000000000000600082015250565b6000612d0e600d836125b1565b9150612d1982612cd8565b602082019050919050565b60006020820190508181036000830152612d3d81612d01565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612d7e82612572565b9150612d8983612572565b9250828203905081811115612da157612da0612d44565b5b92915050565b6000612db282612572565b9150612dbd83612572565b9250828201905080821115612dd557612dd4612d44565b5b92915050565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000600082015250565b6000612e11601b836125b1565b9150612e1c82612ddb565b602082019050919050565b60006020820190508181036000830152612e4081612e04565b9050919050565b7f5a65726f20416d6f756e74000000000000000000000000000000000000000000600082015250565b6000612e7d600b836125b1565b9150612e8882612e47565b602082019050919050565b60006020820190508181036000830152612eac81612e70565b9050919050565b7f5472616e7366657220546f205a65726f00000000000000000000000000000000600082015250565b6000612ee96010836125b1565b9150612ef482612eb3565b602082019050919050565b60006020820190508181036000830152612f1881612edc565b9050919050565b7f5472616e7366657220416d74205a65726f000000000000000000000000000000600082015250565b6000612f556011836125b1565b9150612f6082612f1f565b602082019050919050565b60006020820190508181036000830152612f8481612f48565b9050919050565b7f50726963652043616e6e6f742046616c6c000000000000000000000000000000600082015250565b6000612fc16011836125b1565b9150612fcc82612f8b565b602082019050919050565b60006020820190508181036000830152612ff081612fb4565b9050919050565b7f556e6465726c79696e67205472616e73666572204661696c7572650000000000600082015250565b600061302d601b836125b1565b915061303882612ff7565b602082019050919050565b6000602082019050818103600083015261305c81613020565b9050919050565b60006060820190506130786000830186612971565b613085602083018561257c565b613092604083018461257c565b949350505050565b60006130a582612572565b91506130b083612572565b92508282026130be81612572565b915082820484148315176130d5576130d4612d44565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061311682612572565b915061312183612572565b925082613131576131306130dc565b5b828204905092915050565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60008201527f7700000000000000000000000000000000000000000000000000000000000000602082015250565b60006131986021836125b1565b91506131a38261313c565b604082019050919050565b600060208201905081810360008301526131c78161318b565b905091905056fea2646970667358221220302cebdcbd51dc286e1b40be54f358e6e8aa3dd7b03461d38f46e68134e8e56c64736f6c63430008110033000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27

Deployed ByteCode

0x6080604052600436106101ba5760003560e01c80636ba56b38116100ec578063d348b4091161008a578063e8bba4f611610064578063e8bba4f614610758578063ec58890914610795578063ed13b253146107d2578063ef8ef56f1461080f5761025f565b8063d348b409146106b3578063db006a75146106de578063dd62ed3e1461071b5761025f565b80637314f109116100c65780637314f109146105d157806375fe9fba1461060e57806395d89b411461064b578063a9059cbb146106765761025f565b80636ba56b381461052c5780636cba38841461056957806370a08231146105945761025f565b80632b14ca561161015957806352c08bb41161013357806352c08bb41461045857806359356c5c146104955780635a9b0b89146104c05780636b014f83146104ef5761025f565b80632b14ca56146103d9578063313ce5671461040457806342966c681461042f5761025f565b806313966db51161019557806313966db51461030957806318160ddd146103345780631f02a29c1461035f57806323b872dd1461039c5761025f565b806246516b1461026457806306fdde03146102a1578063095ea7b3146102cc5761025f565b3661025f57600033905060003490507f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561023157600080fd5b505af1158015610245573d6000803e3d6000fd5b50505050506102533061083a565b61025d818361091f565b005b600080fd5b34801561027057600080fd5b5061028b60048036038101906102869190612545565b610b2c565b604051610298919061258b565b60405180910390f35b3480156102ad57600080fd5b506102b6610b78565b6040516102c39190612636565b60405180910390f35b3480156102d857600080fd5b506102f360048036038101906102ee9190612684565b610bb5565b60405161030091906126df565b60405180910390f35b34801561031557600080fd5b5061031e610ca7565b60405161032b919061258b565b60405180910390f35b34801561034057600080fd5b50610349610cad565b604051610356919061258b565b60405180910390f35b34801561036b57600080fd5b5061038660048036038101906103819190612545565b610cb7565b604051610393919061258b565b60405180910390f35b3480156103a857600080fd5b506103c360048036038101906103be91906126fa565b610d08565b6040516103d091906126df565b60405180910390f35b3480156103e557600080fd5b506103ee610eb9565b6040516103fb919061258b565b60405180910390f35b34801561041057600080fd5b50610419610ebf565b6040516104269190612769565b60405180910390f35b34801561043b57600080fd5b5061045660048036038101906104519190612784565b610ec8565b005b34801561046457600080fd5b5061047f600480360381019061047a91906127b1565b61100d565b60405161048c919061258b565b60405180910390f35b3480156104a157600080fd5b506104aa611077565b6040516104b7919061258b565b60405180910390f35b3480156104cc57600080fd5b506104d5611118565b6040516104e69594939291906127f1565b60405180910390f35b3480156104fb57600080fd5b5061051660048036038101906105119190612784565b61114a565b604051610523919061258b565b60405180910390f35b34801561053857600080fd5b50610553600480360381019061054e9190612545565b6111e9565b604051610560919061258b565b60405180910390f35b34801561057557600080fd5b5061057e611235565b60405161058b91906128a3565b60405180910390f35b3480156105a057600080fd5b506105bb60048036038101906105b69190612545565b611259565b6040516105c8919061258b565b60405180910390f35b3480156105dd57600080fd5b506105f860048036038101906105f391906127b1565b6112a2565b604051610605919061258b565b60405180910390f35b34801561061a57600080fd5b5061063560048036038101906106309190612784565b611314565b604051610642919061258b565b60405180910390f35b34801561065757600080fd5b50610660611351565b60405161066d9190612636565b60405180910390f35b34801561068257600080fd5b5061069d60048036038101906106989190612684565b61138e565b6040516106aa91906126df565b60405180910390f35b3480156106bf57600080fd5b506106c86113f8565b6040516106d5919061258b565b60405180910390f35b3480156106ea57600080fd5b5061070560048036038101906107009190612784565b611407565b604051610712919061258b565b60405180910390f35b34801561072757600080fd5b50610742600480360381019061073d91906128be565b611470565b60405161074f919061258b565b60405180910390f35b34801561076457600080fd5b5061077f600480360381019061077a9190612545565b6114f7565b60405161078c919061258b565b60405180910390f35b3480156107a157600080fd5b506107bc60048036038101906107b79190612784565b611543565b6040516107c9919061258b565b60405180910390f35b3480156107de57600080fd5b506107f960048036038101906107f49190612784565b6115eb565b604051610806919061258b565b60405180910390f35b34801561081b57600080fd5b50610824611626565b604051610831919061291f565b60405180910390f35b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506103e881111561091b57600061089261164a565b905061089e838361169f565b7f8a1c945864c85a9dee42b8734075761f7a16095a8384ab751f2417c5767e227e826040516108cd919061258b565b60405180910390a17f046aa811b2923fd55b4ca06375b4045117d4584c66fc40880a8ab8ee32d88ed1816108ff61164a565b6003546040516109119392919061293a565b60405180910390a1505b5050565b6000807f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b815260040161097b9190612980565b602060405180830381865afa158015610998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bc91906129b0565b90506000811180156109ce5750808411155b610a0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0490612a29565b60405180910390fd5b6000610a1761164a565b90506000610a23611077565b90506000610a3087611827565b905082600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000181905550610ace87600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015461197690919063ffffffff16565b600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550610b20868284866119d4565b94505050505092915050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b60606040518060400160405280601381526020017f446567656e2050726f746f636f6c20474f415400000000000000000000000000815250905090565b600081600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610c95919061258b565b60405180910390a36001905092915050565b60085481565b6000600354905090565b6000610d01600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611314565b9050919050565b6000600260005403610d4f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d4690612a95565b60405180910390fd5b6002600081905550610e1d826040518060400160405280601681526020017f496e73756666696369656e7420416c6c6f77616e636500000000000000000000815250600760008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610ea8848484611b59565b905060016000819055509392505050565b60095481565b60006012905090565b600260005403610f0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0490612a95565b60405180910390fd5b60026000819055506000600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110158015610f695750600081115b610fa8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f9f90612b01565b60405180910390fd5b6000610fb261164a565b9050610fbe338461169f565b610fc781611e47565b7fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca53384604051610ff8929190612b21565b60405180910390a15050600160008190555050565b6000600260005403611054576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161104b90612a95565b60405180910390fd5b6002600081905550611067338484611ed7565b9050600160008190555092915050565b60007f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016110d29190612980565b602060405180830381865afa1580156110ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111391906129b0565b905090565b600080600080600060015494506002549350611132611077565b9250600354915061114161164a565b90509091929394565b600080611155611077565b90506000600354146111b6576111b1620186a06111a360085461119585611187896003546121d790919063ffffffff16565b61225190919063ffffffff16565b6121d790919063ffffffff16565b61225190919063ffffffff16565b6111e1565b6111e0620186a06111d2600854866121d790919063ffffffff16565b61225190919063ffffffff16565b5b915050919050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201549050919050565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2781565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60006002600054036112e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112e090612a95565b60405180910390fd5b60026000819055506112fa3061083a565b611304838361091f565b9050600160008190555092915050565b600061134a670de0b6b3a764000061133c8461132e61164a565b6121d790919063ffffffff16565b61225190919063ffffffff16565b9050919050565b60606040518060400160405280600481526020017f474f415400000000000000000000000000000000000000000000000000000000815250905090565b60006002600054036113d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113cc90612a95565b60405180910390fd5b60026000819055506113e8338484611b59565b9050600160008190555092915050565b600061140261164a565b905090565b600060026000540361144e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144590612a95565b60405180910390fd5b6002600081905550611461338333611ed7565b90506001600081905550919050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101549050919050565b6000808211611587576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161157e90612bbc565b60405180910390fd5b6115e46009546115d6620186a06115c861159f61164a565b6115ba670de0b6b3a7640000896121d790919063ffffffff16565b61225190919063ffffffff16565b6121d790919063ffffffff16565b61225190919063ffffffff16565b9050919050565b600061161f61161a620186a061160c600954866121d790919063ffffffff16565b61225190919063ffffffff16565b611314565b9050919050565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2781565b600080600354146116905761168b60035461167d670de0b6b3a764000061166f611077565b6121d790919063ffffffff16565b61225190919063ffffffff16565b61169a565b670de0b6b3a76400005b905090565b611728816040518060400160405280601481526020017f496e73756666696369656e742042616c616e6365000000000000000000000000815250600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506117b7816040518060400160405280600f81526020017f4e6567617469766520537570706c790000000000000000000000000000000000815250600354611af59092919063ffffffff16565b600381905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161181b919061258b565b60405180910390a35050565b600080611832611077565b90507f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b815260040161189193929190612bdc565b6020604051808303816000875af11580156118b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d49190612c3f565b611913576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161190a90612cb8565b60405180910390fd5b600061191d611077565b9050818111611961576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195890612d24565b60405180910390fd5b818161196d9190612d73565b92505050919050565b60008082846119859190612da7565b9050838110156119ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119c190612e27565b60405180910390fd5b8091505092915050565b600080600060035414611a0d57611a08846119fa876003546121d790919063ffffffff16565b61225190919063ffffffff16565b611a0f565b845b90506000611a3d620186a0611a2f600854856121d790919063ffffffff16565b61225190919063ffffffff16565b905060008111611a82576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a7990612e93565b60405180910390fd5b611a8c878261229b565b611a9584611e47565b600160026000828254611aa89190612da7565b925050819055507f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe8782604051611ae0929190612b21565b60405180910390a18092505050949350505050565b6000838311158290611b3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b349190612636565b60405180910390fd5b5060008385611b4c9190612d73565b9050809150509392505050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015611bc45750600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614155b611c03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bfa90612eff565b60405180910390fd5b60008211611c46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c3d90612f6b565b60405180910390fd5b6000611c5061164a565b9050611cdb836040518060400160405280601481526020017f496e73756666696369656e742042616c616e6365000000000000000000000000815250600660008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611af59092919063ffffffff16565b600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611d7083600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461197690919063ffffffff16565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611dbc81611e47565b600160026000828254611dcf9190612da7565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051611e33919061258b565b60405180910390a360019150509392505050565b6000611e5161164a565b905081811015611e96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e8d90612fd7565b60405180910390fd5b7f046aa811b2923fd55b4ca06375b4045117d4584c66fc40880a8ab8ee32d88ed18282600354604051611ecb9392919061293a565b60405180910390a15050565b60008083118015611f27575082600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b611f3057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015611f9a5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611fa357600080fd5b6000611fad61164a565b90506000611fdb620186a0611fcd600954886121d790919063ffffffff16565b61225190919063ffffffff16565b90506000611fe882611314565b9050611ff4878761169f565b7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2773ffffffffffffffffffffffffffffffffffffffff1663a9059cbb86836040518363ffffffff1660e01b815260040161204f929190612b21565b6020604051808303816000875af115801561206e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120929190612c3f565b6120d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c890613043565b60405180910390fd5b6120da83611e47565b6001600260008282546120ed9190612da7565b9250508190555061214981600460008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206002015461197690919063ffffffff16565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201819055507ff3a670cd3af7d64b488926880889d08a8585a138ff455227af6737339a1ec2628787836040516121c293929190613063565b60405180910390a18093505050509392505050565b60008083036121e9576000905061224b565b600082846121f7919061309a565b9050828482612206919061310b565b14612246576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161223d906131ae565b60405180910390fd5b809150505b92915050565b600061229383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061247f565b905092915050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1660ff1603612365576001600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600180600082825461235d9190612da7565b925050819055505b6123b781600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461197690919063ffffffff16565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061240f8160035461197690919063ffffffff16565b6003819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612473919061258b565b60405180910390a35050565b600080831182906124c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124bd9190612636565b60405180910390fd5b50600083856124d5919061310b565b9050809150509392505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612512826124e7565b9050919050565b61252281612507565b811461252d57600080fd5b50565b60008135905061253f81612519565b92915050565b60006020828403121561255b5761255a6124e2565b5b600061256984828501612530565b91505092915050565b6000819050919050565b61258581612572565b82525050565b60006020820190506125a0600083018461257c565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156125e05780820151818401526020810190506125c5565b60008484015250505050565b6000601f19601f8301169050919050565b6000612608826125a6565b61261281856125b1565b93506126228185602086016125c2565b61262b816125ec565b840191505092915050565b6000602082019050818103600083015261265081846125fd565b905092915050565b61266181612572565b811461266c57600080fd5b50565b60008135905061267e81612658565b92915050565b6000806040838503121561269b5761269a6124e2565b5b60006126a985828601612530565b92505060206126ba8582860161266f565b9150509250929050565b60008115159050919050565b6126d9816126c4565b82525050565b60006020820190506126f460008301846126d0565b92915050565b600080600060608486031215612713576127126124e2565b5b600061272186828701612530565b935050602061273286828701612530565b92505060406127438682870161266f565b9150509250925092565b600060ff82169050919050565b6127638161274d565b82525050565b600060208201905061277e600083018461275a565b92915050565b60006020828403121561279a576127996124e2565b5b60006127a88482850161266f565b91505092915050565b600080604083850312156127c8576127c76124e2565b5b60006127d68582860161266f565b92505060206127e785828601612530565b9150509250929050565b600060a082019050612806600083018861257c565b612813602083018761257c565b612820604083018661257c565b61282d606083018561257c565b61283a608083018461257c565b9695505050505050565b6000819050919050565b600061286961286461285f846124e7565b612844565b6124e7565b9050919050565b600061287b8261284e565b9050919050565b600061288d82612870565b9050919050565b61289d81612882565b82525050565b60006020820190506128b86000830184612894565b92915050565b600080604083850312156128d5576128d46124e2565b5b60006128e385828601612530565b92505060206128f485828601612530565b9150509250929050565b600061290982612870565b9050919050565b612919816128fe565b82525050565b60006020820190506129346000830184612910565b92915050565b600060608201905061294f600083018661257c565b61295c602083018561257c565b612969604083018461257c565b949350505050565b61297a81612507565b82525050565b60006020820190506129956000830184612971565b92915050565b6000815190506129aa81612658565b92915050565b6000602082840312156129c6576129c56124e2565b5b60006129d48482850161299b565b91505092915050565b7f496e73756666696369656e742042616c616e6365000000000000000000000000600082015250565b6000612a136014836125b1565b9150612a1e826129dd565b602082019050919050565b60006020820190508181036000830152612a4281612a06565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b6000612a7f601f836125b1565b9150612a8a82612a49565b602082019050919050565b60006020820190508181036000830152612aae81612a72565b9050919050565b7f5a65726f20486f6c64696e677300000000000000000000000000000000000000600082015250565b6000612aeb600d836125b1565b9150612af682612ab5565b602082019050919050565b60006020820190508181036000830152612b1a81612ade565b9050919050565b6000604082019050612b366000830185612971565b612b43602083018461257c565b9392505050565b7f57504c5320616d6f756e74206d7573742062652067726561746572207468616e60008201527f2030000000000000000000000000000000000000000000000000000000000000602082015250565b6000612ba66022836125b1565b9150612bb182612b4a565b604082019050919050565b60006020820190508181036000830152612bd581612b99565b9050919050565b6000606082019050612bf16000830186612971565b612bfe6020830185612971565b612c0b604083018461257c565b949350505050565b612c1c816126c4565b8114612c2757600080fd5b50565b600081519050612c3981612c13565b92915050565b600060208284031215612c5557612c546124e2565b5b6000612c6384828501612c2a565b91505092915050565b7f4661696c757265205472616e736665722046726f6d0000000000000000000000600082015250565b6000612ca26015836125b1565b9150612cad82612c6c565b602082019050919050565b60006020820190508181036000830152612cd181612c95565b9050919050565b7f5a65726f20526563656976656400000000000000000000000000000000000000600082015250565b6000612d0e600d836125b1565b9150612d1982612cd8565b602082019050919050565b60006020820190508181036000830152612d3d81612d01565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612d7e82612572565b9150612d8983612572565b9250828203905081811115612da157612da0612d44565b5b92915050565b6000612db282612572565b9150612dbd83612572565b9250828201905080821115612dd557612dd4612d44565b5b92915050565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000600082015250565b6000612e11601b836125b1565b9150612e1c82612ddb565b602082019050919050565b60006020820190508181036000830152612e4081612e04565b9050919050565b7f5a65726f20416d6f756e74000000000000000000000000000000000000000000600082015250565b6000612e7d600b836125b1565b9150612e8882612e47565b602082019050919050565b60006020820190508181036000830152612eac81612e70565b9050919050565b7f5472616e7366657220546f205a65726f00000000000000000000000000000000600082015250565b6000612ee96010836125b1565b9150612ef482612eb3565b602082019050919050565b60006020820190508181036000830152612f1881612edc565b9050919050565b7f5472616e7366657220416d74205a65726f000000000000000000000000000000600082015250565b6000612f556011836125b1565b9150612f6082612f1f565b602082019050919050565b60006020820190508181036000830152612f8481612f48565b9050919050565b7f50726963652043616e6e6f742046616c6c000000000000000000000000000000600082015250565b6000612fc16011836125b1565b9150612fcc82612f8b565b602082019050919050565b60006020820190508181036000830152612ff081612fb4565b9050919050565b7f556e6465726c79696e67205472616e73666572204661696c7572650000000000600082015250565b600061302d601b836125b1565b915061303882612ff7565b602082019050919050565b6000602082019050818103600083015261305c81613020565b9050919050565b60006060820190506130786000830186612971565b613085602083018561257c565b613092604083018461257c565b949350505050565b60006130a582612572565b91506130b083612572565b92508282026130be81612572565b915082820484148315176130d5576130d4612d44565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061311682612572565b915061312183612572565b925082613131576131306130dc565b5b828204905092915050565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60008201527f7700000000000000000000000000000000000000000000000000000000000000602082015250565b60006131986021836125b1565b91506131a38261313c565b604082019050919050565b600060208201905081810360008301526131c78161318b565b905091905056fea2646970667358221220302cebdcbd51dc286e1b40be54f358e6e8aa3dd7b03461d38f46e68134e8e56c64736f6c63430008110033