Address Details
contract
0xEcBf673465101504cE623b6711D0b70972D424A3
- Contract Name
- ImmortalBondDepository
- Creator
- 0xad5e83–557abf at 0x1a0e89–6bac5d
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 2,345 Transactions
- Transfers
- 2,968 Transfers
- Gas Used
- 509,823,551
- Last Balance Update
- 12586046
Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- ImmortalBondDepository
- Optimization enabled
- true
- Compiler version
- v0.7.5+commit.eb77ed08
- Optimization runs
- 200
- EVM Version
- istanbul
- Verified at
- 2022-01-03T11:32:40.610907Z
BondDepository.sol
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.7.5; interface IOwnable { function policy() external view returns (address); function renounceManagement() external; function pushManagement( address newOwner_ ) external; function pullManagement() external; } contract Ownable is IOwnable { address internal _owner; address internal _newOwner; event OwnershipPushed(address indexed previousOwner, address indexed newOwner); event OwnershipPulled(address indexed previousOwner, address indexed newOwner); constructor () { _owner = msg.sender; emit OwnershipPushed( address(0), _owner ); } function policy() public view override returns (address) { return _owner; } modifier onlyPolicy() { require( _owner == msg.sender, "Ownable: caller is not the owner" ); _; } function renounceManagement() public virtual override onlyPolicy() { emit OwnershipPushed( _owner, address(0) ); _owner = address(0); } function pushManagement( address newOwner_ ) public virtual override onlyPolicy() { require( newOwner_ != address(0), "Ownable: new owner is the zero address"); emit OwnershipPushed( _owner, newOwner_ ); _newOwner = newOwner_; } function pullManagement() public virtual override { require( msg.sender == _newOwner, "Ownable: must be new owner to pull"); emit OwnershipPulled( _owner, _newOwner ); _owner = _newOwner; } } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function sub32(uint32 a, uint32 b) internal pure returns (uint32) { return sub32(a, b, "SafeMath: subtraction overflow"); } function sub32(uint32 a, uint32 b, string memory errorMessage) internal pure returns (uint32) { require(b <= a, errorMessage); uint32 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } function sqrrt(uint256 a) internal pure returns (uint c) { if (a > 3) { c = a; uint b = add( div( a, 2), 1 ); while (b < c) { c = b; b = div( add( div( a, b ), b), 2 ); } } else if (a != 0) { c = 1; } } } library Address { function isContract(address account) internal view returns (bool) { uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } function _functionCallWithValue( address target, bytes memory data, uint256 weiValue, string memory errorMessage ) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) private pure returns(bytes memory) { if (success) { return returndata; } else { if (returndata.length > 0) { assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } function addressToString(address _address) internal pure returns(string memory) { bytes32 _bytes = bytes32(uint256(_address)); bytes memory HEX = "0123456789abcdef"; bytes memory _addr = new bytes(42); _addr[0] = '0'; _addr[1] = 'x'; for(uint256 i = 0; i < 20; i++) { _addr[2+i*2] = HEX[uint8(_bytes[i + 12] >> 4)]; _addr[3+i*2] = HEX[uint8(_bytes[i + 12] & 0x0f)]; } return string(_addr); } } interface IERC20 { function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } abstract contract ERC20 is IERC20 { using SafeMath for uint256; // TODO comment actual hash value. bytes32 constant private ERC20TOKEN_ERC1820_INTERFACE_ID = keccak256( "ERC20Token" ); mapping (address => uint256) internal _balances; mapping (address => mapping (address => uint256)) internal _allowances; uint256 internal _totalSupply; string internal _name; string internal _symbol; uint8 internal _decimals; constructor (string memory name_, string memory symbol_, uint8 decimals_) { _name = name_; _symbol = symbol_; _decimals = decimals_; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view override returns (uint8) { return _decimals; } function totalSupply() public view override returns (uint256) { return _totalSupply; } function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(msg.sender, recipient, amount); return true; } function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(msg.sender, spender, amount); return true; } function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, msg.sender, _allowances[sender][msg.sender] .sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender] .sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } function _mint(address account_, uint256 ammount_) internal virtual { require(account_ != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address( this ), account_, ammount_); _totalSupply = _totalSupply.add(ammount_); _balances[account_] = _balances[account_].add(ammount_); emit Transfer(address( this ), account_, ammount_); } function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _beforeTokenTransfer( address from_, address to_, uint256 amount_ ) internal virtual { } } interface IERC2612Permit { function permit( address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function nonces(address owner) external view returns (uint256); } library Counters { using SafeMath for uint256; struct Counter { uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } abstract contract ERC20Permit is ERC20, IERC2612Permit { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; bytes32 public DOMAIN_SEPARATOR; constructor() { uint256 chainID; assembly { chainID := chainid() } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name())), keccak256(bytes("1")), // Version chainID, address(this) ) ); } function permit( address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "Permit: expired deadline"); bytes32 hashStruct = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, amount, _nonces[owner].current(), deadline)); bytes32 _hash = keccak256(abi.encodePacked(uint16(0x1901), DOMAIN_SEPARATOR, hashStruct)); address signer = ecrecover(_hash, v, r, s); require(signer != address(0) && signer == owner, "ZeroSwapPermit: Invalid signature"); _nonces[owner].increment(); _approve(owner, spender, amount); } function nonces(address owner) public view override returns (uint256) { return _nonces[owner].current(); } } library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove(IERC20 token, address spender, uint256 value) internal { require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender) .sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function _callOptionalReturn(IERC20 token, bytes memory data) private { bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } library FullMath { function fullMul(uint256 x, uint256 y) private pure returns (uint256 l, uint256 h) { uint256 mm = mulmod(x, y, uint256(-1)); l = x * y; h = mm - l; if (mm < l) h -= 1; } function fullDiv( uint256 l, uint256 h, uint256 d ) private pure returns (uint256) { uint256 pow2 = d & -d; d /= pow2; l /= pow2; l += h * ((-pow2) / pow2 + 1); uint256 r = 1; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; r *= 2 - d * r; return l * r; } function mulDiv( uint256 x, uint256 y, uint256 d ) internal pure returns (uint256) { (uint256 l, uint256 h) = fullMul(x, y); uint256 mm = mulmod(x, y, d); if (mm > l) h -= 1; l -= mm; require(h < d, 'FullMath::mulDiv: overflow'); return fullDiv(l, h, d); } } library FixedPoint { struct uq112x112 { uint224 _x; } struct uq144x112 { uint256 _x; } uint8 private constant RESOLUTION = 112; uint256 private constant Q112 = 0x10000000000000000000000000000; uint256 private constant Q224 = 0x100000000000000000000000000000000000000000000000000000000; uint256 private constant LOWER_MASK = 0xffffffffffffffffffffffffffff; // decimal of UQ*x112 (lower 112 bits) function decode(uq112x112 memory self) internal pure returns (uint112) { return uint112(self._x >> RESOLUTION); } function decode112with18(uq112x112 memory self) internal pure returns (uint) { return uint(self._x) / 5192296858534827; } function fraction(uint256 numerator, uint256 denominator) internal pure returns (uq112x112 memory) { require(denominator > 0, 'FixedPoint::fraction: division by zero'); if (numerator == 0) return FixedPoint.uq112x112(0); if (numerator <= uint144(-1)) { uint256 result = (numerator << RESOLUTION) / denominator; require(result <= uint224(-1), 'FixedPoint::fraction: overflow'); return uq112x112(uint224(result)); } else { uint256 result = FullMath.mulDiv(numerator, Q112, denominator); require(result <= uint224(-1), 'FixedPoint::fraction: overflow'); return uq112x112(uint224(result)); } } } interface ITreasury { function deposit( uint _amount, address _token, uint _profit ) external returns ( bool ); function valueOfToken( address _token, uint _amount ) external view returns ( uint value_ ); } interface IBondCalculator { function valuation( address _LP, uint _amount ) external view returns ( uint ); function markdown( address _LP ) external view returns ( uint ); } interface IStaking { function stake( uint _amount, address _recipient ) external returns ( bool ); } interface IStakingHelper { function stake( uint _amount, address _recipient ) external; } contract ImmortalBondDepository is Ownable { using FixedPoint for *; using SafeERC20 for IERC20; using SafeMath for uint; using SafeMath for uint32; /* ======== EVENTS ======== */ event BondCreated( uint deposit, uint indexed payout, uint indexed expires, uint indexed priceInUSD ); event BondRedeemed( address indexed recipient, uint payout, uint remaining ); event BondPriceChanged( uint indexed priceInUSD, uint indexed internalPrice, uint indexed debtRatio ); event ControlVariableAdjustment( uint initialBCV, uint newBCV, uint adjustment, bool addition ); /* ======== STATE VARIABLES ======== */ address public immutable IMMO; // token given as payment for bond address public immutable principle; // token used to create bond address public immutable treasury; // mints OHM when receives principle address public immutable DAO; // receives profit share from bond bool public immutable isLiquidityBond; // LP and Reserve bonds are treated slightly different address public immutable bondCalculator; // calculates value of LP tokens address public staking; // to auto-stake payout address public stakingHelper; // to stake and claim if no staking warmup bool public useHelper; Terms public terms; // stores terms for new bonds Adjust public adjustment; // stores adjustment to BCV data mapping( address => Bond ) public bondInfo; // stores bond information for depositors uint public totalDebt; // total value of outstanding bonds; used for pricing uint32 public lastDecay; // reference time for debt decay /* ======== STRUCTS ======== */ // Info for creating new bonds struct Terms { uint controlVariable; // scaling variable for price uint32 vestingTerm; // in seconds uint minimumPrice; // vs principle value uint maxPayout; // in thousandths of a %. i.e. 500 = 0.5% uint fee; // as % of bond payout, in hundreths. ( 500 = 5% = 0.05 for every 1 paid) uint maxDebt; // 9 decimal debt ratio, max % total supply created as debt } // Info for bond holder struct Bond { uint payout; // OHM remaining to be paid uint32 vesting; // Seconds left to vest uint32 lastTime; // Last interaction uint pricePaid; // In USD, for front end viewing } // Info for incremental adjustments to control variable struct Adjust { bool add; // addition or subtraction uint rate; // increment uint target; // BCV when adjustment finished uint32 buffer; // minimum length (in seconds) between adjustments uint32 lastTime; // time when last adjustment made } /* ======== INITIALIZATION ======== */ constructor ( address _IMMO, address _principle, address _treasury, address _DAO, address _bondCalculator ) { require( _IMMO != address(0) ); IMMO = _IMMO; require( _principle != address(0) ); principle = _principle; require( _treasury != address(0) ); treasury = _treasury; require( _DAO != address(0) ); DAO = _DAO; // bondCalculator should be address(0) if not LP bond bondCalculator = _bondCalculator; isLiquidityBond = ( _bondCalculator != address(0) ); } /** * @notice initializes bond parameters * @param _controlVariable uint * @param _vestingTerm uint32 * @param _minimumPrice uint * @param _maxPayout uint * @param _fee uint * @param _maxDebt uint * @param _initialDebt uint */ function initializeBondTerms( uint _controlVariable, uint _minimumPrice, uint _maxPayout, uint _fee, uint _maxDebt, uint _initialDebt, uint32 _vestingTerm ) external onlyPolicy() { require( terms.controlVariable == 0, "Bonds must be initialized from 0" ); terms = Terms ({ controlVariable: _controlVariable, minimumPrice: _minimumPrice, maxPayout: _maxPayout, fee: _fee, maxDebt: _maxDebt, vestingTerm: _vestingTerm }); totalDebt = _initialDebt; lastDecay = uint32(block.timestamp); } /* ======== POLICY FUNCTIONS ======== */ enum PARAMETER { VESTING, PAYOUT, FEE, DEBT, MINPRICE } /** * @notice set parameters for new bonds * @param _parameter PARAMETER * @param _input uint */ function setBondTerms ( PARAMETER _parameter, uint _input ) external onlyPolicy() { if ( _parameter == PARAMETER.VESTING ) { // 0 require( _input >= 129600, "Vesting must be longer than 36 hours" ); terms.vestingTerm = uint32(_input); } else if ( _parameter == PARAMETER.PAYOUT ) { // 1 require( _input <= 1000, "Payout cannot be above 1 percent" ); terms.maxPayout = _input; } else if ( _parameter == PARAMETER.FEE ) { // 2 require( _input <= 10000, "DAO fee cannot exceed payout" ); terms.fee = _input; } else if ( _parameter == PARAMETER.DEBT ) { // 3 terms.maxDebt = _input; } else if ( _parameter == PARAMETER.MINPRICE ) { // 4 terms.minimumPrice = _input; } } /** * @notice set control variable adjustment * @param _addition bool * @param _increment uint * @param _target uint * @param _buffer uint */ function setAdjustment ( bool _addition, uint _increment, uint _target, uint32 _buffer ) external onlyPolicy() { require( _increment <= terms.controlVariable.mul( 25 ).div( 1000 ), "Increment too large" ); adjustment = Adjust({ add: _addition, rate: _increment, target: _target, buffer: _buffer, lastTime: uint32(block.timestamp) }); } /** * @notice set contract for auto stake * @param _staking address * @param _helper bool */ function setStaking( address _staking, bool _helper ) external onlyPolicy() { require( _staking != address(0) ); if ( _helper ) { useHelper = true; stakingHelper = _staking; } else { useHelper = false; staking = _staking; } } /* ======== USER FUNCTIONS ======== */ /** * @notice deposit bond * @param _amount uint * @param _maxPrice uint * @param _depositor address * @return uint */ function deposit( uint _amount, uint _maxPrice, address _depositor ) external returns ( uint ) { require( _depositor != address(0), "Invalid address" ); decayDebt(); require( totalDebt <= terms.maxDebt, "Max capacity reached" ); uint priceInUSD = bondPriceInUSD(); // Stored in bond info uint nativePrice = _bondPrice(); require( _maxPrice >= nativePrice, "Slippage limit: more than max price" ); // slippage protection uint value = ITreasury( treasury ).valueOfToken( principle, _amount ); uint payout = payoutFor( value ); // payout to bonder is computed require( payout >= 10000000, "Bond too small" ); // must be > 0.01 OHM ( underflow protection ) require( payout <= maxPayout(), "Bond too large"); // size protection because there is no slippage // profits are calculated uint fee = payout.mul( terms.fee ).div( 10000 ); uint profit = value.sub( payout ).sub( fee ); /** principle is transferred in approved and deposited into the treasury, returning (_amount - profit) OHM */ IERC20( principle ).safeTransferFrom( msg.sender, address(this), _amount ); IERC20( principle ).approve( address( treasury ), _amount ); ITreasury( treasury ).deposit( _amount, principle, profit ); if ( fee != 0 ) { // fee is transferred to dao IERC20( IMMO ).safeTransfer( DAO, fee ); } // total debt is increased totalDebt = totalDebt.add( value ); // depositor info is stored bondInfo[ _depositor ] = Bond({ payout: bondInfo[ _depositor ].payout.add( payout ), vesting: terms.vestingTerm, lastTime: uint32(block.timestamp), pricePaid: priceInUSD }); // indexed events are emitted emit BondCreated( _amount, payout, block.timestamp.add( terms.vestingTerm ), priceInUSD ); emit BondPriceChanged( bondPriceInUSD(), _bondPrice(), debtRatio() ); adjust(); // control variable is adjusted return payout; } /** * @notice redeem bond for user * @param _recipient address * @param _stake bool * @return uint */ function redeem( address _recipient, bool _stake ) external returns ( uint ) { Bond memory info = bondInfo[ _recipient ]; // (seconds since last interaction / vesting term remaining) uint percentVested = percentVestedFor( _recipient ); if ( percentVested >= 10000 ) { // if fully vested delete bondInfo[ _recipient ]; // delete user info emit BondRedeemed( _recipient, info.payout, 0 ); // emit bond data return stakeOrSend( _recipient, _stake, info.payout ); // pay user everything due } else { // if unfinished // calculate payout vested uint payout = info.payout.mul( percentVested ).div( 10000 ); // store updated deposit info bondInfo[ _recipient ] = Bond({ payout: info.payout.sub( payout ), vesting: info.vesting.sub32( uint32( block.timestamp ).sub32( info.lastTime ) ), lastTime: uint32(block.timestamp), pricePaid: info.pricePaid }); emit BondRedeemed( _recipient, payout, bondInfo[ _recipient ].payout ); return stakeOrSend( _recipient, _stake, payout ); } } /* ======== INTERNAL HELPER FUNCTIONS ======== */ /** * @notice allow user to stake payout automatically * @param _stake bool * @param _amount uint * @return uint */ function stakeOrSend( address _recipient, bool _stake, uint _amount ) internal returns ( uint ) { if ( !_stake ) { // if user does not want to stake IERC20( IMMO ).transfer( _recipient, _amount ); // send payout } else { // if user wants to stake if ( useHelper ) { // use if staking warmup is 0 IERC20( IMMO ).approve( stakingHelper, _amount ); IStakingHelper( stakingHelper ).stake( _amount, _recipient ); } else { IERC20( IMMO ).approve( staking, _amount ); IStaking( staking ).stake( _amount, _recipient ); } } return _amount; } /** * @notice makes incremental adjustment to control variable */ function adjust() internal { uint timeCanAdjust = adjustment.lastTime.add( adjustment.buffer ); if( adjustment.rate != 0 && block.timestamp >= timeCanAdjust ) { uint initial = terms.controlVariable; if ( adjustment.add ) { terms.controlVariable = terms.controlVariable.add( adjustment.rate ); if ( terms.controlVariable >= adjustment.target ) { adjustment.rate = 0; } } else { terms.controlVariable = terms.controlVariable.sub( adjustment.rate ); if ( terms.controlVariable <= adjustment.target ) { adjustment.rate = 0; } } adjustment.lastTime = uint32(block.timestamp); emit ControlVariableAdjustment( initial, terms.controlVariable, adjustment.rate, adjustment.add ); } } /** * @notice reduce total debt */ function decayDebt() internal { totalDebt = totalDebt.sub( debtDecay() ); lastDecay = uint32(block.timestamp); } /* ======== VIEW FUNCTIONS ======== */ /** * @notice determine maximum bond size * @return uint */ function maxPayout() public view returns ( uint ) { return IERC20( IMMO ).totalSupply().mul( terms.maxPayout ).div( 100000 ); } /** * @notice calculate interest due for new bond * @param _value uint * @return uint */ function payoutFor( uint _value ) public view returns ( uint ) { return FixedPoint.fraction( _value, bondPrice() ).decode112with18().div( 1e16 ); } /** * @notice calculate current bond premium * @return price_ uint */ function bondPrice() public view returns ( uint price_ ) { price_ = terms.controlVariable.mul( debtRatio() ).add( 1000000000 ).div( 1e7 ); if ( price_ < terms.minimumPrice ) { price_ = terms.minimumPrice; } } /** * @notice calculate current bond price and remove floor if above * @return price_ uint */ function _bondPrice() internal returns ( uint price_ ) { price_ = terms.controlVariable.mul( debtRatio() ).add( 1000000000 ).div( 1e7 ); if ( price_ < terms.minimumPrice ) { price_ = terms.minimumPrice; } else if ( terms.minimumPrice != 0 ) { terms.minimumPrice = 0; } } /** * @notice converts bond price to USD value * @return price_ uint */ function bondPriceInUSD() public view returns ( uint price_ ) { if( isLiquidityBond ) { price_ = bondPrice().mul( IBondCalculator( bondCalculator ).markdown( principle ) ).div( 100 ); } else { price_ = bondPrice().mul( 10 ** IERC20( principle ).decimals() ).div( 100 ); } } /** * @notice calculate current ratio of debt to OHM supply * @return debtRatio_ uint */ function debtRatio() public view returns ( uint debtRatio_ ) { uint supply = IERC20( IMMO ).totalSupply(); debtRatio_ = FixedPoint.fraction( currentDebt().mul( 1e9 ), supply ).decode112with18().div( 1e18 ); } /** * @notice debt ratio in same terms for reserve or liquidity bonds * @return uint */ function standardizedDebtRatio() external view returns ( uint ) { if ( isLiquidityBond ) { return debtRatio().mul( IBondCalculator( bondCalculator ).markdown( principle ) ).div( 1e9 ); } else { return debtRatio(); } } /** * @notice calculate debt factoring in decay * @return uint */ function currentDebt() public view returns ( uint ) { return totalDebt.sub( debtDecay() ); } /** * @notice amount to decay total debt by * @return decay_ uint */ function debtDecay() public view returns ( uint decay_ ) { uint32 timeSinceLast = uint32(block.timestamp).sub32( lastDecay ); decay_ = totalDebt.mul( timeSinceLast ).div( terms.vestingTerm ); if ( decay_ > totalDebt ) { decay_ = totalDebt; } } /** * @notice calculate how far into vesting a depositor is * @param _depositor address * @return percentVested_ uint */ function percentVestedFor( address _depositor ) public view returns ( uint percentVested_ ) { Bond memory bond = bondInfo[ _depositor ]; uint secondsSinceLast = uint32(block.timestamp).sub( bond.lastTime ); uint vesting = bond.vesting; if ( vesting > 0 ) { percentVested_ = secondsSinceLast.mul( 10000 ).div( vesting ); } else { percentVested_ = 0; } } /** * @notice calculate amount of OHM available for claim by depositor * @param _depositor address * @return pendingPayout_ uint */ function pendingPayoutFor( address _depositor ) external view returns ( uint pendingPayout_ ) { uint percentVested = percentVestedFor( _depositor ); uint payout = bondInfo[ _depositor ].payout; if ( percentVested >= 10000 ) { pendingPayout_ = payout; } else { pendingPayout_ = payout.mul( percentVested ).div( 10000 ); } } /* ======= AUXILLIARY ======= */ /** * @notice allow anyone to send lost tokens (excluding principle or OHM) to the DAO * @return bool */ function recoverLostToken( address _token ) external returns ( bool ) { require( _token != IMMO ); require( _token != principle ); IERC20( _token ).safeTransfer( DAO, IERC20( _token ).balanceOf( address(this) ) ); return true; } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_IMMO","internalType":"address"},{"type":"address","name":"_principle","internalType":"address"},{"type":"address","name":"_treasury","internalType":"address"},{"type":"address","name":"_DAO","internalType":"address"},{"type":"address","name":"_bondCalculator","internalType":"address"}]},{"type":"event","name":"BondCreated","inputs":[{"type":"uint256","name":"deposit","internalType":"uint256","indexed":false},{"type":"uint256","name":"payout","internalType":"uint256","indexed":true},{"type":"uint256","name":"expires","internalType":"uint256","indexed":true},{"type":"uint256","name":"priceInUSD","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"BondPriceChanged","inputs":[{"type":"uint256","name":"priceInUSD","internalType":"uint256","indexed":true},{"type":"uint256","name":"internalPrice","internalType":"uint256","indexed":true},{"type":"uint256","name":"debtRatio","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"BondRedeemed","inputs":[{"type":"address","name":"recipient","internalType":"address","indexed":true},{"type":"uint256","name":"payout","internalType":"uint256","indexed":false},{"type":"uint256","name":"remaining","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ControlVariableAdjustment","inputs":[{"type":"uint256","name":"initialBCV","internalType":"uint256","indexed":false},{"type":"uint256","name":"newBCV","internalType":"uint256","indexed":false},{"type":"uint256","name":"adjustment","internalType":"uint256","indexed":false},{"type":"bool","name":"addition","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipPulled","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipPushed","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"DAO","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"IMMO","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"add","internalType":"bool"},{"type":"uint256","name":"rate","internalType":"uint256"},{"type":"uint256","name":"target","internalType":"uint256"},{"type":"uint32","name":"buffer","internalType":"uint32"},{"type":"uint32","name":"lastTime","internalType":"uint32"}],"name":"adjustment","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"bondCalculator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"payout","internalType":"uint256"},{"type":"uint32","name":"vesting","internalType":"uint32"},{"type":"uint32","name":"lastTime","internalType":"uint32"},{"type":"uint256","name":"pricePaid","internalType":"uint256"}],"name":"bondInfo","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price_","internalType":"uint256"}],"name":"bondPrice","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price_","internalType":"uint256"}],"name":"bondPriceInUSD","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentDebt","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"decay_","internalType":"uint256"}],"name":"debtDecay","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"debtRatio_","internalType":"uint256"}],"name":"debtRatio","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"deposit","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"uint256","name":"_maxPrice","internalType":"uint256"},{"type":"address","name":"_depositor","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initializeBondTerms","inputs":[{"type":"uint256","name":"_controlVariable","internalType":"uint256"},{"type":"uint256","name":"_minimumPrice","internalType":"uint256"},{"type":"uint256","name":"_maxPayout","internalType":"uint256"},{"type":"uint256","name":"_fee","internalType":"uint256"},{"type":"uint256","name":"_maxDebt","internalType":"uint256"},{"type":"uint256","name":"_initialDebt","internalType":"uint256"},{"type":"uint32","name":"_vestingTerm","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isLiquidityBond","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"lastDecay","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxPayout","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"payoutFor","inputs":[{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"pendingPayout_","internalType":"uint256"}],"name":"pendingPayoutFor","inputs":[{"type":"address","name":"_depositor","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"percentVested_","internalType":"uint256"}],"name":"percentVestedFor","inputs":[{"type":"address","name":"_depositor","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"policy","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"principle","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pullManagement","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pushManagement","inputs":[{"type":"address","name":"newOwner_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"recoverLostToken","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"redeem","inputs":[{"type":"address","name":"_recipient","internalType":"address"},{"type":"bool","name":"_stake","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceManagement","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAdjustment","inputs":[{"type":"bool","name":"_addition","internalType":"bool"},{"type":"uint256","name":"_increment","internalType":"uint256"},{"type":"uint256","name":"_target","internalType":"uint256"},{"type":"uint32","name":"_buffer","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBondTerms","inputs":[{"type":"uint8","name":"_parameter","internalType":"enum ImmortalBondDepository.PARAMETER"},{"type":"uint256","name":"_input","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setStaking","inputs":[{"type":"address","name":"_staking","internalType":"address"},{"type":"bool","name":"_helper","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"staking","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"stakingHelper","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"standardizedDebtRatio","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"controlVariable","internalType":"uint256"},{"type":"uint32","name":"vestingTerm","internalType":"uint32"},{"type":"uint256","name":"minimumPrice","internalType":"uint256"},{"type":"uint256","name":"maxPayout","internalType":"uint256"},{"type":"uint256","name":"fee","internalType":"uint256"},{"type":"uint256","name":"maxDebt","internalType":"uint256"}],"name":"terms","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalDebt","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"treasury","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"useHelper","inputs":[]}]
Contract Creation Code
0x6101406040523480156200001257600080fd5b5060405162002ec738038062002ec7833981810160405260a08110156200003857600080fd5b50805160208201516040808401516060850151608090950151600080546001600160a01b031916331780825593519596949592949391926001600160a01b0392909216917fea8258f2d9ddb679928cf34b78cf645b7feda9acc828e4dd82d014eaae270eba908290a36001600160a01b038516620000b557600080fd5b6001600160601b0319606086901b166080526001600160a01b038416620000db57600080fd5b6001600160601b0319606085901b1660a0526001600160a01b0383166200010157600080fd5b6001600160601b0319606084901b1660c0526001600160a01b0382166200012757600080fd5b6001600160601b0319606092831b811660e0529181901b909116610120526001600160a01b0316151560f81b6101005250505060805160601c60a05160601c60c05160601c60e05160601c6101005160f81c6101205160601c612c996200022e60003980610e765280611636528061197d525080610e4852806116055280611c8552508061147052806116ff52806118ca525080610dd252806110df52806112e252806113c45250806105d75280610ea55280610f4c528061110e528061128952806112b3528061139352806116655280611888525080610654528061144e528061184952806119d75280611cfa5280611e995280611f7e52806120935250612c996000f3fe608060405234801561001057600080fd5b50600436106102115760003560e01c8063844b5c7c11610125578063cf37a891116100ad578063d7ccfb0b1161007c578063d7ccfb0b14610594578063e0176de81461059c578063e392a262146105a4578063f5c2ab5b146105ac578063fc7b9c18146105cd57610211565b8063cf37a891146104d7578063d4d863ce1461051e578063d50256251461054c578063d79690601461058c57610211565b8063ae9832cf116100f4578063ae9832cf14610415578063b4abccba1461044c578063c5332b7c14610472578063cd1234b31461047a578063cea55f57146104cf57610211565b8063844b5c7c146103cb5780638dbdbe6d146103d3578063904b3ece1461040557806398fabd3a1461040d57610211565b8063451ee4a1116101a85780635a96ac0a116101775780635a96ac0a1461038e57806361d027b314610396578063759076e51461039e57806377b81895146103a65780637927ebf8146103ae57610211565b8063451ee4a1146102fc57806346f68ee91461033a5780634cf088d914610360578063507930ec1461036857610211565b8063089208d8116101e4578063089208d8146102825780631e321a0f1461028c5780631feed31f146102b25780632f3f470a146102e057610211565b8063016a42841461021657806301b88ee81461023a578063025de6cd146102725780630505c8c91461027a575b600080fd5b61021e6105d5565b604080516001600160a01b039092168252519081900360200190f35b6102606004803603602081101561025057600080fd5b50356001600160a01b03166105f9565b60408051918252519081900360200190f35b61021e610652565b61021e610676565b61028a610686565b005b61028a600480360360408110156102a257600080fd5b5060ff813516906020013561071d565b610260600480360360408110156102c857600080fd5b506001600160a01b0381351690602001351515610900565b6102e8610b4c565b604080519115158252519081900360200190f35b610304610b5c565b60408051951515865260208601949094528484019290925263ffffffff9081166060850152166080830152519081900360a00190f35b61028a6004803603602081101561035057600080fd5b50356001600160a01b0316610b82565b61021e610c6f565b6102606004803603602081101561037e57600080fd5b50356001600160a01b0316610c7e565b61028a610d26565b61021e610dd0565b610260610df4565b61021e610e0f565b610260600480360360208110156103c457600080fd5b5035610e1e565b610260610e44565b610260600480360360608110156103e957600080fd5b50803590602081013590604001356001600160a01b0316610fdd565b610260611601565b61021e6116fd565b61028a6004803603608081101561042b57600080fd5b5080351515906020810135906040810135906060013563ffffffff16611721565b6102e86004803603602081101561046257600080fd5b50356001600160a01b0316611845565b61021e61197b565b6104a06004803603602081101561049057600080fd5b50356001600160a01b031661199f565b6040805194855263ffffffff938416602086015291909216838201526060830191909152519081900360800190f35b6102606119d2565b61028a600480360360e08110156104ed57600080fd5b5080359060208101359060408101359060608101359060808101359060a08101359060c0013563ffffffff16611a8a565b61028a6004803603604081101561053457600080fd5b506001600160a01b0381351690602001351515611ba2565b610554611c65565b6040805196875263ffffffff9095166020870152858501939093526060850191909152608084015260a0830152519081900360c00190f35b6102e8611c83565b610260611ca7565b610260611ce6565b610260611d83565b6105b4611ddc565b6040805163ffffffff9092168252519081900360200190f35b610260611de8565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008061060583610c7e565b6001600160a01b0384166000908152600e602052604090205490915061271082106106325780925061064b565b6106486127106106428385611dee565b90611e4e565b92505b5050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b03165b90565b6000546001600160a01b031633146106d3576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907fea8258f2d9ddb679928cf34b78cf645b7feda9acc828e4dd82d014eaae270eba908390a3600080546001600160a01b0319169055565b6000546001600160a01b0316331461076a576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b600082600481111561077857fe5b14156107da576201fa408110156107c05760405162461bcd60e51b8152600401808060200182810382526024815260200180612c166024913960400191505060405180910390fd5b6005805463ffffffff191663ffffffff83161790556108fc565b60018260048111156107e857fe5b141561084f576103e8811115610845576040805162461bcd60e51b815260206004820181905260248201527f5061796f75742063616e6e6f742062652061626f766520312070657263656e74604482015290519081900360640190fd5b60078190556108fc565b600282600481111561085d57fe5b14156108c4576127108111156108ba576040805162461bcd60e51b815260206004820152601c60248201527f44414f206665652063616e6e6f7420657863656564207061796f757400000000604482015290519081900360640190fd5b60088190556108fc565b60038260048111156108d257fe5b14156108e25760098190556108fc565b60048260048111156108f057fe5b14156108fc5760068190555b5050565b600061090a612afd565b506001600160a01b0383166000908152600e60209081526040808320815160808101835281548152600182015463ffffffff80821695830195909552600160201b9004909316918301919091526002015460608201529061096a85610c7e565b905061271081106109ff576001600160a01b0385166000818152600e6020908152604080832083815560018101805467ffffffffffffffff19169055600201839055855181519081529182019290925281517f51c99f515c87b0d95ba97f616edd182e8f161c4932eac17c6fefe9dab58b77b1929181900390910190a26109f685858460000151611e90565b92505050610b46565b8151600090610a1690612710906106429085611dee565b90506040518060800160405280610a3a83866000015161219490919063ffffffff16565b8152602001610a78610a5f86604001514263ffffffff166121d690919063ffffffff16565b866020015163ffffffff166121d690919063ffffffff16565b63ffffffff90811682524281166020808401919091526060808801516040948501526001600160a01b038b166000818152600e84528590208651808255878501516001830180548a8a01518916600160201b0267ffffffff00000000199390991663ffffffff19909116179190911696909617909555959091015160029095019490945582518581529081019190915281517f51c99f515c87b0d95ba97f616edd182e8f161c4932eac17c6fefe9dab58b77b1929181900390910190a2610b40868683611e90565b93505050505b92915050565b600354600160a01b900460ff1681565b600a54600b54600c54600d5460ff9093169263ffffffff80821691600160201b90041685565b6000546001600160a01b03163314610bcf576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b6001600160a01b038116610c145760405162461bcd60e51b8152600401808060200182810382526026815260200180612b446026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917fea8258f2d9ddb679928cf34b78cf645b7feda9acc828e4dd82d014eaae270eba91a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6002546001600160a01b031681565b6000610c88612afd565b506001600160a01b0382166000908152600e60209081526040808320815160808101835281548152600182015463ffffffff80821695830195909552600160201b9004841692810183905260029091015460608201529291610cee914282169161219416565b602083015190915063ffffffff168015610d1957610d128161064284612710611dee565b9350610d1e565b600093505b505050919050565b6001546001600160a01b03163314610d6f5760405162461bcd60e51b8152600401808060200182810382526022815260200180612b6a6022913960400191505060405180910390fd5b600154600080546040516001600160a01b0393841693909116917faa151555690c956fc3ea32f106bb9f119b5237a061eaa8557cff3e51e3792c8d91a3600154600080546001600160a01b0319166001600160a01b03909216919091179055565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610e0a610e01611d83565b600f5490612194565b905090565b6003546001600160a01b031681565b6000610b46662386f26fc10000610642610e3f85610e3a611ca7565b612218565b61238f565b60007f000000000000000000000000000000000000000000000000000000000000000015610f4257610f3b60646106427f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166332da80a37f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610f0157600080fd5b505afa158015610f15573d6000803e3d6000fd5b505050506040513d6020811015610f2b57600080fd5b5051610f35611ca7565b90611dee565b9050610683565b610e0a60646106427f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610fa357600080fd5b505afa158015610fb7573d6000803e3d6000fd5b505050506040513d6020811015610fcd57600080fd5b505160ff16600a0a610f35611ca7565b60006001600160a01b03821661102c576040805162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015290519081900360640190fd5b6110346123a7565b600954600f541115611084576040805162461bcd60e51b815260206004820152601460248201527313585e0818d85c1858da5d1e481c995858da195960621b604482015290519081900360640190fd5b600061108e610e44565b9050600061109a6123cc565b9050808510156110db5760405162461bcd60e51b8152600401808060200182810382526023815260200180612bf36023913960400191505060405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d1b317e57f0000000000000000000000000000000000000000000000000000000000000000896040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b15801561117257600080fd5b505afa158015611186573d6000803e3d6000fd5b505050506040513d602081101561119c57600080fd5b5051905060006111ab82610e1e565b9050629896808110156111f6576040805162461bcd60e51b815260206004820152600e60248201526d109bdb99081d1bdbc81cdb585b1b60921b604482015290519081900360640190fd5b6111fe611ce6565b811115611243576040805162461bcd60e51b815260206004820152600e60248201526d426f6e6420746f6f206c6172676560901b604482015290519081900360640190fd5b6000611262612710610642600480015485611dee90919063ffffffff16565b9050600061127a826112748686612194565b90612194565b90506112b16001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308d61240e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663095ea7b37f00000000000000000000000000000000000000000000000000000000000000008c6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561134857600080fd5b505af115801561135c573d6000803e3d6000fd5b505050506040513d602081101561137257600080fd5b50506040805163bc157ac160e01b8152600481018c90526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526044820184905291517f00000000000000000000000000000000000000000000000000000000000000009092169163bc157ac1916064808201926020929091908290030181600087803b15801561140f57600080fd5b505af1158015611423573d6000803e3d6000fd5b505050506040513d602081101561143957600080fd5b50508115611495576114956001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008461246e565b600f546114a290856124c5565b600f55604080516080810182526001600160a01b038a166000908152600e602052919091205481906114d490866124c5565b81526005805463ffffffff9081166020808501919091524280831660408087019190915260609586018d90526001600160a01b038f166000908152600e84528190208751815592870151600184018054928901518616600160201b0267ffffffff000000001992871663ffffffff19909416939093179190911691909117905594909301516002909301929092555488926115749290918116906124c516565b604080518d8152905186917f1fec6dc81f140574bf43f6b1e420ae1dd47928b9d57db8cbd7b8611063b85ae5919081900360200190a46115b26119d2565b6115ba6123cc565b6115c2610e44565b6040517f375b221f40939bfd8f49723a17cf7bc6d576ebf72efe2cc3e991826f5b3f390a90600090a46115f361251f565b509098975050505050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000156116f557610f3b633b9aca006106427f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166332da80a37f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156116c157600080fd5b505afa1580156116d5573d6000803e3d6000fd5b505050506040513d60208110156116eb57600080fd5b5051610f356119d2565b610f3b6119d2565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b0316331461176e576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b600454611784906103e890610642906019611dee565b8311156117ce576040805162461bcd60e51b8152602060048201526013602482015272496e6372656d656e7420746f6f206c6172676560681b604482015290519081900360640190fd5b6040805160a0810182529415158086526020860185905290850183905263ffffffff91821660608601819052429092166080909501859052600a805460ff19169091179055600b92909255600c55600d805463ffffffff191690911767ffffffff000000001916600160201b909202919091179055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561188657600080fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156118c557600080fd5b6119737f0000000000000000000000000000000000000000000000000000000000000000836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561193657600080fd5b505afa15801561194a573d6000803e3d6000fd5b505050506040513d602081101561196057600080fd5b50516001600160a01b038516919061246e565b506001919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600e60205260009081526040902080546001820154600290920154909163ffffffff80821692600160201b909204169084565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a2e57600080fd5b505afa158015611a42573d6000803e3d6000fd5b505050506040513d6020811015611a5857600080fd5b50519050611a84670de0b6b3a7640000610642610e3f611a7e633b9aca00610f35610df4565b85612218565b91505090565b6000546001600160a01b03163314611ad7576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b60045415611b2c576040805162461bcd60e51b815260206004820181905260248201527f426f6e6473206d75737420626520696e697469616c697a65642066726f6d2030604482015290519081900360640190fd5b6040805160c08101825288815263ffffffff92831660208201819052918101889052606081018790526080810186905260a0018490526004979097556005805463ffffffff199081169098179055600695909555600793909355600891909155600955600f556010805490921642909116179055565b6000546001600160a01b03163314611bef576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b6001600160a01b038216611c0257600080fd5b8015611c375760038054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b0384161790556108fc565b6003805460ff60a01b19169055600280546001600160a01b0384166001600160a01b03199091161790555050565b60045460055460065460075460085460095463ffffffff9094169386565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611cd262989680610642633b9aca00611ccc611cc36119d2565b60045490611dee565b906124c5565b600654909150811015610683575060065490565b6000610e0a620186a06106426004600301547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d5157600080fd5b505afa158015611d65573d6000803e3d6000fd5b505050506040513d6020811015611d7b57600080fd5b505190611dee565b6010546000908190611da19063ffffffff428116918116906121d616565b600554600f54919250611dc69163ffffffff91821691610642919080861690611dee16565b9150600f54821115611dd857600f5491505b5090565b60105463ffffffff1681565b600f5481565b600082611dfd57506000610b46565b82820282848281611e0a57fe5b0414611e475760405162461bcd60e51b8152600401808060200182810382526021815260200180612bb26021913960400191505060405180910390fd5b9392505050565b6000611e4783836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061262a565b600082611f40577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb85846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015611f0e57600080fd5b505af1158015611f22573d6000803e3d6000fd5b505050506040513d6020811015611f3857600080fd5b5061218d9050565b600354600160a01b900460ff1615612067576003546040805163095ea7b360e01b81526001600160a01b0392831660048201526024810185905290517f00000000000000000000000000000000000000000000000000000000000000009092169163095ea7b3916044808201926020929091908290030181600087803b158015611fc957600080fd5b505af1158015611fdd573d6000803e3d6000fd5b505050506040513d6020811015611ff357600080fd5b505060035460408051637acb775760e01b8152600481018590526001600160a01b03878116602483015291519190921691637acb775791604480830192600092919082900301818387803b15801561204a57600080fd5b505af115801561205e573d6000803e3d6000fd5b5050505061218d565b6002546040805163095ea7b360e01b81526001600160a01b0392831660048201526024810185905290517f00000000000000000000000000000000000000000000000000000000000000009092169163095ea7b3916044808201926020929091908290030181600087803b1580156120de57600080fd5b505af11580156120f2573d6000803e3d6000fd5b505050506040513d602081101561210857600080fd5b505060025460408051637acb775760e01b8152600481018590526001600160a01b03878116602483015291519190921691637acb77579160448083019260209291908290030181600087803b15801561216057600080fd5b505af1158015612174573d6000803e3d6000fd5b505050506040513d602081101561218a57600080fd5b50505b5092915050565b6000611e4783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506126cc565b6000611e4783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612726565b612220612b31565b6000821161225f5760405162461bcd60e51b8152600401808060200182810382526026815260200180612b8c6026913960400191505060405180910390fd5b826122795750604080516020810190915260008152610b46565b71ffffffffffffffffffffffffffffffffffff831161232057600082607085901b816122a157fe5b0490506001600160e01b03811115612300576040805162461bcd60e51b815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015290519081900360640190fd5b6040518060200160405280826001600160e01b0316815250915050610b46565b600061233184600160701b85612785565b90506001600160e01b03811115612300576040805162461bcd60e51b815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015290519081900360640190fd5b516612725dd1d243ab6001600160e01b039091160490565b6123b2610e01611d83565b600f556010805463ffffffff19164263ffffffff16179055565b60006123e862989680610642633b9aca00611ccc611cc36119d2565b6006549091508110156123fe5750600654610683565b6006541561068357600060065590565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612468908590612825565b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526124c0908490612825565b505050565b600082820183811015611e47576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600d546000906125419063ffffffff600160201b82048116918116906124c516565b600b54909150158015906125555750804210155b1561262757600454600a5460ff161561258f57600b54600454612577916124c5565b6004819055600c541161258a576000600b555b6125b1565b600b5460045461259e91612194565b6004819055600c54106125b1576000600b555b600d805467ffffffff000000001916600160201b4263ffffffff1602179055600454600b54600a546040805185815260208101949094528381019290925260ff1615156060830152517fb923e581a0f83128e9e1d8297aa52b18d6744310476e0b54509c054cd7a93b2a916080908290030190a1505b50565b600081836126b65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561267b578181015183820152602001612663565b50505050905090810190601f1680156126a85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816126c257fe5b0495945050505050565b6000818484111561271e5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561267b578181015183820152602001612663565b505050900390565b60008363ffffffff168363ffffffff161115829061271e5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561267b578181015183820152602001612663565b600080600061279486866128d6565b91509150600084806127a257fe5b8688099050828111156127b6576001820391505b808303925084821061280f576040805162461bcd60e51b815260206004820152601a60248201527f46756c6c4d6174683a3a6d756c4469763a206f766572666c6f77000000000000604482015290519081900360640190fd5b61281a838387612903565b979650505050505050565b606061287a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166129739092919063ffffffff16565b8051909150156124c05780806020019051602081101561289957600080fd5b50516124c05760405162461bcd60e51b815260040180806020018281038252602a815260200180612c3a602a913960400191505060405180910390fd5b60008080600019848609905083850292508281039150828110156128fb576001820391505b509250929050565b6000818103821680838161291357fe5b04925080858161291f57fe5b04945080816000038161292e57fe5b60028581038087028203028087028203028087028203028087028203028087028203028087028203029586029003909402930460010193909302939093010292915050565b6060612982848460008561298a565b949350505050565b606061299585612af7565b6129e6576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310612a255780518252601f199092019160209182019101612a06565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612a87576040519150601f19603f3d011682016040523d82523d6000602084013e612a8c565b606091505b50915091508115612aa05791506129829050565b805115612ab05780518082602001fd5b60405162461bcd60e51b815260206004820181815286516024840152865187939192839260440191908501908083836000831561267b578181015183820152602001612663565b3b151590565b604051806080016040528060008152602001600063ffffffff168152602001600063ffffffff168152602001600081525090565b6040805160208101909152600081529056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734f776e61626c653a206d757374206265206e6577206f776e657220746f2070756c6c4669786564506f696e743a3a6672616374696f6e3a206469766973696f6e206279207a65726f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572536c697070616765206c696d69743a206d6f7265207468616e206d617820707269636556657374696e67206d757374206265206c6f6e676572207468616e20333620686f7572735361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220531263c435184b320a6669449692b7fe5daaa6557e98b7defe035151e57afc9864736f6c63430007050033000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee000000000000000000000000e2adcd126b4275cd75e72ff7ddc8cf7e43fc13d400000000000000000000000056db5115d093c5b83ec42cf5ecdbb1e3095958a30000000000000000000000000f502d5c10138b49466bcd2c66699ca217bfd0dc
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106102115760003560e01c8063844b5c7c11610125578063cf37a891116100ad578063d7ccfb0b1161007c578063d7ccfb0b14610594578063e0176de81461059c578063e392a262146105a4578063f5c2ab5b146105ac578063fc7b9c18146105cd57610211565b8063cf37a891146104d7578063d4d863ce1461051e578063d50256251461054c578063d79690601461058c57610211565b8063ae9832cf116100f4578063ae9832cf14610415578063b4abccba1461044c578063c5332b7c14610472578063cd1234b31461047a578063cea55f57146104cf57610211565b8063844b5c7c146103cb5780638dbdbe6d146103d3578063904b3ece1461040557806398fabd3a1461040d57610211565b8063451ee4a1116101a85780635a96ac0a116101775780635a96ac0a1461038e57806361d027b314610396578063759076e51461039e57806377b81895146103a65780637927ebf8146103ae57610211565b8063451ee4a1146102fc57806346f68ee91461033a5780634cf088d914610360578063507930ec1461036857610211565b8063089208d8116101e4578063089208d8146102825780631e321a0f1461028c5780631feed31f146102b25780632f3f470a146102e057610211565b8063016a42841461021657806301b88ee81461023a578063025de6cd146102725780630505c8c91461027a575b600080fd5b61021e6105d5565b604080516001600160a01b039092168252519081900360200190f35b6102606004803603602081101561025057600080fd5b50356001600160a01b03166105f9565b60408051918252519081900360200190f35b61021e610652565b61021e610676565b61028a610686565b005b61028a600480360360408110156102a257600080fd5b5060ff813516906020013561071d565b610260600480360360408110156102c857600080fd5b506001600160a01b0381351690602001351515610900565b6102e8610b4c565b604080519115158252519081900360200190f35b610304610b5c565b60408051951515865260208601949094528484019290925263ffffffff9081166060850152166080830152519081900360a00190f35b61028a6004803603602081101561035057600080fd5b50356001600160a01b0316610b82565b61021e610c6f565b6102606004803603602081101561037e57600080fd5b50356001600160a01b0316610c7e565b61028a610d26565b61021e610dd0565b610260610df4565b61021e610e0f565b610260600480360360208110156103c457600080fd5b5035610e1e565b610260610e44565b610260600480360360608110156103e957600080fd5b50803590602081013590604001356001600160a01b0316610fdd565b610260611601565b61021e6116fd565b61028a6004803603608081101561042b57600080fd5b5080351515906020810135906040810135906060013563ffffffff16611721565b6102e86004803603602081101561046257600080fd5b50356001600160a01b0316611845565b61021e61197b565b6104a06004803603602081101561049057600080fd5b50356001600160a01b031661199f565b6040805194855263ffffffff938416602086015291909216838201526060830191909152519081900360800190f35b6102606119d2565b61028a600480360360e08110156104ed57600080fd5b5080359060208101359060408101359060608101359060808101359060a08101359060c0013563ffffffff16611a8a565b61028a6004803603604081101561053457600080fd5b506001600160a01b0381351690602001351515611ba2565b610554611c65565b6040805196875263ffffffff9095166020870152858501939093526060850191909152608084015260a0830152519081900360c00190f35b6102e8611c83565b610260611ca7565b610260611ce6565b610260611d83565b6105b4611ddc565b6040805163ffffffff9092168252519081900360200190f35b610260611de8565b7f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee81565b60008061060583610c7e565b6001600160a01b0384166000908152600e602052604090205490915061271082106106325780925061064b565b6106486127106106428385611dee565b90611e4e565b92505b5050919050565b7f000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee81565b6000546001600160a01b03165b90565b6000546001600160a01b031633146106d3576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907fea8258f2d9ddb679928cf34b78cf645b7feda9acc828e4dd82d014eaae270eba908390a3600080546001600160a01b0319169055565b6000546001600160a01b0316331461076a576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b600082600481111561077857fe5b14156107da576201fa408110156107c05760405162461bcd60e51b8152600401808060200182810382526024815260200180612c166024913960400191505060405180910390fd5b6005805463ffffffff191663ffffffff83161790556108fc565b60018260048111156107e857fe5b141561084f576103e8811115610845576040805162461bcd60e51b815260206004820181905260248201527f5061796f75742063616e6e6f742062652061626f766520312070657263656e74604482015290519081900360640190fd5b60078190556108fc565b600282600481111561085d57fe5b14156108c4576127108111156108ba576040805162461bcd60e51b815260206004820152601c60248201527f44414f206665652063616e6e6f7420657863656564207061796f757400000000604482015290519081900360640190fd5b60088190556108fc565b60038260048111156108d257fe5b14156108e25760098190556108fc565b60048260048111156108f057fe5b14156108fc5760068190555b5050565b600061090a612afd565b506001600160a01b0383166000908152600e60209081526040808320815160808101835281548152600182015463ffffffff80821695830195909552600160201b9004909316918301919091526002015460608201529061096a85610c7e565b905061271081106109ff576001600160a01b0385166000818152600e6020908152604080832083815560018101805467ffffffffffffffff19169055600201839055855181519081529182019290925281517f51c99f515c87b0d95ba97f616edd182e8f161c4932eac17c6fefe9dab58b77b1929181900390910190a26109f685858460000151611e90565b92505050610b46565b8151600090610a1690612710906106429085611dee565b90506040518060800160405280610a3a83866000015161219490919063ffffffff16565b8152602001610a78610a5f86604001514263ffffffff166121d690919063ffffffff16565b866020015163ffffffff166121d690919063ffffffff16565b63ffffffff90811682524281166020808401919091526060808801516040948501526001600160a01b038b166000818152600e84528590208651808255878501516001830180548a8a01518916600160201b0267ffffffff00000000199390991663ffffffff19909116179190911696909617909555959091015160029095019490945582518581529081019190915281517f51c99f515c87b0d95ba97f616edd182e8f161c4932eac17c6fefe9dab58b77b1929181900390910190a2610b40868683611e90565b93505050505b92915050565b600354600160a01b900460ff1681565b600a54600b54600c54600d5460ff9093169263ffffffff80821691600160201b90041685565b6000546001600160a01b03163314610bcf576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b6001600160a01b038116610c145760405162461bcd60e51b8152600401808060200182810382526026815260200180612b446026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917fea8258f2d9ddb679928cf34b78cf645b7feda9acc828e4dd82d014eaae270eba91a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6002546001600160a01b031681565b6000610c88612afd565b506001600160a01b0382166000908152600e60209081526040808320815160808101835281548152600182015463ffffffff80821695830195909552600160201b9004841692810183905260029091015460608201529291610cee914282169161219416565b602083015190915063ffffffff168015610d1957610d128161064284612710611dee565b9350610d1e565b600093505b505050919050565b6001546001600160a01b03163314610d6f5760405162461bcd60e51b8152600401808060200182810382526022815260200180612b6a6022913960400191505060405180910390fd5b600154600080546040516001600160a01b0393841693909116917faa151555690c956fc3ea32f106bb9f119b5237a061eaa8557cff3e51e3792c8d91a3600154600080546001600160a01b0319166001600160a01b03909216919091179055565b7f000000000000000000000000e2adcd126b4275cd75e72ff7ddc8cf7e43fc13d481565b6000610e0a610e01611d83565b600f5490612194565b905090565b6003546001600160a01b031681565b6000610b46662386f26fc10000610642610e3f85610e3a611ca7565b612218565b61238f565b60007f000000000000000000000000000000000000000000000000000000000000000115610f4257610f3b60646106427f0000000000000000000000000f502d5c10138b49466bcd2c66699ca217bfd0dc6001600160a01b03166332da80a37f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610f0157600080fd5b505afa158015610f15573d6000803e3d6000fd5b505050506040513d6020811015610f2b57600080fd5b5051610f35611ca7565b90611dee565b9050610683565b610e0a60646106427f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015610fa357600080fd5b505afa158015610fb7573d6000803e3d6000fd5b505050506040513d6020811015610fcd57600080fd5b505160ff16600a0a610f35611ca7565b60006001600160a01b03821661102c576040805162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b604482015290519081900360640190fd5b6110346123a7565b600954600f541115611084576040805162461bcd60e51b815260206004820152601460248201527313585e0818d85c1858da5d1e481c995858da195960621b604482015290519081900360640190fd5b600061108e610e44565b9050600061109a6123cc565b9050808510156110db5760405162461bcd60e51b8152600401808060200182810382526023815260200180612bf36023913960400191505060405180910390fd5b60007f000000000000000000000000e2adcd126b4275cd75e72ff7ddc8cf7e43fc13d46001600160a01b031663d1b317e57f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee896040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b15801561117257600080fd5b505afa158015611186573d6000803e3d6000fd5b505050506040513d602081101561119c57600080fd5b5051905060006111ab82610e1e565b9050629896808110156111f6576040805162461bcd60e51b815260206004820152600e60248201526d109bdb99081d1bdbc81cdb585b1b60921b604482015290519081900360640190fd5b6111fe611ce6565b811115611243576040805162461bcd60e51b815260206004820152600e60248201526d426f6e6420746f6f206c6172676560901b604482015290519081900360640190fd5b6000611262612710610642600480015485611dee90919063ffffffff16565b9050600061127a826112748686612194565b90612194565b90506112b16001600160a01b037f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee1633308d61240e565b7f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee6001600160a01b031663095ea7b37f000000000000000000000000e2adcd126b4275cd75e72ff7ddc8cf7e43fc13d48c6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561134857600080fd5b505af115801561135c573d6000803e3d6000fd5b505050506040513d602081101561137257600080fd5b50506040805163bc157ac160e01b8152600481018c90526001600160a01b037f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee811660248301526044820184905291517f000000000000000000000000e2adcd126b4275cd75e72ff7ddc8cf7e43fc13d49092169163bc157ac1916064808201926020929091908290030181600087803b15801561140f57600080fd5b505af1158015611423573d6000803e3d6000fd5b505050506040513d602081101561143957600080fd5b50508115611495576114956001600160a01b037f000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee167f00000000000000000000000056db5115d093c5b83ec42cf5ecdbb1e3095958a38461246e565b600f546114a290856124c5565b600f55604080516080810182526001600160a01b038a166000908152600e602052919091205481906114d490866124c5565b81526005805463ffffffff9081166020808501919091524280831660408087019190915260609586018d90526001600160a01b038f166000908152600e84528190208751815592870151600184018054928901518616600160201b0267ffffffff000000001992871663ffffffff19909416939093179190911691909117905594909301516002909301929092555488926115749290918116906124c516565b604080518d8152905186917f1fec6dc81f140574bf43f6b1e420ae1dd47928b9d57db8cbd7b8611063b85ae5919081900360200190a46115b26119d2565b6115ba6123cc565b6115c2610e44565b6040517f375b221f40939bfd8f49723a17cf7bc6d576ebf72efe2cc3e991826f5b3f390a90600090a46115f361251f565b509098975050505050505050565b60007f0000000000000000000000000000000000000000000000000000000000000001156116f557610f3b633b9aca006106427f0000000000000000000000000f502d5c10138b49466bcd2c66699ca217bfd0dc6001600160a01b03166332da80a37f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156116c157600080fd5b505afa1580156116d5573d6000803e3d6000fd5b505050506040513d60208110156116eb57600080fd5b5051610f356119d2565b610f3b6119d2565b7f00000000000000000000000056db5115d093c5b83ec42cf5ecdbb1e3095958a381565b6000546001600160a01b0316331461176e576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b600454611784906103e890610642906019611dee565b8311156117ce576040805162461bcd60e51b8152602060048201526013602482015272496e6372656d656e7420746f6f206c6172676560681b604482015290519081900360640190fd5b6040805160a0810182529415158086526020860185905290850183905263ffffffff91821660608601819052429092166080909501859052600a805460ff19169091179055600b92909255600c55600d805463ffffffff191690911767ffffffff000000001916600160201b909202919091179055565b60007f000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee6001600160a01b0316826001600160a01b0316141561188657600080fd5b7f0000000000000000000000007d63809ebf83ef54c7ce8ded3591d4e8fc2102ee6001600160a01b0316826001600160a01b031614156118c557600080fd5b6119737f00000000000000000000000056db5115d093c5b83ec42cf5ecdbb1e3095958a3836001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561193657600080fd5b505afa15801561194a573d6000803e3d6000fd5b505050506040513d602081101561196057600080fd5b50516001600160a01b038516919061246e565b506001919050565b7f0000000000000000000000000f502d5c10138b49466bcd2c66699ca217bfd0dc81565b600e60205260009081526040902080546001820154600290920154909163ffffffff80821692600160201b909204169084565b6000807f000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a2e57600080fd5b505afa158015611a42573d6000803e3d6000fd5b505050506040513d6020811015611a5857600080fd5b50519050611a84670de0b6b3a7640000610642610e3f611a7e633b9aca00610f35610df4565b85612218565b91505090565b6000546001600160a01b03163314611ad7576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b60045415611b2c576040805162461bcd60e51b815260206004820181905260248201527f426f6e6473206d75737420626520696e697469616c697a65642066726f6d2030604482015290519081900360640190fd5b6040805160c08101825288815263ffffffff92831660208201819052918101889052606081018790526080810186905260a0018490526004979097556005805463ffffffff199081169098179055600695909555600793909355600891909155600955600f556010805490921642909116179055565b6000546001600160a01b03163314611bef576040805162461bcd60e51b81526020600482018190526024820152600080516020612bd3833981519152604482015290519081900360640190fd5b6001600160a01b038216611c0257600080fd5b8015611c375760038054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b0384161790556108fc565b6003805460ff60a01b19169055600280546001600160a01b0384166001600160a01b03199091161790555050565b60045460055460065460075460085460095463ffffffff9094169386565b7f000000000000000000000000000000000000000000000000000000000000000181565b6000611cd262989680610642633b9aca00611ccc611cc36119d2565b60045490611dee565b906124c5565b600654909150811015610683575060065490565b6000610e0a620186a06106426004600301547f000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611d5157600080fd5b505afa158015611d65573d6000803e3d6000fd5b505050506040513d6020811015611d7b57600080fd5b505190611dee565b6010546000908190611da19063ffffffff428116918116906121d616565b600554600f54919250611dc69163ffffffff91821691610642919080861690611dee16565b9150600f54821115611dd857600f5491505b5090565b60105463ffffffff1681565b600f5481565b600082611dfd57506000610b46565b82820282848281611e0a57fe5b0414611e475760405162461bcd60e51b8152600401808060200182810382526021815260200180612bb26021913960400191505060405180910390fd5b9392505050565b6000611e4783836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061262a565b600082611f40577f000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee6001600160a01b031663a9059cbb85846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015611f0e57600080fd5b505af1158015611f22573d6000803e3d6000fd5b505050506040513d6020811015611f3857600080fd5b5061218d9050565b600354600160a01b900460ff1615612067576003546040805163095ea7b360e01b81526001600160a01b0392831660048201526024810185905290517f000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee9092169163095ea7b3916044808201926020929091908290030181600087803b158015611fc957600080fd5b505af1158015611fdd573d6000803e3d6000fd5b505050506040513d6020811015611ff357600080fd5b505060035460408051637acb775760e01b8152600481018590526001600160a01b03878116602483015291519190921691637acb775791604480830192600092919082900301818387803b15801561204a57600080fd5b505af115801561205e573d6000803e3d6000fd5b5050505061218d565b6002546040805163095ea7b360e01b81526001600160a01b0392831660048201526024810185905290517f000000000000000000000000e685d21b7b0fc7a248a6a8e03b8db22d013aa2ee9092169163095ea7b3916044808201926020929091908290030181600087803b1580156120de57600080fd5b505af11580156120f2573d6000803e3d6000fd5b505050506040513d602081101561210857600080fd5b505060025460408051637acb775760e01b8152600481018590526001600160a01b03878116602483015291519190921691637acb77579160448083019260209291908290030181600087803b15801561216057600080fd5b505af1158015612174573d6000803e3d6000fd5b505050506040513d602081101561218a57600080fd5b50505b5092915050565b6000611e4783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506126cc565b6000611e4783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612726565b612220612b31565b6000821161225f5760405162461bcd60e51b8152600401808060200182810382526026815260200180612b8c6026913960400191505060405180910390fd5b826122795750604080516020810190915260008152610b46565b71ffffffffffffffffffffffffffffffffffff831161232057600082607085901b816122a157fe5b0490506001600160e01b03811115612300576040805162461bcd60e51b815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015290519081900360640190fd5b6040518060200160405280826001600160e01b0316815250915050610b46565b600061233184600160701b85612785565b90506001600160e01b03811115612300576040805162461bcd60e51b815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015290519081900360640190fd5b516612725dd1d243ab6001600160e01b039091160490565b6123b2610e01611d83565b600f556010805463ffffffff19164263ffffffff16179055565b60006123e862989680610642633b9aca00611ccc611cc36119d2565b6006549091508110156123fe5750600654610683565b6006541561068357600060065590565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612468908590612825565b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526124c0908490612825565b505050565b600082820183811015611e47576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600d546000906125419063ffffffff600160201b82048116918116906124c516565b600b54909150158015906125555750804210155b1561262757600454600a5460ff161561258f57600b54600454612577916124c5565b6004819055600c541161258a576000600b555b6125b1565b600b5460045461259e91612194565b6004819055600c54106125b1576000600b555b600d805467ffffffff000000001916600160201b4263ffffffff1602179055600454600b54600a546040805185815260208101949094528381019290925260ff1615156060830152517fb923e581a0f83128e9e1d8297aa52b18d6744310476e0b54509c054cd7a93b2a916080908290030190a1505b50565b600081836126b65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561267b578181015183820152602001612663565b50505050905090810190601f1680156126a85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816126c257fe5b0495945050505050565b6000818484111561271e5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561267b578181015183820152602001612663565b505050900390565b60008363ffffffff168363ffffffff161115829061271e5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561267b578181015183820152602001612663565b600080600061279486866128d6565b91509150600084806127a257fe5b8688099050828111156127b6576001820391505b808303925084821061280f576040805162461bcd60e51b815260206004820152601a60248201527f46756c6c4d6174683a3a6d756c4469763a206f766572666c6f77000000000000604482015290519081900360640190fd5b61281a838387612903565b979650505050505050565b606061287a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166129739092919063ffffffff16565b8051909150156124c05780806020019051602081101561289957600080fd5b50516124c05760405162461bcd60e51b815260040180806020018281038252602a815260200180612c3a602a913960400191505060405180910390fd5b60008080600019848609905083850292508281039150828110156128fb576001820391505b509250929050565b6000818103821680838161291357fe5b04925080858161291f57fe5b04945080816000038161292e57fe5b60028581038087028203028087028203028087028203028087028203028087028203028087028203029586029003909402930460010193909302939093010292915050565b6060612982848460008561298a565b949350505050565b606061299585612af7565b6129e6576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310612a255780518252601f199092019160209182019101612a06565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612a87576040519150601f19603f3d011682016040523d82523d6000602084013e612a8c565b606091505b50915091508115612aa05791506129829050565b805115612ab05780518082602001fd5b60405162461bcd60e51b815260206004820181815286516024840152865187939192839260440191908501908083836000831561267b578181015183820152602001612663565b3b151590565b604051806080016040528060008152602001600063ffffffff168152602001600063ffffffff168152602001600081525090565b6040805160208101909152600081529056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734f776e61626c653a206d757374206265206e6577206f776e657220746f2070756c6c4669786564506f696e743a3a6672616374696f6e3a206469766973696f6e206279207a65726f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572536c697070616765206c696d69743a206d6f7265207468616e206d617820707269636556657374696e67206d757374206265206c6f6e676572207468616e20333620686f7572735361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220531263c435184b320a6669449692b7fe5daaa6557e98b7defe035151e57afc9864736f6c63430007050033