S Price: $0.534974 (-0.44%)

Token

Impermax Lent S (ibexS)

Overview

Max Total Supply

10,186.090192352165020306 ibexS

Holders

9

Market

Price

$0.00 @ 0.000000 S

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
2.302747331537513517 ibexS

Value
$0.00
0xd3080518e5678DC5464B7D4079d1046929985C59
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
LendingVaultV1

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 999999 runs

Other Settings:
default evmVersion
File 1 of 16 : LendingVaultV1.sol
pragma solidity =0.5.16;

import "./LVSetterV1.sol";
import "./interfaces/ILendingVaultV1Factory.sol";

contract LendingVaultV1 is LVSetterV1 {

	function _getTotalSupplied() internal returns (uint totalSupplied) {
		for (uint i = 0; i < borrowables.length; i++) {
			address borrowable = borrowables[i];
			totalSupplied = totalSupplied.add(borrowable.myUnderlyingBalance());
		}
	}
	
	function _mintReserves(uint _exchangeRate, uint _totalSupply) internal returns (uint) {
		uint _exchangeRateLast = exchangeRateLast;
		if (_exchangeRate > _exchangeRateLast) {
			uint _exchangeRateNew = _exchangeRate.sub( _exchangeRate.sub(_exchangeRateLast).mul(reserveFactor).div(1e18) );
			uint liquidity = _totalSupply.mul(_exchangeRate).div(_exchangeRateNew).sub(_totalSupply);
			if (liquidity > 0) {
				address reservesManager = ILendingVaultV1Factory(factory).reservesManager();
				_mint(reservesManager, liquidity);
			}
			exchangeRateLast = _exchangeRateNew;
			return _exchangeRateNew;
		}
		else return _exchangeRate;
	}
	
	function exchangeRate() public returns (uint) {
		uint _totalSupply = totalSupply;
		uint _actualBalance = totalBalance.add(_getTotalSupplied());
		if (_totalSupply == 0 || _actualBalance == 0) return initialExchangeRate;
		uint _exchangeRate = _actualBalance.mul(1e18).div(_totalSupply);
		return _mintReserves(_exchangeRate, _totalSupply);
	}
	
	// this low-level function should be called from another contract
	function mint(address minter) external nonReentrant update returns (uint mintTokens) {
		uint balance = underlying.myBalance();
		uint mintAmount = balance.sub(totalBalance);
		mintTokens = mintAmount.mul(1e18).div(exchangeRate());

		if(totalSupply == 0) {
			// permanently lock the first MINIMUM_LIQUIDITY tokens
			mintTokens = mintTokens.sub(MINIMUM_LIQUIDITY);
			_mint(address(0), MINIMUM_LIQUIDITY);
		}
		require(mintTokens > 0, "LendingVaultV1: MINT_AMOUNT_ZERO");
		_mint(minter, mintTokens);
		_withdrawAndReallocate(0);
		emit Mint(msg.sender, minter, mintAmount, mintTokens);
	}

	// this low-level function should be called from another contract
	function redeem(address redeemer) external nonReentrant update returns (uint redeemAmount) {
		uint redeemTokens = balanceOf[address(this)];
		redeemAmount = redeemTokens.mul(exchangeRate()).div(1e18);

		require(redeemAmount > 0, "LendingVaultV1: REDEEM_AMOUNT_ZERO");
		_burn(address(this), redeemTokens);
		_withdrawAndReallocate(redeemAmount);
		underlying.safeTransfer(redeemer, redeemAmount);
		emit Redeem(msg.sender, redeemer, redeemAmount, redeemTokens);		
	}

	function reallocate() external nonReentrant update {
		_withdrawAndReallocate(0);
	}
}

File 2 of 16 : ImpermaxERC20.sol
pragma solidity =0.5.16;

import "./libraries/SafeMath.sol";

// This contract is basically UniswapV2ERC20 with small modifications
// src: https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol

contract ImpermaxERC20 {
	using SafeMath for uint;
	
	string public name;
	string public symbol;
	uint8 public decimals = 18;
	uint public totalSupply;
	mapping(address => uint) public balanceOf;
	mapping(address => mapping(address => uint)) public allowance;
	
	bytes32 public DOMAIN_SEPARATOR;
	mapping(address => uint) public nonces;
	
	event Transfer(address indexed from, address indexed to, uint value);
	event Approval(address indexed owner, address indexed spender, uint value);

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

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

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

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

	function _transfer(address from, address to, uint value) internal {
		balanceOf[from] = balanceOf[from].sub(value, "Impermax: TRANSFER_TOO_HIGH");
		balanceOf[to] = balanceOf[to].add(value);
		emit Transfer(from, to, value);
	}

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

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

	function transferFrom(address from, address to, uint value) external returns (bool) {
		if (allowance[from][msg.sender] != uint(-1)) {
			allowance[from][msg.sender] = allowance[from][msg.sender].sub(value, "Impermax: TRANSFER_NOT_ALLOWED");
		}
		_transfer(from, to, value);
		return true;
	}
	
	function _checkSignature(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s, bytes32 typehash) internal {
		require(deadline >= block.timestamp, "Impermax: EXPIRED");
		bytes32 digest = keccak256(
			abi.encodePacked(
				'\x19\x01',
				DOMAIN_SEPARATOR,
				keccak256(abi.encode(typehash, owner, spender, value, nonces[owner]++, deadline))
			)
		);
		address recoveredAddress = ecrecover(digest, v, r, s);
		require(recoveredAddress != address(0) && recoveredAddress == owner, "Impermax: INVALID_SIGNATURE");	
	}

	// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
	bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
	function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
		_checkSignature(owner, spender, value, deadline, v, r, s, PERMIT_TYPEHASH);
		_approve(owner, spender, value);
	}
}

File 3 of 16 : IBorrowable.sol
pragma solidity >=0.5.0;

interface IBorrowable {

	/*** Impermax ERC20 ***/
	
	event Transfer(address indexed from, address indexed to, uint value);
	event Approval(address indexed owner, address indexed spender, uint value);
	
	function name() external pure returns (string memory);
	function symbol() external pure returns (string memory);
	function decimals() external pure returns (uint8);
	function totalSupply() external view returns (uint);
	function balanceOf(address owner) external view returns (uint);
	function allowance(address owner, address spender) external view returns (uint);
	function approve(address spender, uint value) external returns (bool);
	function transfer(address to, uint value) external returns (bool);
	function transferFrom(address from, address to, uint value) external returns (bool);
	
	function DOMAIN_SEPARATOR() external view returns (bytes32);
	function PERMIT_TYPEHASH() external pure returns (bytes32);
	function nonces(address owner) external view returns (uint);
	function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
	
	/*** Pool Token ***/
	
	event Mint(address indexed sender, address indexed minter, uint mintAmount, uint mintTokens);
	event Redeem(address indexed sender, address indexed redeemer, uint redeemAmount, uint redeemTokens);
	event Sync(uint totalBalance);
	
	function underlying() external view returns (address);
	function factory() external view returns (address);
	function totalBalance() external view returns (uint);
	function MINIMUM_LIQUIDITY() external pure returns (uint);

	function exchangeRate() external returns (uint);
	function mint(address minter) external returns (uint mintTokens);
	function redeem(address redeemer) external returns (uint redeemAmount);
	function skim(address to) external;
	function sync() external;
	
	function _setFactory() external;
	
	/*** Borrowable ***/

	event BorrowApproval(address indexed owner, address indexed spender, uint value);
	event Borrow(address indexed sender, address indexed borrower, address indexed receiver, uint borrowAmount, uint repayAmount, uint accountBorrowsPrior, uint accountBorrows, uint totalBorrows);
	event Liquidate(address indexed sender, address indexed borrower, address indexed liquidator, uint seizeTokens, uint repayAmount, uint accountBorrowsPrior, uint accountBorrows, uint totalBorrows);
	
	function BORROW_FEE() external pure returns (uint);
	function collateral() external view returns (address);
	function reserveFactor() external view returns (uint);
	function exchangeRateLast() external view returns (uint);
	function borrowIndex() external view returns (uint);
	function totalBorrows() external view returns (uint);
	function borrowAllowance(address owner, address spender) external view returns (uint);
	function borrowBalance(address borrower) external view returns (uint);	
	function borrowTracker() external view returns (address);
	
	function BORROW_PERMIT_TYPEHASH() external pure returns (bytes32);
	function borrowApprove(address spender, uint256 value) external returns (bool);
	function borrowPermit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
	function borrow(address borrower, address receiver, uint borrowAmount, bytes calldata data) external;
	function liquidate(address borrower, address liquidator) external returns (uint seizeTokens);
	function trackBorrow(address borrower) external;
	
	/*** Borrowable Interest Rate Model ***/

	event AccrueInterest(uint interestAccumulated, uint borrowIndex, uint totalBorrows);
	event CalculateKink(uint kinkRate);
	event CalculateBorrowRate(uint borrowRate);
	
	function KINK_BORROW_RATE_MAX() external pure returns (uint);
	function KINK_BORROW_RATE_MIN() external pure returns (uint);
	function KINK_MULTIPLIER() external pure returns (uint);
	function borrowRate() external view returns (uint);
	function kinkBorrowRate() external view returns (uint);
	function kinkUtilizationRate() external view returns (uint);
	function adjustSpeed() external view returns (uint);
	function rateUpdateTimestamp() external view returns (uint32);
	function accrualTimestamp() external view returns (uint32);
	
	function accrueInterest() external;
	
	/*** Borrowable Setter ***/

	event NewReserveFactor(uint newReserveFactor);
	event NewKinkUtilizationRate(uint newKinkUtilizationRate);
	event NewAdjustSpeed(uint newAdjustSpeed);
	event NewBorrowTracker(address newBorrowTracker);

	function RESERVE_FACTOR_MAX() external pure returns (uint);
	function KINK_UR_MIN() external pure returns (uint);
	function KINK_UR_MAX() external pure returns (uint);
	function ADJUST_SPEED_MIN() external pure returns (uint);
	function ADJUST_SPEED_MAX() external pure returns (uint);
	
	function _initialize (
		string calldata _name, 
		string calldata _symbol,
		address _underlying, 
		address _collateral
	) external;
	function _setReserveFactor(uint newReserveFactor) external;
	function _setKinkUtilizationRate(uint newKinkUtilizationRate) external;
	function _setAdjustSpeed(uint newAdjustSpeed) external;
	function _setBorrowTracker(address newBorrowTracker) external;
}

File 4 of 16 : IERC20.sol
pragma solidity >=0.5.0;

interface IERC20 {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);
}

File 5 of 16 : ILendingVaultV1.sol
pragma solidity >=0.5.0;

interface ILendingVaultV1 {

	/*** Impermax ERC20 ***/
	
	event Transfer(address indexed from, address indexed to, uint value);
	event Approval(address indexed owner, address indexed spender, uint value);
	
	function name() external pure returns (string memory);
	function symbol() external pure returns (string memory);
	function decimals() external pure returns (uint8);
	function totalSupply() external view returns (uint);
	function balanceOf(address owner) external view returns (uint);
	function allowance(address owner, address spender) external view returns (uint);
	function approve(address spender, uint value) external returns (bool);
	function transfer(address to, uint value) external returns (bool);
	function transferFrom(address from, address to, uint value) external returns (bool);
	
	function DOMAIN_SEPARATOR() external view returns (bytes32);
	function PERMIT_TYPEHASH() external pure returns (bytes32);
	function nonces(address owner) external view returns (uint);
	function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
	
	/*** Pool Token ***/
	
	event Mint(address indexed sender, address indexed minter, uint mintAmount, uint mintTokens);
	event Redeem(address indexed sender, address indexed redeemer, uint redeemAmount, uint redeemTokens);
	event Sync(uint totalBalance);
	
	function underlying() external view returns (address);
	function factory() external view returns (address);
	function totalBalance() external view returns (uint);
	function MINIMUM_LIQUIDITY() external pure returns (uint);

	function exchangeRate() external returns (uint);
	function mint(address minter) external returns (uint mintTokens);
	function redeem(address redeemer) external returns (uint redeemAmount);
	function skim(address to) external;
	function sync() external;
	
	function _setFactory() external;
	
	/*** Lending Vault V1 ***/
	
	event AddBorrowable(address indexed borrowable);
	event RemoveBorrowable(address indexed borrowable);
	event EnableBorrowable(address indexed borrowable);
	event DisableBorrowable(address indexed borrowable);
	event UnwindBorrowable(address indexed borrowable, uint256 underlyingBalance, uint256 actualRedeemAmount);
	event AllocateIntoBorrowable(address indexed borrowable, uint256 mintAmount, uint256 mintTokens);
	event DeallocateFromBorrowable(address indexed borrowable, uint256 redeemAmount, uint256 redeemTokens);

	function borrowables(uint) external view returns (address borrowable);
	function borrowableInfo(address borrowable) external view returns (
		bool enabled,
		bool exists
	);
	function getBorrowablesLength() external view returns (uint);
	function indexOfBorrowable(address borrowable) external view returns (uint);

	function reserveFactor() external view returns (uint);
	function exchangeRateLast() external view returns (uint);
	
	function addBorrowable(address borrowable) external;
	function removeBorrowable(address borrowable) external;
	function disableBorrowable(address borrowable) external;
	function enableBorrowable(address borrowable) external;
	function unwindBorrowable(address borrowable) external;
	
	function reallocate() external;
		
	/*** Lending Vault Setter ***/

	event NewReserveFactor(uint newReserveFactor);

	function RESERVE_FACTOR_MAX() external pure returns (uint);
	
	function _initialize (
		address _underlying,
		string calldata _name,
		string calldata _symbol
	) external;
	function _setReserveFactor(uint newReserveFactor) external;
}

File 6 of 16 : ILendingVaultV1Factory.sol
pragma solidity >=0.5.0;

interface ILendingVaultV1Factory {
	event VaultCreated(address indexed underlying, address vault, uint);
	event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);
	event NewAdmin(address oldAdmin, address newAdmin);
	event NewReservesPendingAdmin(address oldReservesPendingAdmin, address newReservesPendingAdmin);
	event NewReservesAdmin(address oldReservesAdmin, address newReservesAdmin);
	event NewReservesManager(address oldReservesManager, address newReservesManager);
	
	function admin() external view returns (address);
	function pendingAdmin() external view returns (address);
	function reservesAdmin() external view returns (address);
	function reservesPendingAdmin() external view returns (address);
	function reservesManager() external view returns (address);

	function allVaults(uint) external view returns (address);
	function allVaultsLength() external view returns (uint);

	function createVault(address underlying, string calldata _name, string calldata _symbol) external returns (address vault);

	function _setPendingAdmin(address newPendingAdmin) external;
	function _acceptAdmin() external;
	function _setReservesPendingAdmin(address newPendingAdmin) external;
	function _acceptReservesAdmin() external;
	function _setReservesManager(address newReservesManager) external;
}

File 7 of 16 : IPoolToken.sol
pragma solidity >=0.5.0;

interface IPoolToken {

	/*** Impermax ERC20 ***/
	
	event Transfer(address indexed from, address indexed to, uint value);
	event Approval(address indexed owner, address indexed spender, uint value);
	
	function name() external pure returns (string memory);
	function symbol() external pure returns (string memory);
	function decimals() external pure returns (uint8);
	function totalSupply() external view returns (uint);
	function balanceOf(address owner) external view returns (uint);
	function allowance(address owner, address spender) external view returns (uint);
	function approve(address spender, uint value) external returns (bool);
	function transfer(address to, uint value) external returns (bool);
	function transferFrom(address from, address to, uint value) external returns (bool);
	
	function DOMAIN_SEPARATOR() external view returns (bytes32);
	function PERMIT_TYPEHASH() external pure returns (bytes32);
	function nonces(address owner) external view returns (uint);
	function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
	
	/*** Pool Token ***/
	
	event Mint(address indexed sender, address indexed minter, uint mintAmount, uint mintTokens);
	event Redeem(address indexed sender, address indexed redeemer, uint redeemAmount, uint redeemTokens);
	event Sync(uint totalBalance);
	
	function underlying() external view returns (address);
	function factory() external view returns (address);
	function totalBalance() external view returns (uint);
	function MINIMUM_LIQUIDITY() external pure returns (uint);

	function exchangeRate() external returns (uint);
	function mint(address minter) external returns (uint mintTokens);
	function redeem(address redeemer) external returns (uint redeemAmount);
	function skim(address to) external;
	function sync() external;
	
	function _setFactory() external;
}

File 8 of 16 : BorrowableHelpers.sol
pragma solidity =0.5.16;

import "./SafeMath.sol";

import "../interfaces/IBorrowable.sol";
import "../interfaces/IERC20.sol";

library BorrowableHelpers {
	using SafeMath for uint256;

	function underlyingValueOf(address borrowable, uint256 borrowableAmount) internal returns (uint256) {
		uint256 exchangeRate = IBorrowable(borrowable).exchangeRate();
		return borrowableAmount.mul(exchangeRate).div(1e18);
	}

	function underlyingBalanceOf(address borrowable, address account) internal returns (uint256) {
		return underlyingValueOf(borrowable, IBorrowable(borrowable).balanceOf(account));
	}

	function myUnderlyingBalance(address borrowable) internal returns (uint256) {
		return underlyingValueOf(borrowable, IBorrowable(borrowable).balanceOf(address(this)));
	}
	
	/*** AMOUNT TO TOKENS CONVERSION ***/
		
	function tokensFor(uint redeemAmount, uint exchangeRate, bool atMost) internal pure returns (uint redeemTokens) {
		uint redeemTokensLow = redeemAmount.mul(1e18).div(exchangeRate);
		uint redeemTokensHigh = redeemTokensLow.add(1);
		
		if (atMost) {
			uint actualRedeemAmountHigh = redeemTokensHigh.mul(exchangeRate).div(1e18);
			return actualRedeemAmountHigh <= redeemAmount ? redeemTokensHigh : redeemTokensLow;
		} else {
			uint actualRedeemAmountLow = redeemTokensLow.mul(exchangeRate).div(1e18);
			return actualRedeemAmountLow >= redeemAmount ? redeemTokensLow : redeemTokensHigh;
		}
	}
	
	function tokensForAtMost(uint redeemAmount, uint exchangeRate) internal pure returns (uint redeemTokens) {
		return tokensFor(redeemAmount, exchangeRate, true);
	}
	
	function tokensForAtLeast(uint redeemAmount, uint exchangeRate) internal pure returns (uint redeemTokens) {
		return tokensFor(redeemAmount, exchangeRate, false);
	}
}

File 9 of 16 : BorrowableObject.sol
pragma solidity =0.5.16;
pragma experimental ABIEncoderV2;

import "./SafeMath.sol";
import "./Math.sol";
import "../interfaces/IBorrowable.sol";


library BorrowableObject {
	using SafeMath for uint;
	using BorrowableObject for Borrowable;

	struct Borrowable {
		IBorrowable borrowableContract;
		uint exchangeRate;
		uint totalBorrows;       // in underlyings
		uint externalSupply;     // in underlyings
		uint initialOwnedSupply; // in underlyings
		uint ownedSupply;        // in underlyings
		uint kinkBorrowRate;
		uint kinkUtilizationRate;
		uint reserveFactor;
		uint kinkMultiplier;
		uint cachedSupplyRate;
	}

	function newBorrowable(IBorrowable borrowableContract, address lendingVault) internal returns (Borrowable memory borrowable) {
		borrowableContract.sync();
		uint exchangeRate = borrowableContract.exchangeRate();
		uint totalSupplyInTokens = borrowableContract.totalSupply();
		uint ownedSupplyInTokens = borrowableContract.balanceOf(lendingVault);
		uint externalSupplyInTokens = totalSupplyInTokens.sub(ownedSupplyInTokens);
		borrowable = Borrowable({
			borrowableContract: borrowableContract,
			exchangeRate: exchangeRate,
			totalBorrows: borrowableContract.totalBorrows(),
			externalSupply: externalSupplyInTokens.mul(exchangeRate).div(1e18),
			initialOwnedSupply: ownedSupplyInTokens.mul(exchangeRate).div(1e18),
			ownedSupply: ownedSupplyInTokens.mul(exchangeRate).div(1e18),
			kinkBorrowRate: borrowableContract.kinkBorrowRate(),
			kinkUtilizationRate: borrowableContract.kinkUtilizationRate(),
			reserveFactor: borrowableContract.reserveFactor(),
			kinkMultiplier: borrowableContract.KINK_MULTIPLIER(),
			cachedSupplyRate: 0
		});
		borrowable.cachedSupplyRate = supplyRate(borrowable);
		return borrowable;
	}

	function totalSupply(Borrowable memory borrowable) internal pure returns (uint) {
		return borrowable.externalSupply.add(borrowable.ownedSupply);
	}

	function utilizationRate(Borrowable memory borrowable) internal pure returns (uint) {
		uint _totalSupply = totalSupply(borrowable);
		if (_totalSupply == 0) return 0;
		return borrowable.totalBorrows.mul(1e18).div(_totalSupply);
	}

	function kinkRate(Borrowable memory borrowable) internal pure returns (uint) {
		return borrowable.kinkUtilizationRate
			.mul(borrowable.kinkBorrowRate).div(1e18)
			.mul(uint(1e18).sub(borrowable.reserveFactor)).div(1e18);
	}

	function supplyRate(Borrowable memory borrowable) internal pure returns (uint rate) {
		uint utilizationRate_ = utilizationRate(borrowable);
		uint ratio = utilizationRate_.mul(1e18).div(borrowable.kinkUtilizationRate);
		uint borrowFactor; //borrowRate to kinkBorrowRate ratio
		if (utilizationRate_ < borrowable.kinkUtilizationRate) {
			borrowFactor = ratio;
		} else {
			uint excessRatio = utilizationRate_.sub(borrowable.kinkUtilizationRate)
				.mul(1e18).div(uint(1e18).sub(borrowable.kinkUtilizationRate));
			borrowFactor = excessRatio.mul(borrowable.kinkMultiplier.sub(1)).add(1e18);
		}
		rate = borrowFactor.mul(kinkRate(borrowable)).div(1e18).mul(ratio).div(1e18);
	}

	function allocate(Borrowable memory borrowable, uint amount) internal pure returns (Borrowable memory) {
		borrowable.ownedSupply = borrowable.ownedSupply.add(amount);
		borrowable.cachedSupplyRate = supplyRate(borrowable);
		return borrowable;
	}

	function deallocate(Borrowable memory borrowable, uint amount) internal pure returns (Borrowable memory) {
		uint availableLiquidity = totalSupply(borrowable).sub(borrowable.totalBorrows, "ERROR: NEGATIVE AVAILABLE LIQUIDITY");
		require(amount <= availableLiquidity, "ERROR: DEALLOCATE AMOUNT > AVAILABLE LIQUIDITY");
		borrowable.ownedSupply = borrowable.ownedSupply.sub(amount);
		borrowable.cachedSupplyRate = supplyRate(borrowable);
		return borrowable;
	}

	function deallocateMax(Borrowable memory borrowable) internal pure returns (Borrowable memory, uint) {
		if (totalSupply(borrowable) < borrowable.totalBorrows) return (borrowable, 0);
		uint availableLiquidity = totalSupply(borrowable).sub(borrowable.totalBorrows);
		uint amount = Math.min(borrowable.ownedSupply, availableLiquidity);
		return (deallocate(borrowable, amount), amount);
	}

	function calculateUtilizationForRate(Borrowable memory borrowable, uint rate) internal pure returns (uint targetUtilizationRate) {
		if (rate <= kinkRate(borrowable)) {
			targetUtilizationRate = Math.sqrt(
				rate.mul(1e18).div(kinkRate(borrowable)).mul(1e18)
			).mul(borrowable.kinkUtilizationRate).div(1e18);
		} else {
			uint a = borrowable.kinkMultiplier.sub(1);
			uint b = borrowable.kinkUtilizationRate.mul(borrowable.kinkMultiplier).sub(1e18);
			uint c = rate.mul(borrowable.kinkUtilizationRate).div(1e18)
				.mul(uint(1e18).sub(borrowable.kinkUtilizationRate)).div(kinkRate(borrowable));
			uint tmp = Math.sqrt(
				b.mul(b).div(1e18).add(a.mul(c).mul(4)).mul(1e18)
			);
			targetUtilizationRate = tmp.add(b).div(a).div(2);
		}
		require(targetUtilizationRate <= 1e18, "ERROR: TARGET UTILIZATION > 100%");
	}

	function calculateAmountForRate(Borrowable memory borrowable, uint rate) internal pure returns (uint) {
		require(rate > 0, "ERROR: rate = 0");
		require(rate <= borrowable.cachedSupplyRate, "ERROR: TARGET RATE > CACHED RATE");
		uint targetUtilizationRate = calculateUtilizationForRate(borrowable, rate);
		require(targetUtilizationRate <= utilizationRate(borrowable), "ERROR: TARGET UTILIZATION > CURRENT UTILIZATION");
		uint targetSupply = borrowable.totalBorrows.mul(1e18).div(targetUtilizationRate);
		return targetSupply.sub(totalSupply(borrowable), "ERROR: TARGET SUPPLY > TOTAL SUPPLY");
	}

	function compare(Borrowable memory borrowableA, Borrowable memory borrowableB) internal pure returns (bool) {
		return borrowableA.cachedSupplyRate > borrowableB.cachedSupplyRate;
	}
}

File 10 of 16 : Math.sol
pragma solidity =0.5.16;

// a library for performing various math operations
// forked from: https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/libraries/Math.sol

library Math {
    function min(uint x, uint y) internal pure returns (uint z) {
        z = x < y ? x : y;
    }

    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    function sqrt(uint y) internal pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }
}

File 11 of 16 : SafeMath.sol
pragma solidity =0.5.16;

// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol
// Subject to the MIT license.

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

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

        return c;
    }

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

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot underflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, errorMessage);

        return c;
    }

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

    /**
     * @dev Returns the integer division of two unsigned integers.
     * Reverts with custom message on division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

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

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

File 12 of 16 : SafeToken.sol
pragma solidity =0.5.16;

interface ERC20Interface {
    function balanceOf(address user) external view returns (uint256);
}

library SafeToken {
    function myBalance(address token) internal view returns (uint256) {
        return ERC20Interface(token).balanceOf(address(this));
    }

    function balanceOf(address token, address user) internal view returns (uint256) {
        return ERC20Interface(token).balanceOf(user);
    }

    function safeApprove(address token, address to, uint256 value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "!safeApprove");
    }

    function safeTransfer(address token, address to, uint256 value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "!safeTransfer");
    }

    function safeTransferFrom(address token, address from, address to, uint256 value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "!safeTransferFrom");
    }

    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call.value(value)(new bytes(0));
        require(success, "!safeTransferETH");
    }
}

File 13 of 16 : LVAllocatorV1.sol
pragma solidity =0.5.16;

import "./PoolToken.sol";
import "./LVStorageV1.sol";
import "./interfaces/ILendingVaultV1.sol";
import "./libraries/BorrowableHelpers.sol";
import "./libraries/BorrowableObject.sol";

contract LVAllocatorV1 is ILendingVaultV1, PoolToken, LVStorageV1 {
	using BorrowableHelpers for address;
	using BorrowableObject for BorrowableObject.Borrowable;
	
	function _allocate(IBorrowable borrowable, uint mintAmount, uint _exchangeRate) internal returns (uint mintTokens) {
		mintTokens = mintAmount.mul(1e18).div(_exchangeRate);
		if (mintTokens == 0) return 0;
		underlying.safeTransfer(address(borrowable), mintAmount);
		mintTokens = borrowable.mint(address(this));

		emit AllocateIntoBorrowable(address(borrowable), mintAmount, mintTokens);
	}
	function _allocate(IBorrowable borrowable, uint mintAmount) internal returns (uint mintTokens) {
		mintTokens = _allocate(borrowable, mintAmount, borrowable.exchangeRate());
	}

	function _deallocate(IBorrowable borrowable, uint redeemTokens, uint _exchangeRate) internal returns (uint redeemAmount) {
		redeemAmount = redeemTokens.mul(_exchangeRate).div(1e18);
		if (redeemAmount == 0) return 0;
		uint totalBalance = borrowable.totalBalance();
		if (redeemAmount > totalBalance) {
			redeemTokens = totalBalance.mul(1e18).div(_exchangeRate);
		}
		address(borrowable).safeTransfer(address(borrowable), redeemTokens);
		redeemAmount = borrowable.redeem(address(this));

		emit DeallocateFromBorrowable(address(borrowable), redeemAmount, redeemTokens);
	}
	function _deallocate(IBorrowable borrowable, uint redeemTokens) internal returns (uint redeemAmount) {
		redeemAmount = _deallocate(borrowable, redeemTokens, borrowable.exchangeRate());
	}
	
	function _deallocateAtLeastOrMax(IBorrowable borrowable, uint redeemAmount, uint _exchangeRate) internal returns (uint actualRedeemAmount) {
		actualRedeemAmount = _deallocate(IBorrowable(borrowable), BorrowableHelpers.tokensForAtLeast(redeemAmount, _exchangeRate), _exchangeRate);
	}
	function _deallocateAtLeastOrMax(IBorrowable borrowable, uint redeemAmount) internal returns (uint actualRedeemAmount) {
		actualRedeemAmount = _deallocateAtLeastOrMax(borrowable, redeemAmount, borrowable.exchangeRate());
	}

	function _withdrawAndReallocate(uint withdrawAmount) internal {
		// initialize borrowablesObj
		BorrowableObject.Borrowable[] memory borrowablesObj = new BorrowableObject.Borrowable[](borrowables.length);
		uint borrowablesLength = borrowables.length;
		for(uint i = 0; i < borrowables.length; i++) {
			if (!borrowableInfo[borrowables[i]].enabled) {
				borrowablesLength--;
				continue;
			}
			uint delta = uint(borrowables.length).sub(borrowablesLength);
			borrowablesObj[i - delta] = BorrowableObject.newBorrowable(IBorrowable(borrowables[i]), address(this));
		}
		
		// deallocate everything
		uint amountToAllocate = underlying.myBalance();
		for(uint i = 0; i < borrowablesLength; i++) {
			uint amount;
			(borrowablesObj[i], amount) = borrowablesObj[i].deallocateMax();
			amountToAllocate = amountToAllocate.add(amount);
		}
		amountToAllocate = amountToAllocate.sub(withdrawAmount, "LendingVaultV1: INSUFFICIENT_LIQUIDITY");
		
		// bubblesort borrowablesObj
		for (uint i = 0; i < borrowablesLength - 1; i++) {
			for (uint j = 0; j < borrowablesLength - 1 - i; j++) {
				if (!borrowablesObj[j].compare(borrowablesObj[j+1])) {
					BorrowableObject.Borrowable memory tmp = borrowablesObj[j];
					borrowablesObj[j] = borrowablesObj[j+1];
					borrowablesObj[j+1] = tmp;
				}
			}
		}

		// Allocate in the pool with the highest APR an amount such that the next APR matches the one
		// of the pool with the second highest APR.
		// Repeat until all the pools with the highest APR have the same APR.
		uint lastCycle = borrowablesLength;
		for(uint i = 1; i < borrowablesLength; i++) {
			uint targetRate = borrowablesObj[i].cachedSupplyRate;
			uint amountThisCycle = 0;
			uint[] memory amounts = new uint[](i);
			if (targetRate == 0) {
				// Unachievable APR
				lastCycle = i;
				break;
			}
			for (uint j = 0; j < i; j++) {
				if (borrowablesObj[j].cachedSupplyRate <= targetRate) break;
				amounts[j] = borrowablesObj[j].calculateAmountForRate(targetRate);
				amountThisCycle = amountThisCycle.add(amounts[j]);
			}
			if (amountThisCycle > amountToAllocate) {
				// We can't afford to complete this cycle
				lastCycle = i;
				break;
			}
			for (uint j = 0; j < i; j++) {
				if (amounts[j] == 0) continue;
				borrowablesObj[j] = borrowablesObj[j].allocate(amounts[j]);
				amountToAllocate = amountToAllocate.sub(amounts[j]);
			}
		}

		// distribute the amount left equally among pools with highest APR proportionally to their total supply
		uint globalTotalSupply = 0;
		uint totalAmountToAllocate = amountToAllocate;
		for (uint i = 0; i < lastCycle; i++) {
			globalTotalSupply = globalTotalSupply.add(borrowablesObj[i].totalSupply());
		}
		for (uint i = 0; i < lastCycle; i++) {
			uint amount = globalTotalSupply > 0 
				? borrowablesObj[i].totalSupply().mul(totalAmountToAllocate).div(globalTotalSupply)
				: amountToAllocate;
			if (amount > amountToAllocate) amount = amountToAllocate;
			borrowablesObj[i] = borrowablesObj[i].allocate(amount);
			amountToAllocate = amountToAllocate.sub(amount);
		}
		
		// redeem
		for(uint i = 0; i < borrowablesLength; i++) {
			if (borrowablesObj[i].ownedSupply < borrowablesObj[i].initialOwnedSupply) {
				uint redeemAmount = borrowablesObj[i].initialOwnedSupply.sub(borrowablesObj[i].ownedSupply);
				_deallocateAtLeastOrMax(borrowablesObj[i].borrowableContract, redeemAmount, borrowablesObj[i].exchangeRate);
			}
		}
		// mint
		amountToAllocate = underlying.myBalance().sub(withdrawAmount, "LendingVaultV1: NEGATIVE AMOUNT TO ALLOCATE");
		for(uint i = 0; i < borrowablesLength; i++) {
			if (borrowablesObj[i].ownedSupply > borrowablesObj[i].initialOwnedSupply) {
				uint mintAmount = borrowablesObj[i].ownedSupply.sub(borrowablesObj[i].initialOwnedSupply);
				if (mintAmount > amountToAllocate) mintAmount = amountToAllocate;
				amountToAllocate = amountToAllocate.sub(mintAmount);
				_allocate(borrowablesObj[i].borrowableContract, mintAmount, borrowablesObj[i].exchangeRate);
			}
		}
	}
}

File 14 of 16 : LVSetterV1.sol
pragma solidity =0.5.16;

import "./LVAllocatorV1.sol";
import "./interfaces/ILendingVaultV1Factory.sol";

contract LVSetterV1 is LVAllocatorV1 {

	uint public constant RESERVE_FACTOR_MAX = 0.90e18; //90%
	uint private constant MAX_BORROWABLES_LENGTH = 10;

	function _initialize(
		address _underlying,
		string calldata _name,
		string calldata _symbol
	) external {
		require(msg.sender == factory, "LendingVaultV1: UNAUTHORIZED"); // sufficient check
		_setName(_name, _symbol);
		underlying = _underlying;
		exchangeRateLast = initialExchangeRate;
	}
	
	function _setReserveFactor(uint newReserveFactor) external onlyAdmin nonReentrant {
		require(newReserveFactor <= RESERVE_FACTOR_MAX, "LendingVaultV1: INVALID_SETTING");
		reserveFactor = newReserveFactor;
		emit NewReserveFactor(newReserveFactor);
	}
	
	/*** Borrowables management ***/

	function addBorrowable(address borrowable) external onlyAdmin nonReentrant {
		require(IBorrowable(borrowable).underlying() == underlying, "LendingVaultV1: INVALID_UNDERLYING");
		require(!borrowableInfo[borrowable].exists, "LendingVaultV1: BORROWABLE_EXISTS");
		require(borrowables.length < MAX_BORROWABLES_LENGTH, "LendingVaultV1: MAX_BORROWABLES_LENGTH");

		borrowableInfo[borrowable].exists = true;
		borrowableInfo[borrowable].enabled = true;
		borrowables.push(borrowable);

		emit AddBorrowable(address(borrowable));
	}

	function removeBorrowable(address borrowable) external onlyAdmin nonReentrant {
		require(borrowableInfo[borrowable].exists, "LendingVaultV1: BORROWABLE_DOESNT_EXISTS");
		require(!borrowableInfo[borrowable].enabled, "LendingVaultV1: BORROWABLE_ENABLED");
		require(borrowable.balanceOf(address(this)) == 0, "LendingVaultV1: NOT_EMPTY");

		uint lastIndex = borrowables.length - 1;
		uint index = indexOfBorrowable(borrowable);

		borrowables[index] = borrowables[lastIndex];
		borrowables.pop();
		delete borrowableInfo[borrowable];

		emit RemoveBorrowable(address(borrowable));
	}

	function disableBorrowable(address borrowable) external onlyAdmin nonReentrant {
		require(borrowableInfo[borrowable].exists, "LendingVaultV1: BORROWABLE_DOESNT_EXISTS");
		require(borrowableInfo[borrowable].enabled, "LendingVaultV1: BORROWABLE_DISABLED");

		borrowableInfo[borrowable].enabled = false;

		emit DisableBorrowable(address(borrowable));
	}

	function enableBorrowable(address borrowable) external onlyAdmin nonReentrant {
		require(borrowableInfo[borrowable].exists, "LendingVaultV1: BORROWABLE_DOESNT_EXISTS");
		require(!borrowableInfo[borrowable].enabled, "LendingVaultV1: BORROWABLE_ENABLED");

		borrowableInfo[borrowable].enabled = true;

		emit EnableBorrowable(address(borrowable));
	}

	function unwindBorrowable(address borrowable) external onlyAdmin nonReentrant update {
		require(borrowableInfo[borrowable].exists, "LendingVaultV1: BORROWABLE_DOESNT_EXISTS");
		require(!borrowableInfo[borrowable].enabled, "LendingVaultV1: BORROWABLE_ENABLED");	
		
		uint underlyingBalance = borrowable.myUnderlyingBalance();
		require(underlyingBalance > 0, "LendingVaultV1: ZERO_AMOUNT");
		uint actualRedeemAmount = _deallocateAtLeastOrMax(IBorrowable(borrowable), underlyingBalance);	

		emit UnwindBorrowable(address(borrowable), underlyingBalance, actualRedeemAmount);
	}
	
	modifier onlyAdmin() {
		require(msg.sender == ILendingVaultV1Factory(factory).admin(), "LendingVaultV1: UNAUTHORIZED");
		_;
	}
}

File 15 of 16 : LVStorageV1.sol
pragma solidity =0.5.16;

contract LVStorageV1 {
	address[] public borrowables;
	struct BorrowableInfo {
		bool enabled;
		bool exists;
	}
	mapping(address => BorrowableInfo) public borrowableInfo;
	function getBorrowablesLength() external view returns (uint) {
		return borrowables.length;
	}
	function indexOfBorrowable(address borrowable) public view returns (uint) {
		for (uint i = 0; i < borrowables.length; i++) {
			if (borrowables[i] == borrowable) {
				return i;
			}
		}
		require(false, "LendingVaultV1: BORROWABLE_NOT_FOUND");
	}

	uint public exchangeRateLast;

	uint public reserveFactor = 0.10e18; //10%
}

File 16 of 16 : PoolToken.sol
pragma solidity =0.5.16;

import "./ImpermaxERC20.sol";
import "./interfaces/IPoolToken.sol";
import "./libraries/SafeToken.sol";

contract PoolToken is IPoolToken, ImpermaxERC20 {
	using SafeToken for address;
	
   	uint internal constant initialExchangeRate = 1e18;
	address public underlying;
	address public factory;
	uint public totalBalance;
	uint public constant MINIMUM_LIQUIDITY = 1000;
	
	event Mint(address indexed sender, address indexed minter, uint mintAmount, uint mintTokens);
	event Redeem(address indexed sender, address indexed redeemer, uint redeemAmount, uint redeemTokens);
	event Sync(uint totalBalance);
	
	/*** Initialize ***/
	
	// called once by the factory
	function _setFactory() external {
		require(factory == address(0), "Impermax: FACTORY_ALREADY_SET");
		factory = msg.sender;
	}
	
	/*** PoolToken ***/
	
	function _update() internal {
		totalBalance = underlying.myBalance();
		emit Sync(totalBalance);
	}

	function exchangeRate() public returns (uint) 
	{
		uint _totalSupply = totalSupply; // gas savings
		uint _totalBalance = totalBalance; // gas savings
		if (_totalSupply == 0 || _totalBalance == 0) return initialExchangeRate;
		return _totalBalance.mul(1e18).div(_totalSupply);
	}
	
	// this low-level function should be called from another contract
	function mint(address minter) external nonReentrant update returns (uint mintTokens) {
		uint balance = underlying.myBalance();
		uint mintAmount = balance.sub(totalBalance);
		mintTokens = mintAmount.mul(1e18).div(exchangeRate());

		if(totalSupply == 0) {
			// permanently lock the first MINIMUM_LIQUIDITY tokens
			mintTokens = mintTokens.sub(MINIMUM_LIQUIDITY);
			_mint(address(0), MINIMUM_LIQUIDITY);
		}
		require(mintTokens > 0, "Impermax: MINT_AMOUNT_ZERO");
		_mint(minter, mintTokens);
		emit Mint(msg.sender, minter, mintAmount, mintTokens);
	}

	// this low-level function should be called from another contract
	function redeem(address redeemer) external nonReentrant update returns (uint redeemAmount) {
		uint redeemTokens = balanceOf[address(this)];
		redeemAmount = redeemTokens.mul(exchangeRate()).div(1e18);

		require(redeemAmount > 0, "Impermax: REDEEM_AMOUNT_ZERO");
		require(redeemAmount <= totalBalance, "Impermax: INSUFFICIENT_CASH");
		_burn(address(this), redeemTokens);
		underlying.safeTransfer(redeemer, redeemAmount);
		emit Redeem(msg.sender, redeemer, redeemAmount, redeemTokens);		
	}

	// force real balance to match totalBalance
	function skim(address to) external nonReentrant {
		underlying.safeTransfer(to, underlying.myBalance().sub(totalBalance));
	}

	// force totalBalance to match real balance
	function sync() external nonReentrant update {}
	
	/*** Utilities ***/
	
	// prevents a contract from calling itself, directly or indirectly.
	bool internal _notEntered = true;
	modifier nonReentrant() {
		require(_notEntered, "Impermax: REENTERED");
		_notEntered = false;
		_;
		_notEntered = true;
	}
	
	// update totalBalance with current balance
	modifier update() {
		_;
		_update();
	}
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrowable","type":"address"}],"name":"AddBorrowable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrowable","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"AllocateIntoBorrowable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrowable","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"DeallocateFromBorrowable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrowable","type":"address"}],"name":"DisableBorrowable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrowable","type":"address"}],"name":"EnableBorrowable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newReserveFactor","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrowable","type":"address"}],"name":"RemoveBorrowable","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalBalance","type":"uint256"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrowable","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualRedeemAmount","type":"uint256"}],"name":"UnwindBorrowable","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"RESERVE_FACTOR_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"_initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"_setFactory","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newReserveFactor","type":"uint256"}],"name":"_setReserveFactor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrowable","type":"address"}],"name":"addBorrowable","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowableInfo","outputs":[{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"bool","name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"borrowables","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrowable","type":"address"}],"name":"disableBorrowable","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrowable","type":"address"}],"name":"enableBorrowable","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exchangeRateLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBorrowablesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"borrowable","type":"address"}],"name":"indexOfBorrowable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"mintTokens","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"reallocate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"redeemer","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrowable","type":"address"}],"name":"removeBorrowable","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"reserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"sync","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrowable","type":"address"}],"name":"unwindBorrowable","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]

60806040526002805460ff19908116601217909155600b8054909116600117905567016345785d8a0000600f5561592f8061003b6000396000f3fe608060405234801561001057600080fd5b50600436106102925760003560e01c80637ecebe0011610160578063bc25cf77116100d8578063d505accf1161008c578063eb1ea9f411610071578063eb1ea9f414610891578063fca7820b146108c4578063fff6cae9146108e157610292565b8063d505accf146107f8578063dd62ed3e1461085657610292565b8063c45a0155116100bd578063c45a0155146107b5578063c5b7e148146107bd578063c72f3fbb146107f057610292565b8063bc25cf771461077a578063be340e32146107ad57610292565b806398084db71161012f578063ad7a672f11610114578063ad7a672f1461074d578063ade37c1314610755578063ba9a7a561461077257610292565b806398084db71461070c578063a9059cbb1461071457610292565b80637ecebe0014610696578063821beaf5146106c957806395a2251f146106d157806395d89b411461070457610292565b80633ba0b9a91161020e57806352ac4b02116101c25780636a627842116101a75780636a627842146105ff5780636f307dc31461063257806370a082311461066357610292565b806352ac4b021461057e578063579ce367146105b157610292565b80634643ec58116101f35780634643ec58146104645780634a5d316c14610543578063506fb0861461054b57610292565b80633ba0b9a9146104545780634322b7141461045c57610292565b806323b872dd11610265578063313ce5671161024a578063313ce567146103fb57806332fe35fd146104195780633644e5151461044c57610292565b806323b872dd146103b057806330adf81f146103f357610292565b806306fdde0314610297578063095ea7b31461031457806318160ddd14610361578063218b5b811461037b575b600080fd5b61029f6108e9565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102d95781810151838201526020016102c1565b50505050905090810190601f1680156103065780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61034d6004803603604081101561032a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610995565b604080519115158252519081900360200190f35b6103696109ac565b60408051918252519081900360200190f35b6103ae6004803603602081101561039157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166109b2565b005b61034d600480360360608110156103c657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e68565b610369610f7d565b610403610fa1565b6040805160ff9092168252519081900360200190f35b6103ae6004803603602081101561042f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610faa565b6103696112fe565b610369611304565b610369611388565b6103ae6004803603606081101561047a57600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691908101906040810160208201356401000000008111156104b257600080fd5b8201836020820111156104c457600080fd5b803590602001918460018302840111640100000000831117156104e657600080fd5b91939092909160208101903564010000000081111561050457600080fd5b82018360208201111561051657600080fd5b8035906020019184600183028401116401000000008311171561053857600080fd5b50909250905061138e565b6103ae6114df565b6103696004803603602081101561056157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611590565b6103ae6004803603602081101561059457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611650565b6105e4600480360360208110156105c757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166119a0565b60408051921515835290151560208301528051918290030190f35b6103696004803603602081101561061557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166119be565b61063a611bfd565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6103696004803603602081101561067957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611c19565b610369600480360360208110156106ac57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611c2b565b610369611c3d565b610369600480360360208110156106e757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611c43565b61029f611e09565b6103ae611e81565b61034d6004803603604081101561072a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135611f59565b610369611f66565b61063a6004803603602081101561076b57600080fd5b5035611f6c565b610369611fa0565b6103ae6004803603602081101561079057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611fa6565b6103696120cf565b61063a6120d5565b6103ae600480360360208110156107d357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166120f1565b6103696124a3565b6103ae600480360360e081101561080e57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c001356124af565b6103696004803603604081101561086c57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166124f3565b6103ae600480360360208110156108a757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612510565b6103ae600480360360208110156108da57600080fd5b5035612a15565b6103ae612ca2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561098d5780601f106109625761010080835404028352916020019161098d565b820191906000526020600020905b81548152906001019060200180831161097057829003601f168201915b505050505081565b60006109a2338484612d43565b5060015b92915050565b60035481565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b158015610a1a57600080fd5b505afa158015610a2e573d6000803e3d6000fd5b505050506040513d6020811015610a4457600080fd5b505173ffffffffffffffffffffffffffffffffffffffff163314610ac957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff16610b3a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600854604080517f6f307dc3000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff92831692841691636f307dc3916004808301926020929190829003018186803b158015610bcf57600080fd5b505afa158015610be3573d6000803e3d6000fd5b505050506040513d6020811015610bf957600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614610c67576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806158186022913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff1615610ceb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806156c96021913960400191505060405180910390fd5b600c54600a11610d46576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806158d56026913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600d602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff90911661010017166001908117909155600c8054918201815583527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180547fffffffffffffffffffffffff00000000000000000000000000000000000000001684179055517f3b94e6c56297c3ab2913d31d1c1adf8279146dbfb5624cc473e7af7a22d9c8469190a250600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff831660009081526005602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610f6757604080518082018252601e81527f496d7065726d61783a205452414e534645525f4e4f545f414c4c4f574544000060208083019190915273ffffffffffffffffffffffffffffffffffffffff87166000908152600582528381203382529091529190912054610f3591849063ffffffff612db216565b73ffffffffffffffffffffffffffffffffffffffff851660009081526005602090815260408083203384529091529020555b610f72848484612e63565b5060015b9392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60025460ff1681565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561101257600080fd5b505afa158015611026573d6000803e3d6000fd5b505050506040513d602081101561103c57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1633146110c157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff1661113257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905573ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff166111dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061583a6028913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff161561125c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806156a76022913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600d602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f54ba33e4b0861b4d81b3384c3b5130b25b55df191223d9e48b317dc289fac3a99190a250600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60065481565b60035460009081611325611316612f7c565b600a549063ffffffff612fe516565b9050811580611332575080155b1561134957670de0b6b3a764000092505050611385565b60006113738361136784670de0b6b3a764000063ffffffff61305916565b9063ffffffff6130cc16565b905061137f818461310e565b93505050505b90565b600f5481565b60095473ffffffffffffffffffffffffffffffffffffffff16331461141457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b61148784848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8801819004810282018101909252868152925086915085908190840183828082843760009201919091525061324092505050565b5050600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff94909416939093179092555050670de0b6b3a7640000600e55565b60095473ffffffffffffffffffffffffffffffffffffffff161561156457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f496d7065726d61783a20464143544f52595f414c52454144595f534554000000604482015290519081900360640190fd5b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055565b6000805b600c548110156115f9578273ffffffffffffffffffffffffffffffffffffffff16600c82815481106115c257fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614156115f157905061164b565b600101611594565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602481526020018061570d6024913960400191505060405180910390fd5b919050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b1580156116b857600080fd5b505afa1580156116cc573d6000803e3d6000fd5b505050506040513d60208110156116e257600080fd5b505173ffffffffffffffffffffffffffffffffffffffff16331461176757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff166117d857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905573ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff16611883576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061583a6028913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16611901576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806157316023913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600d602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f6149acc591caf5f3d506cb615abb39ea3847de4e2aa83f4382531de216bdc6809190a250600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600d6020526000908152604090205460ff8082169161010090041682565b600b5460009060ff16611a3257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600854600090611a7f9073ffffffffffffffffffffffffffffffffffffffff16613324565b90506000611a98600a54836133c690919063ffffffff16565b9050611abd611aa5611304565b61136783670de0b6b3a764000063ffffffff61305916565b925060035460001415611aeb57611adc836103e863ffffffff6133c616565b9250611aeb60006103e8613408565b60008311611b5a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4c656e64696e675661756c7456313a204d494e545f414d4f554e545f5a45524f604482015290519081900360640190fd5b611b648484613408565b611b6e60006134b9565b6040805182815260208101859052815173ffffffffffffffffffffffffffffffffffffffff87169233927f2f00e3cdd69a77be7ed215ec7b2a36784dd158f921fca79ac29deffa353fe6ee929081900390910190a35050611bcd613c21565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055919050565b60085473ffffffffffffffffffffffffffffffffffffffff1681565b60046020526000908152604090205481565b60076020526000908152604090205481565b600c5490565b600b5460009060ff16611cb757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905530600090815260046020526040902054611d13670de0b6b3a7640000611367611d06611304565b849063ffffffff61305916565b915060008211611d6e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806158b36022913960400191505060405180910390fd5b611d783082613c7c565b611d81826134b9565b600854611dab9073ffffffffffffffffffffffffffffffffffffffff16848463ffffffff613d4016565b6040805183815260208101839052815173ffffffffffffffffffffffffffffffffffffffff86169233927f3f693fff038bb8a046aa76d9516190ac7444f7d69cf952c4cbdc086fdef2d6fc929081900390910190a350611bcd613c21565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561098d5780601f106109625761010080835404028352916020019161098d565b600b5460ff16611ef257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055611f2460006134b9565b611f2c613c21565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60006109a2338484612e63565b600a5481565b600c8181548110611f7957fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6103e881565b600b5460ff1661201757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600a546008546120a191839161207b919061206f9073ffffffffffffffffffffffffffffffffffffffff16613324565b9063ffffffff6133c616565b60085473ffffffffffffffffffffffffffffffffffffffff16919063ffffffff613d4016565b50600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600e5481565b60095473ffffffffffffffffffffffffffffffffffffffff1681565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561215957600080fd5b505afa15801561216d573d6000803e3d6000fd5b505050506040513d602081101561218357600080fd5b505173ffffffffffffffffffffffffffffffffffffffff16331461220857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff1661227957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905573ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff16612324576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061583a6028913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16156123a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806156a76022913960400191505060405180910390fd5b60006123c48273ffffffffffffffffffffffffffffffffffffffff16613f1d565b90506000811161243557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4c656e64696e675661756c7456313a205a45524f5f414d4f554e540000000000604482015290519081900360640190fd5b60006124418383613fd1565b90508273ffffffffffffffffffffffffffffffffffffffff167f05750bc9042b6da04fdebec7b024caed5c2e2b35c707bd1fde571f31cdaeb5668383604051808381526020018281526020019250505060405180910390a250506120a1613c21565b670c7d713b49da000081565b6124df878787878787877f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9614051565b6124ea878787612d43565b50505050505050565b600560209081526000928352604080842090915290825290205481565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561257857600080fd5b505afa15801561258c573d6000803e3d6000fd5b505050506040513d60208110156125a257600080fd5b505173ffffffffffffffffffffffffffffffffffffffff16331461262757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff1661269857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905573ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff16612743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061583a6028913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16156127c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806156a76022913960400191505060405180910390fd5b6127e873ffffffffffffffffffffffffffffffffffffffff82163063ffffffff6142f416565b1561285457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4c656e64696e675661756c7456313a204e4f545f454d50545900000000000000604482015290519081900360640190fd5b600c547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600061288483611590565b9050600c828154811061289357fe5b600091825260209091200154600c805473ffffffffffffffffffffffffffffffffffffffff90921691839081106128c657fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600c80548061291957fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff8516808352600d909152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555190917f1f537c1571c0e7fa29083762436cadb3e57564c0f78e857e498cf428124c710e91a25050600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b158015612a7d57600080fd5b505afa158015612a91573d6000803e3d6000fd5b505050506040513d6020811015612aa757600080fd5b505173ffffffffffffffffffffffffffffffffffffffff163314612b2c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff16612b9d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055670c7d713b49da0000811115612c3c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4c656e64696e675661756c7456313a20494e56414c49445f53455454494e4700604482015290519081900360640190fd5b600f8190556040805182815290517f9d9cd27245b4e6b06dcf523ac57b6e851b934e199eee376313f906e94bfbfd559181900360200190a150600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600b5460ff16612d1357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055611f2c613c21565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260056020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b60008184841115612e5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e20578181015183820152602001612e08565b50505050905090810190601f168015612e4d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b604080518082018252601b81527f496d7065726d61783a205452414e534645525f544f4f5f48494748000000000060208083019190915273ffffffffffffffffffffffffffffffffffffffff8616600090815260049091529190912054612ed191839063ffffffff612db216565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600460205260408082209390935590841681522054612f13908263ffffffff612fe516565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526004602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6000805b600c54811015612fe1576000600c8281548110612f9957fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050612fd6612fc982613f1d565b849063ffffffff612fe516565b925050600101612f80565b5090565b600082820183811015610f7657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082613068575060006109a6565b8282028284828161307557fe5b0414610f76576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806157d16021913960400191505060405180910390fd5b6000610f7683836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506143a6565b600e546000908084111561323757600061315f613152670de0b6b3a7640000611367600f54613146878b6133c690919063ffffffff16565b9063ffffffff61305916565b869063ffffffff6133c616565b9050600061317b8561206f84611367838b63ffffffff61305916565b9050801561322857600954604080517f345ef941000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163345ef941916004808301926020929190829003018186803b1580156131ee57600080fd5b505afa158015613202573d6000803e3d6000fd5b505050506040513d602081101561321857600080fd5b505190506132268183613408565b505b50600e81905591506109a69050565b839150506109a6565b8151613253906000906020850190615573565b508051613267906001906020840190615573565b50604051469080605261577f82396040805191829003605201822086516020978801208383018352600184527f310000000000000000000000000000000000000000000000000000000000000093880193909352815180880191909152808201929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606083015260808201939093523060a0808301919091528351808303909101815260c090910190925250805192019190912060065550565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b15801561339457600080fd5b505afa1580156133a8573d6000803e3d6000fd5b505050506040513d60208110156133be57600080fd5b505192915050565b6000610f7683836040518060400160405280601f81526020017f536166654d6174683a207375627472616374696f6e20756e646572666c6f7700815250612db2565b60035461341b908263ffffffff612fe516565b60035573ffffffffffffffffffffffffffffffffffffffff8216600090815260046020526040902054613454908263ffffffff612fe516565b73ffffffffffffffffffffffffffffffffffffffff831660008181526004602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b600c5460408051828152602080840282010190915260609180156134f757816020015b6134e46155ed565b8152602001906001900390816134dc5790505b50600c5490915060005b600c548110156135f257600d6000600c838154811061351c57fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff16835282019290925260400190205460ff1661357f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909101906135ea565b600c54600090613595908463ffffffff6133c616565b90506135cf600c83815481106135a757fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1630614425565b84828403815181106135dd57fe5b6020026020010181905250505b600101613501565b506008546000906136189073ffffffffffffffffffffffffffffffffffffffff16613324565b905060005b8281101561367c57600061364385838151811061363657fe5b60200260200101516149b4565b865187908590811061365157fe5b60209081029190910101919091529050613671838263ffffffff612fe516565b92505060010161361d565b506136a8846040518060600160405280602681526020016157f26026913983919063ffffffff612db216565b905060005b600183038110156137825760005b816001850303811015613779576137048582600101815181106136da57fe5b60200260200101518683815181106136ee57fe5b6020026020010151614a1990919063ffffffff16565b613771576137106155ed565b85828151811061371c57fe5b6020026020010151905085826001018151811061373557fe5b602002602001015186838151811061374957fe5b60200260200101819052508086836001018151811061376457fe5b6020026020010181905250505b6001016136bb565b506001016136ad565b508160015b8381101561395e57600085828151811061379d57fe5b60200260200101516101400151905060008090506060836040519080825280602002602001820160405280156137dd578160200160208202803883390190505b509050826137f05783945050505061395e565b60005b8481101561388d578389828151811061380857fe5b602002602001015161014001511161381f5761388d565b613845848a838151811061382f57fe5b6020026020010151614a2790919063ffffffff16565b82828151811061385157fe5b60200260200101818152505061388382828151811061386c57fe5b602002602001015184612fe590919063ffffffff16565b92506001016137f3565b50858211156138a15783945050505061395e565b60005b8481101561394e578181815181106138b857fe5b6020026020010151600014156138cd57613946565b6139068282815181106138dc57fe5b60200260200101518a83815181106138f057fe5b6020026020010151614bdd90919063ffffffff16565b89828151811061391257fe5b602002602001018190525061394382828151811061392c57fe5b6020026020010151886133c690919063ffffffff16565b96505b6001016138a4565b5050600190920191506137879050565b50600082815b838110156139955761398b612fc988838151811061397e57fe5b6020026020010151614c15565b9250600101613964565b5060005b83811015613a165760008084116139b057856139c7565b6139c784611367856131468c878151811061397e57fe5b9050858111156139d45750845b6139e4818984815181106138f057fe5b8883815181106139f057fe5b6020908102919091010152613a0b868263ffffffff6133c616565b955050600101613999565b5060005b85811015613ae157868181518110613a2e57fe5b602002602001015160800151878281518110613a4657fe5b602002602001015160a001511015613ad9576000613a9b888381518110613a6957fe5b602002602001015160a00151898481518110613a8157fe5b6020026020010151608001516133c690919063ffffffff16565b9050613ad6888381518110613aac57fe5b602002602001015160000151828a8581518110613ac557fe5b602002602001015160200151614c32565b50505b600101613a1a565b50613b2e876040518060600160405280602b8152602001615754602b9139600854613b219073ffffffffffffffffffffffffffffffffffffffff16613324565b919063ffffffff612db216565b935060005b85811015613c1757868181518110613b4757fe5b602002602001015160800151878281518110613b5f57fe5b602002602001015160a001511115613c0f576000613bb4888381518110613b8257fe5b602002602001015160800151898481518110613b9a57fe5b602002602001015160a001516133c690919063ffffffff16565b905085811115613bc15750845b613bd1868263ffffffff6133c616565b9550613c0c888381518110613be257fe5b602002602001015160000151828a8581518110613bfb57fe5b602002602001015160200151614c50565b50505b600101613b33565b5050505050505050565b600854613c439073ffffffffffffffffffffffffffffffffffffffff16613324565b600a81905560408051918252517f8a0df8ef054fae2c3d2d19a7b322e864870cc9fd3cb07fb9526309c596244bf49181900360200190a1565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020526040902054613cb2908263ffffffff6133c616565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260046020526040902055600354613ceb908263ffffffff6133c616565b60035560408051828152905160009173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613e1657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613dd9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613e78576040519150601f19603f3d011682016040523d82523d6000602084013e613e7d565b606091505b5091509150818015613eab575080511580613eab5750808060200190516020811015613ea857600080fd5b50515b613f1657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f21736166655472616e7366657200000000000000000000000000000000000000604482015290519081900360640190fd5b5050505050565b60006109a6828373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613fa057600080fd5b505afa158015613fb4573d6000803e3d6000fd5b505050506040513d6020811015613fca57600080fd5b5051614d9e565b6000610f7683838573ffffffffffffffffffffffffffffffffffffffff16633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561402057600080fd5b505af1158015614034573d6000803e3d6000fd5b505050506040513d602081101561404a57600080fd5b5051614c32565b428510156140c057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f496d7065726d61783a2045585049524544000000000000000000000000000000604482015290519081900360640190fd5b60065473ffffffffffffffffffffffffffffffffffffffff808a1660008181526007602090815260408083208054600180820190925582518085018a905280840196909652958e166060860152608085018d905260a085019590955260c08085018c90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff8a166101828501526101a284018990526101c28401889052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015614202573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81161580159061427d57508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6142e857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f496d7065726d61783a20494e56414c49445f5349474e41545552450000000000604482015290519081900360640190fd5b50505050505050505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a08231836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561437357600080fd5b505afa158015614387573d6000803e3d6000fd5b505050506040513d602081101561439d57600080fd5b50519392505050565b6000818361440f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315612e20578181015183820152602001612e08565b50600083858161441b57fe5b0495945050505050565b61442d6155ed565b8273ffffffffffffffffffffffffffffffffffffffff1663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561447557600080fd5b505af1158015614489573d6000803e3d6000fd5b5050505060008373ffffffffffffffffffffffffffffffffffffffff16633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156144d757600080fd5b505af11580156144eb573d6000803e3d6000fd5b505050506040513d602081101561450157600080fd5b5051604080517f18160ddd000000000000000000000000000000000000000000000000000000008152905191925060009173ffffffffffffffffffffffffffffffffffffffff8716916318160ddd916004808301926020929190829003018186803b15801561456f57600080fd5b505afa158015614583573d6000803e3d6000fd5b505050506040513d602081101561459957600080fd5b5051604080517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529151929350600092918816916370a0823191602480820192602092909190829003018186803b15801561461157600080fd5b505afa158015614625573d6000803e3d6000fd5b505050506040513d602081101561463b57600080fd5b505190506000614651838363ffffffff6133c616565b90506040518061016001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018873ffffffffffffffffffffffffffffffffffffffff166347bd37186040518163ffffffff1660e01b815260040160206040518083038186803b1580156146c757600080fd5b505afa1580156146db573d6000803e3d6000fd5b505050506040513d60208110156146f157600080fd5b50518152602001614714670de0b6b3a7640000611367858963ffffffff61305916565b8152602001614735670de0b6b3a7640000611367868963ffffffff61305916565b8152602001614756670de0b6b3a7640000611367868963ffffffff61305916565b81526020018873ffffffffffffffffffffffffffffffffffffffff166391b427456040518163ffffffff1660e01b815260040160206040518083038186803b1580156147a157600080fd5b505afa1580156147b5573d6000803e3d6000fd5b505050506040513d60208110156147cb57600080fd5b50518152604080517f1aebf12f000000000000000000000000000000000000000000000000000000008152905160209283019273ffffffffffffffffffffffffffffffffffffffff8c1692631aebf12f9260048083019392829003018186803b15801561483757600080fd5b505afa15801561484b573d6000803e3d6000fd5b505050506040513d602081101561486157600080fd5b50518152604080517f4322b714000000000000000000000000000000000000000000000000000000008152905160209283019273ffffffffffffffffffffffffffffffffffffffff8c1692634322b7149260048083019392829003018186803b1580156148cd57600080fd5b505afa1580156148e1573d6000803e3d6000fd5b505050506040513d60208110156148f757600080fd5b50518152604080517f5b2b9d1a000000000000000000000000000000000000000000000000000000008152905160209283019273ffffffffffffffffffffffffffffffffffffffff8c1692635b2b9d1a9260048083019392829003018186803b15801561496357600080fd5b505afa158015614977573d6000803e3d6000fd5b505050506040513d602081101561498d57600080fd5b50518152600060209091015294506149a485614e33565b6101408601525050505092915050565b6149bc6155ed565b600082604001516149cc84614c15565b10156149dd57508190506000614a14565b60006149f0846040015161206f86614c15565b90506000614a028560a0015183614f33565b9050614a0e8582614f49565b93509150505b915091565b610140908101519101511190565b6000808211614a9757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4552524f523a2072617465203d20300000000000000000000000000000000000604482015290519081900360640190fd5b826101400151821115614b0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4552524f523a205441524745542052415445203e204341434845442052415445604482015290519081900360640190fd5b6000614b178484615009565b9050614b22846151e4565b811115614b7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f815260200180615678602f913960400191505060405180910390fd5b6000614b9f82611367670de0b6b3a7640000886040015161305990919063ffffffff16565b9050614bd4614bad86614c15565b6040518060600160405280602381526020016158906023913983919063ffffffff612db216565b95945050505050565b614be56155ed565b60a0830151614bfa908363ffffffff612fe516565b60a0840152614c0883614e33565b6101408401525090919050565b60006109a68260a001518360600151612fe590919063ffffffff16565b6000614c4884614c428585615224565b84615232565b949350505050565b6000614c6e8261136785670de0b6b3a764000063ffffffff61305916565b905080614c7d57506000610f76565b600854614ca79073ffffffffffffffffffffffffffffffffffffffff16858563ffffffff613d4016565b604080517f6a627842000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff861691636a6278429160248083019260209291908290030181600087803b158015614d1557600080fd5b505af1158015614d29573d6000803e3d6000fd5b505050506040513d6020811015614d3f57600080fd5b50516040805185815260208101839052815192935073ffffffffffffffffffffffffffffffffffffffff8716927f20541ba081e1e2ed9b41701070442c1fe618b0fec04825ba790aea8373f4e237929181900390910190a29392505050565b6000808373ffffffffffffffffffffffffffffffffffffffff16633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614de957600080fd5b505af1158015614dfd573d6000803e3d6000fd5b505050506040513d6020811015614e1357600080fd5b50519050614c48670de0b6b3a7640000611367858463ffffffff61305916565b600080614e3f836151e4565b90506000614e668460e00151611367670de0b6b3a76400008561305990919063ffffffff16565b905060008460e00151831015614e7d575080614efe565b6000614ec4614ea18760e00151670de0b6b3a76400006133c690919063ffffffff16565b611367670de0b6b3a76400006131468a60e00151896133c690919063ffffffff16565b9050614efa670de0b6b3a7640000614eee611d0660018a61012001516133c690919063ffffffff16565b9063ffffffff612fe516565b9150505b614bd4670de0b6b3a764000061136784613146670de0b6b3a7640000611367614f268c61541b565b889063ffffffff61305916565b6000818310614f425781610f76565b5090919050565b614f516155ed565b6000614f7d84604001516040518060600160405280602381526020016156ea60239139613b2187614c15565b905080831115614fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180615862602e913960400191505060405180910390fd5b60a0840151614fed908463ffffffff6133c616565b60a0850152614ffb84614e33565b610140850152509192915050565b60006150148361541b565b821161506d57615066670de0b6b3a76400006113678560e00151613146615061670de0b6b3a76400006131466150498b61541b565b6113678b670de0b6b3a764000063ffffffff61305916565b615473565b905061516d565b61012083015160009061508790600163ffffffff6133c616565b905060006150b3670de0b6b3a764000061206f8761012001518860e0015161305990919063ffffffff16565b905060006151086150c38761541b565b6113676150e58960e00151670de0b6b3a76400006133c690919063ffffffff16565b613146670de0b6b3a76400006113678c60e001518c61305990919063ffffffff16565b9050600061514d615061670de0b6b3a76400006131466151316004828a8963ffffffff61305916565b614eee670de0b6b3a76400006113678a8063ffffffff61305916565b905061516660026113678681858863ffffffff612fe516565b9450505050505b670de0b6b3a76400008111156109a657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4552524f523a20544152474554205554494c495a4154494f4e203e2031303025604482015290519081900360640190fd5b6000806151f083614c15565b90508061520157600091505061164b565b610f7681611367670de0b6b3a7640000866040015161305990919063ffffffff16565b6000610f76838360006154c4565b6000615250670de0b6b3a7640000611367858563ffffffff61305916565b90508061525f57506000610f76565b60008473ffffffffffffffffffffffffffffffffffffffff1663ad7a672f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156152a757600080fd5b505afa1580156152bb573d6000803e3d6000fd5b505050506040513d60208110156152d157600080fd5b50519050808211156152fc576152f98361136783670de0b6b3a764000063ffffffff61305916565b93505b61532373ffffffffffffffffffffffffffffffffffffffff8616868663ffffffff613d4016565b604080517f95a2251f000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8716916395a2251f9160248083019260209291908290030181600087803b15801561539157600080fd5b505af11580156153a5573d6000803e3d6000fd5b505050506040513d60208110156153bb57600080fd5b50516040805182815260208101879052815192945073ffffffffffffffffffffffffffffffffffffffff8816927f8d69ef09150dd510133bc8e54e6ca115e8cf3370ea49a4a5ae56a1cdefc835e9929181900390910190a2509392505050565b60006109a6670de0b6b3a764000061136761544c856101000151670de0b6b3a76400006133c690919063ffffffff16565b613146670de0b6b3a76400006113678860c001518960e0015161305990919063ffffffff16565b600060038211156154b6575080600160028204015b818110156154b05780915060028182858161549f57fe5b0401816154a857fe5b049050615488565b5061164b565b811561164b57506001919050565b6000806154e38461136787670de0b6b3a764000063ffffffff61305916565b905060006154f882600163ffffffff612fe516565b9050831561553a57600061551e670de0b6b3a7640000611367848963ffffffff61305916565b90508681111561552e5782615530565b815b9350505050610f76565b6000615558670de0b6b3a7640000611367858963ffffffff61305916565b9050868110156155685781615530565b829350505050610f76565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106155b457805160ff19168380011785556155e1565b828001600101855582156155e1579182015b828111156155e15782518255916020019190600101906155c6565b50612fe192915061565d565b604051806101600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61138591905b80821115612fe1576000815560010161566356fe4552524f523a20544152474554205554494c495a4154494f4e203e2043555252454e54205554494c495a4154494f4e4c656e64696e675661756c7456313a20424f52524f5741424c455f454e41424c45444c656e64696e675661756c7456313a20424f52524f5741424c455f4558495354534552524f523a204e4547415449564520415641494c41424c45204c49515549444954594c656e64696e675661756c7456313a20424f52524f5741424c455f4e4f545f464f554e444c656e64696e675661756c7456313a20424f52524f5741424c455f44495341424c45444c656e64696e675661756c7456313a204e4547415449564520414d4f554e5420544f20414c4c4f43415445454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774c656e64696e675661756c7456313a20494e53554646494349454e545f4c49515549444954594c656e64696e675661756c7456313a20494e56414c49445f554e4445524c59494e474c656e64696e675661756c7456313a20424f52524f5741424c455f444f45534e545f4558495354534552524f523a204445414c4c4f4341544520414d4f554e54203e20415641494c41424c45204c49515549444954594552524f523a2054415247455420535550504c59203e20544f54414c20535550504c594c656e64696e675661756c7456313a2052454445454d5f414d4f554e545f5a45524f4c656e64696e675661756c7456313a204d41585f424f52524f5741424c45535f4c454e475448a265627a7a72315820272b1ff2f5bdfb5ffe4ff85e7b931a1776d5924d30728d423cc60a2c786295d764736f6c63430005100032

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102925760003560e01c80637ecebe0011610160578063bc25cf77116100d8578063d505accf1161008c578063eb1ea9f411610071578063eb1ea9f414610891578063fca7820b146108c4578063fff6cae9146108e157610292565b8063d505accf146107f8578063dd62ed3e1461085657610292565b8063c45a0155116100bd578063c45a0155146107b5578063c5b7e148146107bd578063c72f3fbb146107f057610292565b8063bc25cf771461077a578063be340e32146107ad57610292565b806398084db71161012f578063ad7a672f11610114578063ad7a672f1461074d578063ade37c1314610755578063ba9a7a561461077257610292565b806398084db71461070c578063a9059cbb1461071457610292565b80637ecebe0014610696578063821beaf5146106c957806395a2251f146106d157806395d89b411461070457610292565b80633ba0b9a91161020e57806352ac4b02116101c25780636a627842116101a75780636a627842146105ff5780636f307dc31461063257806370a082311461066357610292565b806352ac4b021461057e578063579ce367146105b157610292565b80634643ec58116101f35780634643ec58146104645780634a5d316c14610543578063506fb0861461054b57610292565b80633ba0b9a9146104545780634322b7141461045c57610292565b806323b872dd11610265578063313ce5671161024a578063313ce567146103fb57806332fe35fd146104195780633644e5151461044c57610292565b806323b872dd146103b057806330adf81f146103f357610292565b806306fdde0314610297578063095ea7b31461031457806318160ddd14610361578063218b5b811461037b575b600080fd5b61029f6108e9565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102d95781810151838201526020016102c1565b50505050905090810190601f1680156103065780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61034d6004803603604081101561032a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610995565b604080519115158252519081900360200190f35b6103696109ac565b60408051918252519081900360200190f35b6103ae6004803603602081101561039157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166109b2565b005b61034d600480360360608110156103c657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e68565b610369610f7d565b610403610fa1565b6040805160ff9092168252519081900360200190f35b6103ae6004803603602081101561042f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610faa565b6103696112fe565b610369611304565b610369611388565b6103ae6004803603606081101561047a57600080fd5b73ffffffffffffffffffffffffffffffffffffffff82351691908101906040810160208201356401000000008111156104b257600080fd5b8201836020820111156104c457600080fd5b803590602001918460018302840111640100000000831117156104e657600080fd5b91939092909160208101903564010000000081111561050457600080fd5b82018360208201111561051657600080fd5b8035906020019184600183028401116401000000008311171561053857600080fd5b50909250905061138e565b6103ae6114df565b6103696004803603602081101561056157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611590565b6103ae6004803603602081101561059457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611650565b6105e4600480360360208110156105c757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166119a0565b60408051921515835290151560208301528051918290030190f35b6103696004803603602081101561061557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166119be565b61063a611bfd565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6103696004803603602081101561067957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611c19565b610369600480360360208110156106ac57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611c2b565b610369611c3d565b610369600480360360208110156106e757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611c43565b61029f611e09565b6103ae611e81565b61034d6004803603604081101561072a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135611f59565b610369611f66565b61063a6004803603602081101561076b57600080fd5b5035611f6c565b610369611fa0565b6103ae6004803603602081101561079057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611fa6565b6103696120cf565b61063a6120d5565b6103ae600480360360208110156107d357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166120f1565b6103696124a3565b6103ae600480360360e081101561080e57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c001356124af565b6103696004803603604081101561086c57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166124f3565b6103ae600480360360208110156108a757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612510565b6103ae600480360360208110156108da57600080fd5b5035612a15565b6103ae612ca2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561098d5780601f106109625761010080835404028352916020019161098d565b820191906000526020600020905b81548152906001019060200180831161097057829003601f168201915b505050505081565b60006109a2338484612d43565b5060015b92915050565b60035481565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b158015610a1a57600080fd5b505afa158015610a2e573d6000803e3d6000fd5b505050506040513d6020811015610a4457600080fd5b505173ffffffffffffffffffffffffffffffffffffffff163314610ac957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff16610b3a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600854604080517f6f307dc3000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff92831692841691636f307dc3916004808301926020929190829003018186803b158015610bcf57600080fd5b505afa158015610be3573d6000803e3d6000fd5b505050506040513d6020811015610bf957600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1614610c67576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806158186022913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff1615610ceb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806156c96021913960400191505060405180910390fd5b600c54600a11610d46576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806158d56026913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600d602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff90911661010017166001908117909155600c8054918201815583527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180547fffffffffffffffffffffffff00000000000000000000000000000000000000001684179055517f3b94e6c56297c3ab2913d31d1c1adf8279146dbfb5624cc473e7af7a22d9c8469190a250600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff831660009081526005602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610f6757604080518082018252601e81527f496d7065726d61783a205452414e534645525f4e4f545f414c4c4f574544000060208083019190915273ffffffffffffffffffffffffffffffffffffffff87166000908152600582528381203382529091529190912054610f3591849063ffffffff612db216565b73ffffffffffffffffffffffffffffffffffffffff851660009081526005602090815260408083203384529091529020555b610f72848484612e63565b5060015b9392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60025460ff1681565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561101257600080fd5b505afa158015611026573d6000803e3d6000fd5b505050506040513d602081101561103c57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff1633146110c157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff1661113257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905573ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff166111dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061583a6028913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff161561125c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806156a76022913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600d602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f54ba33e4b0861b4d81b3384c3b5130b25b55df191223d9e48b317dc289fac3a99190a250600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60065481565b60035460009081611325611316612f7c565b600a549063ffffffff612fe516565b9050811580611332575080155b1561134957670de0b6b3a764000092505050611385565b60006113738361136784670de0b6b3a764000063ffffffff61305916565b9063ffffffff6130cc16565b905061137f818461310e565b93505050505b90565b600f5481565b60095473ffffffffffffffffffffffffffffffffffffffff16331461141457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b61148784848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8801819004810282018101909252868152925086915085908190840183828082843760009201919091525061324092505050565b5050600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff94909416939093179092555050670de0b6b3a7640000600e55565b60095473ffffffffffffffffffffffffffffffffffffffff161561156457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f496d7065726d61783a20464143544f52595f414c52454144595f534554000000604482015290519081900360640190fd5b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055565b6000805b600c548110156115f9578273ffffffffffffffffffffffffffffffffffffffff16600c82815481106115c257fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614156115f157905061164b565b600101611594565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602481526020018061570d6024913960400191505060405180910390fd5b919050565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b1580156116b857600080fd5b505afa1580156116cc573d6000803e3d6000fd5b505050506040513d60208110156116e257600080fd5b505173ffffffffffffffffffffffffffffffffffffffff16331461176757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff166117d857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905573ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff16611883576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061583a6028913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16611901576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806157316023913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600d602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f6149acc591caf5f3d506cb615abb39ea3847de4e2aa83f4382531de216bdc6809190a250600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600d6020526000908152604090205460ff8082169161010090041682565b600b5460009060ff16611a3257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600854600090611a7f9073ffffffffffffffffffffffffffffffffffffffff16613324565b90506000611a98600a54836133c690919063ffffffff16565b9050611abd611aa5611304565b61136783670de0b6b3a764000063ffffffff61305916565b925060035460001415611aeb57611adc836103e863ffffffff6133c616565b9250611aeb60006103e8613408565b60008311611b5a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4c656e64696e675661756c7456313a204d494e545f414d4f554e545f5a45524f604482015290519081900360640190fd5b611b648484613408565b611b6e60006134b9565b6040805182815260208101859052815173ffffffffffffffffffffffffffffffffffffffff87169233927f2f00e3cdd69a77be7ed215ec7b2a36784dd158f921fca79ac29deffa353fe6ee929081900390910190a35050611bcd613c21565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055919050565b60085473ffffffffffffffffffffffffffffffffffffffff1681565b60046020526000908152604090205481565b60076020526000908152604090205481565b600c5490565b600b5460009060ff16611cb757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905530600090815260046020526040902054611d13670de0b6b3a7640000611367611d06611304565b849063ffffffff61305916565b915060008211611d6e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806158b36022913960400191505060405180910390fd5b611d783082613c7c565b611d81826134b9565b600854611dab9073ffffffffffffffffffffffffffffffffffffffff16848463ffffffff613d4016565b6040805183815260208101839052815173ffffffffffffffffffffffffffffffffffffffff86169233927f3f693fff038bb8a046aa76d9516190ac7444f7d69cf952c4cbdc086fdef2d6fc929081900390910190a350611bcd613c21565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561098d5780601f106109625761010080835404028352916020019161098d565b600b5460ff16611ef257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055611f2460006134b9565b611f2c613c21565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60006109a2338484612e63565b600a5481565b600c8181548110611f7957fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6103e881565b600b5460ff1661201757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600a546008546120a191839161207b919061206f9073ffffffffffffffffffffffffffffffffffffffff16613324565b9063ffffffff6133c616565b60085473ffffffffffffffffffffffffffffffffffffffff16919063ffffffff613d4016565b50600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600e5481565b60095473ffffffffffffffffffffffffffffffffffffffff1681565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561215957600080fd5b505afa15801561216d573d6000803e3d6000fd5b505050506040513d602081101561218357600080fd5b505173ffffffffffffffffffffffffffffffffffffffff16331461220857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff1661227957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905573ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff16612324576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061583a6028913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16156123a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806156a76022913960400191505060405180910390fd5b60006123c48273ffffffffffffffffffffffffffffffffffffffff16613f1d565b90506000811161243557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4c656e64696e675661756c7456313a205a45524f5f414d4f554e540000000000604482015290519081900360640190fd5b60006124418383613fd1565b90508273ffffffffffffffffffffffffffffffffffffffff167f05750bc9042b6da04fdebec7b024caed5c2e2b35c707bd1fde571f31cdaeb5668383604051808381526020018281526020019250505060405180910390a250506120a1613c21565b670c7d713b49da000081565b6124df878787878787877f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9614051565b6124ea878787612d43565b50505050505050565b600560209081526000928352604080842090915290825290205481565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561257857600080fd5b505afa15801561258c573d6000803e3d6000fd5b505050506040513d60208110156125a257600080fd5b505173ffffffffffffffffffffffffffffffffffffffff16331461262757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff1661269857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905573ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040902054610100900460ff16612743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061583a6028913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff16156127c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806156a76022913960400191505060405180910390fd5b6127e873ffffffffffffffffffffffffffffffffffffffff82163063ffffffff6142f416565b1561285457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4c656e64696e675661756c7456313a204e4f545f454d50545900000000000000604482015290519081900360640190fd5b600c547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600061288483611590565b9050600c828154811061289357fe5b600091825260209091200154600c805473ffffffffffffffffffffffffffffffffffffffff90921691839081106128c657fe5b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600c80548061291957fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff8516808352600d909152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690555190917f1f537c1571c0e7fa29083762436cadb3e57564c0f78e857e498cf428124c710e91a25050600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b158015612a7d57600080fd5b505afa158015612a91573d6000803e3d6000fd5b505050506040513d6020811015612aa757600080fd5b505173ffffffffffffffffffffffffffffffffffffffff163314612b2c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4c656e64696e675661756c7456313a20554e415554484f52495a454400000000604482015290519081900360640190fd5b600b5460ff16612b9d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055670c7d713b49da0000811115612c3c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4c656e64696e675661756c7456313a20494e56414c49445f53455454494e4700604482015290519081900360640190fd5b600f8190556040805182815290517f9d9cd27245b4e6b06dcf523ac57b6e851b934e199eee376313f906e94bfbfd559181900360200190a150600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600b5460ff16612d1357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f496d7065726d61783a205245454e544552454400000000000000000000000000604482015290519081900360640190fd5b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055611f2c613c21565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260056020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b60008184841115612e5b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e20578181015183820152602001612e08565b50505050905090810190601f168015612e4d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b604080518082018252601b81527f496d7065726d61783a205452414e534645525f544f4f5f48494748000000000060208083019190915273ffffffffffffffffffffffffffffffffffffffff8616600090815260049091529190912054612ed191839063ffffffff612db216565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600460205260408082209390935590841681522054612f13908263ffffffff612fe516565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526004602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6000805b600c54811015612fe1576000600c8281548110612f9957fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169050612fd6612fc982613f1d565b849063ffffffff612fe516565b925050600101612f80565b5090565b600082820183811015610f7657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082613068575060006109a6565b8282028284828161307557fe5b0414610f76576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806157d16021913960400191505060405180910390fd5b6000610f7683836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506143a6565b600e546000908084111561323757600061315f613152670de0b6b3a7640000611367600f54613146878b6133c690919063ffffffff16565b9063ffffffff61305916565b869063ffffffff6133c616565b9050600061317b8561206f84611367838b63ffffffff61305916565b9050801561322857600954604080517f345ef941000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163345ef941916004808301926020929190829003018186803b1580156131ee57600080fd5b505afa158015613202573d6000803e3d6000fd5b505050506040513d602081101561321857600080fd5b505190506132268183613408565b505b50600e81905591506109a69050565b839150506109a6565b8151613253906000906020850190615573565b508051613267906001906020840190615573565b50604051469080605261577f82396040805191829003605201822086516020978801208383018352600184527f310000000000000000000000000000000000000000000000000000000000000093880193909352815180880191909152808201929092527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606083015260808201939093523060a0808301919091528351808303909101815260c090910190925250805192019190912060065550565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff8416916370a0823191602480820192602092909190829003018186803b15801561339457600080fd5b505afa1580156133a8573d6000803e3d6000fd5b505050506040513d60208110156133be57600080fd5b505192915050565b6000610f7683836040518060400160405280601f81526020017f536166654d6174683a207375627472616374696f6e20756e646572666c6f7700815250612db2565b60035461341b908263ffffffff612fe516565b60035573ffffffffffffffffffffffffffffffffffffffff8216600090815260046020526040902054613454908263ffffffff612fe516565b73ffffffffffffffffffffffffffffffffffffffff831660008181526004602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b600c5460408051828152602080840282010190915260609180156134f757816020015b6134e46155ed565b8152602001906001900390816134dc5790505b50600c5490915060005b600c548110156135f257600d6000600c838154811061351c57fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff16835282019290925260400190205460ff1661357f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909101906135ea565b600c54600090613595908463ffffffff6133c616565b90506135cf600c83815481106135a757fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1630614425565b84828403815181106135dd57fe5b6020026020010181905250505b600101613501565b506008546000906136189073ffffffffffffffffffffffffffffffffffffffff16613324565b905060005b8281101561367c57600061364385838151811061363657fe5b60200260200101516149b4565b865187908590811061365157fe5b60209081029190910101919091529050613671838263ffffffff612fe516565b92505060010161361d565b506136a8846040518060600160405280602681526020016157f26026913983919063ffffffff612db216565b905060005b600183038110156137825760005b816001850303811015613779576137048582600101815181106136da57fe5b60200260200101518683815181106136ee57fe5b6020026020010151614a1990919063ffffffff16565b613771576137106155ed565b85828151811061371c57fe5b6020026020010151905085826001018151811061373557fe5b602002602001015186838151811061374957fe5b60200260200101819052508086836001018151811061376457fe5b6020026020010181905250505b6001016136bb565b506001016136ad565b508160015b8381101561395e57600085828151811061379d57fe5b60200260200101516101400151905060008090506060836040519080825280602002602001820160405280156137dd578160200160208202803883390190505b509050826137f05783945050505061395e565b60005b8481101561388d578389828151811061380857fe5b602002602001015161014001511161381f5761388d565b613845848a838151811061382f57fe5b6020026020010151614a2790919063ffffffff16565b82828151811061385157fe5b60200260200101818152505061388382828151811061386c57fe5b602002602001015184612fe590919063ffffffff16565b92506001016137f3565b50858211156138a15783945050505061395e565b60005b8481101561394e578181815181106138b857fe5b6020026020010151600014156138cd57613946565b6139068282815181106138dc57fe5b60200260200101518a83815181106138f057fe5b6020026020010151614bdd90919063ffffffff16565b89828151811061391257fe5b602002602001018190525061394382828151811061392c57fe5b6020026020010151886133c690919063ffffffff16565b96505b6001016138a4565b5050600190920191506137879050565b50600082815b838110156139955761398b612fc988838151811061397e57fe5b6020026020010151614c15565b9250600101613964565b5060005b83811015613a165760008084116139b057856139c7565b6139c784611367856131468c878151811061397e57fe5b9050858111156139d45750845b6139e4818984815181106138f057fe5b8883815181106139f057fe5b6020908102919091010152613a0b868263ffffffff6133c616565b955050600101613999565b5060005b85811015613ae157868181518110613a2e57fe5b602002602001015160800151878281518110613a4657fe5b602002602001015160a001511015613ad9576000613a9b888381518110613a6957fe5b602002602001015160a00151898481518110613a8157fe5b6020026020010151608001516133c690919063ffffffff16565b9050613ad6888381518110613aac57fe5b602002602001015160000151828a8581518110613ac557fe5b602002602001015160200151614c32565b50505b600101613a1a565b50613b2e876040518060600160405280602b8152602001615754602b9139600854613b219073ffffffffffffffffffffffffffffffffffffffff16613324565b919063ffffffff612db216565b935060005b85811015613c1757868181518110613b4757fe5b602002602001015160800151878281518110613b5f57fe5b602002602001015160a001511115613c0f576000613bb4888381518110613b8257fe5b602002602001015160800151898481518110613b9a57fe5b602002602001015160a001516133c690919063ffffffff16565b905085811115613bc15750845b613bd1868263ffffffff6133c616565b9550613c0c888381518110613be257fe5b602002602001015160000151828a8581518110613bfb57fe5b602002602001015160200151614c50565b50505b600101613b33565b5050505050505050565b600854613c439073ffffffffffffffffffffffffffffffffffffffff16613324565b600a81905560408051918252517f8a0df8ef054fae2c3d2d19a7b322e864870cc9fd3cb07fb9526309c596244bf49181900360200190a1565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020526040902054613cb2908263ffffffff6133c616565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260046020526040902055600354613ceb908263ffffffff6133c616565b60035560408051828152905160009173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000178152925182516000946060949389169392918291908083835b60208310613e1657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101613dd9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613e78576040519150601f19603f3d011682016040523d82523d6000602084013e613e7d565b606091505b5091509150818015613eab575080511580613eab5750808060200190516020811015613ea857600080fd5b50515b613f1657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f21736166655472616e7366657200000000000000000000000000000000000000604482015290519081900360640190fd5b5050505050565b60006109a6828373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613fa057600080fd5b505afa158015613fb4573d6000803e3d6000fd5b505050506040513d6020811015613fca57600080fd5b5051614d9e565b6000610f7683838573ffffffffffffffffffffffffffffffffffffffff16633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561402057600080fd5b505af1158015614034573d6000803e3d6000fd5b505050506040513d602081101561404a57600080fd5b5051614c32565b428510156140c057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f496d7065726d61783a2045585049524544000000000000000000000000000000604482015290519081900360640190fd5b60065473ffffffffffffffffffffffffffffffffffffffff808a1660008181526007602090815260408083208054600180820190925582518085018a905280840196909652958e166060860152608085018d905260a085019590955260c08085018c90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff8a166101828501526101a284018990526101c28401889052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015614202573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81161580159061427d57508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6142e857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f496d7065726d61783a20494e56414c49445f5349474e41545552450000000000604482015290519081900360640190fd5b50505050505050505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a08231836040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561437357600080fd5b505afa158015614387573d6000803e3d6000fd5b505050506040513d602081101561439d57600080fd5b50519392505050565b6000818361440f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315612e20578181015183820152602001612e08565b50600083858161441b57fe5b0495945050505050565b61442d6155ed565b8273ffffffffffffffffffffffffffffffffffffffff1663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561447557600080fd5b505af1158015614489573d6000803e3d6000fd5b5050505060008373ffffffffffffffffffffffffffffffffffffffff16633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156144d757600080fd5b505af11580156144eb573d6000803e3d6000fd5b505050506040513d602081101561450157600080fd5b5051604080517f18160ddd000000000000000000000000000000000000000000000000000000008152905191925060009173ffffffffffffffffffffffffffffffffffffffff8716916318160ddd916004808301926020929190829003018186803b15801561456f57600080fd5b505afa158015614583573d6000803e3d6000fd5b505050506040513d602081101561459957600080fd5b5051604080517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301529151929350600092918816916370a0823191602480820192602092909190829003018186803b15801561461157600080fd5b505afa158015614625573d6000803e3d6000fd5b505050506040513d602081101561463b57600080fd5b505190506000614651838363ffffffff6133c616565b90506040518061016001604052808873ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018873ffffffffffffffffffffffffffffffffffffffff166347bd37186040518163ffffffff1660e01b815260040160206040518083038186803b1580156146c757600080fd5b505afa1580156146db573d6000803e3d6000fd5b505050506040513d60208110156146f157600080fd5b50518152602001614714670de0b6b3a7640000611367858963ffffffff61305916565b8152602001614735670de0b6b3a7640000611367868963ffffffff61305916565b8152602001614756670de0b6b3a7640000611367868963ffffffff61305916565b81526020018873ffffffffffffffffffffffffffffffffffffffff166391b427456040518163ffffffff1660e01b815260040160206040518083038186803b1580156147a157600080fd5b505afa1580156147b5573d6000803e3d6000fd5b505050506040513d60208110156147cb57600080fd5b50518152604080517f1aebf12f000000000000000000000000000000000000000000000000000000008152905160209283019273ffffffffffffffffffffffffffffffffffffffff8c1692631aebf12f9260048083019392829003018186803b15801561483757600080fd5b505afa15801561484b573d6000803e3d6000fd5b505050506040513d602081101561486157600080fd5b50518152604080517f4322b714000000000000000000000000000000000000000000000000000000008152905160209283019273ffffffffffffffffffffffffffffffffffffffff8c1692634322b7149260048083019392829003018186803b1580156148cd57600080fd5b505afa1580156148e1573d6000803e3d6000fd5b505050506040513d60208110156148f757600080fd5b50518152604080517f5b2b9d1a000000000000000000000000000000000000000000000000000000008152905160209283019273ffffffffffffffffffffffffffffffffffffffff8c1692635b2b9d1a9260048083019392829003018186803b15801561496357600080fd5b505afa158015614977573d6000803e3d6000fd5b505050506040513d602081101561498d57600080fd5b50518152600060209091015294506149a485614e33565b6101408601525050505092915050565b6149bc6155ed565b600082604001516149cc84614c15565b10156149dd57508190506000614a14565b60006149f0846040015161206f86614c15565b90506000614a028560a0015183614f33565b9050614a0e8582614f49565b93509150505b915091565b610140908101519101511190565b6000808211614a9757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4552524f523a2072617465203d20300000000000000000000000000000000000604482015290519081900360640190fd5b826101400151821115614b0b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4552524f523a205441524745542052415445203e204341434845442052415445604482015290519081900360640190fd5b6000614b178484615009565b9050614b22846151e4565b811115614b7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f815260200180615678602f913960400191505060405180910390fd5b6000614b9f82611367670de0b6b3a7640000886040015161305990919063ffffffff16565b9050614bd4614bad86614c15565b6040518060600160405280602381526020016158906023913983919063ffffffff612db216565b95945050505050565b614be56155ed565b60a0830151614bfa908363ffffffff612fe516565b60a0840152614c0883614e33565b6101408401525090919050565b60006109a68260a001518360600151612fe590919063ffffffff16565b6000614c4884614c428585615224565b84615232565b949350505050565b6000614c6e8261136785670de0b6b3a764000063ffffffff61305916565b905080614c7d57506000610f76565b600854614ca79073ffffffffffffffffffffffffffffffffffffffff16858563ffffffff613d4016565b604080517f6a627842000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff861691636a6278429160248083019260209291908290030181600087803b158015614d1557600080fd5b505af1158015614d29573d6000803e3d6000fd5b505050506040513d6020811015614d3f57600080fd5b50516040805185815260208101839052815192935073ffffffffffffffffffffffffffffffffffffffff8716927f20541ba081e1e2ed9b41701070442c1fe618b0fec04825ba790aea8373f4e237929181900390910190a29392505050565b6000808373ffffffffffffffffffffffffffffffffffffffff16633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381600087803b158015614de957600080fd5b505af1158015614dfd573d6000803e3d6000fd5b505050506040513d6020811015614e1357600080fd5b50519050614c48670de0b6b3a7640000611367858463ffffffff61305916565b600080614e3f836151e4565b90506000614e668460e00151611367670de0b6b3a76400008561305990919063ffffffff16565b905060008460e00151831015614e7d575080614efe565b6000614ec4614ea18760e00151670de0b6b3a76400006133c690919063ffffffff16565b611367670de0b6b3a76400006131468a60e00151896133c690919063ffffffff16565b9050614efa670de0b6b3a7640000614eee611d0660018a61012001516133c690919063ffffffff16565b9063ffffffff612fe516565b9150505b614bd4670de0b6b3a764000061136784613146670de0b6b3a7640000611367614f268c61541b565b889063ffffffff61305916565b6000818310614f425781610f76565b5090919050565b614f516155ed565b6000614f7d84604001516040518060600160405280602381526020016156ea60239139613b2187614c15565b905080831115614fd8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180615862602e913960400191505060405180910390fd5b60a0840151614fed908463ffffffff6133c616565b60a0850152614ffb84614e33565b610140850152509192915050565b60006150148361541b565b821161506d57615066670de0b6b3a76400006113678560e00151613146615061670de0b6b3a76400006131466150498b61541b565b6113678b670de0b6b3a764000063ffffffff61305916565b615473565b905061516d565b61012083015160009061508790600163ffffffff6133c616565b905060006150b3670de0b6b3a764000061206f8761012001518860e0015161305990919063ffffffff16565b905060006151086150c38761541b565b6113676150e58960e00151670de0b6b3a76400006133c690919063ffffffff16565b613146670de0b6b3a76400006113678c60e001518c61305990919063ffffffff16565b9050600061514d615061670de0b6b3a76400006131466151316004828a8963ffffffff61305916565b614eee670de0b6b3a76400006113678a8063ffffffff61305916565b905061516660026113678681858863ffffffff612fe516565b9450505050505b670de0b6b3a76400008111156109a657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4552524f523a20544152474554205554494c495a4154494f4e203e2031303025604482015290519081900360640190fd5b6000806151f083614c15565b90508061520157600091505061164b565b610f7681611367670de0b6b3a7640000866040015161305990919063ffffffff16565b6000610f76838360006154c4565b6000615250670de0b6b3a7640000611367858563ffffffff61305916565b90508061525f57506000610f76565b60008473ffffffffffffffffffffffffffffffffffffffff1663ad7a672f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156152a757600080fd5b505afa1580156152bb573d6000803e3d6000fd5b505050506040513d60208110156152d157600080fd5b50519050808211156152fc576152f98361136783670de0b6b3a764000063ffffffff61305916565b93505b61532373ffffffffffffffffffffffffffffffffffffffff8616868663ffffffff613d4016565b604080517f95a2251f000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8716916395a2251f9160248083019260209291908290030181600087803b15801561539157600080fd5b505af11580156153a5573d6000803e3d6000fd5b505050506040513d60208110156153bb57600080fd5b50516040805182815260208101879052815192945073ffffffffffffffffffffffffffffffffffffffff8816927f8d69ef09150dd510133bc8e54e6ca115e8cf3370ea49a4a5ae56a1cdefc835e9929181900390910190a2509392505050565b60006109a6670de0b6b3a764000061136761544c856101000151670de0b6b3a76400006133c690919063ffffffff16565b613146670de0b6b3a76400006113678860c001518960e0015161305990919063ffffffff16565b600060038211156154b6575080600160028204015b818110156154b05780915060028182858161549f57fe5b0401816154a857fe5b049050615488565b5061164b565b811561164b57506001919050565b6000806154e38461136787670de0b6b3a764000063ffffffff61305916565b905060006154f882600163ffffffff612fe516565b9050831561553a57600061551e670de0b6b3a7640000611367848963ffffffff61305916565b90508681111561552e5782615530565b815b9350505050610f76565b6000615558670de0b6b3a7640000611367858963ffffffff61305916565b9050868110156155685781615530565b829350505050610f76565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106155b457805160ff19168380011785556155e1565b828001600101855582156155e1579182015b828111156155e15782518255916020019190600101906155c6565b50612fe192915061565d565b604051806101600160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61138591905b80821115612fe1576000815560010161566356fe4552524f523a20544152474554205554494c495a4154494f4e203e2043555252454e54205554494c495a4154494f4e4c656e64696e675661756c7456313a20424f52524f5741424c455f454e41424c45444c656e64696e675661756c7456313a20424f52524f5741424c455f4558495354534552524f523a204e4547415449564520415641494c41424c45204c49515549444954594c656e64696e675661756c7456313a20424f52524f5741424c455f4e4f545f464f554e444c656e64696e675661756c7456313a20424f52524f5741424c455f44495341424c45444c656e64696e675661756c7456313a204e4547415449564520414d4f554e5420544f20414c4c4f43415445454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774c656e64696e675661756c7456313a20494e53554646494349454e545f4c49515549444954594c656e64696e675661756c7456313a20494e56414c49445f554e4445524c59494e474c656e64696e675661756c7456313a20424f52524f5741424c455f444f45534e545f4558495354534552524f523a204445414c4c4f4341544520414d4f554e54203e20415641494c41424c45204c49515549444954594552524f523a2054415247455420535550504c59203e20544f54414c20535550504c594c656e64696e675661756c7456313a2052454445454d5f414d4f554e545f5a45524f4c656e64696e675661756c7456313a204d41585f424f52524f5741424c45535f4c454e475448a265627a7a72315820272b1ff2f5bdfb5ffe4ff85e7b931a1776d5924d30728d423cc60a2c786295d764736f6c63430005100032

[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.