Contract Address Details

0x7FCA2B3E1047291f65c2C914083d970c027f4290

Last Balance Update: Block #12334044
Created by 0x5128–22e4bb at 0x17c5–04ad34

Balance

0 Fuse

(@ /Fuse)

Fetching tokens...

Contract name:
FuseStakingV3




Optimization enabled
true
Compiler version
v0.6.12+commit.27d51765




Optimization runs
200
EVM Version
default

Contract source code

/**
* Submitted for verification at blockscout.com on 2021-03-03 08:19:16.780306Z
*/
// SPDX-License-Identifier: MIT
// File: @openzeppelin/contracts-upgradeable/proxy/Initializable.sol
// solhint-disable-next-line compiler-version
pragma solidity >=0.4.24 <0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
/// @dev Returns true if and only if the function is running in the constructor
function _isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
address self = address(this);
uint256 cs;
// solhint-disable-next-line no-inline-assembly
assembly { cs := extcodesize(self) }
return cs == 0;
}
}
// File: @openzeppelin/contracts-upgradeable/GSN/ContextUpgradeable.sol
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal initializer {
__Context_init_unchained();
}
function __Context_init_unchained() internal initializer {
}
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
uint256[50] private __gap;
}
// File: @openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal initializer {
__Context_init_unchained();
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal initializer {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
uint256[49] private __gap;
}
// File: @openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol
/**
* @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 SafeMathUpgradeable {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
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 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) {
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: contracts/utils/DSMath.sol
/// math.sol -- mixin for inline numerical wizardry
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
contract DSMath {
function WAD() internal pure returns (uint256) {
return 10**18;
}
function RAY() internal pure returns (uint256) {
return 10**27;
}
function add(uint256 x, uint256 y) public pure returns (uint256 z) {
require((z = x + y) >= x, "ds-math-add-overflow");
}
function sub(uint256 x, uint256 y) public pure returns (uint256 z) {
require((z = x - y) <= x, "ds-math-sub-underflow");
}
function mul(uint256 x, uint256 y) public pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
}
function min(uint256 x, uint256 y) public pure returns (uint256 z) {
return x <= y ? x : y;
}
function max(uint256 x, uint256 y) public pure returns (uint256 z) {
return x >= y ? x : y;
}
function imin(int256 x, int256 y) public pure returns (int256 z) {
return x <= y ? x : y;
}
function imax(int256 x, int256 y) public pure returns (int256 z) {
return x >= y ? x : y;
}
function wmul(uint256 x, uint256 y) public pure returns (uint256 z) {
z = add(mul(x, y), WAD() / 2) / WAD();
}
function rmul(uint256 x, uint256 y) public pure returns (uint256 z) {
z = add(mul(x, y), RAY() / 2) / RAY();
}
function wdiv(uint256 x, uint256 y) public pure returns (uint256 z) {
z = add(mul(x, WAD()), y / 2) / y;
}
function rdiv(uint256 x, uint256 y) public pure returns (uint256 z) {
z = add(mul(x, RAY()), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint256 x, uint256 n) public pure returns (uint256 z) {
z = n % 2 != 0 ? x : RAY();
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
// File: contracts/Interfaces.sol
pragma experimental ABIEncoderV2;
interface cERC20 {
function mint(uint256 mintAmount) external returns (uint256);
function redeemUnderlying(uint256 mintAmount) external returns (uint256);
function exchangeRateCurrent() external returns (uint256);
function exchangeRateStored() external view returns (uint256);
function balanceOf(address addr) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
}
interface GoodDollar is cERC20 {
function getFees(uint256 value) external view returns (uint256, bool);
function mint(address to, uint256 mintAmount) external returns (uint256);
}
interface Staking {
struct Staker {
// The staked DAI amount
uint256 stakedDAI;
// The latest block number which the
// staker has staked tokens
uint256 lastStake;
}
function stakeDAI(uint256 amount) external;
function withdrawStake() external;
function stakers(address staker) external view returns (Staker memory);
}
interface Uniswap {
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function WETH() external pure returns (address);
function factory() external pure returns (address);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountOut(
uint256 amountI,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
}
interface UniswapFactory {
function getPair(address tokenA, address tokenB)
external
view
returns (address);
}
interface UniswapPair {
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
function kLast() external view returns (uint256);
}
interface Reserve {
function buy(
address _buyWith,
uint256 _tokenAmount,
uint256 _minReturn
) external returns (uint256);
}
interface IIdentity {
function isWhitelisted(address user) external view returns (bool);
function addWhitelistedWithDID(address account, string memory did) external;
function removeWhitelisted(address account) external;
function addIdentityAdmin(address account) external returns (bool);
function setAvatar(address _avatar) external;
}
interface UBIScheme {
function currentDay() external view returns (uint256);
}
interface ProxyAdmin {
function getProxyImplementation(address proxy)
external
view
returns (address);
function getProxyAdmin(address proxy) external view returns (address);
function upgrade(address proxy, address implementation) external;
function owner() external view returns (address);
function transferOwnership(address newOwner) external;
}
// File: contracts/staking/FuseStakingV3.sol
interface IConsensus {
/**
* @dev delegate to a validator
* @param _validator the address of the validator msg.sender is delegating to
*/
function delegate(address _validator) external payable;
/**
* @dev Function to be called when a delegator whishes to withdraw some of his staked funds for a validator
* @param _validator the address of the validator msg.sender has delegating to
* @param _amount the amount msg.sender wishes to withdraw from the contract
*/
function withdraw(address _validator, uint256 _amount) external;
function delegatedAmount(address _address, address _validator)
external
view
returns (uint256);
function stakeAmount(address _address) external view returns (uint256);
function delegators(address _validator)
external
view
returns (address[] memory);
}
contract FuseStakingV3 is Initializable, OwnableUpgradeable, DSMath {
using SafeMathUpgradeable for uint256;
mapping(address => uint256) public stakers;
address[] public validators;
IConsensus public consensus;
Uniswap public uniswap;
GoodDollar public GD;
UBIScheme public ubischeme;
UniswapFactory public uniswapFactory;
UniswapPair public uniswapPair;
uint256 public lastDayCollected; //ubi day from ubischeme
uint256 public stakeBackRatio;
uint256 public maxSlippageRatio;
uint256 public keeperFeeRatio;
uint256 public RATIO_BASE;
uint256 public communityPoolRatio; //out of G$ bought how much should goto pool
uint256 communityPoolBalance;
uint256 pendingFuseEarnings; //earnings not used because of slippage
event UBICollected(
uint256 indexed currentDay,
uint256 ubi, //G$ sent to ubischeme
uint256 communityPool, //G$ added to pool
uint256 gdBought, //actual G$ we got out of swapping stakingRewards + pendingFuseEarnings
uint256 stakingRewards, //rewards earned since previous collection,
uint256 pendingFuseEarnings, //new balance of fuse pending to be swapped for G$
address keeper,
uint256 keeperGDFee
);
/**
* @dev initialize
*/
function initialize() public initializer {
__Ownable_init_unchained();
consensus = IConsensus(
address(0x3014ca10b91cb3D0AD85fEf7A3Cb95BCAc9c0f79)
);
validators.push(address(0xcb876A393F05a6677a8a029f1C6D7603B416C0A6));
}
function upgrade0() public {
if (RATIO_BASE == 0) {
stakeBackRatio = 33333; //%33
communityPoolRatio = 33333; //%33
maxSlippageRatio = 3000; //3%
keeperFeeRatio = 30; //0.03%
RATIO_BASE = 100000; //100%
}
}
function upgrade1(
address _gd,
address _ubischeme,
address _uniswap
) public {
if (address(uniswapPair) == address(0)) {
uniswap = Uniswap(
_uniswap == address(0)
? 0xFB76e9E7d88E308aB530330eD90e84a952570319
: _uniswap
);
GD = GoodDollar(_gd);
ubischeme = UBIScheme(_ubischeme);
uniswapFactory = UniswapFactory(uniswap.factory());
uniswapPair = UniswapPair(
uniswapFactory.getPair(uniswap.WETH(), _gd)
);
upgrade0();
}
}
function setContracts(address _gd, address _ubischeme) public onlyOwner {
if (_gd != address(0)) {
GD = GoodDollar(_gd);
}
if (_ubischeme != address(0)) {
ubischeme = UBIScheme(_ubischeme);
}
}
function stake() public payable returns (bool) {
return stake(address(0));
}
function stake(address _validator) public payable returns (bool) {
require(msg.value > 0, "stake must be > 0");
require(validators.length > 0, "no approved validators");
bool found;
for (
uint256 i = 0;
_validator != address(0) && i < validators.length;
i++
) {
if (validators[i] != _validator) {
found = true;
break;
}
}
require(
_validator == address(0) || found,
"validator not in approved list"
);
bool staked = stakeNextValidator(msg.value, _validator);
stakers[msg.sender] = stakers[msg.sender].add(msg.value);
return staked;
}
function balanceOf(address _owner) public view returns (uint256) {
return stakers[_owner];
}
function withdraw(uint256 _value) public returns (uint256) {
uint256 effectiveBalance = balance(); //use only undelegated funds
uint256 toWithdraw = _value == 0 ? stakers[msg.sender] : _value;
uint256 toCollect = toWithdraw;
require(
toWithdraw > 0 && toWithdraw <= stakers[msg.sender],
"invalid withdraw amount"
);
uint256 perValidator = _value.div(validators.length);
for (uint256 i = 0; i < validators.length; i++) {
uint256 cur =
consensus.delegatedAmount(address(this), validators[i]);
if (cur == 0) continue;
if (cur <= perValidator) {
undelegateWithCatch(validators[i], cur);
toCollect = toCollect.sub(cur);
} else {
undelegateWithCatch(validators[i], perValidator);
toCollect = toCollect.sub(perValidator);
}
if (toCollect == 0) break;
}
effectiveBalance = balance().sub(effectiveBalance); //use only undelegated funds
// in case some funds where not withdrawn
if (toWithdraw > effectiveBalance) {
toWithdraw = effectiveBalance;
}
stakers[msg.sender] = stakers[msg.sender].sub(toWithdraw);
if (toWithdraw > 0) payable(msg.sender).transfer(toWithdraw);
return toWithdraw;
}
function stakeNextValidator(uint256 _value, address _validator)
internal
returns (bool)
{
if (validators.length == 0) return false;
if (_validator != address(0)) {
consensus.delegate{ value: _value }(_validator);
return true;
}
uint256 perValidator =
totalDelegated().add(_value).div(validators.length);
uint256 left = _value;
for (uint256 i = 0; i < validators.length && left > 0; i++) {
uint256 cur =
consensus.delegatedAmount(address(this), validators[i]);
if (cur < perValidator) {
uint256 toDelegate = perValidator.sub(cur);
toDelegate = toDelegate < left ? toDelegate : left;
consensus.delegate{ value: toDelegate }(validators[i]);
left = left.sub(toDelegate);
}
}
return true;
}
function addValidator(address _v) public onlyOwner {
validators.push(_v);
}
function totalDelegated() public view returns (uint256) {
uint256 total = 0;
for (uint256 i = 0; i < validators.length; i++) {
uint256 cur =
consensus.delegatedAmount(address(this), validators[i]);
total = total.add(cur);
}
return total;
}
function removeValidator(address _validator) public onlyOwner {
uint256 delegated =
consensus.delegatedAmount(address(this), _validator);
if (delegated > 0) {
uint256 prevBalance = balance();
undelegateWithCatch(_validator, delegated);
// wasnt withdrawn because validator needs to be taken of active validators
if (balance() == prevBalance) {
// pendingValidators.push(_validator);
return;
}
}
for (uint256 i = 0; i < validators.length; i++) {
if (validators[i] == _validator) {
if (i < validators.length - 1)
validators[i] = validators[validators.length - 1];
validators.pop();
break;
}
}
}
function collectUBIInterest() public {
uint256 curDay = ubischeme.currentDay();
require(
curDay != lastDayCollected,
"can collect only once in a ubi cycle"
);
uint256 earnings = balance() - pendingFuseEarnings;
require(pendingFuseEarnings + earnings > 0, "no earnings to collect");
lastDayCollected = curDay;
uint256 fuseUBI =
earnings.mul(RATIO_BASE - stakeBackRatio).div(RATIO_BASE);
uint256 stakeBack = earnings - fuseUBI;
uint256[] memory fuseswapResult =
_buyGD(fuseUBI.add(pendingFuseEarnings)); //buy GD with X% of earnings
pendingFuseEarnings = fuseUBI.add(pendingFuseEarnings).sub(
fuseswapResult[0]
);
stakeNextValidator(stakeBack, address(0)); //stake back the rest of the earnings
uint256 gdBought = fuseswapResult[1];
uint256 keeperFee = gdBought.mul(keeperFeeRatio).div(RATIO_BASE);
if (keeperFee > 0) GD.transfer(msg.sender, keeperFee);
uint256 communityPoolContribution =
gdBought
.sub(keeperFee) //subtract fee
.mul(communityPoolRatio) // * ommunityPoolRatio
.div(RATIO_BASE); // = G$ after fee * communityPoolRatio%
uint256 ubiAfterFeeAndPool = gdBought.sub(communityPoolContribution);
GD.transfer(address(ubischeme), ubiAfterFeeAndPool); //transfer to ubischeme
communityPoolBalance = communityPoolBalance.add(
communityPoolContribution
);
emit UBICollected(
curDay,
ubiAfterFeeAndPool,
communityPoolContribution,
gdBought,
earnings,
pendingFuseEarnings,
msg.sender,
keeperFee
);
}
/**
* @dev internal method to buy GD from fuseswap
* @param _value fuse to be sold
* @return uniswap coversion results uint256[2]
*/
function _buyGD(uint256 _value) internal returns (uint256[] memory) {
//buy from uniwasp
require(_value > 0, "buy value should be > 0");
uint256 maxFuse = calcMaxFuseWithSlippage(_value);
address[] memory path = new address[](2);
path[1] = address(GD);
path[0] = uniswap.WETH();
return
uniswap.swapExactETHForTokens{ value: maxFuse }(
0,
path,
address(this),
now
);
}
function calcMaxFuseWithSlippage(uint256 _value)
public
view
returns (uint256)
{
(uint256 r_fuse, uint256 r_gd, ) = uniswapPair.getReserves();
return calcMaxFuseWithSlippage(r_fuse, r_gd, _value);
}
/**
* uniswap amountOut helper
*/
function getAmountOut(
uint256 _amountIn,
uint256 _reserveIn,
uint256 _reserveOut
) internal pure returns (uint256 amountOut) {
uint256 amountInWithFee = _amountIn.mul(997);
uint256 numerator = amountInWithFee.mul(_reserveOut);
uint256 denominator = _reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
/**
* @dev use binary search to find quantity that will result with slippage < maxSlippageRatio
*/
function calcMaxFuseWithSlippage(
uint256 r_fuse,
uint256 r_gd,
uint256 _value
) public view returns (uint256) {
uint256 start = 0;
uint256 end = _value.div(1e18); //save iterations by moving precision to whole Fuse quantity
uint256 curPriceWei = uint256(100).mul(r_fuse) / r_gd; //uniswap quote formula UniswapV2Library.sol
uint256 maxPriceWei =
curPriceWei.mul(RATIO_BASE.add(maxSlippageRatio)).div(RATIO_BASE);
uint256 fuseAmount = _value;
//Iterate while start not meets end
while (start <= end) {
// Find the mid index
uint256 midQuantityWei = start.add(end).mul(1e18).div(2); //restore quantity precision
if (midQuantityWei == 0) break;
uint256 gdForQuantity = getAmountOut(midQuantityWei, r_fuse, r_gd);
uint256 priceForQuantityWei =
rdiv(midQuantityWei, gdForQuantity.mul(1e16)).div(1e9);
if (priceForQuantityWei <= maxPriceWei) {
start = midQuantityWei.div(1e18) + 1; //reduce precision to whole quantity div 1e18
fuseAmount = midQuantityWei;
} else end = midQuantityWei.div(1e18) - 1; //reduce precision to whole quantity div 1e18
}
return fuseAmount;
}
function undelegateWithCatch(address _validator, uint256 _amount)
internal
returns (bool)
{
try consensus.withdraw(_validator, _amount) {
return true;
} catch Error(
string memory /*reason*/
) {
// This is executed in case
// revert was called inside getData
// and a reason string was provided.
return false;
} catch (
bytes memory /*lowLevelData*/
) {
// This is executed in case revert() was used
// or there was a failing assertion, division
// by zero, etc. inside getData.
return false;
}
}
function balance() internal view returns (uint256) {
return payable(address(this)).balance;
}
receive() external payable {}
}

Contract ABI

[{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"UBICollected","inputs":[{"type":"uint256","name":"currentDay","internalType":"uint256","indexed":true},{"type":"uint256","name":"ubi","internalType":"uint256","indexed":false},{"type":"uint256","name":"communityPool","internalType":"uint256","indexed":false},{"type":"uint256","name":"gdBought","internalType":"uint256","indexed":false},{"type":"uint256","name":"stakingRewards","internalType":"uint256","indexed":false},{"type":"uint256","name":"pendingFuseEarnings","internalType":"uint256","indexed":false},{"type":"address","name":"keeper","internalType":"address","indexed":false},{"type":"uint256","name":"keeperGDFee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract GoodDollar"}],"name":"GD","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"RATIO_BASE","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"add","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addValidator","inputs":[{"type":"address","name":"_v","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calcMaxFuseWithSlippage","inputs":[{"type":"uint256","name":"r_fuse","internalType":"uint256"},{"type":"uint256","name":"r_gd","internalType":"uint256"},{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calcMaxFuseWithSlippage","inputs":[{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"collectUBIInterest","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"communityPoolRatio","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IConsensus"}],"name":"consensus","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"int256","name":"z","internalType":"int256"}],"name":"imax","inputs":[{"type":"int256","name":"x","internalType":"int256"},{"type":"int256","name":"y","internalType":"int256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"int256","name":"z","internalType":"int256"}],"name":"imin","inputs":[{"type":"int256","name":"x","internalType":"int256"},{"type":"int256","name":"y","internalType":"int256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"keeperFeeRatio","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastDayCollected","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"max","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxSlippageRatio","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"min","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"mul","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"rdiv","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeValidator","inputs":[{"type":"address","name":"_validator","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"rmul","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"rpow","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"n","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContracts","inputs":[{"type":"address","name":"_gd","internalType":"address"},{"type":"address","name":"_ubischeme","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"stake","inputs":[{"type":"address","name":"_validator","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"stake","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakeBackRatio","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stakers","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"sub","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalDelegated","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract UBIScheme"}],"name":"ubischeme","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract Uniswap"}],"name":"uniswap","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract UniswapFactory"}],"name":"uniswapFactory","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract UniswapPair"}],"name":"uniswapPair","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgrade0","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgrade1","inputs":[{"type":"address","name":"_gd","internalType":"address"},{"type":"address","name":"_ubischeme","internalType":"address"},{"type":"address","name":"_uniswap","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"validators","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"wdiv","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdraw","inputs":[{"type":"uint256","name":"_value","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"z","internalType":"uint256"}],"name":"wmul","inputs":[{"type":"uint256","name":"x","internalType":"uint256"},{"type":"uint256","name":"y","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
            

Contract Byte Code

0x6080604052600436106102605760003560e01c8063771602f7116101445780639168ae72116100b6578063c816841b1161007a578063c816841b14610669578063c8a4ac9c1461067e578063c8e6c7d91461069e578063d22e9b06146106be578063d8952a49146106d3578063f2fde38b146106f357610267565b80639168ae72146105df578063a5a90636146105ff578063ae94e44814610614578063b67d77c514610634578063c11a56301461065457610267565b80638918c4a2116101085780638918c4a21461054b5780638b9af5c1146105605780638bdb2afa146105805780638da5cb5b146105955780638ef3f761146105aa5780638f907195146105bf57610267565b8063771602f7146104cc5780637ae2b5c7146104ec57806380d04de81461050c57806381028f67146105215780638129fc1c1461053657610267565b80633fb1ccf1116101dd5780636021a9d5116101a15780636021a9d51461042d5780636711281c1461044257806367457022146104575780636d5433e61461047757806370a0823114610497578063715018a6146104b757610267565b80633fb1ccf11461039657806340a141ff146103ab57806347a1671a146103cd5780634d238c8e146103ed5780635fde731c1461040d57610267565b80632681f7e4116102245780632681f7e41461030c5780632cda89431461032e5780632e1a7d4d1461034e57806335aa2e441461036e5780633a4b66f11461038e57610267565b806304d26ebf1461026c57806309b6afb2146102975780630e2286d3146102b7578063150d7e47146102d757806326476204146102ec57610267565b3661026757005b600080fd5b34801561027857600080fd5b50610281610713565b60405161028e919061244f565b60405180910390f35b3480156102a357600080fd5b506102816102b23660046123d2565b610719565b3480156102c357600080fd5b506102816102d2366004612338565b610835565b3480156102e357600080fd5b50610281610860565b6102ff6102fa3660046121c9565b610866565b60405161028e9190612444565b34801561031857600080fd5b50610321610983565b60405161028e91906123fd565b34801561033a57600080fd5b506102816103493660046123a2565b610992565b34801561035a57600080fd5b506102816103693660046123a2565b610a47565b34801561037a57600080fd5b506103216103893660046123a2565b610ca7565b6102ff610cce565b3480156103a257600080fd5b50610321610ce0565b3480156103b757600080fd5b506103cb6103c63660046121c9565b610cef565b005b3480156103d957600080fd5b506103cb6103e8366004612239565b610ed2565b3480156103f957600080fd5b506103cb6104083660046121c9565b6110ea565b34801561041957600080fd5b50610281610428366004612338565b611171565b34801561043957600080fd5b50610281611183565b34801561044e57600080fd5b506103cb611189565b34801561046357600080fd5b50610281610472366004612338565b6111b0565b34801561048357600080fd5b50610281610492366004612338565b6111d8565b3480156104a357600080fd5b506102816104b23660046121c9565b6111f3565b3480156104c357600080fd5b506103cb61120e565b3480156104d857600080fd5b506102816104e7366004612338565b61128d565b3480156104f857600080fd5b50610281610507366004612338565b6112b0565b34801561051857600080fd5b506102816112c0565b34801561052d57600080fd5b5061032161139a565b34801561054257600080fd5b506103cb6113a9565b34801561055757600080fd5b506102816114ab565b34801561056c57600080fd5b5061028161057b366004612338565b6114b1565b34801561058c57600080fd5b506103216114d2565b3480156105a157600080fd5b506103216114e1565b3480156105b657600080fd5b506103216114f0565b3480156105cb57600080fd5b506102816105da366004612338565b6114ff565b3480156105eb57600080fd5b506102816105fa3660046121c9565b611554565b34801561060b57600080fd5b506103cb611566565b34801561062057600080fd5b5061028161062f366004612338565b6118a1565b34801561064057600080fd5b5061028161064f366004612338565b6118b1565b34801561066057600080fd5b506102816118d4565b34801561067557600080fd5b506103216118da565b34801561068a57600080fd5b50610281610699366004612338565b6118e9565b3480156106aa57600080fd5b506102816106b9366004612338565b611920565b3480156106ca57600080fd5b50610281611930565b3480156106df57600080fd5b506103cb6106ee366004612201565b611936565b3480156106ff57600080fd5b506103cb61070e3660046121c9565b6119c5565b606f5481565b6000808061072f84670de0b6b3a7640000611a7c565b905060008561073f606489611abe565b8161074657fe5b049050600061077860715461077261076b606f54607154611af890919063ffffffff16565b8590611abe565b90611a7c565b9050855b8385116108295760006107a66002610772670de0b6b3a76400006107a08a8a611af8565b90611abe565b9050806107b35750610829565b60006107c0828c8c611b1d565b905060006107e1633b9aca00610772856102d286662386f26fc10000611abe565b9050848111610809576107fc83670de0b6b3a7640000611a7c565b6001019750829350610821565b600161081d84670de0b6b3a7640000611a7c565b0396505b50505061077c565b98975050505050505050565b60008161085161084785610699611b6b565b6002855b0461128d565b8161085857fe5b049392505050565b60705481565b60008034116108905760405162461bcd60e51b8152600401610887906127c2565b60405180910390fd5b6066546108af5760405162461bcd60e51b8152600401610887906127ed565b6000805b6001600160a01b038416158015906108cc575060665481105b1561091357836001600160a01b0316606682815481106108e857fe5b6000918252602090912001546001600160a01b03161461090b5760019150610913565b6001016108b3565b506001600160a01b03831615806109275750805b6109435760405162461bcd60e51b81526004016108879061281d565b600061094f3485611b7b565b3360009081526065602052604090205490915061096c9034611af8565b336000908152606560205260409020559392505050565b6068546001600160a01b031681565b6000806000606c60009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156109e557600080fd5b505afa1580156109f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1d9190612359565b506001600160701b031691506001600160701b03169150610a3f828286610719565b949350505050565b600080610a52611dcc565b905060008315610a625783610a73565b336000908152606560205260409020545b9050808015801590610a945750336000908152606560205260409020548211155b610ab05760405162461bcd60e51b815260040161088790612756565b606654600090610ac1908790611a7c565b905060005b606654811015610c1d57606754606680546000926001600160a01b0316916321429e609130919086908110610af757fe5b6000918252602090912001546040516001600160e01b031960e085901b168152610b2e92916001600160a01b031690600401612411565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7e91906123ba565b905080610b8b5750610c15565b828111610bcf57610bbd60668381548110610ba257fe5b6000918252602090912001546001600160a01b031682611dd1565b50610bc88482611e92565b9350610c08565b610bfa60668381548110610bdf57fe5b6000918252602090912001546001600160a01b031684611dd1565b50610c058484611e92565b93505b83610c135750610c1d565b505b600101610ac6565b50610c3084610c2a611dcc565b90611e92565b935083831115610c3e578392505b33600090815260656020526040902054610c589084611e92565b336000908152606560205260409020558215610c9d57604051339084156108fc029085906000818181858888f19350505050158015610c9b573d6000803e3d6000fd5b505b5090949350505050565b60668181548110610cb457fe5b6000918252602090912001546001600160a01b0316905081565b6000610cda6000610866565b90505b90565b6069546001600160a01b031681565b610cf7611ed4565b6033546001600160a01b03908116911614610d245760405162461bcd60e51b81526004016108879061278d565b60675460405163010a14f360e51b81526000916001600160a01b0316906321429e6090610d579030908690600401612411565b60206040518083038186803b158015610d6f57600080fd5b505afa158015610d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da791906123ba565b90508015610dde576000610db9611dcc565b9050610dc58383611dd1565b5080610dcf611dcc565b1415610ddc575050610ecf565b505b60005b606654811015610ecc57826001600160a01b031660668281548110610e0257fe5b6000918252602090912001546001600160a01b03161415610ec45760665460001901811015610e9257606680546000198101908110610e3d57fe5b600091825260209091200154606680546001600160a01b039092169183908110610e6357fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6066805480610e9d57fe5b600082815260209020810160001990810180546001600160a01b0319169055019055610ecc565b600101610de1565b50505b50565b606c546001600160a01b0316610ecc576001600160a01b03811615610ef75780610f0d565b73fb76e9e7d88e308ab530330ed90e84a9525703195b606880546001600160a01b03199081166001600160a01b039384161791829055606980548216878516179055606a80549091168584161790556040805163c45a015560e01b81529051919092169163c45a0155916004808301926020929190829003018186803b158015610f8057600080fd5b505afa158015610f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb891906121e5565b606b80546001600160a01b0319166001600160a01b039283161790819055606854604080516315ab88c960e31b815290519284169363e6a439059392169163ad5c464891600480820192602092909190829003018186803b15801561101c57600080fd5b505afa158015611030573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105491906121e5565b856040518363ffffffff1660e01b8152600401611072929190612411565b60206040518083038186803b15801561108a57600080fd5b505afa15801561109e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c291906121e5565b606c80546001600160a01b0319166001600160a01b0392909216919091179055610ecc611189565b6110f2611ed4565b6033546001600160a01b0390811691161461111f5760405162461bcd60e51b81526004016108879061278d565b606680546001810182556000919091527f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943540180546001600160a01b0319166001600160a01b0392909216919091179055565b60008161085161084785610699611ed8565b606e5481565b6071546111ae57618235606e819055607255610bb8606f55601e607055620186a06071555b565b60006111ba611b6b565b6108516111c785856118e9565b60026111d1611b6b565b8161084b57fe5b6000818310156111e857816111ea565b825b90505b92915050565b6001600160a01b031660009081526065602052604090205490565b611216611ed4565b6033546001600160a01b039081169116146112435760405162461bcd60e51b81526004016108879061278d565b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380546001600160a01b0319169055565b808201828110156111ed5760405162461bcd60e51b815260040161088790612625565b6000818311156111e857816111ea565b600080805b60665481101561139457606754606680546000926001600160a01b0316916321429e6091309190869081106112f657fe5b6000918252602090912001546040516001600160e01b031960e085901b16815261132d92916001600160a01b031690600401612411565b60206040518083038186803b15801561134557600080fd5b505afa158015611359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137d91906123ba565b90506113898382611af8565b9250506001016112c5565b50905090565b606a546001600160a01b031681565b600054610100900460ff16806113c257506113c2611ee4565b806113d0575060005460ff16155b6113ec5760405162461bcd60e51b815260040161088790612683565b600054610100900460ff16158015611417576000805460ff1961ff0019909116610100171660011790555b61141f611eea565b606780546001600160a01b0319908116733014ca10b91cb3d0ad85fef7a3cb95bcac9c0f7917909155606680546001810182556000919091527f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e9435401805490911673cb876a393f05a6677a8a029f1c6d7603b416c0a61790558015610ecf576000805461ff001916905550565b606d5481565b60006114bb611ed8565b6108516114c885856118e9565b60026111d1611ed8565b606b546001600160a01b031681565b6033546001600160a01b031690565b6067546001600160a01b031681565b60006002820661151657611511611b6b565b611518565b825b90506002820491505b81156111ed5761153183846111b0565b925060028206156115495761154681846111b0565b90505b600282049150611521565b60656020526000908152604090205481565b606a5460408051635c9302c960e01b815290516000926001600160a01b031691635c9302c9916004808301926020929190829003018186803b1580156115ab57600080fd5b505afa1580156115bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e391906123ba565b9050606d548114156116075760405162461bcd60e51b8152600401610887906126d1565b6000607454611614611dcc565b039050600081607454011161163b5760405162461bcd60e51b815260040161088790612653565b606d829055607154606e5460009161165a916107729085908303611abe565b905060008183039050606061168261167d60745485611af890919063ffffffff16565b611fc4565b90506116b18160008151811061169457fe5b6020026020010151610c2a60745486611af890919063ffffffff16565b6074556116bf826000611b7b565b506000816001815181106116cf57fe5b6020026020010151905060006116f660715461077260705485611abe90919063ffffffff16565b905080156117845760695460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611730903390859060040161242b565b602060405180830381600087803b15801561174a57600080fd5b505af115801561175e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117829190612318565b505b60006117a56071546107726072546107a08688611e9290919063ffffffff16565b905060006117b38483611e92565b606954606a5460405163a9059cbb60e01b81529293506001600160a01b039182169263a9059cbb926117eb921690859060040161242b565b602060405180830381600087803b15801561180557600080fd5b505af1158015611819573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061183d9190612318565b5060735461184b9083611af8565b6073556074546040518a917f49a079c90e07ed02ae8283e86eaeb643c637381d30aa7ba06d155e5b744a85439161188e91859187918a918f919033908c90612854565b60405180910390a2505050505050505050565b6000818312156111e857816111ea565b808203828111156111ed5760405162461bcd60e51b815260040161088790612514565b60715481565b606c546001600160a01b031681565b60008115806119045750508082028282828161190157fe5b04145b6111ed5760405162461bcd60e51b8152600401610887906125c0565b6000818313156111e857816111ea565b60725481565b61193e611ed4565b6033546001600160a01b0390811691161461196b5760405162461bcd60e51b81526004016108879061278d565b6001600160a01b0382161561199657606980546001600160a01b0319166001600160a01b0384161790555b6001600160a01b038116156119c157606a80546001600160a01b0319166001600160a01b0383161790555b5050565b6119cd611ed4565b6033546001600160a01b039081169116146119fa5760405162461bcd60e51b81526004016108879061278d565b6001600160a01b038116611a205760405162461bcd60e51b81526004016108879061257a565b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b60006111ea83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612166565b600082611acd575060006111ed565b82820282848281611ada57fe5b04146111ea5760405162461bcd60e51b815260040161088790612715565b6000828201838110156111ea5760405162461bcd60e51b8152600401610887906125ee565b600080611b2c856103e5611abe565b90506000611b3a8285611abe565b90506000611b5483611b4e886103e8611abe565b90611af8565b9050808281611b5f57fe5b04979650505050505050565b6b033b2e3c9fd0803ce800000090565b606654600090611b8d575060006111ed565b6001600160a01b03821615611c09576067546040516317066a5760e21b81526001600160a01b0390911690635c19a95c908590611bce9086906004016123fd565b6000604051808303818588803b158015611be757600080fd5b505af1158015611bfb573d6000803e3d6000fd5b5050505050600190506111ed565b606654600090611c1f9061077286611b4e6112c0565b90508360005b60665481108015611c365750600082115b15611dc057606754606680546000926001600160a01b0316916321429e609130919086908110611c6257fe5b6000918252602090912001546040516001600160e01b031960e085901b168152611c9992916001600160a01b031690600401612411565b60206040518083038186803b158015611cb157600080fd5b505afa158015611cc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce991906123ba565b905083811015611db7576000611cff8583611e92565b9050838110611d0e5783611d10565b805b606754606680549293506001600160a01b0390911691635c19a95c91849187908110611d3857fe5b6000918252602090912001546040516001600160e01b031960e085901b168152611d6e916001600160a01b0316906004016123fd565b6000604051808303818588803b158015611d8757600080fd5b505af1158015611d9b573d6000803e3d6000fd5b5050505050611db38185611e9290919063ffffffff16565b9350505b50600101611c25565b50600195945050505050565b303190565b60675460405163f3fef3a360e01b81526000916001600160a01b03169063f3fef3a390611e04908690869060040161242b565b600060405180830381600087803b158015611e1e57600080fd5b505af1925050508015611e2f575060015b611e8a57611e3b6128da565b80611e465750611e50565b60009150506111ed565b3d808015611e7a576040519150601f19603f3d011682016040523d82523d6000602084013e611e7f565b606091505b5060009150506111ed565b5060016111ed565b60006111ea83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061219d565b3390565b670de0b6b3a764000090565b303b1590565b600054610100900460ff1680611f035750611f03611ee4565b80611f11575060005460ff16155b611f2d5760405162461bcd60e51b815260040161088790612683565b600054610100900460ff16158015611f58576000805460ff1961ff0019909116610100171660011790555b6000611f62611ed4565b603380546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508015610ecf576000805461ff001916905550565b606060008211611fe65760405162461bcd60e51b815260040161088790612543565b6000611ff183610992565b604080516002808252606080830184529394509091602083019080368337505060695482519293506001600160a01b031691839150600190811061203157fe5b6001600160a01b03928316602091820292909201810191909152606854604080516315ab88c960e31b81529051919093169263ad5c4648926004808301939192829003018186803b15801561208557600080fd5b505afa158015612099573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120bd91906121e5565b816000815181106120ca57fe5b6001600160a01b039283166020918202929092010152606854604051637ff36ab560e01b8152911690637ff36ab590849061211090600090869030904290600401612458565b6000604051808303818588803b15801561212957600080fd5b505af115801561213d573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052610a3f9190810190612283565b600081836121875760405162461bcd60e51b815260040161088791906124c1565b50600083858161219357fe5b0495945050505050565b600081848411156121c15760405162461bcd60e51b815260040161088791906124c1565b505050900390565b6000602082840312156121da578081fd5b81356111ea8161297f565b6000602082840312156121f6578081fd5b81516111ea8161297f565b60008060408385031215612213578081fd5b823561221e8161297f565b9150602083013561222e8161297f565b809150509250929050565b60008060006060848603121561224d578081fd5b83356122588161297f565b925060208401356122688161297f565b915060408401356122788161297f565b809150509250925092565b60006020808385031215612295578182fd5b825167ffffffffffffffff8111156122ab578283fd5b8301601f810185136122bb578283fd5b80516122ce6122c9826128b4565b61288d565b81815283810190838501858402850186018910156122ea578687fd5b8694505b8385101561230c5780518352600194909401939185019185016122ee565b50979650505050505050565b600060208284031215612329578081fd5b815180151581146111ea578182fd5b6000806040838503121561234a578182fd5b50508035926020909101359150565b60008060006060848603121561236d578283fd5b835161237881612994565b602085015190935061238981612994565b604085015190925063ffffffff81168114612278578182fd5b6000602082840312156123b3578081fd5b5035919050565b6000602082840312156123cb578081fd5b5051919050565b6000806000606084860312156123e6578283fd5b505081359360208301359350604090920135919050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b600060808201868352602060808185015281875180845260a0860191508289019350845b818110156124a15784516001600160a01b03168352938301939183019160010161247c565b50506001600160a01b039690961660408501525050506060015292915050565b6000602080835283518082850152825b818110156124ed578581018301518582016040015282016124d1565b818111156124fe5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b60208082526017908201527f6275792076616c75652073686f756c64206265203e2030000000000000000000604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601690820152751b9bc819585c9b9a5b99dcc81d1bc818dbdb1b1958dd60521b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60208082526024908201527f63616e20636f6c6c656374206f6e6c79206f6e636520696e206120756269206360408201526379636c6560e01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527f696e76616c696420776974686472617720616d6f756e74000000000000000000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526011908201527007374616b65206d757374206265203e203607c1b604082015260600190565b6020808252601690820152756e6f20617070726f7665642076616c696461746f727360501b604082015260600190565b6020808252601e908201527f76616c696461746f72206e6f7420696e20617070726f766564206c6973740000604082015260600190565b96875260208701959095526040860193909352606085019190915260808401526001600160a01b031660a083015260c082015260e00190565b60405181810167ffffffffffffffff811182821017156128ac57600080fd5b604052919050565b600067ffffffffffffffff8211156128ca578081fd5b5060209081020190565b60e01c90565b600060443d10156128ea57610cdd565b600481823e6308c379a06128fe82516128d4565b1461290857610cdd565b6040513d600319016004823e80513d67ffffffffffffffff81602484011181841117156129385750505050610cdd565b828401925082519150808211156129525750505050610cdd565b503d8301602082840101111561296a57505050610cdd565b601f01601f1916810160200160405291505090565b6001600160a01b0381168114610ecf57600080fd5b6001600160701b0381168114610ecf57600080fdfea2646970667358221220c81644fb5118b2211dedf7e78b5379ae287bb2d47b14cc2f7cefe056fc6ac46564736f6c634300060c0033