Source Code
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
BishopStableSwapV2
Compiler Version
v0.6.12+commit.27d51765
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
import "../interfaces/IPrimaryMarketV3.sol";
import "../interfaces/ITrancheIndexV2.sol";
import "./StableSwapV2.sol";
contract BishopStableSwapV2 is StableSwapV2, ITrancheIndexV2 {
event Rebalanced(uint256 base, uint256 quote, uint256 version);
uint256 public immutable tradingCurbThreshold;
uint256 public currentVersion;
constructor(
address lpToken_,
address fund_,
address quoteAddress_,
uint256 quoteDecimals_,
uint256 ampl_,
address feeCollector_,
uint256 feeRate_,
uint256 adminFeeRate_,
uint256 tradingCurbThreshold_
)
public
StableSwapV2(
lpToken_,
fund_,
TRANCHE_B,
quoteAddress_,
quoteDecimals_,
ampl_,
feeCollector_,
feeRate_,
adminFeeRate_
)
{
tradingCurbThreshold = tradingCurbThreshold_;
currentVersion = IFundV3(fund_).getRebalanceSize();
}
/// @dev Make sure the user-specified version is the latest rebalance version.
function _checkVersion(uint256 version) internal view override {
require(version == fund.getRebalanceSize(), "Obsolete rebalance version");
}
function _getRebalanceResult(
uint256 latestVersion
)
internal
view
override
returns (
uint256 newBase,
uint256 newQuote,
uint256 excessiveQ,
uint256 excessiveB,
uint256 excessiveR,
uint256 excessiveQuote,
bool isRebalanced
)
{
if (latestVersion == currentVersion) {
return (baseBalance, quoteBalance, 0, 0, 0, 0, false);
}
isRebalanced = true;
uint256 oldBaseBalance = baseBalance;
uint256 oldQuoteBalance = quoteBalance;
(excessiveQ, newBase, ) = fund.batchRebalance(
0,
oldBaseBalance,
0,
currentVersion,
latestVersion
);
if (newBase < oldBaseBalance) {
// We split all QUEEN from rebalance if the amount of BISHOP is smaller than before.
// In almost all cases, the total amount of BISHOP after the split is still smaller
// than before.
excessiveR = IPrimaryMarketV3(fund.primaryMarket()).getSplit(excessiveQ);
newBase = newBase.add(excessiveR);
}
if (newBase < oldBaseBalance) {
// If BISHOP amount is still smaller than before, we remove quote tokens proportionally.
newQuote = oldQuoteBalance.mul(newBase).div(oldBaseBalance);
excessiveQuote = oldQuoteBalance - newQuote;
} else {
// In most cases when we reach here, the BISHOP amount remains the same (ratioBR = 1).
newQuote = oldQuoteBalance;
excessiveB = newBase - oldBaseBalance;
newBase = oldBaseBalance;
}
}
function _handleRebalance(
uint256 latestVersion
) internal override returns (uint256 newBase, uint256 newQuote) {
uint256 excessiveQ;
uint256 excessiveB;
uint256 excessiveR;
uint256 excessiveQuote;
bool isRebalanced;
(
newBase,
newQuote,
excessiveQ,
excessiveB,
excessiveR,
excessiveQuote,
isRebalanced
) = _getRebalanceResult(latestVersion);
if (isRebalanced) {
baseBalance = newBase;
quoteBalance = newQuote;
currentVersion = latestVersion;
emit Rebalanced(newBase, newQuote, latestVersion);
if (excessiveQ > 0) {
if (excessiveR > 0) {
IPrimaryMarketV3(fund.primaryMarket()).split(
address(this),
excessiveQ,
latestVersion
);
excessiveQ = 0;
} else {
fund.trancheTransfer(TRANCHE_Q, lpToken, excessiveQ, latestVersion);
}
}
if (excessiveB > 0) {
fund.trancheTransfer(TRANCHE_B, lpToken, excessiveB, latestVersion);
}
if (excessiveR > 0) {
fund.trancheTransfer(TRANCHE_R, lpToken, excessiveR, latestVersion);
}
if (excessiveQuote > 0) {
IERC20(quoteAddress).safeTransfer(lpToken, excessiveQuote);
}
ILiquidityGauge(lpToken).distribute(
excessiveQ,
excessiveB,
excessiveR,
excessiveQuote,
latestVersion
);
}
}
function getOraclePrice() public view override returns (uint256) {
uint256 price = fund.twapOracle().getLatest();
(, uint256 navB, uint256 navR) = fund.extrapolateNav(price);
require(navR >= navB.multiplyDecimal(tradingCurbThreshold), "Trading curb");
return navB;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
interface AggregatorV3Interface {
function decimals()
external
view
returns (
uint8
);
function description()
external
view
returns (
string memory
);
function version()
external
view
returns (
uint256
);
// getRoundData and latestRoundData should both raise "No data present"
// if they do not have data to report, instead of returning unset values
// which could be misinterpreted as actual reported values.
function getRoundData(
uint80 _roundId
)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
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));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
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));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
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");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
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");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
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");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
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);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
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);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
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 {
// 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);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
pragma experimental ABIEncoderV2;
import "./ITwapOracleV2.sol";
interface IFundV3 {
/// @notice A linear transformation matrix that represents a rebalance.
///
/// ```
/// [ 1 0 0 ]
/// R = [ ratioB2Q ratioBR 0 ]
/// [ ratioR2Q 0 ratioBR ]
/// ```
///
/// Amounts of the three tranches `q`, `b` and `r` can be rebalanced by multiplying the matrix:
///
/// ```
/// [ q', b', r' ] = [ q, b, r ] * R
/// ```
struct Rebalance {
uint256 ratioB2Q;
uint256 ratioR2Q;
uint256 ratioBR;
uint256 timestamp;
}
function tokenUnderlying() external view returns (address);
function tokenQ() external view returns (address);
function tokenB() external view returns (address);
function tokenR() external view returns (address);
function tokenShare(uint256 tranche) external view returns (address);
function primaryMarket() external view returns (address);
function primaryMarketUpdateProposal() external view returns (address, uint256);
function strategy() external view returns (address);
function strategyUpdateProposal() external view returns (address, uint256);
function underlyingDecimalMultiplier() external view returns (uint256);
function twapOracle() external view returns (ITwapOracleV2);
function feeCollector() external view returns (address);
function endOfDay(uint256 timestamp) external pure returns (uint256);
function trancheTotalSupply(uint256 tranche) external view returns (uint256);
function trancheBalanceOf(uint256 tranche, address account) external view returns (uint256);
function trancheAllBalanceOf(address account) external view returns (uint256, uint256, uint256);
function trancheBalanceVersion(address account) external view returns (uint256);
function trancheAllowance(
uint256 tranche,
address owner,
address spender
) external view returns (uint256);
function trancheAllowanceVersion(
address owner,
address spender
) external view returns (uint256);
function trancheTransfer(
uint256 tranche,
address recipient,
uint256 amount,
uint256 version
) external;
function trancheTransferFrom(
uint256 tranche,
address sender,
address recipient,
uint256 amount,
uint256 version
) external;
function trancheApprove(
uint256 tranche,
address spender,
uint256 amount,
uint256 version
) external;
function getRebalanceSize() external view returns (uint256);
function getRebalance(uint256 index) external view returns (Rebalance memory);
function getRebalanceTimestamp(uint256 index) external view returns (uint256);
function currentDay() external view returns (uint256);
function splitRatio() external view returns (uint256);
function historicalSplitRatio(uint256 version) external view returns (uint256);
function fundActivityStartTime() external view returns (uint256);
function isFundActive(uint256 timestamp) external view returns (bool);
function getEquivalentTotalB() external view returns (uint256);
function getEquivalentTotalQ() external view returns (uint256);
function historicalEquivalentTotalB(uint256 timestamp) external view returns (uint256);
function historicalNavs(uint256 timestamp) external view returns (uint256 navB, uint256 navR);
function extrapolateNav(uint256 price) external view returns (uint256, uint256, uint256);
function doRebalance(
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 index
) external view returns (uint256 newAmountQ, uint256 newAmountB, uint256 newAmountR);
function batchRebalance(
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 fromIndex,
uint256 toIndex
) external view returns (uint256 newAmountQ, uint256 newAmountB, uint256 newAmountR);
function refreshBalance(address account, uint256 targetVersion) external;
function refreshAllowance(address owner, address spender, uint256 targetVersion) external;
function shareTransfer(address sender, address recipient, uint256 amount) external;
function shareTransferFrom(
address spender,
address sender,
address recipient,
uint256 amount
) external returns (uint256 newAllowance);
function shareIncreaseAllowance(
address sender,
address spender,
uint256 addedValue
) external returns (uint256 newAllowance);
function shareDecreaseAllowance(
address sender,
address spender,
uint256 subtractedValue
) external returns (uint256 newAllowance);
function shareApprove(address owner, address spender, uint256 amount) external;
function historicalUnderlying(uint256 timestamp) external view returns (uint256);
function getTotalUnderlying() external view returns (uint256);
function getStrategyUnderlying() external view returns (uint256);
function getTotalDebt() external view returns (uint256);
event RebalanceTriggered(
uint256 indexed index,
uint256 indexed day,
uint256 navSum,
uint256 navB,
uint256 navROrZero,
uint256 ratioB2Q,
uint256 ratioR2Q,
uint256 ratioBR
);
event Settled(uint256 indexed day, uint256 navB, uint256 navR, uint256 interestRate);
event InterestRateUpdated(uint256 baseInterestRate, uint256 floatingInterestRate);
event BalancesRebalanced(
address indexed account,
uint256 version,
uint256 balanceQ,
uint256 balanceB,
uint256 balanceR
);
event AllowancesRebalanced(
address indexed owner,
address indexed spender,
uint256 version,
uint256 allowanceQ,
uint256 allowanceB,
uint256 allowanceR
);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface ILiquidityGauge is IERC20 {
function mint(address account, uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
function workingSupply() external view returns (uint256);
function workingBalanceOf(address account) external view returns (uint256);
function claimableRewards(
address account
)
external
returns (
uint256 chessAmount,
uint256 bonusAmount,
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 quoteAmount
);
function claimRewards(address account) external;
function distribute(
uint256 amountQ,
uint256 amountB,
uint256 amountR,
uint256 quoteAmount,
uint256 version
) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
interface IPrimaryMarketV3 {
function fund() external view returns (address);
function getCreation(uint256 underlying) external view returns (uint256 outQ);
function getCreationForQ(uint256 minOutQ) external view returns (uint256 underlying);
function getRedemption(uint256 inQ) external view returns (uint256 underlying, uint256 fee);
function getRedemptionForUnderlying(uint256 minUnderlying) external view returns (uint256 inQ);
function getSplit(uint256 inQ) external view returns (uint256 outB);
function getSplitForB(uint256 minOutB) external view returns (uint256 inQ);
function getMerge(uint256 inB) external view returns (uint256 outQ, uint256 feeQ);
function getMergeForQ(uint256 minOutQ) external view returns (uint256 inB);
function canBeRemovedFromFund() external view returns (bool);
function create(
address recipient,
uint256 minOutQ,
uint256 version
) external returns (uint256 outQ);
function redeem(
address recipient,
uint256 inQ,
uint256 minUnderlying,
uint256 version
) external returns (uint256 underlying);
function redeemAndUnwrap(
address recipient,
uint256 inQ,
uint256 minUnderlying,
uint256 version
) external returns (uint256 underlying);
function queueRedemption(
address recipient,
uint256 inQ,
uint256 minUnderlying,
uint256 version
) external returns (uint256 underlying, uint256 index);
function claimRedemptions(
address account,
uint256[] calldata indices
) external returns (uint256 underlying);
function claimRedemptionsAndUnwrap(
address account,
uint256[] calldata indices
) external returns (uint256 underlying);
function split(address recipient, uint256 inQ, uint256 version) external returns (uint256 outB);
function merge(address recipient, uint256 inB, uint256 version) external returns (uint256 outQ);
function settle(uint256 day) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
import "../interfaces/IFundV3.sol";
interface IStableSwapCore {
function getQuoteOut(uint256 baseIn) external view returns (uint256 quoteOut);
function getQuoteIn(uint256 baseOut) external view returns (uint256 quoteIn);
function getBaseOut(uint256 quoteIn) external view returns (uint256 baseOut);
function getBaseIn(uint256 quoteOut) external view returns (uint256 baseIn);
function buy(
uint256 version,
uint256 baseOut,
address recipient,
bytes calldata data
) external returns (uint256 realBaseOut);
function sell(
uint256 version,
uint256 quoteOut,
address recipient,
bytes calldata data
) external returns (uint256 realQuoteOut);
}
interface IStableSwap is IStableSwapCore {
function fund() external view returns (IFundV3);
function baseTranche() external view returns (uint256);
function baseAddress() external view returns (address);
function quoteAddress() external view returns (address);
function allBalances() external view returns (uint256, uint256);
function getOraclePrice() external view returns (uint256);
function getCurrentD() external view returns (uint256);
function getCurrentPriceOverOracle() external view returns (uint256);
function getCurrentPrice() external view returns (uint256);
function getPriceOverOracleIntegral() external view returns (uint256);
function addLiquidity(uint256 version, address recipient) external returns (uint256);
function removeLiquidity(
uint256 version,
uint256 lpIn,
uint256 minBaseOut,
uint256 minQuoteOut
) external returns (uint256 baseOut, uint256 quoteOut);
function removeLiquidityUnwrap(
uint256 version,
uint256 lpIn,
uint256 minBaseOut,
uint256 minQuoteOut
) external returns (uint256 baseOut, uint256 quoteOut);
function removeBaseLiquidity(
uint256 version,
uint256 lpIn,
uint256 minBaseOut
) external returns (uint256 baseOut);
function removeQuoteLiquidity(
uint256 version,
uint256 lpIn,
uint256 minQuoteOut
) external returns (uint256 quoteOut);
function removeQuoteLiquidityUnwrap(
uint256 version,
uint256 lpIn,
uint256 minQuoteOut
) external returns (uint256 quoteOut);
}
/// @dev The interface shares the same function names as in `IStableSwapCore`;
/// all getters are defined as non-view functions in order to parse and
/// return the internal revert messages
interface IStableSwapCoreInternalRevertExpected {
function getQuoteOut(uint256 baseIn) external returns (uint256 quoteOut);
function getQuoteIn(uint256 baseOut) external returns (uint256 quoteIn);
function getBaseOut(uint256 quoteIn) external returns (uint256 baseOut);
function getBaseIn(uint256 quoteOut) external returns (uint256 baseIn);
function buy(
uint256 version,
uint256 baseOut,
address recipient,
bytes calldata data
) external returns (uint256 realBaseOut);
function sell(
uint256 version,
uint256 quoteOut,
address recipient,
bytes calldata data
) external returns (uint256 realQuoteOut);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
/// @notice Amounts of QUEEN, BISHOP and ROOK are sometimes stored in a `uint256[3]` array.
/// This contract defines index of each tranche in this array.
///
/// Solidity does not allow constants to be defined in interfaces. So this contract follows
/// the naming convention of interfaces but is implemented as an `abstract contract`.
abstract contract ITrancheIndexV2 {
uint256 internal constant TRANCHE_Q = 0;
uint256 internal constant TRANCHE_B = 1;
uint256 internal constant TRANCHE_R = 2;
uint256 internal constant TRANCHE_COUNT = 3;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
interface ITranchessSwapCallee {
function tranchessSwapCallback(
uint256 baseDeltaOut,
uint256 quoteDeltaOut,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
interface ITwapOracle {
enum UpdateType {
PRIMARY,
SECONDARY,
OWNER,
CHAINLINK,
UNISWAP_V2
}
function getTwap(uint256 timestamp) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
import "./ITwapOracle.sol";
interface ITwapOracleV2 is ITwapOracle {
function getLatest() external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWrappedERC20 is IERC20 {
function deposit() external payable;
function withdraw(uint256 wad) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "../interfaces/IStableSwap.sol";
import "../interfaces/ILiquidityGauge.sol";
import "../interfaces/ITranchessSwapCallee.sol";
import "../interfaces/IWrappedERC20.sol";
import "../utils/SafeDecimalMath.sol";
import "../utils/AdvancedMath.sol";
import "../utils/ManagedPausable.sol";
abstract contract StableSwapV2 is IStableSwap, Ownable, ReentrancyGuard, ManagedPausable {
using SafeMath for uint256;
using SafeDecimalMath for uint256;
using SafeERC20 for IERC20;
event LiquidityAdded(
address indexed sender,
address indexed recipient,
uint256 baseIn,
uint256 quoteIn,
uint256 lpOut,
uint256 fee,
uint256 adminFee,
uint256 oraclePrice
);
event LiquidityRemoved(
address indexed account,
uint256 lpIn,
uint256 baseOut,
uint256 quotOut,
uint256 fee,
uint256 adminFee,
uint256 oraclePrice
);
event Swap(
address indexed sender,
address indexed recipient,
uint256 baseIn,
uint256 quoteIn,
uint256 baseOut,
uint256 quoteOut,
uint256 fee,
uint256 adminFee,
uint256 oraclePrice
);
event Sync(uint256 base, uint256 quote, uint256 oraclePrice);
event AmplRampUpdated(uint256 start, uint256 end, uint256 startTimestamp, uint256 endTimestamp);
event FeeCollectorUpdated(address newFeeCollector);
event FeeRateUpdated(uint256 newFeeRate);
event AdminFeeRateUpdated(uint256 newAdminFeeRate);
uint256 private constant AMPL_MAX_VALUE = 1e6;
uint256 private constant AMPL_RAMP_MIN_TIME = 86400;
uint256 private constant AMPL_RAMP_MAX_CHANGE = 10;
uint256 private constant MAX_FEE_RATE = 0.5e18;
uint256 private constant MAX_ADMIN_FEE_RATE = 1e18;
uint256 private constant MAX_ITERATION = 255;
uint256 private constant MINIMUM_LIQUIDITY = 1e3;
address public immutable lpToken;
IFundV3 public immutable override fund;
uint256 public immutable override baseTranche;
address public immutable override quoteAddress;
/// @dev A multipler that normalizes a quote asset balance to 18 decimal places.
uint256 internal immutable _quoteDecimalMultiplier;
uint256 public baseBalance;
uint256 public quoteBalance;
uint256 private _priceOverOracleIntegral;
uint256 private _priceOverOracleTimestamp;
uint256 public amplRampStart;
uint256 public amplRampEnd;
uint256 public amplRampStartTimestamp;
uint256 public amplRampEndTimestamp;
address public feeCollector;
uint256 public feeRate;
uint256 public adminFeeRate;
uint256 public totalAdminFee;
constructor(
address lpToken_,
address fund_,
uint256 baseTranche_,
address quoteAddress_,
uint256 quoteDecimals_,
uint256 ampl_,
address feeCollector_,
uint256 feeRate_,
uint256 adminFeeRate_
) public {
lpToken = lpToken_;
fund = IFundV3(fund_);
baseTranche = baseTranche_;
quoteAddress = quoteAddress_;
require(quoteDecimals_ <= 18, "Quote asset decimals larger than 18");
_quoteDecimalMultiplier = 10 ** (18 - quoteDecimals_);
require(ampl_ > 0 && ampl_ < AMPL_MAX_VALUE, "Invalid A");
amplRampEnd = ampl_;
emit AmplRampUpdated(ampl_, ampl_, 0, 0);
_updateFeeCollector(feeCollector_);
_updateFeeRate(feeRate_);
_updateAdminFeeRate(adminFeeRate_);
_initializeManagedPausable(msg.sender);
}
receive() external payable {}
function baseAddress() external view override returns (address) {
return fund.tokenShare(baseTranche);
}
function allBalances() external view override returns (uint256, uint256) {
(uint256 base, uint256 quote, , , , , ) = _getRebalanceResult(fund.getRebalanceSize());
return (base, quote);
}
function getAmpl() public view returns (uint256) {
uint256 endTimestamp = amplRampEndTimestamp;
if (block.timestamp < endTimestamp) {
uint256 startTimestamp = amplRampStartTimestamp;
uint256 start = amplRampStart;
uint256 end = amplRampEnd;
if (end > start) {
return
start +
((end - start) * (block.timestamp - startTimestamp)) /
(endTimestamp - startTimestamp);
} else {
return
start -
((start - end) * (block.timestamp - startTimestamp)) /
(endTimestamp - startTimestamp);
}
} else {
return amplRampEnd;
}
}
function getCurrentD() external view override returns (uint256) {
(uint256 base, uint256 quote, , , , , ) = _getRebalanceResult(fund.getRebalanceSize());
return _getD(base, quote, getAmpl(), getOraclePrice());
}
function getCurrentPriceOverOracle() public view override returns (uint256) {
(uint256 base, uint256 quote, , , , , ) = _getRebalanceResult(fund.getRebalanceSize());
if (base == 0 || quote == 0) {
return 1e18;
}
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
uint256 d = _getD(base, quote, ampl, oraclePrice);
return _getPriceOverOracle(base, quote, ampl, oraclePrice, d);
}
/// @notice Get the current swap price, i.e. negative slope at the current point on the curve.
/// The returned value is computed after both base and quote balances are normalized to
/// 18 decimal places. If the quote token does not have 18 decimal places, the returned
/// value has a different order of magnitude than the ratio of quote amount to base
/// amount in a swap.
function getCurrentPrice() external view override returns (uint256) {
(uint256 base, uint256 quote, , , , , ) = _getRebalanceResult(fund.getRebalanceSize());
uint256 oraclePrice = getOraclePrice();
if (base == 0 || quote == 0) {
return oraclePrice;
}
uint256 ampl = getAmpl();
uint256 d = _getD(base, quote, ampl, oraclePrice);
return _getPriceOverOracle(base, quote, ampl, oraclePrice, d).multiplyDecimal(oraclePrice);
}
function getPriceOverOracleIntegral() external view override returns (uint256) {
return
_priceOverOracleIntegral +
getCurrentPriceOverOracle() *
(block.timestamp - _priceOverOracleTimestamp);
}
function getQuoteOut(uint256 baseIn) external view override returns (uint256 quoteOut) {
(uint256 oldBase, uint256 oldQuote, , , , , ) = _getRebalanceResult(
fund.getRebalanceSize()
);
uint256 newBase = oldBase.add(baseIn);
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
// Add 1 in case of rounding errors
uint256 d = _getD(oldBase, oldQuote, ampl, oraclePrice) + 1;
uint256 newQuote = _getQuote(ampl, newBase, oraclePrice, d) + 1;
quoteOut = oldQuote.sub(newQuote);
// Round down output after fee
quoteOut = quoteOut.multiplyDecimal(1e18 - feeRate);
}
function getQuoteIn(uint256 baseOut) external view override returns (uint256 quoteIn) {
(uint256 oldBase, uint256 oldQuote, , , , , ) = _getRebalanceResult(
fund.getRebalanceSize()
);
uint256 newBase = oldBase.sub(baseOut);
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
// Add 1 in case of rounding errors
uint256 d = _getD(oldBase, oldQuote, ampl, oraclePrice) + 1;
uint256 newQuote = _getQuote(ampl, newBase, oraclePrice, d) + 1;
quoteIn = newQuote.sub(oldQuote);
uint256 feeRate_ = feeRate;
// Round up input before fee
quoteIn = quoteIn.mul(1e18).add(1e18 - feeRate_ - 1) / (1e18 - feeRate_);
}
function getBaseOut(uint256 quoteIn) external view override returns (uint256 baseOut) {
(uint256 oldBase, uint256 oldQuote, , , , , ) = _getRebalanceResult(
fund.getRebalanceSize()
);
// Round down input after fee
uint256 quoteInAfterFee = quoteIn.multiplyDecimal(1e18 - feeRate);
uint256 newQuote = oldQuote.add(quoteInAfterFee);
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
// Add 1 in case of rounding errors
uint256 d = _getD(oldBase, oldQuote, ampl, oraclePrice) + 1;
uint256 newBase = _getBase(ampl, newQuote, oraclePrice, d) + 1;
baseOut = oldBase.sub(newBase);
}
function getBaseIn(uint256 quoteOut) external view override returns (uint256 baseIn) {
(uint256 oldBase, uint256 oldQuote, , , , , ) = _getRebalanceResult(
fund.getRebalanceSize()
);
uint256 feeRate_ = feeRate;
// Round up output before fee
uint256 quoteOutBeforeFee = quoteOut.mul(1e18).add(1e18 - feeRate_ - 1) / (1e18 - feeRate_);
uint256 newQuote = oldQuote.sub(quoteOutBeforeFee);
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
// Add 1 in case of rounding errors
uint256 d = _getD(oldBase, oldQuote, ampl, oraclePrice) + 1;
uint256 newBase = _getBase(ampl, newQuote, oraclePrice, d) + 1;
baseIn = newBase.sub(oldBase);
}
function buy(
uint256 version,
uint256 baseOut,
address recipient,
bytes calldata data
)
external
override
nonReentrant
checkVersion(version)
whenNotPaused
returns (uint256 realBaseOut)
{
require(baseOut > 0, "Zero output");
realBaseOut = baseOut;
(uint256 oldBase, uint256 oldQuote) = _handleRebalance(version);
require(baseOut < oldBase, "Insufficient liquidity");
// Optimistically transfer tokens.
fund.trancheTransfer(baseTranche, recipient, baseOut, version);
if (data.length > 0) {
ITranchessSwapCallee(msg.sender).tranchessSwapCallback(baseOut, 0, data);
_checkVersion(version); // Make sure no rebalance is triggered in the callback
}
uint256 newQuote = _getNewQuoteBalance();
uint256 quoteIn = newQuote.sub(oldQuote);
uint256 fee = quoteIn.multiplyDecimal(feeRate);
uint256 oraclePrice = getOraclePrice();
{
uint256 ampl = getAmpl();
uint256 oldD = _getD(oldBase, oldQuote, ampl, oraclePrice);
_updatePriceOverOracleIntegral(oldBase, oldQuote, ampl, oraclePrice, oldD);
uint256 newD = _getD(oldBase - baseOut, newQuote.sub(fee), ampl, oraclePrice);
require(newD >= oldD, "Invariant mismatch");
}
uint256 adminFee = fee.multiplyDecimal(adminFeeRate);
baseBalance = oldBase - baseOut;
quoteBalance = newQuote.sub(adminFee);
totalAdminFee = totalAdminFee.add(adminFee);
uint256 baseOut_ = baseOut;
emit Swap(msg.sender, recipient, 0, quoteIn, baseOut_, 0, fee, adminFee, oraclePrice);
}
function sell(
uint256 version,
uint256 quoteOut,
address recipient,
bytes calldata data
)
external
override
nonReentrant
checkVersion(version)
whenNotPaused
returns (uint256 realQuoteOut)
{
require(quoteOut > 0, "Zero output");
realQuoteOut = quoteOut;
(uint256 oldBase, uint256 oldQuote) = _handleRebalance(version);
// Optimistically transfer tokens.
IERC20(quoteAddress).safeTransfer(recipient, quoteOut);
if (data.length > 0) {
ITranchessSwapCallee(msg.sender).tranchessSwapCallback(0, quoteOut, data);
_checkVersion(version); // Make sure no rebalance is triggered in the callback
}
uint256 newBase = fund.trancheBalanceOf(baseTranche, address(this));
uint256 baseIn = newBase.sub(oldBase);
uint256 fee;
{
uint256 feeRate_ = feeRate;
fee = quoteOut.mul(feeRate_).div(1e18 - feeRate_);
}
require(quoteOut.add(fee) < oldQuote, "Insufficient liquidity");
uint256 oraclePrice = getOraclePrice();
{
uint256 newQuote = oldQuote - quoteOut;
uint256 ampl = getAmpl();
uint256 oldD = _getD(oldBase, oldQuote, ampl, oraclePrice);
_updatePriceOverOracleIntegral(oldBase, oldQuote, ampl, oraclePrice, oldD);
uint256 newD = _getD(newBase, newQuote - fee, ampl, oraclePrice);
require(newD >= oldD, "Invariant mismatch");
}
uint256 adminFee = fee.multiplyDecimal(adminFeeRate);
baseBalance = newBase;
quoteBalance = oldQuote - quoteOut - adminFee;
totalAdminFee = totalAdminFee.add(adminFee);
uint256 quoteOut_ = quoteOut;
emit Swap(msg.sender, recipient, baseIn, 0, 0, quoteOut_, fee, adminFee, oraclePrice);
}
/// @notice Add liquidity. This function should be called by a smart contract, which transfers
/// base and quote tokens to this contract in the same transaction.
/// @param version The latest rebalance version
/// @param recipient Recipient of minted LP tokens
/// @param lpOut Amount of minted LP tokens
function addLiquidity(
uint256 version,
address recipient
) external override nonReentrant checkVersion(version) whenNotPaused returns (uint256 lpOut) {
(uint256 oldBase, uint256 oldQuote) = _handleRebalance(version);
uint256 newBase = fund.trancheBalanceOf(baseTranche, address(this));
uint256 newQuote = _getNewQuoteBalance();
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
uint256 lpSupply = IERC20(lpToken).totalSupply();
if (lpSupply == 0) {
require(newBase > 0 && newQuote > 0, "Zero initial balance");
baseBalance = newBase;
quoteBalance = newQuote;
// Overflow is desired
_priceOverOracleIntegral += 1e18 * (block.timestamp - _priceOverOracleTimestamp);
_priceOverOracleTimestamp = block.timestamp;
uint256 d1 = _getD(newBase, newQuote, ampl, oraclePrice);
ILiquidityGauge(lpToken).mint(address(this), MINIMUM_LIQUIDITY);
ILiquidityGauge(lpToken).mint(recipient, d1.sub(MINIMUM_LIQUIDITY));
emit LiquidityAdded(msg.sender, recipient, newBase, newQuote, d1, 0, 0, oraclePrice);
return d1;
}
uint256 fee;
uint256 adminFee;
{
// Initial invariant
uint256 d0 = _getD(oldBase, oldQuote, ampl, oraclePrice);
_updatePriceOverOracleIntegral(oldBase, oldQuote, ampl, oraclePrice, d0);
{
// New invariant before charging fee
uint256 d1 = _getD(newBase, newQuote, ampl, oraclePrice);
uint256 idealQuote = d1.mul(oldQuote) / d0;
uint256 difference = idealQuote > newQuote
? idealQuote - newQuote
: newQuote - idealQuote;
fee = difference.multiplyDecimal(feeRate);
}
adminFee = fee.multiplyDecimal(adminFeeRate);
totalAdminFee = totalAdminFee.add(adminFee);
baseBalance = newBase;
quoteBalance = newQuote.sub(adminFee);
// New invariant after charging fee
uint256 d2 = _getD(newBase, newQuote.sub(fee), ampl, oraclePrice);
require(d2 > d0, "No liquidity is added");
lpOut = lpSupply.mul(d2.sub(d0)).div(d0);
}
ILiquidityGauge(lpToken).mint(recipient, lpOut);
emit LiquidityAdded(
msg.sender,
recipient,
newBase - oldBase,
newQuote - oldQuote,
lpOut,
fee,
adminFee,
oraclePrice
);
}
/// @dev Remove liquidity proportionally.
/// @param lpIn Exact amount of LP token to burn
/// @param minBaseOut Least amount of base asset to withdraw
/// @param minQuoteOut Least amount of quote asset to withdraw
function removeLiquidity(
uint256 version,
uint256 lpIn,
uint256 minBaseOut,
uint256 minQuoteOut
)
external
override
nonReentrant
checkVersion(version)
returns (uint256 baseOut, uint256 quoteOut)
{
(baseOut, quoteOut) = _removeLiquidity(version, lpIn, minBaseOut, minQuoteOut);
IERC20(quoteAddress).safeTransfer(msg.sender, quoteOut);
}
/// @dev Remove liquidity proportionally and unwrap for native token.
/// @param lpIn Exact amount of LP token to burn
/// @param minBaseOut Least amount of base asset to withdraw
/// @param minQuoteOut Least amount of quote asset to withdraw
function removeLiquidityUnwrap(
uint256 version,
uint256 lpIn,
uint256 minBaseOut,
uint256 minQuoteOut
)
external
override
nonReentrant
checkVersion(version)
returns (uint256 baseOut, uint256 quoteOut)
{
(baseOut, quoteOut) = _removeLiquidity(version, lpIn, minBaseOut, minQuoteOut);
IWrappedERC20(quoteAddress).withdraw(quoteOut);
(bool success, ) = msg.sender.call{value: quoteOut}("");
require(success, "Transfer failed");
}
function _removeLiquidity(
uint256 version,
uint256 lpIn,
uint256 minBaseOut,
uint256 minQuoteOut
) private returns (uint256 baseOut, uint256 quoteOut) {
uint256 lpSupply = IERC20(lpToken).totalSupply();
(uint256 oldBase, uint256 oldQuote) = _handleRebalance(version);
baseOut = oldBase.mul(lpIn).div(lpSupply);
quoteOut = oldQuote.mul(lpIn).div(lpSupply);
require(baseOut >= minBaseOut, "Insufficient output");
require(quoteOut >= minQuoteOut, "Insufficient output");
baseBalance = oldBase.sub(baseOut);
quoteBalance = oldQuote.sub(quoteOut);
ILiquidityGauge(lpToken).burnFrom(msg.sender, lpIn);
fund.trancheTransfer(baseTranche, msg.sender, baseOut, version);
emit LiquidityRemoved(msg.sender, lpIn, baseOut, quoteOut, 0, 0, 0);
}
/// @dev Remove base liquidity only.
/// @param lpIn Exact amount of LP token to burn
/// @param minBaseOut Least amount of base asset to withdraw
function removeBaseLiquidity(
uint256 version,
uint256 lpIn,
uint256 minBaseOut
) external override nonReentrant checkVersion(version) whenNotPaused returns (uint256 baseOut) {
(uint256 oldBase, uint256 oldQuote) = _handleRebalance(version);
uint256 lpSupply = IERC20(lpToken).totalSupply();
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
uint256 d1;
{
uint256 d0 = _getD(oldBase, oldQuote, ampl, oraclePrice);
_updatePriceOverOracleIntegral(oldBase, oldQuote, ampl, oraclePrice, d0);
d1 = d0.sub(d0.mul(lpIn).div(lpSupply));
}
{
uint256 fee = oldQuote.mul(lpIn).div(lpSupply).multiplyDecimal(feeRate);
// Add 1 in case of rounding errors
uint256 newBase = _getBase(ampl, oldQuote.sub(fee), oraclePrice, d1) + 1;
baseOut = oldBase.sub(newBase);
require(baseOut >= minBaseOut, "Insufficient output");
ILiquidityGauge(lpToken).burnFrom(msg.sender, lpIn);
baseBalance = newBase;
uint256 adminFee = fee.multiplyDecimal(adminFeeRate);
totalAdminFee = totalAdminFee.add(adminFee);
quoteBalance = oldQuote.sub(adminFee);
emit LiquidityRemoved(msg.sender, lpIn, baseOut, 0, fee, adminFee, oraclePrice);
}
fund.trancheTransfer(baseTranche, msg.sender, baseOut, version);
}
/// @dev Remove quote liquidity only.
/// @param lpIn Exact amount of LP token to burn
/// @param minQuoteOut Least amount of quote asset to withdraw
function removeQuoteLiquidity(
uint256 version,
uint256 lpIn,
uint256 minQuoteOut
)
external
override
nonReentrant
checkVersion(version)
whenNotPaused
returns (uint256 quoteOut)
{
quoteOut = _removeQuoteLiquidity(version, lpIn, minQuoteOut);
IERC20(quoteAddress).safeTransfer(msg.sender, quoteOut);
}
/// @dev Remove quote liquidity only and unwrap for native token.
/// @param lpIn Exact amount of LP token to burn
/// @param minQuoteOut Least amount of quote asset to withdraw
function removeQuoteLiquidityUnwrap(
uint256 version,
uint256 lpIn,
uint256 minQuoteOut
)
external
override
nonReentrant
checkVersion(version)
whenNotPaused
returns (uint256 quoteOut)
{
quoteOut = _removeQuoteLiquidity(version, lpIn, minQuoteOut);
IWrappedERC20(quoteAddress).withdraw(quoteOut);
(bool success, ) = msg.sender.call{value: quoteOut}("");
require(success, "Transfer failed");
}
function _removeQuoteLiquidity(
uint256 version,
uint256 lpIn,
uint256 minQuoteOut
) private returns (uint256 quoteOut) {
(uint256 oldBase, uint256 oldQuote) = _handleRebalance(version);
uint256 lpSupply = IERC20(lpToken).totalSupply();
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
uint256 d1;
{
uint256 d0 = _getD(oldBase, oldQuote, ampl, oraclePrice);
_updatePriceOverOracleIntegral(oldBase, oldQuote, ampl, oraclePrice, d0);
d1 = d0.sub(d0.mul(lpIn).div(lpSupply));
}
uint256 idealQuote = oldQuote.mul(lpSupply.sub(lpIn)).div(lpSupply);
// Add 1 in case of rounding errors
uint256 newQuote = _getQuote(ampl, oldBase, oraclePrice, d1) + 1;
uint256 fee = idealQuote.sub(newQuote).multiplyDecimal(feeRate);
quoteOut = oldQuote.sub(newQuote).sub(fee);
require(quoteOut >= minQuoteOut, "Insufficient output");
ILiquidityGauge(lpToken).burnFrom(msg.sender, lpIn);
uint256 adminFee = fee.multiplyDecimal(adminFeeRate);
totalAdminFee = totalAdminFee.add(adminFee);
quoteBalance = newQuote.add(fee).sub(adminFee);
emit LiquidityRemoved(msg.sender, lpIn, 0, quoteOut, fee, adminFee, oraclePrice);
}
/// @notice Force stored values to match balances.
function sync() external nonReentrant {
(uint256 oldBase, uint256 oldQuote) = _handleRebalance(fund.getRebalanceSize());
uint256 ampl = getAmpl();
uint256 oraclePrice = getOraclePrice();
uint256 d = _getD(oldBase, oldQuote, ampl, oraclePrice);
_updatePriceOverOracleIntegral(oldBase, oldQuote, ampl, oraclePrice, d);
uint256 newBase = fund.trancheBalanceOf(baseTranche, address(this));
uint256 newQuote = _getNewQuoteBalance();
baseBalance = newBase;
quoteBalance = newQuote;
emit Sync(newBase, newQuote, oraclePrice);
}
function collectFee() external {
uint256 totalAdminFee_ = totalAdminFee;
delete totalAdminFee;
IERC20(quoteAddress).safeTransfer(feeCollector, totalAdminFee_);
}
function _getNewQuoteBalance() private view returns (uint256) {
return IERC20(quoteAddress).balanceOf(address(this)).sub(totalAdminFee);
}
function _updatePriceOverOracleIntegral(
uint256 base,
uint256 quote,
uint256 ampl,
uint256 oraclePrice,
uint256 d
) private {
// Overflow is desired
_priceOverOracleIntegral +=
_getPriceOverOracle(base, quote, ampl, oraclePrice, d) *
(block.timestamp - _priceOverOracleTimestamp);
_priceOverOracleTimestamp = block.timestamp;
}
function _getD(
uint256 base,
uint256 quote,
uint256 ampl,
uint256 oraclePrice
) private view returns (uint256) {
// Newtonian: D' = (4A(kx + y) + D^3 / 2kxy)D / ((4A - 1)D + 3D^3 / 4kxy)
uint256 normalizedQuote = quote.mul(_quoteDecimalMultiplier);
uint256 baseValue = base.multiplyDecimal(oraclePrice);
uint256 sum = baseValue.add(normalizedQuote);
if (sum == 0) return 0;
uint256 prev = 0;
uint256 d = sum;
for (uint256 i = 0; i < MAX_ITERATION; i++) {
prev = d;
uint256 d3 = d.mul(d).div(baseValue).mul(d) / normalizedQuote / 4;
d = (sum.mul(4 * ampl) + 2 * d3).mul(d) / d.mul(4 * ampl - 1).add(3 * d3);
if (d <= prev + 1 && prev <= d + 1) {
break;
}
}
return d;
}
function _getPriceOverOracle(
uint256 base,
uint256 quote,
uint256 ampl,
uint256 oraclePrice,
uint256 d
) private view returns (uint256) {
uint256 commonExp = d.multiplyDecimal(4e18 - 1e18 / ampl);
uint256 baseValue = base.multiplyDecimal(oraclePrice);
uint256 normalizedQuote = quote.mul(_quoteDecimalMultiplier);
return
(baseValue.mul(8).add(normalizedQuote.mul(4)).sub(commonExp))
.multiplyDecimal(normalizedQuote)
.divideDecimal(normalizedQuote.mul(8).add(baseValue.mul(4)).sub(commonExp))
.divideDecimal(baseValue);
}
function _getBase(
uint256 ampl,
uint256 quote,
uint256 oraclePrice,
uint256 d
) private view returns (uint256 base) {
// Solve 16Ayk^2·x^2 + 4ky(4Ay - 4AD + D)·x - D^3 = 0
// Newtonian: kx' = ((kx)^2 + D^3 / 16Ay) / (2kx + y - D + D/4A)
uint256 normalizedQuote = quote.mul(_quoteDecimalMultiplier);
uint256 d3 = d.mul(d).div(normalizedQuote).mul(d) / (16 * ampl);
uint256 prev = 0;
uint256 baseValue = d;
for (uint256 i = 0; i < MAX_ITERATION; i++) {
prev = baseValue;
baseValue =
baseValue.mul(baseValue).add(d3) /
(2 * baseValue).add(normalizedQuote).add(d / (4 * ampl)).sub(d);
if (baseValue <= prev + 1 && prev <= baseValue + 1) {
break;
}
}
base = baseValue.divideDecimal(oraclePrice);
}
function _getQuote(
uint256 ampl,
uint256 base,
uint256 oraclePrice,
uint256 d
) private view returns (uint256 quote) {
// Solve 16Axk·y^2 + 4kx(4Akx - 4AD + D)·y - D^3 = 0
// Newtonian: y' = (y^2 + D^3 / 16Akx) / (2y + kx - D + D/4A)
uint256 baseValue = base.multiplyDecimal(oraclePrice);
uint256 d3 = d.mul(d).div(baseValue).mul(d) / (16 * ampl);
uint256 prev = 0;
uint256 normalizedQuote = d;
for (uint256 i = 0; i < MAX_ITERATION; i++) {
prev = normalizedQuote;
normalizedQuote =
normalizedQuote.mul(normalizedQuote).add(d3) /
(2 * normalizedQuote).add(baseValue).add(d / (4 * ampl)).sub(d);
if (normalizedQuote <= prev + 1 && prev <= normalizedQuote + 1) {
break;
}
}
quote = normalizedQuote / _quoteDecimalMultiplier;
}
function updateAmplRamp(uint256 endAmpl, uint256 endTimestamp) external onlyOwner {
require(endAmpl > 0 && endAmpl < AMPL_MAX_VALUE, "Invalid A");
require(endTimestamp >= block.timestamp + AMPL_RAMP_MIN_TIME, "A ramp time too short");
uint256 ampl = getAmpl();
require(
(endAmpl >= ampl && endAmpl <= ampl * AMPL_RAMP_MAX_CHANGE) ||
(endAmpl < ampl && endAmpl * AMPL_RAMP_MAX_CHANGE >= ampl),
"A ramp change too large"
);
amplRampStart = ampl;
amplRampEnd = endAmpl;
amplRampStartTimestamp = block.timestamp;
amplRampEndTimestamp = endTimestamp;
emit AmplRampUpdated(ampl, endAmpl, block.timestamp, endTimestamp);
}
function _updateFeeCollector(address newFeeCollector) private {
feeCollector = newFeeCollector;
emit FeeCollectorUpdated(newFeeCollector);
}
function updateFeeCollector(address newFeeCollector) external onlyOwner {
_updateFeeCollector(newFeeCollector);
}
function _updateFeeRate(uint256 newFeeRate) private {
require(newFeeRate <= MAX_FEE_RATE, "Exceed max fee rate");
feeRate = newFeeRate;
emit FeeRateUpdated(newFeeRate);
}
function updateFeeRate(uint256 newFeeRate) external onlyOwner {
_updateFeeRate(newFeeRate);
}
function _updateAdminFeeRate(uint256 newAdminFeeRate) private {
require(newAdminFeeRate <= MAX_ADMIN_FEE_RATE, "Exceed max admin fee rate");
adminFeeRate = newAdminFeeRate;
emit AdminFeeRateUpdated(newAdminFeeRate);
}
function updateAdminFeeRate(uint256 newAdminFeeRate) external onlyOwner {
_updateAdminFeeRate(newAdminFeeRate);
}
/// @dev Check if the user-specified version is correct.
modifier checkVersion(uint256 version) {
_checkVersion(version);
_;
}
/// @dev Revert if the user-specified version is not correct.
function _checkVersion(uint256 version) internal view virtual {}
/// @dev Compute the new base and quote amount after rebalanced to the latest version.
/// If any tokens should be distributed to LP holders, their amounts are also returned.
///
/// The latest rebalance version is passed in a parameter and it is caller's responsibility
/// to pass the correct version.
/// @param latestVersion The latest rebalance version
/// @return newBase Amount of base tokens after rebalance
/// @return newQuote Amount of quote tokens after rebalance
/// @return excessiveQ Amount of QUEEN that should be distributed to LP holders due to rebalance
/// @return excessiveB Amount of BISHOP that should be distributed to LP holders due to rebalance
/// @return excessiveR Amount of ROOK that should be distributed to LP holders due to rebalance
/// @return excessiveQuote Amount of quote tokens that should be distributed to LP holders due to rebalance
/// @return isRebalanced Whether the stored base and quote amount are rebalanced
function _getRebalanceResult(
uint256 latestVersion
)
internal
view
virtual
returns (
uint256 newBase,
uint256 newQuote,
uint256 excessiveQ,
uint256 excessiveB,
uint256 excessiveR,
uint256 excessiveQuote,
bool isRebalanced
);
/// @dev Update the stored base and quote balance to the latest rebalance version and distribute
/// any excessive tokens to LP holders.
///
/// The latest rebalance version is passed in a parameter and it is caller's responsibility
/// to pass the correct version.
/// @param latestVersion The latest rebalance version
/// @return newBase Amount of stored base tokens after rebalance
/// @return newQuote Amount of stored quote tokens after rebalance
function _handleRebalance(
uint256 latestVersion
) internal virtual returns (uint256 newBase, uint256 newQuote);
/// @notice Get the base token price from the price oracle. The returned price is normalized
/// to 18 decimal places.
function getOraclePrice() public view virtual override returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.10 <0.8.0;
library AdvancedMath {
/// @dev Calculate square root.
///
/// Reference: https://en.wikipedia.org/wiki/Integer_square_root#Algorithm_using_Newton's_method
function sqrt(uint256 s) internal pure returns (uint256) {
if (s == 0) return 0;
uint256 t = s;
uint256 x0 = 2;
if (t >= 1 << 128) {
t >>= 128;
x0 <<= 64;
}
if (t >= 1 << 64) {
t >>= 64;
x0 <<= 32;
}
if (t >= 1 << 32) {
t >>= 32;
x0 <<= 16;
}
if (t >= 1 << 16) {
t >>= 16;
x0 <<= 8;
}
if (t >= 1 << 8) {
t >>= 8;
x0 <<= 4;
}
if (t >= 1 << 4) {
t >>= 4;
x0 <<= 2;
}
if (t >= 1 << 2) {
x0 <<= 1;
}
uint256 x1 = (x0 + s / x0) >> 1;
while (x1 < x0) {
x0 = x1;
x1 = (x0 + s / x0) >> 1;
}
return x0;
}
/// @notice Calculate cubic root.
function cbrt(uint256 s) internal pure returns (uint256) {
if (s == 0) return 0;
uint256 t = s;
uint256 x0 = 2;
if (t >= 1 << 192) {
t >>= 192;
x0 <<= 64;
}
if (t >= 1 << 96) {
t >>= 96;
x0 <<= 32;
}
if (t >= 1 << 48) {
t >>= 48;
x0 <<= 16;
}
if (t >= 1 << 24) {
t >>= 24;
x0 <<= 8;
}
if (t >= 1 << 12) {
t >>= 12;
x0 <<= 4;
}
if (t >= 1 << 6) {
t >>= 6;
x0 <<= 2;
}
if (t >= 1 << 3) {
x0 <<= 1;
}
uint256 x1 = (2 * x0 + s / x0 / x0) / 3;
while (x1 < x0) {
x0 = x1;
x1 = (2 * x0 + s / x0 / x0) / 3;
}
return x0;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Contract of an emergency stop mechanism that can be triggered by an authorized account.
*
* This module is modified based on Pausable in OpenZeppelin v3.3.0, adding public functions to
* pause, unpause and manage the pauser role. It is also designed to be used by upgradable
* contracts, like PausableUpgradable but with compact storage slots and no dependencies.
*/
abstract contract ManagedPausable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
event PauserRoleTransferred(address indexed previousPauser, address indexed newPauser);
uint256 private constant FALSE = 0;
uint256 private constant TRUE = 1;
uint256 private _initialized;
uint256 private _paused;
address private _pauser;
function _initializeManagedPausable(address pauser_) internal {
require(_initialized == FALSE);
_initialized = TRUE;
_paused = FALSE;
_pauser = pauser_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view returns (bool) {
return _paused != FALSE;
}
function pauser() public view returns (address) {
return _pauser;
}
function renouncePauserRole() external onlyPauser {
emit PauserRoleTransferred(_pauser, address(0));
_pauser = address(0);
}
function transferPauserRole(address newPauser) external onlyPauser {
require(newPauser != address(0));
emit PauserRoleTransferred(_pauser, newPauser);
_pauser = newPauser;
}
modifier onlyPauser() {
require(_pauser == msg.sender, "Pausable: only pauser");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
require(_paused == FALSE, "Pausable: paused");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
require(_paused != FALSE, "Pausable: not paused");
_;
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function pause() external onlyPauser whenNotPaused {
_paused = TRUE;
emit Paused(msg.sender);
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function unpause() external onlyPauser whenPaused {
_paused = FALSE;
emit Unpaused(msg.sender);
}
}// SPDX-License-Identifier: MIT
//
// Copyright (c) 2019 Synthetix
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
pragma solidity >=0.6.10 <0.8.0;
import "@openzeppelin/contracts/math/SafeMath.sol";
library SafeDecimalMath {
using SafeMath for uint256;
/* Number of decimal places in the representations. */
uint256 private constant decimals = 18;
uint256 private constant highPrecisionDecimals = 27;
/* The number representing 1.0. */
uint256 private constant UNIT = 10 ** uint256(decimals);
/* The number representing 1.0 for higher fidelity numbers. */
uint256 private constant PRECISE_UNIT = 10 ** uint256(highPrecisionDecimals);
uint256 private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR =
10 ** uint256(highPrecisionDecimals - decimals);
/**
* @return The result of multiplying x and y, interpreting the operands as fixed-point
* decimals.
*
* @dev A unit factor is divided out after the product of x and y is evaluated,
* so that product must be less than 2**256. As this is an integer division,
* the internal division always rounds down. This helps save on gas. Rounding
* is more expensive on gas.
*/
function multiplyDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
/* Divide by UNIT to remove the extra factor introduced by the product. */
return x.mul(y).div(UNIT);
}
function multiplyDecimalPrecise(uint256 x, uint256 y) internal pure returns (uint256) {
/* Divide by UNIT to remove the extra factor introduced by the product. */
return x.mul(y).div(PRECISE_UNIT);
}
/**
* @return The result of safely dividing x and y. The return value is a high
* precision decimal.
*
* @dev y is divided after the product of x and the standard precision unit
* is evaluated, so the product of x and UNIT must be less than 2**256. As
* this is an integer division, the result is always rounded down.
* This helps save on gas. Rounding is more expensive on gas.
*/
function divideDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
/* Reintroduce the UNIT factor that will be divided out by y. */
return x.mul(UNIT).div(y);
}
function divideDecimalPrecise(uint256 x, uint256 y) internal pure returns (uint256) {
/* Reintroduce the UNIT factor that will be divided out by y. */
return x.mul(PRECISE_UNIT).div(y);
}
/**
* @dev Convert a standard decimal representation to a high precision one.
*/
function decimalToPreciseDecimal(uint256 i) internal pure returns (uint256) {
return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
}
/**
* @dev Convert a high precision decimal to a standard decimal representation.
*/
function preciseDecimalToDecimal(uint256 i) internal pure returns (uint256) {
uint256 quotientTimesTen = i.mul(10).div(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
if (quotientTimesTen % 10 >= 5) {
quotientTimesTen = quotientTimesTen.add(10);
}
return quotientTimesTen.div(10);
}
/**
* @dev Returns the multiplication of two unsigned integers, and the max value of
* uint256 on overflow.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
return c / a != b ? type(uint256).max : c;
}
function saturatingMultiplyDecimal(uint256 x, uint256 y) internal pure returns (uint256) {
/* Divide by UNIT to remove the extra factor introduced by the product. */
return saturatingMul(x, y).div(UNIT);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"lpToken_","type":"address"},{"internalType":"address","name":"fund_","type":"address"},{"internalType":"address","name":"quoteAddress_","type":"address"},{"internalType":"uint256","name":"quoteDecimals_","type":"uint256"},{"internalType":"uint256","name":"ampl_","type":"uint256"},{"internalType":"address","name":"feeCollector_","type":"address"},{"internalType":"uint256","name":"feeRate_","type":"uint256"},{"internalType":"uint256","name":"adminFeeRate_","type":"uint256"},{"internalType":"uint256","name":"tradingCurbThreshold_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAdminFeeRate","type":"uint256"}],"name":"AdminFeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"AmplRampUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"FeeCollectorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"baseIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quoteIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oraclePrice","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"lpIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quotOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oraclePrice","type":"uint256"}],"name":"LiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousPauser","type":"address"},{"indexed":true,"internalType":"address","name":"newPauser","type":"address"}],"name":"PauserRoleTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"base","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quote","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"}],"name":"Rebalanced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"baseIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quoteIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quoteOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oraclePrice","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"base","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quote","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oraclePrice","type":"uint256"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"lpOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"adminFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amplRampEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amplRampEndTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amplRampStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amplRampStartTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTranche","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"baseOut","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"buy","outputs":[{"internalType":"uint256","name":"realBaseOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentVersion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fund","outputs":[{"internalType":"contract IFundV3","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAmpl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quoteOut","type":"uint256"}],"name":"getBaseIn","outputs":[{"internalType":"uint256","name":"baseIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quoteIn","type":"uint256"}],"name":"getBaseOut","outputs":[{"internalType":"uint256","name":"baseOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentPriceOverOracle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOraclePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPriceOverOracleIntegral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseOut","type":"uint256"}],"name":"getQuoteIn","outputs":[{"internalType":"uint256","name":"quoteIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseIn","type":"uint256"}],"name":"getQuoteOut","outputs":[{"internalType":"uint256","name":"quoteOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"lpIn","type":"uint256"},{"internalType":"uint256","name":"minBaseOut","type":"uint256"}],"name":"removeBaseLiquidity","outputs":[{"internalType":"uint256","name":"baseOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"lpIn","type":"uint256"},{"internalType":"uint256","name":"minBaseOut","type":"uint256"},{"internalType":"uint256","name":"minQuoteOut","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"baseOut","type":"uint256"},{"internalType":"uint256","name":"quoteOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"lpIn","type":"uint256"},{"internalType":"uint256","name":"minBaseOut","type":"uint256"},{"internalType":"uint256","name":"minQuoteOut","type":"uint256"}],"name":"removeLiquidityUnwrap","outputs":[{"internalType":"uint256","name":"baseOut","type":"uint256"},{"internalType":"uint256","name":"quoteOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"lpIn","type":"uint256"},{"internalType":"uint256","name":"minQuoteOut","type":"uint256"}],"name":"removeQuoteLiquidity","outputs":[{"internalType":"uint256","name":"quoteOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"lpIn","type":"uint256"},{"internalType":"uint256","name":"minQuoteOut","type":"uint256"}],"name":"removeQuoteLiquidityUnwrap","outputs":[{"internalType":"uint256","name":"quoteOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renouncePauserRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"quoteOut","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"sell","outputs":[{"internalType":"uint256","name":"realQuoteOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalAdminFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradingCurbThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPauser","type":"address"}],"name":"transferPauserRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newAdminFeeRate","type":"uint256"}],"name":"updateAdminFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"endAmpl","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"updateAmplRamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"updateFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"updateFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6101406040523480156200001257600080fd5b50604051620057503803806200575083398181016040526101208110156200003957600080fd5b508051602082015160408301516060840151608085015160a086015160c087015160e0880151610100909801519697959694959394929391929091908888600189898989898960006200008b620002a3565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600180556001600160601b031960608a811b821660805289811b821660a05260c089905287901b1660e0526012851115620001425760405162461bcd60e51b81526004018080602001828103825260238152602001806200572d6023913960400191505060405180910390fd5b6012859003600a0a610100528315801590620001605750620f424084105b6200019e576040805162461bcd60e51b8152602060048201526009602482015268496e76616c6964204160b81b604482015290519081900360640190fd5b600a84905560408051858152602081018690526000818301819052606082015290517f4d37ead28a6f2a793e583c75de178de526aaf341b06b0699a40341118a04b3d99181900360800190a1620001f583620002a7565b6200020082620002fb565b6200020b8162000394565b62000216336200042d565b505050505050505050806101208181525050876001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b1580156200026257600080fd5b505afa15801562000277573d6000803e3d6000fd5b505050506040513d60208110156200028e57600080fd5b50516011555062000467975050505050505050565b3390565b600d80546001600160a01b0383166001600160a01b0319909116811790915560408051918252517fe5693914d19c789bdee50a362998c0bc8d035a835f9871da5d51152f0582c34f9181900360200190a150565b6706f05b59d3b2000081111562000359576040805162461bcd60e51b815260206004820152601360248201527f457863656564206d617820666565207261746500000000000000000000000000604482015290519081900360640190fd5b600e8190556040805182815290517f208f1b468d3d61f0f085e975bd9d04367c930d599642faad06695229f3eadcd89181900360200190a150565b670de0b6b3a7640000811115620003f2576040805162461bcd60e51b815260206004820152601960248201527f457863656564206d61782061646d696e20666565207261746500000000000000604482015290519081900360640190fd5b600f8190556040805182815290517f576be7f9615bb4c6e139635cf4380b1ce9f6aa425dabe6b9057c24a86cc3c9799181900360200190a150565b600254156200043b57600080fd5b60016002556000600355600480546001600160a01b0319166001600160a01b0392909216919091179055565b60805160601c60a05160601c60c05160e05160601c610100516101205161514c620005e160003980611fc95280612831525080613a9c52806146f452806147ca52806148c3525080610ccd528061119d5280611c3d52806130cf52806132a8528061344052806135d2528061408552806149cc525080610a835280610dae52806116c05280611a2b52806123fa5280612a2e52806137365280614cc3525080610a545280610b185280610de752806113cc52806116245280611a6f5280611d5f5280611e275280611f41528061204152806123cb52806126e6528061285552806129ff528061310252806131f35280613665528061376f52806138c852806139505280613bb45280613d125280613e255280613eec5280613fb35280614d0752508061169c5280611795528061192c5280612ae85280612c285280612c905280612eca5280613e565280613f1d5280613fe452806140a7528061410952806143a352806145475280614ac95280614c56525061514c6000f3fe6080604052600436106102e85760003560e01c80638cece52711610190578063c95f9d0e116100dc578063f0a0b44e11610095578063f467c2bd1161006f578063f467c2bd146109ae578063f88bf15a146109ea578063fe3cfe8314610a26578063fff6cae914610a3b576102ef565b8063f0a0b44e14610951578063f1a2e84914610966578063f2fde38b1461097b576102ef565b8063c95f9d0e1461087c578063d2c35ce8146108b5578063d4526cdc146108e8578063d4d5d32a146108fd578063e6d7059a14610912578063eb91d37e1461093c576102ef565b80639d888e8611610149578063a3ba010311610123578063a3ba01031461080a578063b60d42881461081f578063bad383a614610834578063c415b95c14610867576102ef565b80639d888e86146107cb5780639fd0506d146107e0578063a1415b7f146107f5576102ef565b80638cece527146106b45780638da5cb5b146106c95780639000ff09146106de57806395d6abf814610777578063978bbdb9146107a157806398466227146107b6576102ef565b8063555b61621161024f578063715018a611610208578063796da7af116101e2578063796da7af146106365780637b31ae641461064b5780637b84fda5146106755780638456cb591461069f576102ef565b8063715018a6146105d657806377c795bf146105eb5780637884578514610621576102ef565b8063555b61621461050a5780635c975abb146105385780635e23ebe4146105615780635fcbd2851461057657806369b459e31461058b57806369f2db41146105a0576102ef565b806330b29402116102a157806330b294021461042657806338b602ca1461045c57806338bde7911461048c5780633a66ff97146104a15780633f4ba83a146104cb578063546ccda1146104e0576102ef565b80630589a478146102f45780630750f290146103255780630faf3f971461034c5780631033e4cd1461036157806318f73472146103fa578063242708df14610411576102ef565b366102ef57005b600080fd5b34801561030057600080fd5b50610309610a50565b604080516001600160a01b039092168252519081900360200190f35b34801561033157600080fd5b5061033a610b08565b60408051918252519081900360200190f35b34801561035857600080fd5b5061033a610b0e565b34801561036d57600080fd5b5061033a6004803603608081101561038457600080fd5b8135916020810135916001600160a01b0360408301351691908101906080810160608201356401000000008111156103bb57600080fd5b8201836020820111156103cd57600080fd5b803590602001918460018302840111640100000000831117156103ef57600080fd5b509092509050610bca565b34801561040657600080fd5b5061040f61103d565b005b34801561041d57600080fd5b5061033a6110de565b34801561043257600080fd5b5061033a6004803603606081101561044957600080fd5b50803590602081013590604001356110e4565b34801561046857600080fd5b5061040f6004803603604081101561047f57600080fd5b50803590602001356111d0565b34801561049857600080fd5b5061033a6113bc565b3480156104ad57600080fd5b5061033a600480360360208110156104c457600080fd5b50356113c2565b3480156104d757600080fd5b5061040f6114cf565b3480156104ec57600080fd5b5061040f6004803603602081101561050357600080fd5b50356115ab565b34801561051657600080fd5b5061051f611619565b6040805192835260208301919091528051918290030190f35b34801561054457600080fd5b5061054d61168c565b604080519115158252519081900360200190f35b34801561056d57600080fd5b5061033a611694565b34801561058257600080fd5b5061030961169a565b34801561059757600080fd5b5061033a6116be565b3480156105ac57600080fd5b5061033a600480360360608110156105c357600080fd5b50803590602081013590604001356116e2565b3480156105e257600080fd5b5061040f611ae3565b3480156105f757600080fd5b5061033a6004803603606081101561060e57600080fd5b5080359060208101359060400135611b8f565b34801561062d57600080fd5b5061033a611d55565b34801561064257600080fd5b5061033a611e22565b34801561065757600080fd5b5061033a6004803603602081101561066e57600080fd5b5035612037565b34801561068157600080fd5b5061040f6004803603602081101561069857600080fd5b503561212e565b3480156106ab57600080fd5b5061040f612199565b3480156106c057600080fd5b5061033a612272565b3480156106d557600080fd5b50610309612278565b3480156106ea57600080fd5b5061033a6004803603608081101561070157600080fd5b8135916020810135916001600160a01b03604083013516919081019060808101606082013564010000000081111561073857600080fd5b82018360208201111561074a57600080fd5b8035906020019184600183028401116401000000008311171561076c57600080fd5b509092509050612287565b34801561078357600080fd5b5061033a6004803603602081101561079a57600080fd5b50356126dc565b3480156107ad57600080fd5b5061033a6127f5565b3480156107c257600080fd5b5061033a6127fb565b3480156107d757600080fd5b5061033a612814565b3480156107ec57600080fd5b5061030961281a565b34801561080157600080fd5b5061033a612829565b34801561081657600080fd5b5061033a61282f565b34801561082b57600080fd5b50610309612853565b34801561084057600080fd5b5061040f6004803603602081101561085757600080fd5b50356001600160a01b0316612877565b34801561087357600080fd5b5061030961293d565b34801561088857600080fd5b5061033a6004803603604081101561089f57600080fd5b50803590602001356001600160a01b031661294c565b3480156108c157600080fd5b5061040f600480360360208110156108d857600080fd5b50356001600160a01b0316612fe3565b3480156108f457600080fd5b5061033a61304e565b34801561090957600080fd5b5061040f6130b5565b34801561091e57600080fd5b5061033a6004803603602081101561093557600080fd5b50356130f8565b34801561094857600080fd5b5061033a6131e9565b34801561095d57600080fd5b506103096132a6565b34801561097257600080fd5b5061033a6132ca565b34801561098757600080fd5b5061040f6004803603602081101561099e57600080fd5b50356001600160a01b03166132d0565b3480156109ba57600080fd5b5061051f600480360360808110156109d157600080fd5b50803590602081013590604081013590606001356133d2565b3480156109f657600080fd5b5061051f60048036036080811015610a0d57600080fd5b508035906020810135906040810135906060013561355c565b348015610a3257600080fd5b5061033a613609565b348015610a4757600080fd5b5061040f61360f565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fb73de937f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610ad657600080fd5b505afa158015610aea573d6000803e3d6000fd5b505050506040513d6020811015610b0057600080fd5b505190505b90565b60095481565b6000806000610ba07f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b505afa158015610b83573d6000803e3d6000fd5b505050506040513d6020811015610b9957600080fd5b5051613849565b505050505091509150610bc38282610bb661304e565b610bbe611e22565b613a93565b9250505090565b600060026001541415610c12576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b600260015585610c2181613bb2565b60035415610c69576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60008611610cac576040805162461bcd60e51b815260206004820152600b60248201526a16995c9bc81bdd5d1c1d5d60aa1b604482015290519081900360640190fd5b859150600080610cbb89613c8a565b9092509050610cf46001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016888a614173565b8415610d9e57336001600160a01b031663714e109760008a89896040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b158015610d7d57600080fd5b505af1158015610d91573d6000803e3d6000fd5b50505050610d9e89613bb2565b60408051636c73303160e11b81527f0000000000000000000000000000000000000000000000000000000000000000600482015230602482015290516000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163d8e6606291604480820192602092909190829003018186803b158015610e2e57600080fd5b505afa158015610e42573d6000803e3d6000fd5b505050506040513d6020811015610e5857600080fd5b505190506000610e6882856141ca565b600e54909150600090610e90670de0b6b3a7640000829003610e8a8e8461422c565b9061428c565b9150849050610e9f8c836142f3565b10610eea576040805162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e74206c697175696469747960501b604482015290519081900360640190fd5b6000610ef4611e22565b90508b85036000610f0361304e565b90506000610f1389898487613a93565b9050610f22898984878561434d565b6000610f32888786038588613a93565b905081811015610f7e576040805162461bcd60e51b8152602060048201526012602482015271092dcecc2e4d2c2dce840dad2e6dac2e8c6d60731b604482015290519081900360640190fd5b505050506000610f99600f548461437590919063ffffffff16565b60058690558d8703819003600655601054909150610fb790826142f3565b6010556040805185815260006020820181905281830152606081018f90526080810185905260a0810183905260c0810184905290518e916001600160a01b038f169133917f2ad8739d64c070ab4ae9d9c0743d56550b22c3c8c96e7a6045fac37b5b8e89e3919081900360e00190a350506001805550959b9a5050505050505050505050565b6004546001600160a01b03163314611094576040805162461bcd60e51b81526020600482015260156024820152742830bab9b0b136329d1037b7363c903830bab9b2b960591b604482015290519081900360640190fd5b6004546040516000916001600160a01b0316907ffb34c91b8734ef26ee8085a0fa11d2692042c6edac57dc40d8850cad2f1bc3ef908390a3600480546001600160a01b0319169055565b60105481565b60006002600154141561112c576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b60026001558361113b81613bb2565b60035415611183576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b61118e85858561438d565b91506111c46001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163384614173565b50600180559392505050565b6111d861464a565b6001600160a01b03166111e9612278565b6001600160a01b031614611232576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b6000821180156112445750620f424082105b611281576040805162461bcd60e51b8152602060048201526009602482015268496e76616c6964204160b81b604482015290519081900360640190fd5b6201518042018110156112d3576040805162461bcd60e51b815260206004820152601560248201527410481c985b5c081d1a5b59481d1bdbc81cda1bdc9d605a1b604482015290519081900360640190fd5b60006112dd61304e565b90508083101580156112f25750600a81028311155b8061130a5750808310801561130a575080600a840210155b61135b576040805162461bcd60e51b815260206004820152601760248201527f412072616d70206368616e676520746f6f206c61726765000000000000000000604482015290519081900360640190fd5b6009819055600a83905542600b819055600c83905560408051838152602081018690528082019290925260608201849052517f4d37ead28a6f2a793e583c75de178de526aaf341b06b0699a40341118a04b3d99181900360800190a1505050565b60055481565b60008060006114237f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b505050505091509150600061144185846141ca90919063ffffffff16565b9050600061144d61304e565b90506000611459611e22565b9050600061146986868585613a93565b6001019050600061147c8486858561464e565b600101905061148b81876141ca565b600e54909850670de0b6b3a7640000818103906114b9906000198301906114b3908d9061422c565b906142f3565b816114c057fe5b049a9950505050505050505050565b6004546001600160a01b03163314611526576040805162461bcd60e51b81526020600482015260156024820152742830bab9b0b136329d1037b7363c903830bab9b2b960591b604482015290519081900360640190fd5b600354611571576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b60006003556040805133815290517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9181900360200190a1565b6115b361464a565b6001600160a01b03166115c4612278565b6001600160a01b03161461160d576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b61161681614729565b50565b60008060008061167b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b509498509296505050505050509091565b600354151590565b600b5481565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006002600154141561172a576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b60026001558361173981613bb2565b60035415611781576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60008061178d87613c8a565b9150915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117ec57600080fd5b505afa158015611800573d6000803e3d6000fd5b505050506040513d602081101561181657600080fd5b50519050600061182461304e565b90506000611830611e22565b905060008061184187878686613a93565b9050611850878786868561434d565b61186861186186610e8a848f61422c565b82906141ca565b9150506000611890600e5461188a87610e8a8f8b61422c90919063ffffffff16565b90614375565b905060006118a9856118a289856141ca565b86866147c1565b60010190506118b888826141ca565b99508a8a1015611905576040805162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081bdd5d1c1d5d606a1b604482015290519081900360640190fd5b6040805163079cc67960e41b8152336004820152602481018e905290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916379cc679091604480830192600092919082900301818387803b15801561197357600080fd5b505af1158015611987573d6000803e3d6000fd5b505050600582905550600f546000906119a1908490614375565b6010549091506119b190826142f3565b6010556119be88826141ca565b600655604080518e8152602081018d9052600081830152606081018590526080810183905260a08101879052905133917f16db8cd72937fc971d5ff44547c6a645bfee7a7537d2a2eacd0b7d919ecfbf0f919081900360c00190a2505060408051634d1eef9360e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152336024820152604481018b9052606481018e905290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169250639a3ddf269160848082019260009290919082900301818387803b158015611ab857600080fd5b505af1158015611acc573d6000803e3d6000fd5b50506001805550979b9a5050505050505050505050565b611aeb61464a565b6001600160a01b0316611afc612278565b6001600160a01b031614611b45576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600060026001541415611bd7576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b600260015583611be681613bb2565b60035415611c2e576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b611c3985858561438d565b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611ca157600080fd5b505af1158015611cb5573d6000803e3d6000fd5b50506040516000925033915084908381818185875af1925050503d8060008114611cfb576040519150601f19603f3d011682016040523d82523d6000602084013e611d00565b606091505b5050905080611d48576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b5050600180559392505050565b6000806000611db67f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b5050505050915091508160001480611dcc575080155b15611de357670de0b6b3a764000092505050610b05565b6000611ded61304e565b90506000611df9611e22565b90506000611e0985858585613a93565b9050611e188585858585614881565b9550505050505090565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639043292a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e7e57600080fd5b505afa158015611e92573d6000803e3d6000fd5b505050506040513d6020811015611ea857600080fd5b50516040805163061b57a360e51b815290516001600160a01b039092169163c36af46091600480820192602092909190829003018186803b158015611eec57600080fd5b505afa158015611f00573d6000803e3d6000fd5b505050506040513d6020811015611f1657600080fd5b50516040805163133b5f7560e01b815260048101839052905191925060009182916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163133b5f7591602480820192606092909190829003018186803b158015611f8857600080fd5b505afa158015611f9c573d6000803e3d6000fd5b505050506040513d6060811015611fb257600080fd5b5060208101516040909101519092509050611fed827f0000000000000000000000000000000000000000000000000000000000000000614375565b811015612030576040805162461bcd60e51b815260206004820152600c60248201526b2a3930b234b7339031bab93160a11b604482015290519081900360640190fd5b5091505090565b60008060006120987f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b50505050509150915060006120b685846142f390919063ffffffff16565b905060006120c261304e565b905060006120ce611e22565b905060006120de86868585613a93565b600101905060006120f18486858561464e565b600101905061210086826141ca565b9750612121600e54670de0b6b3a7640000038961437590919063ffffffff16565b9998505050505050505050565b61213661464a565b6001600160a01b0316612147612278565b6001600160a01b031614612190576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b61161681614934565b6004546001600160a01b031633146121f0576040805162461bcd60e51b81526020600482015260156024820152742830bab9b0b136329d1037b7363c903830bab9b2b960591b604482015290519081900360640190fd5b60035415612238576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60016003556040805133815290517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589181900360200190a1565b600f5481565b6000546001600160a01b031690565b6000600260015414156122cf576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b6002600155856122de81613bb2565b60035415612326576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60008611612369576040805162461bcd60e51b815260206004820152600b60248201526a16995c9bc81bdd5d1c1d5d60aa1b604482015290519081900360640190fd5b85915060008061237889613c8a565b915091508188106123c9576040805162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e74206c697175696469747960501b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639a3ddf267f0000000000000000000000000000000000000000000000000000000000000000898b8d6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03168152602001838152602001828152602001945050505050600060405180830381600087803b15801561247057600080fd5b505af1158015612484573d6000803e3d6000fd5b505086159150612534905057336001600160a01b031663714e109789600089896040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561251357600080fd5b505af1158015612527573d6000803e3d6000fd5b5050505061253489613bb2565b600061253e6149c2565b9050600061254c82846141ca565b90506000612565600e548361437590919063ffffffff16565b90506000612571611e22565b9050600061257d61304e565b9050600061258d88888486613a93565b905061259c888884868561434d565b60006125b58f8a036125ae89886141ca565b8587613a93565b905081811015612601576040805162461bcd60e51b8152602060048201526012602482015271092dcecc2e4d2c2dce840dad2e6dac2e8c6d60731b604482015290519081900360640190fd5b505050600061261b600f548461437590919063ffffffff16565b8d8803600555905061262d85826141ca565b60065560105461263d90826142f3565b60108190555060008d90508c6001600160a01b0316336001600160a01b03167f2ad8739d64c070ab4ae9d9c0743d56550b22c3c8c96e7a6045fac37b5b8e89e36000888560008a898b6040518088815260200187815260200186815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390a350506001805550959b9a5050505050505050505050565b600080600061273d7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b5050505050915091506000600e549050600081670de0b6b3a764000003612786600184670de0b6b3a764000003036114b3670de0b6b3a76400008a61422c90919063ffffffff16565b8161278d57fe5b049050600061279c84836141ca565b905060006127a861304e565b905060006127b4611e22565b905060006127c488888585613a93565b600101905060006127d7848685856147c1565b60010190506127e6818a6141ca565b9b9a5050505050505050505050565b600e5481565b6000600854420361280a611d55565b0260075401905090565b60115481565b6004546001600160a01b031690565b600a5481565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6004546001600160a01b031633146128ce576040805162461bcd60e51b81526020600482015260156024820152742830bab9b0b136329d1037b7363c903830bab9b2b960591b604482015290519081900360640190fd5b6001600160a01b0381166128e157600080fd5b6004546040516001600160a01b038084169216907ffb34c91b8734ef26ee8085a0fa11d2692042c6edac57dc40d8850cad2f1bc3ef90600090a3600480546001600160a01b0319166001600160a01b0392909216919091179055565b600d546001600160a01b031681565b600060026001541415612994576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b6002600155826129a381613bb2565b600354156129eb576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000806129f786613c8a565b9150915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d8e660627f0000000000000000000000000000000000000000000000000000000000000000306040518363ffffffff1660e01b815260040180838152602001826001600160a01b031681526020019250505060206040518083038186803b158015612a9257600080fd5b505afa158015612aa6573d6000803e3d6000fd5b505050506040513d6020811015612abc57600080fd5b505190506000612aca6149c2565b90506000612ad661304e565b90506000612ae2611e22565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b3f57600080fd5b505afa158015612b53573d6000803e3d6000fd5b505050506040513d6020811015612b6957600080fd5b5051905080612d9557600085118015612b825750600084115b612bca576040805162461bcd60e51b81526020600482015260146024820152735a65726f20696e697469616c2062616c616e636560601b604482015290519081900360640190fd5b600585905560068490556008805460078054670de0b6b3a7640000429384030201905590556000612bfd86868686613a93565b604080516340c10f1960e01b81523060048201526103e8602482015290519192506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916340c10f199160448082019260009290919082900301818387803b158015612c7057600080fd5b505af1158015612c84573d6000803e3d6000fd5b50506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691506340c10f1990508c612cc6846103e86141ca565b6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015612d0c57600080fd5b505af1158015612d20573d6000803e3d6000fd5b50506040805189815260208101899052808201859052600060608201819052608082015260a0810187905290516001600160a01b038f1693503392507f8d5439f1c76c5d28b239832e1c3afd5c0c595a311000b6bb5854065ac00dadf69181900360c00190a39850612fd89650505050505050565b6000806000612da68a8a8888613a93565b9050612db58a8a88888561434d565b6000612dc389898989613a93565b9050600082612dd2838d61422c565b81612dd957fe5b0490506000898211612ded57818a03612df1565b8982035b9050612e08600e548261437590919063ffffffff16565b9550505050612e22600f548461437590919063ffffffff16565b601054909250612e3290836142f3565b6010556005889055612e4487836141ca565b6006556000612e5e89612e578a876141ca565b8989613a93565b9050818111612eac576040805162461bcd60e51b8152602060048201526015602482015274139bc81b1a5c5d5a591a5d1e481a5cc81859191959605a1b604482015290519081900360640190fd5b612ec482610e8a612ebd84836141ca565b889061422c565b9c5050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340c10f198d8d6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015612f3f57600080fd5b505af1158015612f53573d6000803e3d6000fd5b505050508b6001600160a01b0316336001600160a01b03167f8d5439f1c76c5d28b239832e1c3afd5c0c595a311000b6bb5854065ac00dadf68b8a038b8a038f87878b60405180878152602001868152602001858152602001848152602001838152602001828152602001965050505050505060405180910390a35050505050505050505b506001805592915050565b612feb61464a565b6001600160a01b0316612ffc612278565b6001600160a01b031614613045576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b61161681614a6e565b600c54600090428111156130ab57600b54600954600a548181111561308c57828403834203838303028161307e57fe5b048201945050505050610b05565b828403834203828403028161309d57fe5b048203945050505050610b05565b5050600a54610b05565b601080546000909155600d54611616906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683614173565b60008060006131597f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b5050505050915091506000613183600e54670de0b6b3a7640000038661437590919063ffffffff16565b9050600061319183836142f3565b9050600061319d61304e565b905060006131a9611e22565b905060006131b987878585613a93565b600101905060006131cc848685856147c1565b60010190506131db88826141ca565b9a9950505050505050505050565b600080600061324a7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b505050505091509150600061325d611e22565b905082158061326a575081155b15613279579250610b05915050565b600061328361304e565b9050600061329385858486613a93565b9050611e188361188a8787868887614881565b7f000000000000000000000000000000000000000000000000000000000000000081565b60065481565b6132d861464a565b6001600160a01b03166132e9612278565b6001600160a01b031614613332576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b6001600160a01b0381166133775760405162461bcd60e51b81526004018080602001828103825260268152602001806150866026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000806002600154141561341b576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b60026001558561342a81613bb2565b61343687878787614ac2565b80935081945050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156134a457600080fd5b505af11580156134b8573d6000803e3d6000fd5b50506040516000925033915084908381818185875af1925050503d80600081146134fe576040519150601f19603f3d011682016040523d82523d6000602084013e613503565b606091505b505090508061354b576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b505060018055909590945092505050565b600080600260015414156135a5576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b6002600155856135b481613bb2565b6135c087878787614ac2565b90935091506135f96001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163384614173565b5060018055909590945092505050565b600c5481565b60026001541415613655576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b60026001819055506000806136ed7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b1580156136bc57600080fd5b505afa1580156136d0573d6000803e3d6000fd5b505050506040513d60208110156136e657600080fd5b5051613c8a565b9150915060006136fb61304e565b90506000613707611e22565b9050600061371785858585613a93565b9050613726858585858561434d565b60408051636c73303160e11b81527f0000000000000000000000000000000000000000000000000000000000000000600482015230602482015290516000916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163d8e6606291604480820192602092909190829003018186803b1580156137b657600080fd5b505afa1580156137ca573d6000803e3d6000fd5b505050506040513d60208110156137e057600080fd5b5051905060006137ee6149c2565b60058390556006819055604080518481526020810183905280820187905290519192507f9ea8a9dd7d3733c6dd274b7139f05a2bfce1a4bb22f0f7bdc1ccd49c267b858d919081900360600190a15050600180555050505050565b600080600080600080600060115488141561387c5750506005546006549095509350600092508291508190508080613a88565b506005546006546011546040805163ed056e2160e01b81526000600482018190526024820186905260448201526064810192909252608482018b90525160019392916001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163ed056e219160a480820192606092909190829003018186803b15801561390f57600080fd5b505afa158015613923573d6000803e3d6000fd5b505050506040513d606081101561393957600080fd5b5080516020909101519950965081891015613a57577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631e77ceda6040518163ffffffff1660e01b815260040160206040518083038186803b1580156139a757600080fd5b505afa1580156139bb573d6000803e3d6000fd5b505050506040513d60208110156139d157600080fd5b505160408051630514a68160e41b8152600481018a905290516001600160a01b039092169163514a681091602480820192602092909190829003018186803b158015613a1c57600080fd5b505afa158015613a30573d6000803e3d6000fd5b505050506040513d6020811015613a4657600080fd5b50519450613a5489866142f3565b98505b81891015613a7957613a6d82610e8a838c61422c565b97508781039350613a85565b80975081890395508198505b50505b919395979092949650565b600080613ac0857f000000000000000000000000000000000000000000000000000000000000000061422c565b90506000613ace8785614375565b90506000613adc82846142f3565b905080613aef5760009350505050613baa565b600081815b60ff811015613ba25790915081906000600487613b1f85613b198a610e8a838061422c565b9061422c565b81613b2657fe5b0481613b2e57fe5b049050613b49600382026114b38560001960048f020161422c565b613b6e8483600202613b678e6004028a61422c90919063ffffffff16565b019061422c565b81613b7557fe5b049250836001018311158015613b8e5750826001018411155b15613b995750613ba2565b50600101613af4565b509450505050505b949350505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015613c0b57600080fd5b505afa158015613c1f573d6000803e3d6000fd5b505050506040513d6020811015613c3557600080fd5b50518114611616576040805162461bcd60e51b815260206004820152601a60248201527f4f62736f6c65746520726562616c616e63652076657273696f6e000000000000604482015290519081900360640190fd5b6000806000806000806000613c9e88613849565b959c50939a50919850965094509250905080156141695760058790556006869055601188905560408051888152602081018890528082018a905290517f83387a3342ff1ebc5e437dc9ae0f98274afda12a11cf547eebec05a3e0b8f8a79181900360600190a18415613ee4578215613e23577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631e77ceda6040518163ffffffff1660e01b815260040160206040518083038186803b158015613d6957600080fd5b505afa158015613d7d573d6000803e3d6000fd5b505050506040513d6020811015613d9357600080fd5b505160408051638afbc1ed60e01b815230600482015260248101889052604481018b905290516001600160a01b0390921691638afbc1ed916064808201926020929091908290030181600087803b158015613ded57600080fd5b505af1158015613e01573d6000803e3d6000fd5b505050506040513d6020811015613e1757600080fd5b5060009550613ee49050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639a3ddf2660007f0000000000000000000000000000000000000000000000000000000000000000888c6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03168152602001838152602001828152602001945050505050600060405180830381600087803b158015613ecb57600080fd5b505af1158015613edf573d6000803e3d6000fd5b505050505b8315613fab577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639a3ddf2660017f0000000000000000000000000000000000000000000000000000000000000000878c6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03168152602001838152602001828152602001945050505050600060405180830381600087803b158015613f9257600080fd5b505af1158015613fa6573d6000803e3d6000fd5b505050505b8215614072577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639a3ddf2660027f0000000000000000000000000000000000000000000000000000000000000000868c6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03168152602001838152602001828152602001945050505050600060405180830381600087803b15801561405957600080fd5b505af115801561406d573d6000803e3d6000fd5b505050505b81156140cc576140cc6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000084614173565b60408051630828122960e41b815260048101879052602481018690526044810185905260648101849052608481018a905290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163828122909160a480830192600092919082900301818387803b15801561415057600080fd5b505af1158015614164573d6000803e3d6000fd5b505050505b5050505050915091565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526141c5908490614dcc565b505050565b600082821115614221576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b508082035b92915050565b60008261423b57506000614226565b8282028284828161424857fe5b04146142855760405162461bcd60e51b81526004018080602001828103825260218152602001806150ac6021913960400191505060405180910390fd5b9392505050565b60008082116142e2576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816142eb57fe5b049392505050565b600082820183811015614285576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600854420361435f8686868686614881565b6007805491909202019055505042600855505050565b6000614285670de0b6b3a7640000610e8a858561422c565b600080600061439b86613c8a565b9150915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156143fa57600080fd5b505afa15801561440e573d6000803e3d6000fd5b505050506040513d602081101561442457600080fd5b50519050600061443261304e565b9050600061443e611e22565b905060008061444f87878686613a93565b905061445e878786868561434d565b61446f61186186610e8a848e61422c565b91506000905061448d85610e8a614486828e6141ca565b899061422c565b9050600061449d8589868661464e565b600101905060006144bd600e5461188a84866141ca90919063ffffffff16565b90506144d3816144cd8a856141ca565b906141ca565b99508a8a1015614520576040805162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081bdd5d1c1d5d606a1b604482015290519081900360640190fd5b6040805163079cc67960e41b8152336004820152602481018e905290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916379cc679091604480830192600092919082900301818387803b15801561458e57600080fd5b505af11580156145a2573d6000803e3d6000fd5b5050505060006145bd600f548361437590919063ffffffff16565b6010549091506145cd90826142f3565b6010556145de816144cd85856142f3565b600655604080518e8152600060208201528082018d9052606081018490526080810183905260a08101889052905133917f16db8cd72937fc971d5ff44547c6a645bfee7a7537d2a2eacd0b7d919ecfbf0f919081900360c00190a2505050505050505050509392505050565b3390565b60008061465b8585614375565b905060006010870261467585613b1985610e8a838061422c565b8161467c57fe5b049050600084815b60ff8110156146f1578192506146b1876144cd8c6004028a816146a357fe5b046114b3600287028a6142f3565b6146bf856114b3858061422c565b816146c657fe5b0491508260010182111580156146df5750816001018311155b156146e9576146f1565b600101614684565b507f0000000000000000000000000000000000000000000000000000000000000000818161471b57fe5b049998505050505050505050565b670de0b6b3a7640000811115614786576040805162461bcd60e51b815260206004820152601960248201527f457863656564206d61782061646d696e20666565207261746500000000000000604482015290519081900360640190fd5b600f8190556040805182815290517f576be7f9615bb4c6e139635cf4380b1ce9f6aa425dabe6b9057c24a86cc3c9799181900360200190a150565b6000806147ee857f000000000000000000000000000000000000000000000000000000000000000061422c565b905060006010870261480885613b1985610e8a838061422c565b8161480f57fe5b049050600084815b60ff81101561487657819250614836876144cd8c6004028a816146a357fe5b614844856114b3858061422c565b8161484b57fe5b0491508260010182111580156148645750816001018311155b1561486e57614876565b600101614817565b506121218188614e7d565b6000806148ab85670de0b6b3a76400008161489857fe5b85919004673782dace9d90000003614375565b905060006148b98886614375565b905060006148e7887f000000000000000000000000000000000000000000000000000000000000000061422c565b90506121218261492e61490d866144cd61490285600461422c565b6114b388600861422c565b61492e8561188a896144cd61492384600461422c565b6114b38c600861422c565b90614e7d565b6706f05b59d3b20000811115614987576040805162461bcd60e51b8152602060048201526013602482015272457863656564206d617820666565207261746560681b604482015290519081900360640190fd5b600e8190556040805182815290517f208f1b468d3d61f0f085e975bd9d04367c930d599642faad06695229f3eadcd89181900360200190a150565b6000614a696010547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015614a3757600080fd5b505afa158015614a4b573d6000803e3d6000fd5b505050506040513d6020811015614a6157600080fd5b5051906141ca565b905090565b600d80546001600160a01b0383166001600160a01b0319909116811790915560408051918252517fe5693914d19c789bdee50a362998c0bc8d035a835f9871da5d51152f0582c34f9181900360200190a150565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015614b2057600080fd5b505afa158015614b34573d6000803e3d6000fd5b505050506040513d6020811015614b4a57600080fd5b50519050600080614b5a89613c8a565b9092509050614b6d83610e8a848b61422c565b9450614b7d83610e8a838b61422c565b935086851015614bca576040805162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081bdd5d1c1d5d606a1b604482015290519081900360640190fd5b85841015614c15576040805162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081bdd5d1c1d5d606a1b604482015290519081900360640190fd5b614c1f82866141ca565b600555614c2c81856141ca565b6006556040805163079cc67960e41b8152336004820152602481018a905290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916379cc679091604480830192600092919082900301818387803b158015614c9d57600080fd5b505af1158015614cb1573d6000803e3d6000fd5b505060408051634d1eef9360e11b81527f0000000000000000000000000000000000000000000000000000000000000000600482015233602482015260448101899052606481018d905290516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169350639a3ddf269250608480830192600092919082900301818387803b158015614d5057600080fd5b505af1158015614d64573d6000803e3d6000fd5b5050604080518b8152602081018990528082018890526000606082018190526080820181905260a082015290513393507f16db8cd72937fc971d5ff44547c6a645bfee7a7537d2a2eacd0b7d919ecfbf0f92509081900360c00190a250505094509492505050565b6060614e21826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e959092919063ffffffff16565b8051909150156141c557808060200190516020811015614e4057600080fd5b50516141c55760405162461bcd60e51b815260040180806020018281038252602a8152602001806150ed602a913960400191505060405180910390fd5b600061428582610e8a85670de0b6b3a764000061422c565b6060613baa848460008585614ea985614fbb565b614efa576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310614f395780518252601f199092019160209182019101614f1a565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614f9b576040519150601f19603f3d011682016040523d82523d6000602084013e614fa0565b606091505b5091509150614fb0828286614fc1565b979650505050505050565b3b151590565b60608315614fd0575081614285565b825115614fe05782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561502a578181015183820152602001615012565b50505050905090810190601f1680156150575780820380516001836020036101000a031916815260200191505b509250505060405180910390fdfe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220550d6eb4dede49d97f7543fadc12873f8a8108268c6ccb954c90bfa7dc614df364736f6c634300060c003351756f746520617373657420646563696d616c73206c6172676572207468616e203138000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d00000000000000000000000080137510979822322193fc997d400d5a6c747bf700000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000014000000000000000000000000dec17f71ef579123939aca1bdfaeec21eae00d670000000000000000000000000000000000000000000000000001c6bf5263400000000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106102e85760003560e01c80638cece52711610190578063c95f9d0e116100dc578063f0a0b44e11610095578063f467c2bd1161006f578063f467c2bd146109ae578063f88bf15a146109ea578063fe3cfe8314610a26578063fff6cae914610a3b576102ef565b8063f0a0b44e14610951578063f1a2e84914610966578063f2fde38b1461097b576102ef565b8063c95f9d0e1461087c578063d2c35ce8146108b5578063d4526cdc146108e8578063d4d5d32a146108fd578063e6d7059a14610912578063eb91d37e1461093c576102ef565b80639d888e8611610149578063a3ba010311610123578063a3ba01031461080a578063b60d42881461081f578063bad383a614610834578063c415b95c14610867576102ef565b80639d888e86146107cb5780639fd0506d146107e0578063a1415b7f146107f5576102ef565b80638cece527146106b45780638da5cb5b146106c95780639000ff09146106de57806395d6abf814610777578063978bbdb9146107a157806398466227146107b6576102ef565b8063555b61621161024f578063715018a611610208578063796da7af116101e2578063796da7af146106365780637b31ae641461064b5780637b84fda5146106755780638456cb591461069f576102ef565b8063715018a6146105d657806377c795bf146105eb5780637884578514610621576102ef565b8063555b61621461050a5780635c975abb146105385780635e23ebe4146105615780635fcbd2851461057657806369b459e31461058b57806369f2db41146105a0576102ef565b806330b29402116102a157806330b294021461042657806338b602ca1461045c57806338bde7911461048c5780633a66ff97146104a15780633f4ba83a146104cb578063546ccda1146104e0576102ef565b80630589a478146102f45780630750f290146103255780630faf3f971461034c5780631033e4cd1461036157806318f73472146103fa578063242708df14610411576102ef565b366102ef57005b600080fd5b34801561030057600080fd5b50610309610a50565b604080516001600160a01b039092168252519081900360200190f35b34801561033157600080fd5b5061033a610b08565b60408051918252519081900360200190f35b34801561035857600080fd5b5061033a610b0e565b34801561036d57600080fd5b5061033a6004803603608081101561038457600080fd5b8135916020810135916001600160a01b0360408301351691908101906080810160608201356401000000008111156103bb57600080fd5b8201836020820111156103cd57600080fd5b803590602001918460018302840111640100000000831117156103ef57600080fd5b509092509050610bca565b34801561040657600080fd5b5061040f61103d565b005b34801561041d57600080fd5b5061033a6110de565b34801561043257600080fd5b5061033a6004803603606081101561044957600080fd5b50803590602081013590604001356110e4565b34801561046857600080fd5b5061040f6004803603604081101561047f57600080fd5b50803590602001356111d0565b34801561049857600080fd5b5061033a6113bc565b3480156104ad57600080fd5b5061033a600480360360208110156104c457600080fd5b50356113c2565b3480156104d757600080fd5b5061040f6114cf565b3480156104ec57600080fd5b5061040f6004803603602081101561050357600080fd5b50356115ab565b34801561051657600080fd5b5061051f611619565b6040805192835260208301919091528051918290030190f35b34801561054457600080fd5b5061054d61168c565b604080519115158252519081900360200190f35b34801561056d57600080fd5b5061033a611694565b34801561058257600080fd5b5061030961169a565b34801561059757600080fd5b5061033a6116be565b3480156105ac57600080fd5b5061033a600480360360608110156105c357600080fd5b50803590602081013590604001356116e2565b3480156105e257600080fd5b5061040f611ae3565b3480156105f757600080fd5b5061033a6004803603606081101561060e57600080fd5b5080359060208101359060400135611b8f565b34801561062d57600080fd5b5061033a611d55565b34801561064257600080fd5b5061033a611e22565b34801561065757600080fd5b5061033a6004803603602081101561066e57600080fd5b5035612037565b34801561068157600080fd5b5061040f6004803603602081101561069857600080fd5b503561212e565b3480156106ab57600080fd5b5061040f612199565b3480156106c057600080fd5b5061033a612272565b3480156106d557600080fd5b50610309612278565b3480156106ea57600080fd5b5061033a6004803603608081101561070157600080fd5b8135916020810135916001600160a01b03604083013516919081019060808101606082013564010000000081111561073857600080fd5b82018360208201111561074a57600080fd5b8035906020019184600183028401116401000000008311171561076c57600080fd5b509092509050612287565b34801561078357600080fd5b5061033a6004803603602081101561079a57600080fd5b50356126dc565b3480156107ad57600080fd5b5061033a6127f5565b3480156107c257600080fd5b5061033a6127fb565b3480156107d757600080fd5b5061033a612814565b3480156107ec57600080fd5b5061030961281a565b34801561080157600080fd5b5061033a612829565b34801561081657600080fd5b5061033a61282f565b34801561082b57600080fd5b50610309612853565b34801561084057600080fd5b5061040f6004803603602081101561085757600080fd5b50356001600160a01b0316612877565b34801561087357600080fd5b5061030961293d565b34801561088857600080fd5b5061033a6004803603604081101561089f57600080fd5b50803590602001356001600160a01b031661294c565b3480156108c157600080fd5b5061040f600480360360208110156108d857600080fd5b50356001600160a01b0316612fe3565b3480156108f457600080fd5b5061033a61304e565b34801561090957600080fd5b5061040f6130b5565b34801561091e57600080fd5b5061033a6004803603602081101561093557600080fd5b50356130f8565b34801561094857600080fd5b5061033a6131e9565b34801561095d57600080fd5b506103096132a6565b34801561097257600080fd5b5061033a6132ca565b34801561098757600080fd5b5061040f6004803603602081101561099e57600080fd5b50356001600160a01b03166132d0565b3480156109ba57600080fd5b5061051f600480360360808110156109d157600080fd5b50803590602081013590604081013590606001356133d2565b3480156109f657600080fd5b5061051f60048036036080811015610a0d57600080fd5b508035906020810135906040810135906060013561355c565b348015610a3257600080fd5b5061033a613609565b348015610a4757600080fd5b5061040f61360f565b60007f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b031663fb73de937f00000000000000000000000000000000000000000000000000000000000000016040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015610ad657600080fd5b505afa158015610aea573d6000803e3d6000fd5b505050506040513d6020811015610b0057600080fd5b505190505b90565b60095481565b6000806000610ba07f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b505afa158015610b83573d6000803e3d6000fd5b505050506040513d6020811015610b9957600080fd5b5051613849565b505050505091509150610bc38282610bb661304e565b610bbe611e22565b613a93565b9250505090565b600060026001541415610c12576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b600260015585610c2181613bb2565b60035415610c69576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60008611610cac576040805162461bcd60e51b815260206004820152600b60248201526a16995c9bc81bdd5d1c1d5d60aa1b604482015290519081900360640190fd5b859150600080610cbb89613c8a565b9092509050610cf46001600160a01b037f00000000000000000000000080137510979822322193fc997d400d5a6c747bf716888a614173565b8415610d9e57336001600160a01b031663714e109760008a89896040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b158015610d7d57600080fd5b505af1158015610d91573d6000803e3d6000fd5b50505050610d9e89613bb2565b60408051636c73303160e11b81527f0000000000000000000000000000000000000000000000000000000000000001600482015230602482015290516000916001600160a01b037f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d169163d8e6606291604480820192602092909190829003018186803b158015610e2e57600080fd5b505afa158015610e42573d6000803e3d6000fd5b505050506040513d6020811015610e5857600080fd5b505190506000610e6882856141ca565b600e54909150600090610e90670de0b6b3a7640000829003610e8a8e8461422c565b9061428c565b9150849050610e9f8c836142f3565b10610eea576040805162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e74206c697175696469747960501b604482015290519081900360640190fd5b6000610ef4611e22565b90508b85036000610f0361304e565b90506000610f1389898487613a93565b9050610f22898984878561434d565b6000610f32888786038588613a93565b905081811015610f7e576040805162461bcd60e51b8152602060048201526012602482015271092dcecc2e4d2c2dce840dad2e6dac2e8c6d60731b604482015290519081900360640190fd5b505050506000610f99600f548461437590919063ffffffff16565b60058690558d8703819003600655601054909150610fb790826142f3565b6010556040805185815260006020820181905281830152606081018f90526080810185905260a0810183905260c0810184905290518e916001600160a01b038f169133917f2ad8739d64c070ab4ae9d9c0743d56550b22c3c8c96e7a6045fac37b5b8e89e3919081900360e00190a350506001805550959b9a5050505050505050505050565b6004546001600160a01b03163314611094576040805162461bcd60e51b81526020600482015260156024820152742830bab9b0b136329d1037b7363c903830bab9b2b960591b604482015290519081900360640190fd5b6004546040516000916001600160a01b0316907ffb34c91b8734ef26ee8085a0fa11d2692042c6edac57dc40d8850cad2f1bc3ef908390a3600480546001600160a01b0319169055565b60105481565b60006002600154141561112c576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b60026001558361113b81613bb2565b60035415611183576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b61118e85858561438d565b91506111c46001600160a01b037f00000000000000000000000080137510979822322193fc997d400d5a6c747bf7163384614173565b50600180559392505050565b6111d861464a565b6001600160a01b03166111e9612278565b6001600160a01b031614611232576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b6000821180156112445750620f424082105b611281576040805162461bcd60e51b8152602060048201526009602482015268496e76616c6964204160b81b604482015290519081900360640190fd5b6201518042018110156112d3576040805162461bcd60e51b815260206004820152601560248201527410481c985b5c081d1a5b59481d1bdbc81cda1bdc9d605a1b604482015290519081900360640190fd5b60006112dd61304e565b90508083101580156112f25750600a81028311155b8061130a5750808310801561130a575080600a840210155b61135b576040805162461bcd60e51b815260206004820152601760248201527f412072616d70206368616e676520746f6f206c61726765000000000000000000604482015290519081900360640190fd5b6009819055600a83905542600b819055600c83905560408051838152602081018690528082019290925260608201849052517f4d37ead28a6f2a793e583c75de178de526aaf341b06b0699a40341118a04b3d99181900360800190a1505050565b60055481565b60008060006114237f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b505050505091509150600061144185846141ca90919063ffffffff16565b9050600061144d61304e565b90506000611459611e22565b9050600061146986868585613a93565b6001019050600061147c8486858561464e565b600101905061148b81876141ca565b600e54909850670de0b6b3a7640000818103906114b9906000198301906114b3908d9061422c565b906142f3565b816114c057fe5b049a9950505050505050505050565b6004546001600160a01b03163314611526576040805162461bcd60e51b81526020600482015260156024820152742830bab9b0b136329d1037b7363c903830bab9b2b960591b604482015290519081900360640190fd5b600354611571576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b60006003556040805133815290517f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa9181900360200190a1565b6115b361464a565b6001600160a01b03166115c4612278565b6001600160a01b03161461160d576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b61161681614729565b50565b60008060008061167b7f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b509498509296505050505050509091565b600354151590565b600b5481565b7f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d81565b7f000000000000000000000000000000000000000000000000000000000000000181565b60006002600154141561172a576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b60026001558361173981613bb2565b60035415611781576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60008061178d87613c8a565b9150915060007f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117ec57600080fd5b505afa158015611800573d6000803e3d6000fd5b505050506040513d602081101561181657600080fd5b50519050600061182461304e565b90506000611830611e22565b905060008061184187878686613a93565b9050611850878786868561434d565b61186861186186610e8a848f61422c565b82906141ca565b9150506000611890600e5461188a87610e8a8f8b61422c90919063ffffffff16565b90614375565b905060006118a9856118a289856141ca565b86866147c1565b60010190506118b888826141ca565b99508a8a1015611905576040805162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081bdd5d1c1d5d606a1b604482015290519081900360640190fd5b6040805163079cc67960e41b8152336004820152602481018e905290516001600160a01b037f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d16916379cc679091604480830192600092919082900301818387803b15801561197357600080fd5b505af1158015611987573d6000803e3d6000fd5b505050600582905550600f546000906119a1908490614375565b6010549091506119b190826142f3565b6010556119be88826141ca565b600655604080518e8152602081018d9052600081830152606081018590526080810183905260a08101879052905133917f16db8cd72937fc971d5ff44547c6a645bfee7a7537d2a2eacd0b7d919ecfbf0f919081900360c00190a2505060408051634d1eef9360e11b81527f00000000000000000000000000000000000000000000000000000000000000016004820152336024820152604481018b9052606481018e905290516001600160a01b037f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d169250639a3ddf269160848082019260009290919082900301818387803b158015611ab857600080fd5b505af1158015611acc573d6000803e3d6000fd5b50506001805550979b9a5050505050505050505050565b611aeb61464a565b6001600160a01b0316611afc612278565b6001600160a01b031614611b45576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600060026001541415611bd7576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b600260015583611be681613bb2565b60035415611c2e576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b611c3985858561438d565b91507f00000000000000000000000080137510979822322193fc997d400d5a6c747bf76001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611ca157600080fd5b505af1158015611cb5573d6000803e3d6000fd5b50506040516000925033915084908381818185875af1925050503d8060008114611cfb576040519150601f19603f3d011682016040523d82523d6000602084013e611d00565b606091505b5050905080611d48576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b5050600180559392505050565b6000806000611db67f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b5050505050915091508160001480611dcc575080155b15611de357670de0b6b3a764000092505050610b05565b6000611ded61304e565b90506000611df9611e22565b90506000611e0985858585613a93565b9050611e188585858585614881565b9550505050505090565b6000807f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316639043292a6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e7e57600080fd5b505afa158015611e92573d6000803e3d6000fd5b505050506040513d6020811015611ea857600080fd5b50516040805163061b57a360e51b815290516001600160a01b039092169163c36af46091600480820192602092909190829003018186803b158015611eec57600080fd5b505afa158015611f00573d6000803e3d6000fd5b505050506040513d6020811015611f1657600080fd5b50516040805163133b5f7560e01b815260048101839052905191925060009182916001600160a01b037f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d169163133b5f7591602480820192606092909190829003018186803b158015611f8857600080fd5b505afa158015611f9c573d6000803e3d6000fd5b505050506040513d6060811015611fb257600080fd5b5060208101516040909101519092509050611fed827f0000000000000000000000000000000000000000000000000000000000000000614375565b811015612030576040805162461bcd60e51b815260206004820152600c60248201526b2a3930b234b7339031bab93160a11b604482015290519081900360640190fd5b5091505090565b60008060006120987f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b50505050509150915060006120b685846142f390919063ffffffff16565b905060006120c261304e565b905060006120ce611e22565b905060006120de86868585613a93565b600101905060006120f18486858561464e565b600101905061210086826141ca565b9750612121600e54670de0b6b3a7640000038961437590919063ffffffff16565b9998505050505050505050565b61213661464a565b6001600160a01b0316612147612278565b6001600160a01b031614612190576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b61161681614934565b6004546001600160a01b031633146121f0576040805162461bcd60e51b81526020600482015260156024820152742830bab9b0b136329d1037b7363c903830bab9b2b960591b604482015290519081900360640190fd5b60035415612238576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60016003556040805133815290517f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589181900360200190a1565b600f5481565b6000546001600160a01b031690565b6000600260015414156122cf576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b6002600155856122de81613bb2565b60035415612326576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60008611612369576040805162461bcd60e51b815260206004820152600b60248201526a16995c9bc81bdd5d1c1d5d60aa1b604482015290519081900360640190fd5b85915060008061237889613c8a565b915091508188106123c9576040805162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e74206c697175696469747960501b604482015290519081900360640190fd5b7f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316639a3ddf267f0000000000000000000000000000000000000000000000000000000000000001898b8d6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03168152602001838152602001828152602001945050505050600060405180830381600087803b15801561247057600080fd5b505af1158015612484573d6000803e3d6000fd5b505086159150612534905057336001600160a01b031663714e109789600089896040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561251357600080fd5b505af1158015612527573d6000803e3d6000fd5b5050505061253489613bb2565b600061253e6149c2565b9050600061254c82846141ca565b90506000612565600e548361437590919063ffffffff16565b90506000612571611e22565b9050600061257d61304e565b9050600061258d88888486613a93565b905061259c888884868561434d565b60006125b58f8a036125ae89886141ca565b8587613a93565b905081811015612601576040805162461bcd60e51b8152602060048201526012602482015271092dcecc2e4d2c2dce840dad2e6dac2e8c6d60731b604482015290519081900360640190fd5b505050600061261b600f548461437590919063ffffffff16565b8d8803600555905061262d85826141ca565b60065560105461263d90826142f3565b60108190555060008d90508c6001600160a01b0316336001600160a01b03167f2ad8739d64c070ab4ae9d9c0743d56550b22c3c8c96e7a6045fac37b5b8e89e36000888560008a898b6040518088815260200187815260200186815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390a350506001805550959b9a5050505050505050505050565b600080600061273d7f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b5050505050915091506000600e549050600081670de0b6b3a764000003612786600184670de0b6b3a764000003036114b3670de0b6b3a76400008a61422c90919063ffffffff16565b8161278d57fe5b049050600061279c84836141ca565b905060006127a861304e565b905060006127b4611e22565b905060006127c488888585613a93565b600101905060006127d7848685856147c1565b60010190506127e6818a6141ca565b9b9a5050505050505050505050565b600e5481565b6000600854420361280a611d55565b0260075401905090565b60115481565b6004546001600160a01b031690565b600a5481565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d81565b6004546001600160a01b031633146128ce576040805162461bcd60e51b81526020600482015260156024820152742830bab9b0b136329d1037b7363c903830bab9b2b960591b604482015290519081900360640190fd5b6001600160a01b0381166128e157600080fd5b6004546040516001600160a01b038084169216907ffb34c91b8734ef26ee8085a0fa11d2692042c6edac57dc40d8850cad2f1bc3ef90600090a3600480546001600160a01b0319166001600160a01b0392909216919091179055565b600d546001600160a01b031681565b600060026001541415612994576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b6002600155826129a381613bb2565b600354156129eb576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6000806129f786613c8a565b9150915060007f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b031663d8e660627f0000000000000000000000000000000000000000000000000000000000000001306040518363ffffffff1660e01b815260040180838152602001826001600160a01b031681526020019250505060206040518083038186803b158015612a9257600080fd5b505afa158015612aa6573d6000803e3d6000fd5b505050506040513d6020811015612abc57600080fd5b505190506000612aca6149c2565b90506000612ad661304e565b90506000612ae2611e22565b905060007f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b3f57600080fd5b505afa158015612b53573d6000803e3d6000fd5b505050506040513d6020811015612b6957600080fd5b5051905080612d9557600085118015612b825750600084115b612bca576040805162461bcd60e51b81526020600482015260146024820152735a65726f20696e697469616c2062616c616e636560601b604482015290519081900360640190fd5b600585905560068490556008805460078054670de0b6b3a7640000429384030201905590556000612bfd86868686613a93565b604080516340c10f1960e01b81523060048201526103e8602482015290519192506001600160a01b037f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d16916340c10f199160448082019260009290919082900301818387803b158015612c7057600080fd5b505af1158015612c84573d6000803e3d6000fd5b50506001600160a01b037f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d1691506340c10f1990508c612cc6846103e86141ca565b6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015612d0c57600080fd5b505af1158015612d20573d6000803e3d6000fd5b50506040805189815260208101899052808201859052600060608201819052608082015260a0810187905290516001600160a01b038f1693503392507f8d5439f1c76c5d28b239832e1c3afd5c0c595a311000b6bb5854065ac00dadf69181900360c00190a39850612fd89650505050505050565b6000806000612da68a8a8888613a93565b9050612db58a8a88888561434d565b6000612dc389898989613a93565b9050600082612dd2838d61422c565b81612dd957fe5b0490506000898211612ded57818a03612df1565b8982035b9050612e08600e548261437590919063ffffffff16565b9550505050612e22600f548461437590919063ffffffff16565b601054909250612e3290836142f3565b6010556005889055612e4487836141ca565b6006556000612e5e89612e578a876141ca565b8989613a93565b9050818111612eac576040805162461bcd60e51b8152602060048201526015602482015274139bc81b1a5c5d5a591a5d1e481a5cc81859191959605a1b604482015290519081900360640190fd5b612ec482610e8a612ebd84836141ca565b889061422c565b9c5050507f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d6001600160a01b03166340c10f198d8d6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015612f3f57600080fd5b505af1158015612f53573d6000803e3d6000fd5b505050508b6001600160a01b0316336001600160a01b03167f8d5439f1c76c5d28b239832e1c3afd5c0c595a311000b6bb5854065ac00dadf68b8a038b8a038f87878b60405180878152602001868152602001858152602001848152602001838152602001828152602001965050505050505060405180910390a35050505050505050505b506001805592915050565b612feb61464a565b6001600160a01b0316612ffc612278565b6001600160a01b031614613045576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b61161681614a6e565b600c54600090428111156130ab57600b54600954600a548181111561308c57828403834203838303028161307e57fe5b048201945050505050610b05565b828403834203828403028161309d57fe5b048203945050505050610b05565b5050600a54610b05565b601080546000909155600d54611616906001600160a01b037f00000000000000000000000080137510979822322193fc997d400d5a6c747bf78116911683614173565b60008060006131597f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b5050505050915091506000613183600e54670de0b6b3a7640000038661437590919063ffffffff16565b9050600061319183836142f3565b9050600061319d61304e565b905060006131a9611e22565b905060006131b987878585613a93565b600101905060006131cc848685856147c1565b60010190506131db88826141ca565b9a9950505050505050505050565b600080600061324a7f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015610b6f57600080fd5b505050505091509150600061325d611e22565b905082158061326a575081155b15613279579250610b05915050565b600061328361304e565b9050600061329385858486613a93565b9050611e188361188a8787868887614881565b7f00000000000000000000000080137510979822322193fc997d400d5a6c747bf781565b60065481565b6132d861464a565b6001600160a01b03166132e9612278565b6001600160a01b031614613332576040805162461bcd60e51b815260206004820181905260248201526000805160206150cd833981519152604482015290519081900360640190fd5b6001600160a01b0381166133775760405162461bcd60e51b81526004018080602001828103825260268152602001806150866026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000806002600154141561341b576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b60026001558561342a81613bb2565b61343687878787614ac2565b80935081945050507f00000000000000000000000080137510979822322193fc997d400d5a6c747bf76001600160a01b0316632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156134a457600080fd5b505af11580156134b8573d6000803e3d6000fd5b50506040516000925033915084908381818185875af1925050503d80600081146134fe576040519150601f19603f3d011682016040523d82523d6000602084013e613503565b606091505b505090508061354b576040805162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b505060018055909590945092505050565b600080600260015414156135a5576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b6002600155856135b481613bb2565b6135c087878787614ac2565b90935091506135f96001600160a01b037f00000000000000000000000080137510979822322193fc997d400d5a6c747bf7163384614173565b5060018055909590945092505050565b600c5481565b60026001541415613655576040805162461bcd60e51b815260206004820152601f6024820152600080516020615066833981519152604482015290519081900360640190fd5b60026001819055506000806136ed7f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b1580156136bc57600080fd5b505afa1580156136d0573d6000803e3d6000fd5b505050506040513d60208110156136e657600080fd5b5051613c8a565b9150915060006136fb61304e565b90506000613707611e22565b9050600061371785858585613a93565b9050613726858585858561434d565b60408051636c73303160e11b81527f0000000000000000000000000000000000000000000000000000000000000001600482015230602482015290516000916001600160a01b037f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d169163d8e6606291604480820192602092909190829003018186803b1580156137b657600080fd5b505afa1580156137ca573d6000803e3d6000fd5b505050506040513d60208110156137e057600080fd5b5051905060006137ee6149c2565b60058390556006819055604080518481526020810183905280820187905290519192507f9ea8a9dd7d3733c6dd274b7139f05a2bfce1a4bb22f0f7bdc1ccd49c267b858d919081900360600190a15050600180555050505050565b600080600080600080600060115488141561387c5750506005546006549095509350600092508291508190508080613a88565b506005546006546011546040805163ed056e2160e01b81526000600482018190526024820186905260448201526064810192909252608482018b90525160019392916001600160a01b037f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d169163ed056e219160a480820192606092909190829003018186803b15801561390f57600080fd5b505afa158015613923573d6000803e3d6000fd5b505050506040513d606081101561393957600080fd5b5080516020909101519950965081891015613a57577f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316631e77ceda6040518163ffffffff1660e01b815260040160206040518083038186803b1580156139a757600080fd5b505afa1580156139bb573d6000803e3d6000fd5b505050506040513d60208110156139d157600080fd5b505160408051630514a68160e41b8152600481018a905290516001600160a01b039092169163514a681091602480820192602092909190829003018186803b158015613a1c57600080fd5b505afa158015613a30573d6000803e3d6000fd5b505050506040513d6020811015613a4657600080fd5b50519450613a5489866142f3565b98505b81891015613a7957613a6d82610e8a838c61422c565b97508781039350613a85565b80975081890395508198505b50505b919395979092949650565b600080613ac0857f000000000000000000000000000000000000000000000000000000000000000161422c565b90506000613ace8785614375565b90506000613adc82846142f3565b905080613aef5760009350505050613baa565b600081815b60ff811015613ba25790915081906000600487613b1f85613b198a610e8a838061422c565b9061422c565b81613b2657fe5b0481613b2e57fe5b049050613b49600382026114b38560001960048f020161422c565b613b6e8483600202613b678e6004028a61422c90919063ffffffff16565b019061422c565b81613b7557fe5b049250836001018311158015613b8e5750826001018411155b15613b995750613ba2565b50600101613af4565b509450505050505b949350505050565b7f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316635264e6816040518163ffffffff1660e01b815260040160206040518083038186803b158015613c0b57600080fd5b505afa158015613c1f573d6000803e3d6000fd5b505050506040513d6020811015613c3557600080fd5b50518114611616576040805162461bcd60e51b815260206004820152601a60248201527f4f62736f6c65746520726562616c616e63652076657273696f6e000000000000604482015290519081900360640190fd5b6000806000806000806000613c9e88613849565b959c50939a50919850965094509250905080156141695760058790556006869055601188905560408051888152602081018890528082018a905290517f83387a3342ff1ebc5e437dc9ae0f98274afda12a11cf547eebec05a3e0b8f8a79181900360600190a18415613ee4578215613e23577f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316631e77ceda6040518163ffffffff1660e01b815260040160206040518083038186803b158015613d6957600080fd5b505afa158015613d7d573d6000803e3d6000fd5b505050506040513d6020811015613d9357600080fd5b505160408051638afbc1ed60e01b815230600482015260248101889052604481018b905290516001600160a01b0390921691638afbc1ed916064808201926020929091908290030181600087803b158015613ded57600080fd5b505af1158015613e01573d6000803e3d6000fd5b505050506040513d6020811015613e1757600080fd5b5060009550613ee49050565b7f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316639a3ddf2660007f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d888c6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03168152602001838152602001828152602001945050505050600060405180830381600087803b158015613ecb57600080fd5b505af1158015613edf573d6000803e3d6000fd5b505050505b8315613fab577f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316639a3ddf2660017f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d878c6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03168152602001838152602001828152602001945050505050600060405180830381600087803b158015613f9257600080fd5b505af1158015613fa6573d6000803e3d6000fd5b505050505b8215614072577f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d6001600160a01b0316639a3ddf2660027f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d868c6040518563ffffffff1660e01b815260040180858152602001846001600160a01b03168152602001838152602001828152602001945050505050600060405180830381600087803b15801561405957600080fd5b505af115801561406d573d6000803e3d6000fd5b505050505b81156140cc576140cc6001600160a01b037f00000000000000000000000080137510979822322193fc997d400d5a6c747bf7167f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d84614173565b60408051630828122960e41b815260048101879052602481018690526044810185905260648101849052608481018a905290516001600160a01b037f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d169163828122909160a480830192600092919082900301818387803b15801561415057600080fd5b505af1158015614164573d6000803e3d6000fd5b505050505b5050505050915091565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526141c5908490614dcc565b505050565b600082821115614221576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b508082035b92915050565b60008261423b57506000614226565b8282028284828161424857fe5b04146142855760405162461bcd60e51b81526004018080602001828103825260218152602001806150ac6021913960400191505060405180910390fd5b9392505050565b60008082116142e2576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816142eb57fe5b049392505050565b600082820183811015614285576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600854420361435f8686868686614881565b6007805491909202019055505042600855505050565b6000614285670de0b6b3a7640000610e8a858561422c565b600080600061439b86613c8a565b9150915060007f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156143fa57600080fd5b505afa15801561440e573d6000803e3d6000fd5b505050506040513d602081101561442457600080fd5b50519050600061443261304e565b9050600061443e611e22565b905060008061444f87878686613a93565b905061445e878786868561434d565b61446f61186186610e8a848e61422c565b91506000905061448d85610e8a614486828e6141ca565b899061422c565b9050600061449d8589868661464e565b600101905060006144bd600e5461188a84866141ca90919063ffffffff16565b90506144d3816144cd8a856141ca565b906141ca565b99508a8a1015614520576040805162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081bdd5d1c1d5d606a1b604482015290519081900360640190fd5b6040805163079cc67960e41b8152336004820152602481018e905290516001600160a01b037f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d16916379cc679091604480830192600092919082900301818387803b15801561458e57600080fd5b505af11580156145a2573d6000803e3d6000fd5b5050505060006145bd600f548361437590919063ffffffff16565b6010549091506145cd90826142f3565b6010556145de816144cd85856142f3565b600655604080518e8152600060208201528082018d9052606081018490526080810183905260a08101889052905133917f16db8cd72937fc971d5ff44547c6a645bfee7a7537d2a2eacd0b7d919ecfbf0f919081900360c00190a2505050505050505050509392505050565b3390565b60008061465b8585614375565b905060006010870261467585613b1985610e8a838061422c565b8161467c57fe5b049050600084815b60ff8110156146f1578192506146b1876144cd8c6004028a816146a357fe5b046114b3600287028a6142f3565b6146bf856114b3858061422c565b816146c657fe5b0491508260010182111580156146df5750816001018311155b156146e9576146f1565b600101614684565b507f0000000000000000000000000000000000000000000000000000000000000001818161471b57fe5b049998505050505050505050565b670de0b6b3a7640000811115614786576040805162461bcd60e51b815260206004820152601960248201527f457863656564206d61782061646d696e20666565207261746500000000000000604482015290519081900360640190fd5b600f8190556040805182815290517f576be7f9615bb4c6e139635cf4380b1ce9f6aa425dabe6b9057c24a86cc3c9799181900360200190a150565b6000806147ee857f000000000000000000000000000000000000000000000000000000000000000161422c565b905060006010870261480885613b1985610e8a838061422c565b8161480f57fe5b049050600084815b60ff81101561487657819250614836876144cd8c6004028a816146a357fe5b614844856114b3858061422c565b8161484b57fe5b0491508260010182111580156148645750816001018311155b1561486e57614876565b600101614817565b506121218188614e7d565b6000806148ab85670de0b6b3a76400008161489857fe5b85919004673782dace9d90000003614375565b905060006148b98886614375565b905060006148e7887f000000000000000000000000000000000000000000000000000000000000000161422c565b90506121218261492e61490d866144cd61490285600461422c565b6114b388600861422c565b61492e8561188a896144cd61492384600461422c565b6114b38c600861422c565b90614e7d565b6706f05b59d3b20000811115614987576040805162461bcd60e51b8152602060048201526013602482015272457863656564206d617820666565207261746560681b604482015290519081900360640190fd5b600e8190556040805182815290517f208f1b468d3d61f0f085e975bd9d04367c930d599642faad06695229f3eadcd89181900360200190a150565b6000614a696010547f00000000000000000000000080137510979822322193fc997d400d5a6c747bf76001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015614a3757600080fd5b505afa158015614a4b573d6000803e3d6000fd5b505050506040513d6020811015614a6157600080fd5b5051906141ca565b905090565b600d80546001600160a01b0383166001600160a01b0319909116811790915560408051918252517fe5693914d19c789bdee50a362998c0bc8d035a835f9871da5d51152f0582c34f9181900360200190a150565b60008060007f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015614b2057600080fd5b505afa158015614b34573d6000803e3d6000fd5b505050506040513d6020811015614b4a57600080fd5b50519050600080614b5a89613c8a565b9092509050614b6d83610e8a848b61422c565b9450614b7d83610e8a838b61422c565b935086851015614bca576040805162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081bdd5d1c1d5d606a1b604482015290519081900360640190fd5b85841015614c15576040805162461bcd60e51b8152602060048201526013602482015272125b9cdd59999a58da595b9d081bdd5d1c1d5d606a1b604482015290519081900360640190fd5b614c1f82866141ca565b600555614c2c81856141ca565b6006556040805163079cc67960e41b8152336004820152602481018a905290516001600160a01b037f000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d16916379cc679091604480830192600092919082900301818387803b158015614c9d57600080fd5b505af1158015614cb1573d6000803e3d6000fd5b505060408051634d1eef9360e11b81527f0000000000000000000000000000000000000000000000000000000000000001600482015233602482015260448101899052606481018d905290516001600160a01b037f0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d169350639a3ddf269250608480830192600092919082900301818387803b158015614d5057600080fd5b505af1158015614d64573d6000803e3d6000fd5b5050604080518b8152602081018990528082018890526000606082018190526080820181905260a082015290513393507f16db8cd72937fc971d5ff44547c6a645bfee7a7537d2a2eacd0b7d919ecfbf0f92509081900360c00190a250505094509492505050565b6060614e21826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e959092919063ffffffff16565b8051909150156141c557808060200190516020811015614e4057600080fd5b50516141c55760405162461bcd60e51b815260040180806020018281038252602a8152602001806150ed602a913960400191505060405180910390fd5b600061428582610e8a85670de0b6b3a764000061422c565b6060613baa848460008585614ea985614fbb565b614efa576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310614f395780518252601f199092019160209182019101614f1a565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614f9b576040519150601f19603f3d011682016040523d82523d6000602084013e614fa0565b606091505b5091509150614fb0828286614fc1565b979650505050505050565b3b151590565b60608315614fd0575081614285565b825115614fe05782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561502a578181015183820152602001615012565b50505050905090810190601f1680156150575780820380516001836020036101000a031916815260200191505b509250505060405180910390fdfe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220550d6eb4dede49d97f7543fadc12873f8a8108268c6ccb954c90bfa7dc614df364736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d00000000000000000000000080137510979822322193fc997d400d5a6c747bf700000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000014000000000000000000000000dec17f71ef579123939aca1bdfaeec21eae00d670000000000000000000000000000000000000000000000000001c6bf5263400000000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : lpToken_ (address): 0xb5031D4c4b1bED0756caCAd96239C6805d94c14D
Arg [1] : fund_ (address): 0x5956F0d618B8a4F8c5473f3804918E7Fa7f4fA8D
Arg [2] : quoteAddress_ (address): 0x80137510979822322193FC997d400D5A6C747bf7
Arg [3] : quoteDecimals_ (uint256): 18
Arg [4] : ampl_ (uint256): 20
Arg [5] : feeCollector_ (address): 0xdEC17F71Ef579123939ACA1bdfAEeC21eaE00D67
Arg [6] : feeRate_ (uint256): 500000000000000
Arg [7] : adminFeeRate_ (uint256): 200000000000000000
Arg [8] : tradingCurbThreshold_ (uint256): 0
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000b5031d4c4b1bed0756cacad96239c6805d94c14d
Arg [1] : 0000000000000000000000005956f0d618b8a4f8c5473f3804918e7fa7f4fa8d
Arg [2] : 00000000000000000000000080137510979822322193fc997d400d5a6c747bf7
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [5] : 000000000000000000000000dec17f71ef579123939aca1bdfaeec21eae00d67
Arg [6] : 0000000000000000000000000000000000000000000000000001c6bf52634000
Arg [7] : 00000000000000000000000000000000000000000000000002c68af0bb140000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.