Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- sKCS
- Optimization enabled
- true
- Compiler version
- v0.8.4+commit.c7e474f2
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2022-07-19T13:14:39.223566Z
Contract source code
// Sources flattened with hardhat v2.9.3 https://hardhat.org
// File @openzeppelin/contracts-upgradeable/token/ERC20/[email protected]
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from,
address to,
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);
}
// File contracts/interfaces/IERC4626.sol
//
pragma solidity ^0.8.0;
/// @title ERC4626 interface
/// See: https://eips.ethereum.org/EIPS/eip-4626
abstract contract IERC4626 is IERC20Upgradeable {
/*////////////////////////////////////////////////////////
/// Events
////////////////////////////////////////////////////////*/
/// @notice `sender` has exchanged `assets` for `shares`,
/// and transferred those `shares` to `receiver`.
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
/// @notice `sender` has exchanged `shares` for `assets`,
/// and transferred those `assets` to `receiver`.
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
/*////////////////////////////////////////////////////////
/// Vault properties ///
////////////////////////////////////////////////////////*/
/// @notice The address of the underlying ERC20 token used for
/// the Vault for accounting, depositing, and withdrawing.
function asset() external view virtual returns(address _asset);
/// @notice Total amount of the underlying asset that
/// is "managed" by Vault.
function totalAssets() external view virtual returns(uint256 _totalAssets);
/*////////////////////////////////////////////////////////
/// Deposit/Withdrawal Logic
////////////////////////////////////////////////////////*/
/// @notice Mints `shares` Vault shares to `receiver` by
/// depositing exactly `assets` of underlying tokens.
function deposit(uint256 assets, address receiver) external virtual returns(uint256 shares);
/// @notice Mints exactly `shares` Vault shares to `receiver`
/// by depositing `assets` of underlying tokens.
function mint(uint256 shares, address receiver) external virtual returns(uint256 assets);
/// @notice Redeems `shares` from `owner` and sends `assets`
/// of underlying tokens to `receiver`.
function withdraw(uint256 assets, address receiver, address owner) external virtual returns(uint256 shares);
/// @notice Redeems `shares` from `owner` and sends `assets`
/// of underlying tokens to `receiver`.
function redeem(uint256 shares, address receiver, address owner) external virtual returns(uint256 assets);
/*////////////////////////////////////////////////////////
/// Vault Accounting Logic ///
////////////////////////////////////////////////////////*/
/// @notice The amount of shares that the vault would
/// exchange for the amount of assets provided, in an
/// ideal scenario where all the conditions are met.
function convertToShares(uint256 assets) external view virtual returns(uint256 shares);
/// @notice The amount of assets that the vault would
/// exchange for the amount of shares provided, in an
/// ideal scenario where all the conditions are met.
function convertToAssets(uint256 shares) external view virtual returns(uint256 assets);
/// @notice Total number of underlying assets that can
/// be deposited by `owner` into the Vault, where `owner`
/// corresponds to the input parameter `receiver` of a
/// `deposit` call.
function maxDeposit(address owner) external view virtual returns(uint256 maxAssets);
/// @notice Allows an on-chain or off-chain user to simulate
/// the effects of their deposit at the current block, given
/// current on-chain conditions.
function previewDeposit(uint256 assets) external view virtual returns(uint256 shares);
/// @notice Total number of underlying shares that can be minted
/// for `owner`, where `owner` corresponds to the input
/// parameter `receiver` of a `mint` call.
function maxMint(address owner) external view virtual returns(uint256 maxShares);
/// @notice Allows an on-chain or off-chain user to simulate
/// the effects of their mint at the current block, given
/// current on-chain conditions.
function previewMint(uint256 shares) external view virtual returns(uint256 assets);
/// @notice Total number of underlying assets that can be
/// withdrawn from the Vault by `owner`, where `owner`
/// corresponds to the input parameter of a `withdraw` call.
function maxWithdraw(address owner) external view virtual returns(uint256 maxAssets);
/// @notice Allows an on-chain or off-chain user to simulate
/// the effects of their withdrawal at the current block,
/// given current on-chain conditions.
function previewWithdraw(uint256 assets) external view virtual returns(uint256 shares);
/// @notice Total number of underlying shares that can be
/// redeemed from the Vault by `owner`, where `owner` corresponds
/// to the input parameter of a `redeem` call.
function maxRedeem(address owner) external view virtual returns(uint256 maxShares);
/// @notice Allows an on-chain or off-chain user to simulate
/// the effects of their redeemption at the current block,
/// given current on-chain conditions.
function previewRedeem(uint256 shares) external view virtual returns(uint256 assets);
}
// File contracts/interfaces/IsKCS.sol
//
pragma solidity ^0.8.0;
/// @title The facet for "processRedemptionRequests"
abstract contract IsKCSProcessRedemptionRequests {
function processRedemptionRequests() external virtual;
}
/// @title sKCS interface
abstract contract IsKCS is IsKCSProcessRedemptionRequests,IERC4626 {
/// @notice deposit `msg.value` KCS and send sKCS to `receiver`
/// @return The amount of sKCS received by the `receiver`
function depositKCS(address receiver) external payable virtual returns (uint256);
/// @notice If a user wants to redeem KCS from sKCS, she/he must call
/// requestRedemption first, then wait for 3~6 days before calling withdrawKCS.
///
/// @dev If the owner approves some sKCS to "the other", "the other" can call requestRedemption
/// to request redeeming the owner's sKCS. But only "the other" can later call withdrawKCS to
/// withdraw the redeemed KCS.
///
/// @param owner the owner of sKCS
/// @param _sKCSAmount the amount of sKCS to redeem
function requestRedemption(uint256 _sKCSAmount, address owner) external virtual;
/// @notice You cannot redeem your sKCS for KCS instantly.
/// The Redemption contains two separate steps:
///
/// (1) Call requestRedemption to request a redemption.
/// (2) Wait for 3~6 days, and then call withdrawKCS to withdraw the redeemed KCS.
function withdrawKCS(address owner, address receiver) external virtual;
function compound() external virtual;
function addUnderlyingValidator(address _validator, uint256 _weight) external virtual;
function disableUnderlyingValidator(address _validator) external virtual;
function setProtocolFee(uint256 _rate) external virtual;
}
// File @openzeppelin/contracts-upgradeable/utils/structs/[email protected]
// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSetUpgradeable {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
// File @openzeppelin/contracts-upgradeable/utils/math/[email protected]
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMathUpgradeable {
/**
* @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) {
unchecked {
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) {
unchecked {
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) {
unchecked {
// 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) {
unchecked {
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) {
unchecked {
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) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return 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) {
return a * b;
}
/**
* @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.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
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) {
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) {
unchecked {
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.
*
* 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) {
unchecked {
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) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
// File @openzeppelin/contracts-upgradeable/utils/[email protected]
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 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");
(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");
(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");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal 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
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// File @openzeppelin/contracts-upgradeable/proxy/utils/[email protected]
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
* initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() initializer {}
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
// contract may have been reentered.
require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} modifier, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
function _isConstructor() private view returns (bool) {
return !AddressUpgradeable.isContract(address(this));
}
}
// File @openzeppelin/contracts-upgradeable/security/[email protected]
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^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 ReentrancyGuardUpgradeable is Initializable {
// 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;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_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 making 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;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
// File @openzeppelin/contracts-upgradeable/utils/math/[email protected]
// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a / b + (a % b == 0 ? 0 : 1);
}
}
// File @openzeppelin/contracts-upgradeable/utils/[email protected]
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^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 meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
// File @openzeppelin/contracts-upgradeable/access/[email protected]
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_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 {
_transferOwnership(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");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
// File @openzeppelin/contracts-upgradeable/security/[email protected]
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @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);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @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(), "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(), "Pausable: not paused");
_;
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
// File contracts/interfaces/IValidator.sol
//
pragma solidity ^0.8.0;
interface IValidators {
/// @dev calling vote will automatically claim pending rewards
function vote(address _val) external payable;
function pendingReward(address _val, address _user) external view returns (uint256);
function claimReward(address _val) external;
/// @dev calling withdraw will automatically claim pending rewards
function revokeVote(address _val, uint256 _ballots) external;
/// @dev calling withdraw will not automatically claim pending rewards
function withdraw(address _val) external;
function isWithdrawable(address _user, address _val) external view returns (bool);
function isActiveValidator(address _val) external view returns (bool);
}
// File contracts/fifoPool.sol
//
pragma solidity ^0.8.0;
library FifoPool{
/// @dev A fifo implemented with fixed length ring buffer
struct Pool {
address[] _buffer; // the array storing the entries
uint256 _nextWrite; // The index of the next entry to write
uint256 _nextRead; // The index of the next entry to read
}
/// @dev initialize the pool, you can only call this once
function initialize(Pool storage p, uint256 length) internal{
address[] storage buffer = p._buffer;
// FIXME: Gas saving with Yul?
// assembly { sstore(buffer.slot, length) }
for(uint i =0; i< length; i++){
buffer.push(address(0));
}
require(buffer.length == length, "reinitialized");
}
/// @dev the capacity of the pool, i.e, the maximum elements can be
/// stored in the pool
function capacity(Pool storage p) internal view returns(uint256){
return p._buffer.length;
}
/// @dev the number of elements in the pool
function size(Pool storage p) internal view returns(uint256){
return p._nextWrite - p._nextRead;
}
/// @dev Peek the next entry to read if not emtpy
function peek(Pool storage p) internal view returns(address){
require(p._nextRead != p._nextWrite, "empty");
return p._buffer[p._nextRead % p._buffer.length];
}
/// @dev Pop the next entry to read if not empty
function pop(Pool storage p) internal returns(address){
address e = peek(p);
p._nextRead++;
return e;
}
/// @dev Write entry if not full
function add(Pool storage p, address e) internal{
require(p._nextWrite - p._nextRead < p._buffer.length,"full");
p._buffer[p._nextWrite % p._buffer.length] = e;
p._nextWrite++;
}
}
// File contracts/interfaces/IWKCS.sol
//
pragma solidity ^0.8.0;
interface IWKCS {
function deposit() external payable;
function withdraw(uint wad) external;
function totalSupply() external view returns (uint);
function approve(address guy, uint wad) external returns (bool);
function transfer(address dst, uint wad) external returns (bool) ;
function transferFrom(address src, address dst, uint wad) external returns (bool);
}
// File @openzeppelin/contracts-upgradeable/token/ERC20/extensions/[email protected]
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// File @openzeppelin/contracts-upgradeable/token/ERC20/extensions/[email protected]
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
// File @openzeppelin/contracts-upgradeable/token/ERC20/[email protected]
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, _allowances[owner][spender] + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = _allowances[owner][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `sender` to `recipient`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Spend `amount` form the allowance of `owner` toward `spender`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[45] private __gap;
}
// File @openzeppelin/contracts-upgradeable/utils/[email protected]
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
// File @openzeppelin/contracts-upgradeable/utils/cryptography/[email protected]
// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSAUpgradeable {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
// File @openzeppelin/contracts-upgradeable/utils/cryptography/[email protected]
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)
pragma solidity ^0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* _Available since v3.4._
*/
abstract contract EIP712Upgradeable is Initializable {
/* solhint-disable var-name-mixedcase */
bytes32 private _HASHED_NAME;
bytes32 private _HASHED_VERSION;
bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
/* solhint-enable var-name-mixedcase */
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
__EIP712_init_unchained(name, version);
}
function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash());
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev The hash of the name parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712NameHash() internal virtual view returns (bytes32) {
return _HASHED_NAME;
}
/**
* @dev The hash of the version parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712VersionHash() internal virtual view returns (bytes32) {
return _HASHED_VERSION;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
// File @openzeppelin/contracts-upgradeable/utils/[email protected]
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)
pragma solidity ^0.8.0;
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
*/
library CountersUpgradeable {
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
// File @openzeppelin/contracts-upgradeable/token/ERC20/extensions/[email protected]
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* _Available since v3.4._
*/
abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20PermitUpgradeable, EIP712Upgradeable {
using CountersUpgradeable for CountersUpgradeable.Counter;
mapping(address => CountersUpgradeable.Counter) private _nonces;
// solhint-disable-next-line var-name-mixedcase
bytes32 private _PERMIT_TYPEHASH;
/**
* @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
*
* It's a good idea to use the same `name` that is defined as the ERC20 token name.
*/
function __ERC20Permit_init(string memory name) internal onlyInitializing {
__EIP712_init_unchained(name, "1");
__ERC20Permit_init_unchained(name);
}
function __ERC20Permit_init_unchained(string memory) internal onlyInitializing {
_PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");}
/**
* @dev See {IERC20Permit-permit}.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSAUpgradeable.recover(hash, v, r, s);
require(signer == owner, "ERC20Permit: invalid signature");
_approve(owner, spender, value);
}
/**
* @dev See {IERC20Permit-nonces}.
*/
function nonces(address owner) public view virtual override returns (uint256) {
return _nonces[owner].current();
}
/**
* @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view override returns (bytes32) {
return _domainSeparatorV4();
}
/**
* @dev "Consume a nonce": return the current value and increment.
*
* _Available since v4.1._
*/
function _useNonce(address owner) internal virtual returns (uint256 current) {
CountersUpgradeable.Counter storage nonce = _nonces[owner];
current = nonce.current();
nonce.increment();
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
// File @openzeppelin/contracts-upgradeable/governance/utils/[email protected]
// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.0;
/**
* @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
*
* _Available since v4.5._
*/
interface IVotesUpgradeable {
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/**
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
/**
* @dev Returns the current amount of votes that `account` has.
*/
function getVotes(address account) external view returns (uint256);
/**
* @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
*/
function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
/**
* @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
*
* NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*/
function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
/**
* @dev Returns the delegate that `account` has chosen.
*/
function delegates(address account) external view returns (address);
/**
* @dev Delegates votes from the sender to `delegatee`.
*/
function delegate(address delegatee) external;
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
// File @openzeppelin/contracts-upgradeable/utils/math/[email protected]
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such 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.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCastUpgradeable {
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128) {
require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
return int128(value);
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64) {
require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
return int64(value);
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32) {
require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
return int32(value);
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16) {
require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
return int16(value);
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8) {
require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
return int8(value);
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
// File @openzeppelin/contracts-upgradeable/token/ERC20/extensions/[email protected]
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Votes.sol)
pragma solidity ^0.8.0;
/**
* @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,
* and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.
*
* NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.
*
* This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either
* by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting
* power can be queried through the public accessors {getVotes} and {getPastVotes}.
*
* By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it
* requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.
*
* _Available since v4.2._
*/
abstract contract ERC20VotesUpgradeable is Initializable, IVotesUpgradeable, ERC20PermitUpgradeable {
function __ERC20Votes_init() internal onlyInitializing {
}
function __ERC20Votes_init_unchained() internal onlyInitializing {
}
struct Checkpoint {
uint32 fromBlock;
uint224 votes;
}
bytes32 private constant _DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
mapping(address => address) private _delegates;
mapping(address => Checkpoint[]) private _checkpoints;
Checkpoint[] private _totalSupplyCheckpoints;
/**
* @dev Get the `pos`-th checkpoint for `account`.
*/
function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
return _checkpoints[account][pos];
}
/**
* @dev Get number of checkpoints for `account`.
*/
function numCheckpoints(address account) public view virtual returns (uint32) {
return SafeCastUpgradeable.toUint32(_checkpoints[account].length);
}
/**
* @dev Get the address `account` is currently delegating to.
*/
function delegates(address account) public view virtual override returns (address) {
return _delegates[account];
}
/**
* @dev Gets the current votes balance for `account`
*/
function getVotes(address account) public view virtual override returns (uint256) {
uint256 pos = _checkpoints[account].length;
return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
}
/**
* @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
*
* Requirements:
*
* - `blockNumber` must have been already mined
*/
function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
require(blockNumber < block.number, "ERC20Votes: block not yet mined");
return _checkpointsLookup(_checkpoints[account], blockNumber);
}
/**
* @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
* It is but NOT the sum of all the delegated votes!
*
* Requirements:
*
* - `blockNumber` must have been already mined
*/
function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
require(blockNumber < block.number, "ERC20Votes: block not yet mined");
return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
}
/**
* @dev Lookup a value in a list of (sorted) checkpoints.
*/
function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
// We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
//
// During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
// With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
// - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
// - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
// Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
// out of bounds (in which case we're looking too far in the past and the result is 0).
// Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
// past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
// the same.
uint256 high = ckpts.length;
uint256 low = 0;
while (low < high) {
uint256 mid = MathUpgradeable.average(low, high);
if (ckpts[mid].fromBlock > blockNumber) {
high = mid;
} else {
low = mid + 1;
}
}
return high == 0 ? 0 : ckpts[high - 1].votes;
}
/**
* @dev Delegate votes from the sender to `delegatee`.
*/
function delegate(address delegatee) public virtual override {
_delegate(_msgSender(), delegatee);
}
/**
* @dev Delegates votes from signer to `delegatee`
*/
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= expiry, "ERC20Votes: signature expired");
address signer = ECDSAUpgradeable.recover(
_hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
v,
r,
s
);
require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
_delegate(signer, delegatee);
}
/**
* @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
*/
function _maxSupply() internal view virtual returns (uint224) {
return type(uint224).max;
}
/**
* @dev Snapshots the totalSupply after it has been increased.
*/
function _mint(address account, uint256 amount) internal virtual override {
super._mint(account, amount);
require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
_writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
}
/**
* @dev Snapshots the totalSupply after it has been decreased.
*/
function _burn(address account, uint256 amount) internal virtual override {
super._burn(account, amount);
_writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
}
/**
* @dev Move voting power when tokens are transferred.
*
* Emits a {DelegateVotesChanged} event.
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual override {
super._afterTokenTransfer(from, to, amount);
_moveVotingPower(delegates(from), delegates(to), amount);
}
/**
* @dev Change delegation for `delegator` to `delegatee`.
*
* Emits events {DelegateChanged} and {DelegateVotesChanged}.
*/
function _delegate(address delegator, address delegatee) internal virtual {
address currentDelegate = delegates(delegator);
uint256 delegatorBalance = balanceOf(delegator);
_delegates[delegator] = delegatee;
emit DelegateChanged(delegator, currentDelegate, delegatee);
_moveVotingPower(currentDelegate, delegatee, delegatorBalance);
}
function _moveVotingPower(
address src,
address dst,
uint256 amount
) private {
if (src != dst && amount > 0) {
if (src != address(0)) {
(uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
emit DelegateVotesChanged(src, oldWeight, newWeight);
}
if (dst != address(0)) {
(uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
emit DelegateVotesChanged(dst, oldWeight, newWeight);
}
}
}
function _writeCheckpoint(
Checkpoint[] storage ckpts,
function(uint256, uint256) view returns (uint256) op,
uint256 delta
) private returns (uint256 oldWeight, uint256 newWeight) {
uint256 pos = ckpts.length;
oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;
newWeight = op(oldWeight, delta);
if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {
ckpts[pos - 1].votes = SafeCastUpgradeable.toUint224(newWeight);
} else {
ckpts.push(Checkpoint({fromBlock: SafeCastUpgradeable.toUint32(block.number), votes: SafeCastUpgradeable.toUint224(newWeight)}));
}
}
function _add(uint256 a, uint256 b) private pure returns (uint256) {
return a + b;
}
function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
return a - b;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[47] private __gap;
}
// File contracts/sKCSBase.sol
//
pragma solidity ^0.8.0;
/// @dev SKCSBase inherits OZ contracts and includes all the storage variables.
/// SKCSBase also includes some common internal methods shared by different facets.
contract SKCSBase is ReentrancyGuardUpgradeable,OwnableUpgradeable,PausableUpgradeable,ERC20VotesUpgradeable {
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
/// Maximum protocol fee: 20%
uint256 public constant MAX_PROTOCOL_FEE = 2000;
uint256 public constant VOTE_UNIT = 1e18;
/// @notice the maximum number of underlying validators
uint256 public constant MAX_NUM_VALIDATORS = 29;
// Wrapped KCS
IWKCS public WKCS;
// KCC Staking Contract Address
IValidators public VALIDATOR_CONTRACT; // solhint-disable var-name-mixedcase
/// @notice
/// @dev Any validator that is enabled is either in the _redeemingPool or in the _availablePool:
///
/// Whenever we want to redeem from KCC Staking, we will take a validator from the _availablePool to
/// handle the redemption (revokeVote from KCC Staking), and then we will move this validator to the _redeemingPool.
/// After the locking period is over, we will withdraw the redeemed KCS from this validator, and then it will be
/// put back into the _availablePool.
///
struct ValidatorInfo {
address val; /// @dev the address of the validator
uint256 weight;
uint256 stakedKCS; /// staked KCS amount in wei
/// The amount of KCS that is actually being redeemed from this validator (wei)
/// Due to the restrictions by KCC staking , this must be an integer multiple of 1 ether.
uint256 actualRedeeming;
/// The amount of KCS that is expected to be redeemed from this validator (wei)
/// This can be any amount, but it must be less than or equal to actualRedeeming.
uint256 userRedeeming;
uint256 lastRedemptionTime;
/// When we move this validator from _redeemingPool into _availablePool,
/// all the redemption requests with ID < nextWithdrawingID are withdrawable.
uint256 nextWithdrawingID;
}
// Validator Pools
// Any validator that is enabled is either in the _redeemingPool or in the _availablePool.
FifoPool.Pool internal _redeemingPool;
EnumerableSetUpgradeable.AddressSet internal _availablePool;
// _disablingPool contains the validators that are being disabled
EnumerableSetUpgradeable.AddressSet internal _disablingPool;
// The address of all active validators
address[] public activeValidators;
// The detailed info of each validator
mapping(address => ValidatorInfo) internal _validators;
/// @notice The request for redeeming sKCS
struct RedemptionRequest {
address requester;
uint256 amountSKCS; // input sKCS amount
uint256 amountKCS; // ouput KCS amount
uint256 timestamp;
/// When we call processRedemptionRequests to process redemption requests,
/// we may not be able to process all the requests in the RedemptionRequestBox at once.
/// In such cases, some requests may be partially processed.
/// partiallyRedeemedKCS is the amount of KCS in the request has been partially processed.
uint256 partiallyRedeemedKCS;
/// If the ID of this RedemptionRequest is X, accAmountKCSBefore is the total amount of redeemed KCS
/// from all the previous RedemptionRequests in RedemptionRequestBox with an ID ∈ [0,X).
uint256 accAmountKCSBefore;
}
/// @dev The RedemptionRequestBox contains all historical RedemptionRequests
struct RedemptionRequestBox {
/// All RedemptionRequests
mapping(uint256 => RedemptionRequest) requests;
/// @dev redeemingID is the ID of the next RedemptionRequest to process.
/// All the RedemptionRequest with an ID less than redeemingID have been processed.
/// Notice: After a RedemptionRequest has been processed, you will need to wait
/// for 3 days before the RedemptionRequest become withdrawable.
uint256 redeemingID;
/// @dev withdrawingID can be viewed as the next ID of the RedemptionRequest which will become withrawable.
/// And all the RedemptionRequest with an ID less than withdrawingID are withrawable.
uint256 withdrawingID;
uint256 length;
/// @dev The total amount of redeemed KCS from all the previous RedemptionRequests.
/// (i.e All the RedemptionRequests with an ID ∈ [0,RedemptionRequestBox.length) )
uint256 accAmountKCS;
}
RedemptionRequestBox public redemptionRequestBox;
/// @dev The info of the pending redemptions
struct PendingRedemptions {
/// @dev The pending Request IDs (may contain withdrawable request)
EnumerableSetUpgradeable.UintSet pendingIDs;
}
/// @dev You cannot redeem your sKCS for KCS instantly. The Redemption contains two separate steps:
/// (1) Call requestRedemption to request a redemption.
/// (2) Wait for 3~6 days and call withdrawKCS to withdraw the redeemed KCS.
///
/// After a user request a redemption, the ID of the RedemptionRequest will be put into _pendingRedemptions.
///
/// (1) If the owner of sKCS calls requestRedemption from his own address, the ID will be put into
/// _pendingRedemptions[owner][owner].pendingIDs . And only owner can withdraw the redeemded KCS later.
//
/// (2) If the owner approves some sKCS to other, and the other calls requestRedemption, the ID will be
/// put into _pendingRedemption[owner][other].pendingIDs . And only other can withdraw the redeemed KCS later.
mapping(address => mapping(address => PendingRedemptions)) internal _pendingRedemptions;
/// @notice accumulatedStakedKCSAmount is the accumulative amount of KCS deposited.
uint256 public accumulatedStakedKCSAmount;
/// @notice accumulatedRewardKCSAmount is the accumulative rewards without pending rewards from KCC Staking.
uint256 public accumulatedRewardKCSAmount;
/// @notice Number of sKCS holders
uint256 public numberOfHolders;
/// @notice The timestamp of last redemption from KCC staking
uint256 public timelastRedemptionFromKCCStaking;
/// @notice protocol-wide parameters
struct ProtocolParameters {
/// @notice unit is 1/10000
uint256 protocolFee;
/// @notice Minimum amount of KCS staked to KCC staking each time
uint256 minStakingKCSAmount;
/// @notice The maximum number of pending redemption requests of a user
uint256 maximumPendingRedemptionRequestPerUser;
/// @notice The minimum interval between redeeming from KCC staking if there is only 1 validator
uint256 minIntervalRedeemFromKCCStakingSingleValidator;
/// @notice The sum of weights of all the enabled validators.
uint256 sumOfWeight;
}
ProtocolParameters public protocolParams;
struct KCSBalance{
/// @notice The amount of KCS that should be staked to
/// KCC staking but not yet.
uint256 buffer;
/// @notice The amount of KCS can be withdrawn by users
/// who previously requested redemptions.
uint256 debt;
/// @notice protocol fee
uint256 fee;
}
KCSBalance public kcsBalances;
// Diamond pattern facets
// each facet implements part of sKCS
IsKCSProcessRedemptionRequests internal _processRedemptionFacet;
// events
event Compound(address sender, uint256 timestamp, uint256 claimAmount);
event NewRequestRedemption(address indexed owner, address indexed receiver, uint256 indexed id, uint256 amountsKCS, uint256 amountKCS);
event RedeemFromBufferOnly(uint256 indexed preRedeemingID, uint256 indexed newRedeemingID, uint256 indexed blocknumber,uint256 amount);
event RedeemFromBufferAndKCCStaking(uint256 indexed preRedeemingID, uint256 indexed newRedeemingID, uint256 indexed blocknumber,uint256 amount);
event AddValidator(address sender, address validator, uint256 weight);
event DisablingValidator(address sender, address validator);
event UpdateWeightOfValidator(address sender, address validator, uint256 weight);
event ClaimPendingRewards(address sender, uint256 height, uint256 amount);
event SetProtocolFeeRate(address sender, uint256 rate);
event ClaimProtocolFee(address sender, uint256 indexed height, uint256 amount);
event Receive(address sender, uint256 amount);
//
// methods shared by multiple facets
//
/// @dev withdraw KCS from KCC staking
/// @return amount
function _withdrawKCSFromKCCStaking(address val) internal returns (uint256 amount){
uint256 preBalance = address(this).balance;
VALIDATOR_CONTRACT.withdraw(val);
return address(this).balance - preBalance;
}
/// @notice claims all pending rewards
/// @return amount of rewards
function _claimAllPendingRewards() internal returns(uint256) {
uint256 amount;
for (uint8 i = 0; i < activeValidators.length; i++) {
amount += _claimPendingRewards(_validators[activeValidators[i]].val);
}
emit ClaimPendingRewards(msg.sender, block.number, amount);
return amount;
}
function _claimPendingRewards(address _val) internal returns (uint256) {
require(_val != address(0), "invalid address");
uint256 before = address(this).balance;
// @audit Fix Item 4: Unchecked pendingReward before claiming rewards
uint256 pending = VALIDATOR_CONTRACT.pendingReward(_val, address(this));
if (pending == 0) {
return 0;
}
VALIDATOR_CONTRACT.claimReward(_val);
uint256 amount = address(this).balance - before;
accumulatedRewardKCSAmount += amount;
(uint256 fee, uint256 leftAmount) = _calculateProtocolFee(amount);
kcsBalances.fee += fee;
return leftAmount;
}
/// @notice Calculate protocol fees
function _calculateProtocolFee(uint256 totalAmount) internal view returns(uint256 feeAmount, uint256 leftAmount) {
if(totalAmount == 0){
return (0,0);
}
// @audit Fix Item 2: Continuous division
feeAmount = totalAmount * 1e12 * protocolParams.protocolFee / (10000 * 1e12);
leftAmount = totalAmount - feeAmount;
}
function _calculatePendingRewards() internal view returns (uint256 ) {
uint256 total;
for (uint8 i = 0; i < activeValidators.length; i++) {
total += VALIDATOR_CONTRACT.pendingReward(_validators[activeValidators[i]].val, address(this));
}
return total;
}
/// @return staked The total amount of KCS staked in validators
/// @return pendingRewards The total amount of pending rewards from all validators
/// @return residual If we are redeeming from a validator, the actualRedeeming amount will always be
/// greater than or equal to the userRedeeming. The difference between actualRedeeming and userRedeeming
/// is the residual, and it will be put into the buffer later.
function _totalAmountOfValidators() internal view returns (uint256 staked, uint256 pendingRewards, uint256 residual) {
for (uint8 i = 0; i < activeValidators.length; i++) {
address val = activeValidators[i];
// @audit Item 3: Unhandled staked amount
staked += _validators[val].stakedKCS;
residual += (_validators[val].actualRedeeming - _validators[val].userRedeeming);
pendingRewards += VALIDATOR_CONTRACT.pendingReward(_validators[activeValidators[i]].val, address(this));
}
// @audit Item 3: Unhandled staked amount
for (uint8 i = 0; i < _disablingPool.length(); i++) {
address val = _disablingPool.at(i);
// @audit: gas saving
//
// _validators[val].stakedKCS == 0
// _validators[val].userRedeeming ==
//
// staked += _validators[val].stakedKCS;
// residual += (_validators[val].actualRedeeming - _validators[val].userRedeeming);
residual += _validators[val].actualRedeeming;
}
}
/// @notice getAccumulatedRewardKCSAmount returns the accumulative rewards from KCC Staking.
function getAccumulatedRewardKCSAmount() external view returns (uint256) {
return accumulatedRewardKCSAmount + _calculatePendingRewards();
}
// function getRedeemingPoolInfo() external view returns (FifoPool.Pool memory) {
// return _redeemingPool;
// }
function getAvailablePoolInfo(address _val) external view returns (bool exist, uint256 len) {
exist = _availablePool.contains(_val);
len = _availablePool.length();
}
function getDisablingPoolInfo(address _val) external view returns (bool exist, uint256 len) {
exist = _disablingPool.contains(_val);
len = _disablingPool.length();
}
}
// File contracts/sKCS.sol
//
pragma solidity ^0.8.0;
/// @title sKCS
contract sKCS is IsKCS,SKCSBase {
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.UintSet;
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
/// @dev the initializer
/// @param wkcs the address of warpped KCS
function initialize(address wkcs,
address validatorContract,
address processRedemptionFacet,
uint protocolFee,
uint minStakingKCSAmount,
uint maximumPendingRedemptionRequestPerUser,
address admin) external initializer{
__Ownable_init();
__ReentrancyGuard_init();
__Pausable_init();
__ERC20_init("Staked KCS","sKCS");
__ERC20Permit_init("Staked KCS");
__ERC20Votes_init();
FifoPool.initialize(_redeemingPool, MAX_NUM_VALIDATORS);
require(FifoPool.capacity(_redeemingPool) == MAX_NUM_VALIDATORS, "invalid capacity");
WKCS = IWKCS(wkcs);
VALIDATOR_CONTRACT = IValidators(validatorContract);
protocolParams.protocolFee = protocolFee;
protocolParams.minStakingKCSAmount = minStakingKCSAmount;
protocolParams.maximumPendingRedemptionRequestPerUser = maximumPendingRedemptionRequestPerUser;
protocolParams.minIntervalRedeemFromKCCStakingSingleValidator = 3 days;
transferOwnership(admin);
// facets
_processRedemptionFacet = IsKCSProcessRedemptionRequests(processRedemptionFacet);
}
function pause() external onlyOwner{
_pause();
}
function unpause() external onlyOwner{
_unpause();
}
/// @notice deposit `msg.value` KCS and send sKCS to `receiver`
/// @dev It will staking to a specified validator by weight, when there are lots of validator.
/// @return The amount of sKCS received by the `receiver`
function depositKCS(address receiver)
external
payable
override
returns (uint256) {
require(receiver != address(0), "invalid address");
require(msg.value > 0, "invalid amount");
(uint256 num, uint256 dem) = exchangeRate();
// @audit Fix Item-1: Wrong calculation over user shares
uint256 shares = msg.value * dem / num;
_depositKCS(receiver, msg.value, shares);
return shares;
}
function _depositKCS(address receiver, uint256 amount, uint256 shares) internal nonReentrant whenNotPaused{
kcsBalances.buffer += amount;
accumulatedStakedKCSAmount += amount;
_tryStake();
// @dev mint sKCS
_mint(receiver,shares);
emit Deposit(msg.sender, receiver, amount, shares);
}
/// @inheritdoc IsKCS
function requestRedemption(uint256 _shares, address owner) external nonReentrant whenNotPaused override {
require(_shares > 0, "Redemption: 0 shares");
// If the gas cost of "withdrawKCS" is more than the block gas limit, the user's funds
// will get stuck forever. We avoid this by limiting the maximum number of
// pending redemption requests of a user.
EnumerableSetUpgradeable.UintSet storage userPendingIDs = _pendingRedemptions[owner][msg.sender].pendingIDs;
require(userPendingIDs.length() < protocolParams.maximumPendingRedemptionRequestPerUser, "Redemption: too many pending");
if (msg.sender != owner){
_spendAllowance(owner, msg.sender, _shares);
}
(uint256 num, uint256 dem) = exchangeRate();
uint256 amountKCS = _shares * num / dem;
// This will Possibly Change the number of holders
_burn(owner, _shares);
// Add a new Redemption Request to the RedemptionRequestBox.
uint256 id = redemptionRequestBox.length;
// Build the redemption request
RedemptionRequest storage request = redemptionRequestBox.requests[id];
request.requester = msg.sender;
request.amountSKCS = _shares;
request.amountKCS = amountKCS;
request.timestamp = block.timestamp;
request.accAmountKCSBefore = redemptionRequestBox.accAmountKCS;
// update RedemptionRequestBox
redemptionRequestBox.accAmountKCS += request.amountKCS;
redemptionRequestBox.length += 1;
// Bookkeeping user's pending ID
userPendingIDs.add(id);
emit NewRequestRedemption(owner, msg.sender, id, _shares, amountKCS);
}
/// @inheritdoc IsKCS
function withdrawKCS(address owner, address receiver) external override {
_withdrawKCS(msg.sender, owner, receiver, false);
}
function processRedemptionRequests() external override{
address imp = address(_processRedemptionFacet);
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize())
let result := delegatecall(gas(),imp, ptr, calldatasize(), 0, 0)
let size := returndatasize()
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
/// @dev other has requested redeeming owner's sKCS, and now other is withdrawing
/// the previously redeemed KCS and the redeemed KCS will be sent to the receiver
function _withdrawKCS(address other, address owner, address receiver, bool wrapKCS) internal nonReentrant whenNotPaused {
EnumerableSetUpgradeable.UintSet storage pendingIDs = _pendingRedemptions[owner][other].pendingIDs;
RedemptionRequestBox storage box = redemptionRequestBox;
uint256 amountToWithdraw = 0 ;
uint256 amountSKCS = 0;
for(uint i=0; i < pendingIDs.length();){
uint256 id = pendingIDs.at(i);
if (id < box.withdrawingID){
RedemptionRequest storage r = box.requests[id];
amountToWithdraw += r.amountKCS;
amountSKCS += r.amountSKCS;
// remove ID
pendingIDs.remove(id);
// After removing "id" from pendingIDs,
// pendingIDs.at(i) will change.
// We need to check pendingIDs.at(i) again in the next loop.
continue;
}
i++;
}
kcsBalances.debt -= amountToWithdraw;
if(!wrapKCS){
AddressUpgradeable.sendValue(payable(receiver), amountToWithdraw);
}else{
WKCS.deposit{value: amountToWithdraw}();
require(WKCS.transfer(receiver, amountToWithdraw), "E5");
}
emit Withdraw(other, receiver, owner, amountToWithdraw, amountSKCS);
}
function compound() external nonReentrant whenNotPaused override {
_compound();
}
function _compound() internal {
_tryRemoveDisabledValidator();
(,uint256 pendingRewards) = _calculateProtocolFee(_calculatePendingRewards());
// staking to KCC Staking when the balance of protocol reaches the minStakingKCSAmount
if (kcsBalances.buffer + pendingRewards < protocolParams.minStakingKCSAmount) {
return;
}
uint256 rewards = _claimAllPendingRewards();
kcsBalances.buffer += rewards;
accumulatedStakedKCSAmount += rewards;
_tryStake();
emit Compound(msg.sender, block.timestamp, rewards);
}
/// @param _weight is the weight of validator, _weight ∈ (0, 100]
function addUnderlyingValidator(address _val, uint256 _weight) external onlyOwner override {
// @audit Fix Item 5: Unchecked validator
require(VALIDATOR_CONTRACT.isActiveValidator(_val), "active validator only");
require(_val != address(0), "invalid address");
require(_weight > 0 && _weight <= 100, "invalid weight");
require(activeValidators.length < MAX_NUM_VALIDATORS,"too many validators");
if (_validators[_val].val == address(0)) {
_validators[_val] = ValidatorInfo(_val, _weight, 0, 0, 0, 0, 0);
_availablePool.add(_val);
activeValidators.push(_val);
protocolParams.sumOfWeight += _weight;
emit AddValidator(msg.sender, _val, _weight);
}
}
/// @notice Disable a underlying validator
/// @dev It can be removed when the validator was in _availablePool.
function disableUnderlyingValidator(address _val) external onlyOwner override {
// It can't to be removed if there ware only one validator
require(activeValidators.length > 1, "not enough validator!");
require(_val != address(0), "invalid address");
if (_availablePool.contains(_val)) {
_availablePool.remove(_val);
kcsBalances.buffer += _claimPendingRewards(_val);
if(_validators[_val].stakedKCS > 0 ){
VALIDATOR_CONTRACT.revokeVote(_val, (_validators[_val].stakedKCS / VOTE_UNIT));
// @audit Fix Item 3: Unhandled staked amount
_validators[_val].actualRedeeming = _validators[_val].stakedKCS;
_validators[_val].userRedeeming = 0;
_validators[_val].stakedKCS = 0;
}
_disablingPool.add(_val);
_removeActiveValidator(_val);
emit DisablingValidator(msg.sender, _val);
}
}
function _removeActiveValidator(address _val) internal returns (bool) {
for (uint8 i = 0; i < activeValidators.length; i++) {
if (activeValidators[i] == _val) {
activeValidators[i] = activeValidators[activeValidators.length - 1];
activeValidators.pop();
return true;
}
}
// it will return true when the validator is not in activeValidators array
return true;
}
function updateWeightOfValidator(address _val, uint256 _weight) external onlyOwner {
require(_val != address(0), "invalid address");
require(_weight > 0 && _weight <= 100, "invalid weight");
ValidatorInfo storage valInfo = _validators[_val];
if (valInfo.val != address(0)) {
protocolParams.sumOfWeight -= valInfo.weight;
valInfo.weight = _weight;
protocolParams.sumOfWeight += valInfo.weight;
emit UpdateWeightOfValidator(msg.sender, _val, _weight);
}
}
/// @dev withdraw the KCS and add to the buffer when the locking period of the validator in the _disablingPool has expired.
function _tryRemoveDisabledValidator() internal {
for (uint8 i = 0; i < _disablingPool.length(); ) {
address val = _disablingPool.at(i);
if (VALIDATOR_CONTRACT.isWithdrawable(address(this), val)) {
uint256 amount = _withdrawKCSFromKCCStaking(val);
protocolParams.sumOfWeight -= _validators[val].weight;
_validators[val] = ValidatorInfo(address(0), 0, 0, 0, 0, 0, 0);
kcsBalances.buffer += amount;
_disablingPool.remove(val);
// @audit Fix Item 3: Unhandled staked amount
// checker actualRedeeming rather than stakedKCS
} else if (_validators[val].actualRedeeming == 0){
protocolParams.sumOfWeight -= _validators[val].weight;
// @audit Fix Item 6: Permanently disabled validator
_validators[val] = ValidatorInfo(address(0), 0, 0, 0, 0, 0, 0);
_disablingPool.remove(val);
}else{
i++;
}
}
}
function setProtocolFee(uint256 _rate) external onlyOwner override {
require(_rate > 0 && _rate <= MAX_PROTOCOL_FEE, "invalid rate");
require(_rate != protocolParams.protocolFee, "not changed");
protocolParams.protocolFee = _rate;
emit SetProtocolFeeRate(msg.sender, _rate);
}
/// @notice claim protocol fee
function claimProtocolFee(uint256 amount) external nonReentrant onlyOwner {
require(amount < kcsBalances.fee && amount > 0 , "invalid amount to claim");
kcsBalances.fee -= amount;
AddressUpgradeable.sendValue(payable(msg.sender), amount);
emit ClaimProtocolFee(msg.sender, block.number, amount);
}
///
/// Read only methods
///
/// @notice exchange rate of from KCS to sKCS
/// @return num is the amount of total KCS in protocol
/// @return dem is the total supply of sKCS
function exchangeRate() public view returns(uint256 num, uint256 dem) {
if (totalSupply() == 0) {
// initialize exchange rate
return (1,1);
}
uint256 total;
uint256 staked;
uint256 pendingRewards;
uint256 residual;
// all staked KCS and all yielded pending rewards
(staked, pendingRewards,residual) = _totalAmountOfValidators();
total += staked;
total += kcsBalances.buffer;
total += residual; // @audit Item 3: Unhandled staked amount
// rewards with fee excluded.
(,uint256 rewardsExcludingFee) = _calculateProtocolFee(pendingRewards);
total += rewardsExcludingFee;
uint256 boxRedeemingID = redemptionRequestBox.redeemingID;
if (redemptionRequestBox.length > boxRedeemingID) {
// the amount of KCS of all requested redemption
uint256 totalRedeemingAmount = redemptionRequestBox.accAmountKCS
- redemptionRequestBox.requests[boxRedeemingID].accAmountKCSBefore
- redemptionRequestBox.requests[boxRedeemingID].partiallyRedeemedKCS;
total -= totalRedeemingAmount;
}
return (total, totalSupply());
}
// internal function
/// @dev Try to staking when kcsBalances.buffer greater than protocolParams.minStakingKCSAmount
function _tryStake() internal {
if(kcsBalances.buffer < protocolParams.minStakingKCSAmount){
return;
}
// pick a validator to staking
address validator = _getValidatorForStaking();
if(validator == address(0)){ // There is no available validator temporarily
return;
}
// Claim pending rewards before voting for the validator
//
// Warning: If there are pending rewards from the validator,
// calling "vote" will automatically claim the pending rewards
// and will result in wrong kcsBalances.buffer.
//
kcsBalances.buffer += _claimPendingRewards(validator);
// processing to integer
uint256 amount = kcsBalances.buffer / VOTE_UNIT;
uint256 staked = amount * VOTE_UNIT;
kcsBalances.buffer -= staked;
_validators[validator].stakedKCS += staked;
VALIDATOR_CONTRACT.vote{value: staked}(validator);
}
/// @notice Get a validator for staking by weight.
function _getValidatorForStaking() internal view returns (address) {
(uint totalStaked, ,) = _totalAmountOfValidators();
// If no KCS has been staked to any of the validators,
// simply pick the first validator.
if (totalStaked== 0) {
return activeValidators.length == 0? address(0) : activeValidators[0];
}
int256 minWeight = type(int256).max;
address available;
for (uint8 i = 0; i < activeValidators.length; i++) {
ValidatorInfo storage info = _validators[activeValidators[i]];
int256 pri = int256((info.stakedKCS * 1e9 / totalStaked)) - int256(info.weight * 1e9 / protocolParams.sumOfWeight);
if (pri <= minWeight) {
minWeight = pri;
available = activeValidators[i];
}
}
return available;
}
/// @notice You cannot redeem your sKCS for KCS instantly.
/// The Redemption includes two separate steps:
///
/// (1) Call requestRedemption to request a redemption.
/// (2) Wait for 3~6 days, then call withdrawKCS to withdraw the redeemed KCS.
///
/// This function returns the amount of KCS (assets) can be withdrawn by msg.sender, and
/// the amount of KCS (assets) is corresponding to the amounts in previous redemption requests
/// sent by msg.sender for redeeming the owner's sKCS.
function withdrawable(address owner) public view returns (uint256 assets, uint256 shares){
EnumerableSetUpgradeable.UintSet storage pendingIDs = _pendingRedemptions[owner][msg.sender].pendingIDs;
RedemptionRequestBox storage box = redemptionRequestBox;
for(uint i=0; i < pendingIDs.length(); i++){
uint256 id = pendingIDs.at(i);
if (id < box.withdrawingID){
RedemptionRequest storage r = box.requests[id];
assets += r.amountKCS;
shares += r.amountSKCS;
}
}
}
/// @notice You cannot redeem your sKCS for KCS instantly.
/// The Redemption includes two separate steps:
///
/// (1) Call requestRedemption to request a redemption.
/// (2) Wait for 3~6 days, then call withdrawKCS to withdraw the redeemed KCS.
///
/// This function returns the amount of KCS (assets) that is not yet withdrawable, which
/// has been requested in previous redemption requests sent from msg.sender for
/// redeeming the owner's sKCS,
///
///
function notWithdrawable(address owner) public view returns (uint256 assets, uint256 shares){
EnumerableSetUpgradeable.UintSet storage pendingIDs = _pendingRedemptions[owner][msg.sender].pendingIDs;
RedemptionRequestBox storage box = redemptionRequestBox;
for(uint i=0; i < pendingIDs.length(); i++){
uint256 id = pendingIDs.at(i);
if (id >= box.withdrawingID){
RedemptionRequest storage r = box.requests[id];
assets += r.amountKCS;
shares += r.amountSKCS;
}
}
}
//
// Before & After transfer hooks
//
/// @dev We use _beforeTokenTransfer & _afterTokenTransfer to manage numberOfHolders
function _beforeTokenTransfer(address from, address to, uint256 amount) internal override{
super._beforeTokenTransfer(from,to,amount);
numberOfHolders -= ((balanceOf(from) != 0 ? 1: 0) + (balanceOf(to) != 0 ? 1: 0));
}
/// @dev We use _beforeTokenTransfer & _afterTokenTransfer to manage numberOfHolders
function _afterTokenTransfer(address from, address to, uint256 amount) internal override{
super._afterTokenTransfer(from,to,amount);
numberOfHolders += ((balanceOf(from) != 0 ? 1: 0) + (balanceOf(to) != 0 ? 1: 0));
}
//
// fall back function
//
receive() external payable {
// @audit Fix Item 7: Implement receive logic
require(AddressUpgradeable.isContract(msg.sender), "only contract");
emit Receive(msg.sender, msg.value);
}
//
// Other Read-only Methods
//
function getValidatorInfo(address _val) external view returns (ValidatorInfo memory) {
return _validators[_val];
}
function getRedemptionRequest(uint256 id) external view returns(RedemptionRequest memory){
require(id < redemptionRequestBox.length,"no such id");
return redemptionRequestBox.requests[id];
}
function isActiveValidator(address _val) external view returns (bool) {
for (uint8 i = 0; i < activeValidators.length; i++) {
if (activeValidators[i] == _val) {
return true;
}
}
return false;
}
function getActiveValidators() external view returns (address[] memory) {
return activeValidators;
}
/*////////////////////////////////////////////////////////
// The following methods Implement ERC4626
////////////////////////////////////////////////////////*/
/// @inheritdoc IERC4626
/// @notice The address of the underlying ERC20 token used for
/// the Vault for accounting, depositing, and withdrawing.
function asset() external view override returns(address _asset){
return address(WKCS);
}
/// @inheritdoc IERC4626
function totalAssets() external view override returns(uint256 _totalAssets) {
(_totalAssets, ) = exchangeRate();
if (totalSupply() == 0) {
_totalAssets = 0;
}
}
/// @inheritdoc IERC4626
/// @notice Mints `shares` Vault shares to `receiver` by
/// depositing exactly `assets` of underlying tokens.
function deposit(uint256 assets, address receiver) external override returns(uint256 shares) {
// transfer WKCS from owner to sKCS Contract.
require(WKCS.transferFrom(msg.sender, address(this), assets),"E11");
// withdraw KCS from WKCS contract
WKCS.withdraw(assets);
// calculate shares to mint
(uint256 num, uint256 dem) = exchangeRate();
// @audit Fix Item-1: Wrong calculation over user shares
shares = assets * dem / num;
_depositKCS(receiver, assets, shares);
}
/// @inheritdoc IERC4626
/// @notice Mints exactly `shares` Vault shares to `receiver`
/// by depositing `assets` of underlying tokens.
function mint(uint256 shares, address receiver) external override returns(uint256 assets) {
(uint256 num, uint256 dem) = exchangeRate();
assets = shares * dem / num;
// transfer WKCS from owner to sKCS Contract.
require(WKCS.transferFrom(msg.sender, address(this), assets),"E11");
// withdraw WKCS to KCS
WKCS.withdraw(assets);
_depositKCS(receiver, assets, shares);
}
/// @inheritdoc IERC4626
/// @notice You cannot redeem your sKCS for KCS instantly.
/// The Redemption contains two separate steps:
///
/// (1) Call requestRedemption to request a redemption.
/// (2) Wait for 3~6 days, and call withdrawKCS to withdraw the redeemed KCS.
/// (3) `assets` must be get by calling withdrawable
///
/// @param assets the amount of KCS to withdraw must be the same as that withdrawable returns.
function withdraw(uint256 assets, address receiver, address owner) external override returns(uint256 shares) {
uint amount;
(amount, shares)= withdrawable(owner);
require(assets == amount, "shares amount does not match with amount in redemption requests");
_withdrawKCS(msg.sender, owner, receiver, true);
}
/// @inheritdoc IERC4626
/// @notice You cannot redeem your sKCS for KCS instantly.
/// The Redemption contains two separate steps:
///
/// (1) Call requestRedemption to request a redemption.
/// (2) Wait for 3~6 days, and call withdrawKCS to withdraw the redeemed KCS.
/// (3) `shares` must be get by calling withdrawable
///
/// @param shares the amount of KCS to withdraw must be the same as that withdrawable returns.
function redeem(uint256 shares, address receiver, address owner) external override returns(uint256 assets) {
uint sKCSAmount;
(assets, sKCSAmount)= withdrawable(owner);
require(shares == sKCSAmount, "shares amount does not match with amount in redemption requests");
_withdrawKCS(msg.sender, owner, receiver, true);
}
/// @inheritdoc IERC4626
function convertToShares(uint256 assets) external view override returns(uint256) {
return _convertToShares(assets);
}
function _convertToShares(uint256 assets) internal view returns(uint256) {
(uint256 assets_, uint256 shares_) = exchangeRate();
return assets * shares_ / assets_;
}
/// @inheritdoc IERC4626
/// @notice You cannot redeem your sKCS for KCS instantly.
/// The Redemption contains two separate steps:
///
/// (1) Call requestRedemption to request a redemption.
/// (2) Wait for 3~6 days, and call withdrawKCS to withdraw the redeemed KCS.
///
/// This function converts shares to assets when you call requestRedemption.
function convertToAssets(uint256 shares) external view override returns(uint256) {
return _convertToAssets(shares);
}
function _convertToAssets(uint256 shares) internal view returns(uint256) {
(uint256 assets_, uint256 shares_) = exchangeRate();
return shares * assets_ / shares_ ;
}
/// @inheritdoc IERC4626
/// @notice There is not limit to deposit KCS
function maxDeposit(address /* owner */) external view override returns(uint256) {
return type(uint256).max;
}
/// @inheritdoc IERC4626
/// @notice There is not limit to mint sKCS
function maxMint(address /* owner */) external view override returns(uint256) {
return type(uint256).max;
}
/// @inheritdoc IERC4626
function previewDeposit(uint256 assets) external view override returns(uint256 shares) {
return _convertToShares(assets);
}
/// @inheritdoc IERC4626
function previewMint(uint256 shares) external view override returns(uint256 assets) {
return _convertToAssets(shares);
}
/// @inheritdoc IERC4626
function maxWithdraw(address owner) external view override returns(uint256) {
return _convertToAssets(_maxRedeem(owner));
}
/// @inheritdoc IERC4626
function previewWithdraw(uint256 assets) external view override returns(uint256 shares) {
return _convertToShares(assets);
}
/// @inheritdoc IERC4626
function maxRedeem(address owner) external view override returns(uint256) {
return _maxRedeem(owner);
}
function _maxRedeem(address owner) internal view returns(uint256) {
if(msg.sender == owner){
return balanceOf(owner);
}
return MathUpgradeable.min(balanceOf(owner), allowance(owner, msg.sender));
}
/// @inheritdoc IERC4626
/// @notice You cannot redeem your sKCS for KCS instantly.
/// The Redemption contains two separate steps:
///
/// (1) Call requestRedemption to request a redemption.
/// (2) Wait for 3~6 days, and call withdrawKCS to withdraw the redeemed KCS.
///
/// This function converts shares to assets when you call requestRedemption.
function previewRedeem(uint256 shares) external view override returns(uint256 assets) {
return _convertToAssets(shares);
}
}
Contract ABI
[{"type":"event","name":"AddValidator","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"validator","internalType":"address","indexed":false},{"type":"uint256","name":"weight","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ClaimPendingRewards","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"uint256","name":"height","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ClaimProtocolFee","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"uint256","name":"height","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Compound","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"claimAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DelegateChanged","inputs":[{"type":"address","name":"delegator","internalType":"address","indexed":true},{"type":"address","name":"fromDelegate","internalType":"address","indexed":true},{"type":"address","name":"toDelegate","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"DelegateVotesChanged","inputs":[{"type":"address","name":"delegate","internalType":"address","indexed":true},{"type":"uint256","name":"previousBalance","internalType":"uint256","indexed":false},{"type":"uint256","name":"newBalance","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"caller","internalType":"address","indexed":true},{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"assets","internalType":"uint256","indexed":false},{"type":"uint256","name":"shares","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DisablingValidator","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"validator","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"NewRequestRedemption","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"receiver","internalType":"address","indexed":true},{"type":"uint256","name":"id","internalType":"uint256","indexed":true},{"type":"uint256","name":"amountsKCS","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountKCS","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Receive","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RedeemFromBufferAndKCCStaking","inputs":[{"type":"uint256","name":"preRedeemingID","internalType":"uint256","indexed":true},{"type":"uint256","name":"newRedeemingID","internalType":"uint256","indexed":true},{"type":"uint256","name":"blocknumber","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RedeemFromBufferOnly","inputs":[{"type":"uint256","name":"preRedeemingID","internalType":"uint256","indexed":true},{"type":"uint256","name":"newRedeemingID","internalType":"uint256","indexed":true},{"type":"uint256","name":"blocknumber","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetProtocolFeeRate","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"uint256","name":"rate","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateWeightOfValidator","inputs":[{"type":"address","name":"sender","internalType":"address","indexed":false},{"type":"address","name":"validator","internalType":"address","indexed":false},{"type":"uint256","name":"weight","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Withdraw","inputs":[{"type":"address","name":"caller","internalType":"address","indexed":true},{"type":"address","name":"receiver","internalType":"address","indexed":true},{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"assets","internalType":"uint256","indexed":false},{"type":"uint256","name":"shares","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DOMAIN_SEPARATOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_NUM_VALIDATORS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_PROTOCOL_FEE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IValidators"}],"name":"VALIDATOR_CONTRACT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"VOTE_UNIT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IWKCS"}],"name":"WKCS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accumulatedRewardKCSAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accumulatedStakedKCSAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"activeValidators","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addUnderlyingValidator","inputs":[{"type":"address","name":"_val","internalType":"address"},{"type":"uint256","name":"_weight","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_asset","internalType":"address"}],"name":"asset","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct ERC20VotesUpgradeable.Checkpoint","components":[{"type":"uint32","name":"fromBlock","internalType":"uint32"},{"type":"uint224","name":"votes","internalType":"uint224"}]}],"name":"checkpoints","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint32","name":"pos","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimProtocolFee","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"compound","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"convertToAssets","inputs":[{"type":"uint256","name":"shares","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"convertToShares","inputs":[{"type":"uint256","name":"assets","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"delegate","inputs":[{"type":"address","name":"delegatee","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"delegateBySig","inputs":[{"type":"address","name":"delegatee","internalType":"address"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint256","name":"expiry","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"delegates","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"shares","internalType":"uint256"}],"name":"deposit","inputs":[{"type":"uint256","name":"assets","internalType":"uint256"},{"type":"address","name":"receiver","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"depositKCS","inputs":[{"type":"address","name":"receiver","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"disableUnderlyingValidator","inputs":[{"type":"address","name":"_val","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"num","internalType":"uint256"},{"type":"uint256","name":"dem","internalType":"uint256"}],"name":"exchangeRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAccumulatedRewardKCSAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getActiveValidators","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"exist","internalType":"bool"},{"type":"uint256","name":"len","internalType":"uint256"}],"name":"getAvailablePoolInfo","inputs":[{"type":"address","name":"_val","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"exist","internalType":"bool"},{"type":"uint256","name":"len","internalType":"uint256"}],"name":"getDisablingPoolInfo","inputs":[{"type":"address","name":"_val","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPastTotalSupply","inputs":[{"type":"uint256","name":"blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPastVotes","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"blockNumber","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct SKCSBase.RedemptionRequest","components":[{"type":"address","name":"requester","internalType":"address"},{"type":"uint256","name":"amountSKCS","internalType":"uint256"},{"type":"uint256","name":"amountKCS","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint256","name":"partiallyRedeemedKCS","internalType":"uint256"},{"type":"uint256","name":"accAmountKCSBefore","internalType":"uint256"}]}],"name":"getRedemptionRequest","inputs":[{"type":"uint256","name":"id","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct SKCSBase.ValidatorInfo","components":[{"type":"address","name":"val","internalType":"address"},{"type":"uint256","name":"weight","internalType":"uint256"},{"type":"uint256","name":"stakedKCS","internalType":"uint256"},{"type":"uint256","name":"actualRedeeming","internalType":"uint256"},{"type":"uint256","name":"userRedeeming","internalType":"uint256"},{"type":"uint256","name":"lastRedemptionTime","internalType":"uint256"},{"type":"uint256","name":"nextWithdrawingID","internalType":"uint256"}]}],"name":"getValidatorInfo","inputs":[{"type":"address","name":"_val","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getVotes","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"wkcs","internalType":"address"},{"type":"address","name":"validatorContract","internalType":"address"},{"type":"address","name":"processRedemptionFacet","internalType":"address"},{"type":"uint256","name":"protocolFee","internalType":"uint256"},{"type":"uint256","name":"minStakingKCSAmount","internalType":"uint256"},{"type":"uint256","name":"maximumPendingRedemptionRequestPerUser","internalType":"uint256"},{"type":"address","name":"admin","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isActiveValidator","inputs":[{"type":"address","name":"_val","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"buffer","internalType":"uint256"},{"type":"uint256","name":"debt","internalType":"uint256"},{"type":"uint256","name":"fee","internalType":"uint256"}],"name":"kcsBalances","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxDeposit","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxMint","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxRedeem","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxWithdraw","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"assets","internalType":"uint256"}],"name":"mint","inputs":[{"type":"uint256","name":"shares","internalType":"uint256"},{"type":"address","name":"receiver","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"nonces","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"assets","internalType":"uint256"},{"type":"uint256","name":"shares","internalType":"uint256"}],"name":"notWithdrawable","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"numCheckpoints","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"numberOfHolders","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"permit","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"shares","internalType":"uint256"}],"name":"previewDeposit","inputs":[{"type":"uint256","name":"assets","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"assets","internalType":"uint256"}],"name":"previewMint","inputs":[{"type":"uint256","name":"shares","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"assets","internalType":"uint256"}],"name":"previewRedeem","inputs":[{"type":"uint256","name":"shares","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"shares","internalType":"uint256"}],"name":"previewWithdraw","inputs":[{"type":"uint256","name":"assets","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"processRedemptionRequests","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"protocolFee","internalType":"uint256"},{"type":"uint256","name":"minStakingKCSAmount","internalType":"uint256"},{"type":"uint256","name":"maximumPendingRedemptionRequestPerUser","internalType":"uint256"},{"type":"uint256","name":"minIntervalRedeemFromKCCStakingSingleValidator","internalType":"uint256"},{"type":"uint256","name":"sumOfWeight","internalType":"uint256"}],"name":"protocolParams","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"assets","internalType":"uint256"}],"name":"redeem","inputs":[{"type":"uint256","name":"shares","internalType":"uint256"},{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"redeemingID","internalType":"uint256"},{"type":"uint256","name":"withdrawingID","internalType":"uint256"},{"type":"uint256","name":"length","internalType":"uint256"},{"type":"uint256","name":"accAmountKCS","internalType":"uint256"}],"name":"redemptionRequestBox","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestRedemption","inputs":[{"type":"uint256","name":"_shares","internalType":"uint256"},{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setProtocolFee","inputs":[{"type":"uint256","name":"_rate","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"timelastRedemptionFromKCCStaking","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_totalAssets","internalType":"uint256"}],"name":"totalAssets","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateWeightOfValidator","inputs":[{"type":"address","name":"_val","internalType":"address"},{"type":"uint256","name":"_weight","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"shares","internalType":"uint256"}],"name":"withdraw","inputs":[{"type":"uint256","name":"assets","internalType":"uint256"},{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"owner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawKCS","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"receiver","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"assets","internalType":"uint256"},{"type":"uint256","name":"shares","internalType":"uint256"}],"name":"withdrawable","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x608060405234801561001057600080fd5b50615f4280620000216000396000f3fe6080604052600436106104615760003560e01c80637ecebe001161023f578063b460af9411610139578063ce513b6f116100b6578063e14077fb1161007a578063e14077fb14610e66578063ef8b30f7146105d0578063f1127ed814610ea3578063f2fde38b14610eed578063f69e204614610f0d57600080fd5b8063ce513b6f14610dc6578063ce96cb7714610de6578063d505accf14610e06578063d905777e14610e26578063dd62ed3e14610e4657600080fd5b8063c3cda520116100fd578063c3cda52014610d6a578063c531869d14610d8a578063c5e59ec714610da6578063c63d75b6146107ec578063c6e6f592146105d057600080fd5b8063b460af9414610ce1578063b803eb6b14610d01578063b8ca3b8314610d21578063ba08765214610d37578063c1edf31914610d5757600080fd5b80639ab24eb0116101c7578063a9059cbb1161018b578063a9059cbb14610c69578063acab21e014610c89578063af02b1bc14610caa578063b39ba67714610cca578063b3d7f6b91461054957600080fd5b80639ab24eb014610bc75780639c33452314610be75780639de7025814610c07578063a457c2d714610c29578063a63b8bfb14610c4957600080fd5b80638da5cb5b1161020e5780638da5cb5b14610b005780638e539e8c14610b1e57806393aab9d514610b3e57806394bf804d14610b9257806395d89b4114610bb257600080fd5b80637ecebe0014610a315780638456cb5914610a515780638754bbc614610a665780638a11d7c914610a8657600080fd5b80633ba0b9a91161035b578063686dc24a116102d8578063715018a61161029c578063715018a614610980578063728d246314610995578063749ac1e6146109aa578063787dce3d146109ca5780637e1e23ef146109ea57600080fd5b8063686dc24a146108d65780636e553f65146108eb5780636f16b50d1461090b5780636fcfff451461092b57806370a082311461096057600080fd5b80634cdad5061161031f5780634cdad50614610549578063587cde1e1461084f5780635c19a95c146108895780635c975abb146108a9578063601b120b146108c157600080fd5b80633ba0b9a9146107ad5780633f4ba83a146107d7578063402d267d146107ec57806340550a1c1461080e57806346f751381461082e57600080fd5b806318160ddd116103e95780633644e515116103ad5780633644e515146106c957806338d52e0f146106de57806339509351146106fd5780633a46b1a81461071d5780633aa6f0ee1461073d57600080fd5b806318160ddd1461063f5780631fe45bd91461065457806323b872dd1461066b57806329c30d031461068b578063313ce567146106ad57600080fd5b806308da82061161043057806308da820614610569578063095ea7b3146105a05780630a28a477146105d057806310f26287146105f057806314f64c781461060757600080fd5b80630199c7b2146104e857806301e1d1141461051257806306fdde031461052757806307a2d13a1461054957600080fd5b366104e357333b6104a95760405162461bcd60e51b815260206004820152600d60248201526c1bdb9b1e4818dbdb9d1c9858dd609a1b60448201526064015b60405180910390fd5b604080513381523460208201527fd6717f327e0cb88b4a97a7f67a453e9258252c34937ccbdd86de7cb840e7def3910160405180910390a1005b600080fd5b3480156104f457600080fd5b506104ff6101a75481565b6040519081526020015b60405180910390f35b34801561051e57600080fd5b506104ff610f22565b34801561053357600080fd5b5061053c610f43565b6040516105099190615bfa565b34801561055557600080fd5b506104ff610564366004615afc565b610fd5565b34801561057557600080fd5b506105896105843660046158be565b610fe6565b604080519215158352602083019190915201610509565b3480156105ac57600080fd5b506105c06105bb366004615a1e565b611009565b6040519015158152602001610509565b3480156105dc57600080fd5b506104ff6105eb366004615afc565b611021565b3480156105fc57600080fd5b506104ff6101a65481565b34801561061357600080fd5b50610627610622366004615afc565b61102c565b6040516001600160a01b039091168152602001610509565b34801561064b57600080fd5b5060cb546104ff565b34801561066057600080fd5b506104ff6101a55481565b34801561067757600080fd5b506105c061068636600461597a565b611057565b34801561069757600080fd5b506106ab6106a6366004615afc565b61107b565b005b3480156106b957600080fd5b5060405160128152602001610509565b3480156106d557600080fd5b506104ff611193565b3480156106ea57600080fd5b50610194546001600160a01b0316610627565b34801561070957600080fd5b506105c0610718366004615a1e565b6111a2565b34801561072957600080fd5b506104ff610738366004615a1e565b6111e1565b34801561074957600080fd5b5061075d610758366004615afc565b61125c565b604051610509919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0918201519181019190915260c00190565b3480156107b957600080fd5b506107c2611340565b60408051928352602083019190915201610509565b3480156107e357600080fd5b506106ab61141d565b3480156107f857600080fd5b506104ff6108073660046158be565b5060001990565b34801561081a57600080fd5b506105c06108293660046158be565b611451565b34801561083a57600080fd5b5061019554610627906001600160a01b031681565b34801561085b57600080fd5b5061062761086a3660046158be565b6001600160a01b03908116600090815261016260205260409020541690565b34801561089557600080fd5b506106ab6108a43660046158be565b6114d1565b3480156108b557600080fd5b5060975460ff166105c0565b3480156108cd57600080fd5b506104ff601d81565b3480156108e257600080fd5b506104ff6114de565b3480156108f757600080fd5b506104ff610906366004615b2c565b6114f6565b34801561091757600080fd5b506106ab610926366004615b2c565b611649565b34801561093757600080fd5b5061094b6109463660046158be565b61187d565b60405163ffffffff9091168152602001610509565b34801561096c57600080fd5b506104ff61097b3660046158be565b6118a0565b34801561098c57600080fd5b506106ab6118bb565b3480156109a157600080fd5b506106ab6118ef565b3480156109b657600080fd5b506106ab6109c53660046158d8565b611924565b3480156109d657600080fd5b506106ab6109e5366004615afc565b611935565b3480156109f657600080fd5b506101a0546101a1546101a2546101a354610a119392919084565b604080519485526020850193909352918301526060820152608001610509565b348015610a3d57600080fd5b506104ff610a4c3660046158be565b611a30565b348015610a5d57600080fd5b506106ab611a4f565b348015610a7257600080fd5b506106ab610a8136600461590a565b611a81565b348015610a9257600080fd5b50610aa6610aa13660046158be565b611c9e565b604051610509919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0828101519082015260c0918201519181019190915260e00190565b348015610b0c57600080fd5b506065546001600160a01b0316610627565b348015610b2a57600080fd5b506104ff610b39366004615afc565b611d57565b348015610b4a57600080fd5b506101a9546101aa546101ab546101ac546101ad54610b6a949392919085565b604080519586526020860194909452928401919091526060830152608082015260a001610509565b348015610b9e57600080fd5b506104ff610bad366004615b2c565b611db4565b348015610bbe57600080fd5b5061053c611eff565b348015610bd357600080fd5b506104ff610be23660046158be565b611f0e565b348015610bf357600080fd5b506106ab610c02366004615a1e565b611fa5565b348015610c1357600080fd5b50610c1c6122af565b6040516105099190615bad565b348015610c3557600080fd5b506105c0610c44366004615a1e565b612311565b348015610c5557600080fd5b50610589610c643660046158be565b6123a3565b348015610c7557600080fd5b506105c0610c84366004615a1e565b6123bf565b348015610c9557600080fd5b5061019454610627906001600160a01b031681565b348015610cb657600080fd5b506107c2610cc53660046158be565b6123cd565b348015610cd657600080fd5b506104ff6101a85481565b348015610ced57600080fd5b506104ff610cfc366004615b4e565b61246f565b348015610d0d57600080fd5b506106ab610d1c3660046158be565b6124b3565b348015610d2d57600080fd5b506104ff6107d081565b348015610d4357600080fd5b506104ff610d52366004615b4e565b6126d0565b6104ff610d653660046158be565b612700565b348015610d7657600080fd5b506106ab610d85366004615a47565b6127a5565b348015610d9657600080fd5b506104ff670de0b6b3a764000081565b348015610db257600080fd5b506106ab610dc1366004615a1e565b6128db565b348015610dd257600080fd5b506107c2610de13660046158be565b612a1e565b348015610df257600080fd5b506104ff610e013660046158be565b612ab9565b348015610e1257600080fd5b506106ab610e213660046159b5565b612acc565b348015610e3257600080fd5b506104ff610e413660046158be565b612c13565b348015610e5257600080fd5b506104ff610e613660046158d8565b612c1e565b348015610e7257600080fd5b506101ae546101af546101b054610e8892919083565b60408051938452602084019290925290820152606001610509565b348015610eaf57600080fd5b50610ec3610ebe366004615a9e565b612c49565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610509565b348015610ef957600080fd5b506106ab610f083660046158be565b612cdc565b348015610f1957600080fd5b506106ab612d74565b6000610f2c611340565b509050610f3860cb5490565b610f40575060005b90565b606060cc8054610f5290615e86565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7e90615e86565b8015610fcb5780601f10610fa057610100808354040283529160200191610fcb565b820191906000526020600020905b815481529060010190602001808311610fae57829003601f168201915b5050505050905090565b6000610fe082612dcd565b92915050565b600080610ff561019984612df4565b9150611002610199612e16565b9050915091565b600033611017818585612e20565b5060019392505050565b6000610fe082612f44565b61019d818154811061103d57600080fd5b6000918252602090912001546001600160a01b0316905081565b600033611065858285612f61565b611070858585612fdb565b506001949350505050565b6002600154141561109e5760405162461bcd60e51b81526004016104a090615d7d565b60026001556065546001600160a01b031633146110cd5760405162461bcd60e51b81526004016104a090615ca0565b6101b054811080156110df5750600081115b61112b5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420616d6f756e7420746f20636c61696d00000000000000000060448201526064016104a0565b806101ae60020160008282546111419190615e6f565b90915550611151905033826131ba565b604080513381526020810183905243917f379da6c373c474a7957620f46a6ebd7eab654b69b9df1b748503e1487177efcc910160405180910390a25060018055565b600061119d6132d3565b905090565b33600081815260ca602090815260408083206001600160a01b038716845290915281205490919061101790829086906111dc908790615db4565b612e20565b60004382106112325760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e65640060448201526064016104a0565b6001600160a01b038316600090815261016360205260409020611255908361334e565b9392505050565b61129e6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6101a25482106112dd5760405162461bcd60e51b815260206004820152600a6024820152691b9bc81cdd58da081a5960b21b60448201526064016104a0565b50600090815261019f6020908152604091829020825160c08101845281546001600160a01b03168152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260059091015460a082015290565b60008061134c60cb5490565b6113595750600191829150565b600080600080611367613427565b919450925090506113788385615db4565b6101ae549094506113899085615db4565b93506113958185615db4565b935060006113a283613651565b91506113b090508186615db4565b6101a0546101a2549196509081101561140557600081815261019f6020526040812060048101546005909101546101a3546113eb9190615e6f565b6113f59190615e6f565b90506114018188615e6f565b9650505b8561140f60cb5490565b975097505050505050509091565b6065546001600160a01b031633146114475760405162461bcd60e51b81526004016104a090615ca0565b61144f6136a0565b565b6000805b61019d5460ff821610156114c857826001600160a01b031661019d8260ff168154811061149257634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614156114b65750600192915050565b806114c081615ed6565b915050611455565b50600092915050565b6114db3382613733565b50565b60006114e86137c4565b6101a65461119d9190615db4565b610194546040516323b872dd60e01b81526000916001600160a01b0316906323b872dd9061152c90339030908890600401615b89565b602060405180830381600087803b15801561154657600080fd5b505af115801561155a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157e9190615adc565b6115b05760405162461bcd60e51b815260206004820152600360248201526245313160e81b60448201526064016104a0565b61019454604051632e1a7d4d60e01b8152600481018590526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b1580156115f757600080fd5b505af115801561160b573d6000803e3d6000fd5b5050505060008061161a611340565b90925090508161162a8287615e11565b6116349190615df1565b92506116418486856138de565b505092915050565b6002600154141561166c5760405162461bcd60e51b81526004016104a090615d7d565b600260015560975460ff16156116945760405162461bcd60e51b81526004016104a090615c4d565b600082116116db5760405162461bcd60e51b8152602060048201526014602482015273526564656d7074696f6e3a20302073686172657360601b60448201526064016104a0565b6001600160a01b03811660009081526101a46020908152604080832033845290915290206101ab5461170c82612e16565b106117595760405162461bcd60e51b815260206004820152601c60248201527f526564656d7074696f6e3a20746f6f206d616e792070656e64696e670000000060448201526064016104a0565b336001600160a01b0383161461177457611774823385612f61565b60008061177f611340565b90925090506000816117918488615e11565b61179b9190615df1565b90506117a785876139c0565b6101a254600081815261019f6020526040812080546001600160a01b0319163317815560018101899055600281018490554260038201556101a3805460058301819055919285926117f9908490615db4565b90915550506101a2805460019190600090611815908490615db4565b90915550611825905086836139d9565b506040805189815260208101859052839133916001600160a01b038b16917ffdf3f15b057962b89bdbe4a4651fbcffc001edd8acea6d9f5317bbeaceede6fd91015b60405180910390a4505060018055505050505050565b6001600160a01b03811660009081526101636020526040812054610fe0906139e5565b6001600160a01b0316600090815260c9602052604090205490565b6065546001600160a01b031633146118e55760405162461bcd60e51b81526004016104a090615ca0565b61144f6000613a4e565b6101b1546040516001600160a01b039091169036600082376000803683855af43d806000843e818015611920578184f35b8184fd5b6119313383836000613aa0565b5050565b6065546001600160a01b0316331461195f5760405162461bcd60e51b81526004016104a090615ca0565b60008111801561197157506107d08111155b6119ac5760405162461bcd60e51b815260206004820152600c60248201526b696e76616c6964207261746560a01b60448201526064016104a0565b6101a9548114156119ed5760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd0818da185b99d95960aa1b60448201526064016104a0565b6101a981905560408051338152602081018390527fde36a2e55e70e033bfc76a70f779635cdb034d90eac53e0a2b24f6037af5edda91015b60405180910390a150565b6001600160a01b038116600090815261012f6020526040812054610fe0565b6065546001600160a01b03163314611a795760405162461bcd60e51b81526004016104a090615ca0565b61144f613d47565b600054610100900460ff16611a9c5760005460ff1615611aa0565b303b155b611b035760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104a0565b600054610100900460ff16158015611b25576000805461ffff19166101011790555b611b2d613d9f565b611b35613dce565b611b3d613dfd565b611b856040518060400160405280600a8152602001695374616b6564204b435360b01b81525060405180604001604052806004815260200163734b435360e01b815250613e2c565b611bb06040518060400160405280600a8152602001695374616b6564204b435360b01b815250613e5d565b611bb8613eb0565b611bc5610196601d613ed7565b601d611bd16101965490565b14611c115760405162461bcd60e51b815260206004820152601060248201526f696e76616c696420636170616369747960801b60448201526064016104a0565b61019480546001600160a01b03808b166001600160a01b0319928316179092556101958054928a16929091169190911790556101a98590556101aa8490556101ab8390556203f4806101ac55611c6682612cdc565b6101b180546001600160a01b0319166001600160a01b0388161790558015611c94576000805461ff00191690555b5050505050505050565b611ce76040518060e0016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b506001600160a01b03908116600090815261019e6020908152604091829020825160e081018452815490941684526001810154918401919091526002810154918301919091526003810154606083015260048101546080830152600581015460a08301526006015460c082015290565b6000438210611da85760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e65640060448201526064016104a0565b610fe06101648361334e565b6000806000611dc1611340565b909250905081611dd18287615e11565b611ddb9190615df1565b610194546040516323b872dd60e01b81529194506001600160a01b0316906323b872dd90611e1190339030908890600401615b89565b602060405180830381600087803b158015611e2b57600080fd5b505af1158015611e3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e639190615adc565b611e955760405162461bcd60e51b815260206004820152600360248201526245313160e81b60448201526064016104a0565b61019454604051632e1a7d4d60e01b8152600481018590526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b158015611edc57600080fd5b505af1158015611ef0573d6000803e3d6000fd5b505050506116418484876138de565b606060cd8054610f5290615e86565b6001600160a01b038116600090815261016360205260408120548015611f92576001600160a01b038316600090815261016360205260409020611f52600183615e6f565b81548110611f7057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015464010000000090046001600160e01b0316611f95565b60005b6001600160e01b03169392505050565b6065546001600160a01b03163314611fcf5760405162461bcd60e51b81526004016104a090615ca0565b61019554604051631015428760e21b81526001600160a01b038481166004830152909116906340550a1c9060240160206040518083038186803b15801561201557600080fd5b505afa158015612029573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204d9190615adc565b6120915760405162461bcd60e51b81526020600482015260156024820152746163746976652076616c696461746f72206f6e6c7960581b60448201526064016104a0565b6001600160a01b0382166120b75760405162461bcd60e51b81526004016104a090615c77565b6000811180156120c8575060648111155b6121055760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081dd95a59da1d60921b60448201526064016104a0565b61019d54601d1161214e5760405162461bcd60e51b8152602060048201526013602482015272746f6f206d616e792076616c696461746f727360681b60448201526064016104a0565b6001600160a01b03828116600090815261019e602052604090205416611931576040805160e0810182526001600160a01b0384811680835260208084018681526000858701818152606087018281526080880183815260a0890184815260c08a0185815297855261019e90965298909220965187546001600160a01b031916961695909517865590516001860155925160028501559151600384015592516004830155516005820155905160069091015561220b61019983613f56565b5061019d805460018101825560009182527f71880bb8535eda3be1bc3614789b84ba72ab02d5ae26ba282fa1178bb7fea1e60180546001600160a01b0319166001600160a01b0385161790556101ad805483929061226a908490615db4565b90915550506040517f09a4c0758c99f52fc2d8f37f71ca95b67c463c947ef47a32c16e9493f46a3f81906122a390339085908590615b89565b60405180910390a15050565b606061019d805480602002602001604051908101604052809291908181526020018280548015610fcb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122ea575050505050905090565b33600081815260ca602090815260408083206001600160a01b0387168452909152812054909190838110156123965760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016104a0565b6110708286868403612e20565b6000806123b261019b84612df4565b915061100261019b612e16565b600033611017818585612fdb565b6001600160a01b03811660009081526101a4602090815260408083203384529091528120819061019f825b61240183612e16565b8110156124675760006124148483613f6b565b905082600201548110612454576000818152602084905260409020600281015461243e9088615db4565b96508060010154866124509190615db4565b9550505b508061245f81615ebb565b9150506123f8565b505050915091565b60008061247b83612a1e565b9250905084811461249e5760405162461bcd60e51b81526004016104a090615d20565b6124ab3384866001613aa0565b509392505050565b6065546001600160a01b031633146124dd5760405162461bcd60e51b81526004016104a090615ca0565b61019d546001106125285760405162461bcd60e51b81526020600482015260156024820152746e6f7420656e6f7567682076616c696461746f722160581b60448201526064016104a0565b6001600160a01b03811661254e5760405162461bcd60e51b81526004016104a090615c77565b61255a61019982612df4565b156114db5761256b61019982613f77565b5061257581613f8c565b6101ae8054600090612588908490615db4565b90915550506001600160a01b038116600090815261019e60205260409020600201541561267b57610195546001600160a01b03828116600090815261019e602052604090206002015491169063ee16442e9083906125ef90670de0b6b3a764000090615df1565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561263557600080fd5b505af1158015612649573d6000803e3d6000fd5b5050506001600160a01b038216600090815261019e602052604081206002810180546003830155600490910182905555505b61268761019b82613f56565b506126918161410c565b50604080513381526001600160a01b03831660208201527f373de1e40a19b3955370231ed6a2fb9e540299dacac08e76f46f30006209fb439101611a25565b6000806126dc83612a1e565b909250905084811461249e5760405162461bcd60e51b81526004016104a090615d20565b60006001600160a01b0382166127285760405162461bcd60e51b81526004016104a090615c77565b600034116127695760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a5908185b5bdd5b9d60921b60448201526064016104a0565b600080612774611340565b90925090506000826127868334615e11565b6127909190615df1565b905061279d8534836138de565b949350505050565b834211156127f55760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e6174757265206578706972656400000060448201526064016104a0565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b03881691810191909152606081018690526080810185905260009061286f906128679060a00160405160208183030381529060405280519060200120614269565b8585856142b7565b905061287a816142df565b86146128c85760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e63650000000000000060448201526064016104a0565b6128d28188613733565b50505050505050565b6065546001600160a01b031633146129055760405162461bcd60e51b81526004016104a090615ca0565b6001600160a01b03821661292b5760405162461bcd60e51b81526004016104a090615c77565b60008111801561293c575060648111155b6129795760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081dd95a59da1d60921b60448201526064016104a0565b6001600160a01b03808316600090815261019e60205260409020805490911615612a195760018101546101ad80546000906129b5908490615e6f565b9091555050600181018290556101ad80548391906000906129d7908490615db4565b90915550506040517f59dc32f3648f08109d4de7f5122971e1c26167b086d67f6faad7e2b894c9c67890612a1090339086908690615b89565b60405180910390a15b505050565b6001600160a01b03811660009081526101a4602090815260408083203384529091528120819061019f825b612a5283612e16565b811015612467576000612a658483613f6b565b90508260020154811015612aa65760008181526020849052604090206002810154612a909088615db4565b9650806001015486612aa29190615db4565b9550505b5080612ab181615ebb565b915050612a49565b6000610fe0612ac783614306565b612dcd565b83421115612b1c5760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016104a0565b600061013054888888612b2e8c6142df565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000612b8982614269565b90506000612b99828787876142b7565b9050896001600160a01b0316816001600160a01b031614612bfc5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016104a0565b612c078a8a8a612e20565b50505050505050505050565b6000610fe082614306565b6001600160a01b03918216600090815260ca6020908152604080832093909416825291909152205490565b60408051808201909152600080825260208201526001600160a01b038316600090815261016360205260409020805463ffffffff8416908110612c9c57634e487b7160e01b600052603260045260246000fd5b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b6065546001600160a01b03163314612d065760405162461bcd60e51b81526004016104a090615ca0565b6001600160a01b038116612d6b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104a0565b6114db81613a4e565b60026001541415612d975760405162461bcd60e51b81526004016104a090615d7d565b600260015560975460ff1615612dbf5760405162461bcd60e51b81526004016104a090615c4d565b612dc761433d565b60018055565b6000806000612dda611340565b909250905080612dea8386615e11565b61279d9190615df1565b6001600160a01b03811660009081526001830160205260408120541515611255565b6000610fe0825490565b6001600160a01b038316612e825760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016104a0565b6001600160a01b038216612ee35760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104a0565b6001600160a01b03838116600081815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000806000612f51611340565b909250905081612dea8286615e11565b6000612f6d8484612c1e565b90506000198114612fd55781811015612fc85760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104a0565b612fd58484848403612e20565b50505050565b6001600160a01b03831661303f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104a0565b6001600160a01b0382166130a15760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104a0565b6130ac8383836143ff565b6001600160a01b038316600090815260c96020526040902054818110156131245760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016104a0565b6001600160a01b03808516600090815260c9602052604080822085850390559185168152908120805484929061315b908490615db4565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516131a791815260200190565b60405180910390a3612fd5848484614456565b8047101561320a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016104a0565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613257576040519150601f19603f3d011682016040523d82523d6000602084013e61325c565b606091505b5050905080612a195760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016104a0565b600061119d7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61330260fb5490565b60fc546040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b8154600090815b818110156133c057600061336982846144ae565b90508486828154811061338c57634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff1611156133ac578092506133ba565b6133b7816001615db4565b91505b50613355565b811561341257846133d2600184615e6f565b815481106133f057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015464010000000090046001600160e01b0316613415565b60005b6001600160e01b031695945050505050565b60008080805b61019d5460ff821610156135e157600061019d8260ff168154811061346257634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b031680835261019e9091526040909120600201549091506134989086615db4565b6001600160a01b038216600090815261019e6020526040902060048101546003909101549196506134c891615e6f565b6134d29084615db4565b925061019560009054906101000a90046001600160a01b03166001600160a01b0316639ced7e7661019e600061019d8660ff168154811061352357634e487b7160e01b600052603260045260246000fd5b6000918252602080832091909101546001600160a01b039081168452908301939093526040918201902054905160e084901b6001600160e01b03191681529116600482015230602482015260440160206040518083038186803b15801561358957600080fd5b505afa15801561359d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135c19190615b14565b6135cb9085615db4565b93505080806135d990615ed6565b91505061342d565b5060005b6135f061019b612e16565b8160ff16101561364b57600061360b61019b60ff8416613f6b565b6001600160a01b038116600090815261019e60205260409020600301549091506136359084615db4565b925050808061364390615ed6565b9150506135e5565b50909192565b6000808261366457506000928392509050565b6101a954662386f26fc10000906136808564e8d4a51000615e11565b61368a9190615e11565b6136949190615df1565b91506110028284615e6f565b60975460ff166136e95760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016104a0565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03828116600090815261016260205260408120549091169061375b846118a0565b6001600160a01b038581166000818152610162602052604080822080546001600160a01b031916898616908117909155905194955093928616927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4612fd58284836144c9565b60008060005b61019d5460ff821610156138d8576101955461019d80546001600160a01b0390921691639ced7e769161019e916000919060ff871690811061381c57634e487b7160e01b600052603260045260246000fd5b6000918252602080832091909101546001600160a01b039081168452908301939093526040918201902054905160e084901b6001600160e01b03191681529116600482015230602482015260440160206040518083038186803b15801561388257600080fd5b505afa158015613896573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ba9190615b14565b6138c49083615db4565b9150806138d081615ed6565b9150506137ca565b50919050565b600260015414156139015760405162461bcd60e51b81526004016104a090615d7d565b600260015560975460ff16156139295760405162461bcd60e51b81526004016104a090615c4d565b816101ae600001600082825461393f9190615db4565b92505081905550816101a560008282546139599190615db4565b909155506139679050614608565b6139718382614731565b60408051838152602081018390526001600160a01b0385169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a350506001805550565b6139ca82826147bc565b612fd561016461491d83614929565b60006112558383614acc565b600063ffffffff821115613a4a5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016104a0565b5090565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60026001541415613ac35760405162461bcd60e51b81526004016104a090615d7d565b600260015560975460ff1615613aeb5760405162461bcd60e51b81526004016104a090615c4d565b6001600160a01b0380841660009081526101a46020908152604080832093881683529290529081209061019f9080805b613b2485612e16565b811015613b9b576000613b378683613f6b565b90508460020154811015613b885760008181526020869052604090206002810154613b629086615db4565b9450806001015484613b749190615db4565b9350613b808783614b1b565b505050613b1b565b81613b9281615ebb565b92505050613b1b565b50816101ae6001016000828254613bb29190615e6f565b90915550859050613bcc57613bc786836131ba565b613cef565b61019460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015613c1d57600080fd5b505af1158015613c31573d6000803e3d6000fd5b50506101945460405163a9059cbb60e01b81526001600160a01b038b8116600483015260248201889052909116935063a9059cbb92506044019050602060405180830381600087803b158015613c8657600080fd5b505af1158015613c9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbe9190615adc565b613cef5760405162461bcd60e51b8152602060048201526002602482015261453560f01b60448201526064016104a0565b866001600160a01b0316866001600160a01b0316896001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051611867929190918252602082015260400190565b60975460ff1615613d6a5760405162461bcd60e51b81526004016104a090615c4d565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586137163390565b600054610100900460ff16613dc65760405162461bcd60e51b81526004016104a090615cd5565b61144f614b27565b600054610100900460ff16613df55760405162461bcd60e51b81526004016104a090615cd5565b61144f614b57565b600054610100900460ff16613e245760405162461bcd60e51b81526004016104a090615cd5565b61144f614b7e565b600054610100900460ff16613e535760405162461bcd60e51b81526004016104a090615cd5565b6119318282614bb1565b600054610100900460ff16613e845760405162461bcd60e51b81526004016104a090615cd5565b613ea781604051806040016040528060018152602001603160f81b815250614bff565b6114db81614c40565b600054610100900460ff1661144f5760405162461bcd60e51b81526004016104a090615cd5565b8160005b82811015613f155781546001810183556000838152602090200180546001600160a01b031916905580613f0d81615ebb565b915050613edb565b5080548214612a195760405162461bcd60e51b815260206004820152600d60248201526c1c995a5b9a5d1a585b1a5e9959609a1b60448201526064016104a0565b6000611255836001600160a01b038416614acc565b60006112558383614c8f565b6000611255836001600160a01b038416614cc7565b60006001600160a01b038216613fb45760405162461bcd60e51b81526004016104a090615c77565b61019554604051634e76bf3b60e11b81526001600160a01b0384811660048301523060248301524792600092911690639ced7e769060440160206040518083038186803b15801561400457600080fd5b505afa158015614018573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061403c9190615b14565b90508061404d575060009392505050565b6101955460405163d279c19160e01b81526001600160a01b0386811660048301529091169063d279c19190602401600060405180830381600087803b15801561409557600080fd5b505af11580156140a9573d6000803e3d6000fd5b50505050600082476140bb9190615e6f565b9050806101a660008282546140d09190615db4565b9091555060009050806140e283613651565b91509150816101ae60020160008282546140fc9190615db4565b9091555090979650505050505050565b6000805b61019d5460ff8216101561426057826001600160a01b031661019d8260ff168154811061414d57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316141561424e5761019d805461417990600190615e6f565b8154811061419757634e487b7160e01b600052603260045260246000fd5b60009182526020909120015461019d80546001600160a01b039092169160ff84169081106141d557634e487b7160e01b600052603260045260246000fd5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061019d80548061422357634e487b7160e01b600052603160045260246000fd5b600082815260209020810160001990810180546001600160a01b031916905501905550600192915050565b8061425881615ed6565b915050614110565b50600192915050565b6000610fe06142766132d3565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006142c887878787614de4565b915091506142d581614ed1565b5095945050505050565b6001600160a01b038116600090815261012f602052604090208054600181018255906138d8565b6000336001600160a01b038316141561432257610fe0826118a0565b610fe061432e836118a0565b6143388433612c1e565b6150d2565b6143456150e8565b60006143576143526137c4565b613651565b6101aa546101ae54919350915061436f908390615db4565b10156143785750565b60006143826153a4565b9050806101ae600001600082825461439a9190615db4565b92505081905550806101a560008282546143b49190615db4565b909155506143c29050614608565b604080513381524260208201529081018290527f0e311a2c6dbfb0153ec3a8a5bdca09070b3e5f60768fdc10a20453f38d186873906060016122a3565b614408826118a0565b614413576000614416565b60015b61441f846118a0565b61442a57600061442d565b60015b6144379190615dcc565b60ff166101a7600082825461444c9190615e6f565b9091555050505050565b614461838383615479565b61446a826118a0565b614475576000614478565b60015b614481846118a0565b61448c57600061448f565b60015b6144999190615dcc565b60ff166101a7600082825461444c9190615db4565b60006144bd6002848418615df1565b61125590848416615db4565b816001600160a01b0316836001600160a01b0316141580156144eb5750600081115b15612a19576001600160a01b0383161561457a576001600160a01b03831660009081526101636020526040812081906145279061491d85614929565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724838360405161456f929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615612a19576001600160a01b03821660009081526101636020526040812081906145b1906154ac85614929565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a72483836040516145f9929190918252602082015260400190565b60405180910390a25050505050565b6101aa546101ae54101561461857565b60006146226154b8565b90506001600160a01b0381166146355750565b61463e81613f8c565b6101ae8054600090614651908490615db4565b90915550506101ae5460009061467090670de0b6b3a764000090615df1565b90506000614686670de0b6b3a764000083615e11565b9050806101ae600001600082825461469e9190615e6f565b90915550506001600160a01b038316600090815261019e6020526040812060020180548392906146cf908490615db4565b9091555050610195546040516336ebec7560e11b81526001600160a01b03858116600483015290911690636dd7d8ea9083906024016000604051808303818588803b15801561471d57600080fd5b505af1158015611c94573d6000803e3d6000fd5b61473b8282615635565b60cb546001600160e01b0310156147ad5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b60648201526084016104a0565b612fd56101646154ac83614929565b6001600160a01b03821661481c5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016104a0565b614828826000836143ff565b6001600160a01b038216600090815260c960205260409020548181101561489c5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016104a0565b6001600160a01b038316600090815260c960205260408120838303905560cb80548492906148cb908490615e6f565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3612a1983600084614456565b60006112558284615e6f565b8254600090819080156149825785614942600183615e6f565b8154811061496057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015464010000000090046001600160e01b0316614985565b60005b6001600160e01b0316925061499e83858763ffffffff16565b91506000811180156149ea575043866149b8600184615e6f565b815481106149d657634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16145b15614a58576149f882615728565b86614a04600184615e6f565b81548110614a2257634e487b7160e01b600052603260045260246000fd5b9060005260206000200160000160046101000a8154816001600160e01b0302191690836001600160e01b03160217905550614ac3565b856040518060400160405280614a6d436139e5565b63ffffffff168152602001614a8185615728565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b50935093915050565b6000818152600183016020526040812054614b1357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610fe0565b506000610fe0565b60006112558383614cc7565b600054610100900460ff16614b4e5760405162461bcd60e51b81526004016104a090615cd5565b61144f33613a4e565b600054610100900460ff16612dc75760405162461bcd60e51b81526004016104a090615cd5565b600054610100900460ff16614ba55760405162461bcd60e51b81526004016104a090615cd5565b6097805460ff19169055565b600054610100900460ff16614bd85760405162461bcd60e51b81526004016104a090615cd5565b8151614beb9060cc906020850190615801565b508051612a199060cd906020840190615801565b600054610100900460ff16614c265760405162461bcd60e51b81526004016104a090615cd5565b81516020928301208151919092012060fb9190915560fc55565b600054610100900460ff16614c675760405162461bcd60e51b81526004016104a090615cd5565b507f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961013055565b6000826000018281548110614cb457634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b60008181526001830160205260408120548015614dda576000614ceb600183615e6f565b8554909150600090614cff90600190615e6f565b9050818114614d80576000866000018281548110614d2d57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905080876000018481548110614d5e57634e487b7160e01b600052603260045260246000fd5b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614d9f57634e487b7160e01b600052603160045260246000fd5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610fe0565b6000915050610fe0565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614e1b5750600090506003614ec8565b8460ff16601b14158015614e3357508460ff16601c14155b15614e445750600090506004614ec8565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614e98573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614ec157600060019250925050614ec8565b9150600090505b94509492505050565b6000816004811115614ef357634e487b7160e01b600052602160045260246000fd5b1415614efc5750565b6001816004811115614f1e57634e487b7160e01b600052602160045260246000fd5b1415614f6c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016104a0565b6002816004811115614f8e57634e487b7160e01b600052602160045260246000fd5b1415614fdc5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016104a0565b6003816004811115614ffe57634e487b7160e01b600052602160045260246000fd5b14156150575760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016104a0565b600481600481111561507957634e487b7160e01b600052602160045260246000fd5b14156114db5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016104a0565b60008183106150e15781611255565b5090919050565b60005b6150f661019b612e16565b8160ff1610156114db57600061511161019b60ff8416613f6b565b6101955460405163badca81960e01b81523060048201526001600160a01b03808416602483015292935091169063badca8199060440160206040518083038186803b15801561515f57600080fd5b505afa158015615173573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151979190615adc565b1561529a5760006151a782615791565b6001600160a01b038316600090815261019e60205260408120600101546101ad805493945090929091906151dc908490615e6f565b90915550506040805160e08101825260008082526020808301828152838501838152606085018481526080860185815260a0870186815260c088018781526001600160a01b038c8116895261019e909752988720975188546001600160a01b0319169616959095178755925160018701559051600286015551600385015551600484015551600583015591516006909101556101ae8054839290615281908490615db4565b90915550615293905061019b83613f77565b505061539e565b6001600160a01b038116600090815261019e6020526040902060030154615390576001600160a01b038116600090815261019e60205260408120600101546101ad8054919290916152ec908490615e6f565b90915550506040805160e08101825260008082526020808301828152838501838152606085018481526080860185815260a0870186815260c088018781526001600160a01b038b8116895261019e90975298909620965187546001600160a01b031916951694909417865591516001860155516002850155516003840155516004830155516005820155905160069091015561538a61019b82613f77565b5061539e565b8161539a81615ed6565b9250505b506150eb565b60008060005b61019d5460ff821610156154335761541561019e600061019d8460ff16815481106153e557634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03908116845290830193909352604090910190205416613f8c565b61541f9083615db4565b91508061542b81615ed6565b9150506153aa565b50604080513381524360208201529081018290527f6fd374a97f893367a4c9cf189b53a9d33200335b92191b4b0aa5edfd182dc4c19060600160405180910390a1919050565b6001600160a01b0383811660009081526101626020526040808220548584168352912054612a19929182169116836144c9565b60006112558284615db4565b6000806154c3613427565b50509050806000141561551f5761019d54156155165761019d6000815481106154fc57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316615519565b60005b91505090565b6001600160ff1b036000805b61019d5460ff821610156124ab57600061019e600061019d8460ff168154811061556557634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316835282019290925260400181206101ad546001820154919350906155a490633b9aca00615e11565b6155ae9190615df1565b868360020154633b9aca006155c39190615e11565b6155cd9190615df1565b6155d79190615e30565b90508481136156205780945061019d8360ff168154811061560857634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031693505b5050808061562d90615ed6565b91505061552b565b6001600160a01b03821661568b5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104a0565b615697600083836143ff565b8060cb60008282546156a99190615db4565b90915550506001600160a01b038216600090815260c96020526040812080548392906156d6908490615db4565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a361193160008383614456565b60006001600160e01b03821115613a4a5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b60648201526084016104a0565b610195546040516351cff8d960e01b81526001600160a01b03838116600483015260009247929116906351cff8d990602401600060405180830381600087803b1580156157dd57600080fd5b505af11580156157f1573d6000803e3d6000fd5b5050505080476112559190615e6f565b82805461580d90615e86565b90600052602060002090601f01602090048101928261582f5760008555615875565b82601f1061584857805160ff1916838001178555615875565b82800160010185558215615875579182015b8281111561587557825182559160200191906001019061585a565b50613a4a9291505b80821115613a4a576000815560010161587d565b80356001600160a01b03811681146158a857600080fd5b919050565b803560ff811681146158a857600080fd5b6000602082840312156158cf578081fd5b61125582615891565b600080604083850312156158ea578081fd5b6158f383615891565b915061590160208401615891565b90509250929050565b600080600080600080600060e0888a031215615924578283fd5b61592d88615891565b965061593b60208901615891565b955061594960408901615891565b9450606088013593506080880135925060a0880135915061596c60c08901615891565b905092959891949750929550565b60008060006060848603121561598e578283fd5b61599784615891565b92506159a560208501615891565b9150604084013590509250925092565b600080600080600080600060e0888a0312156159cf578283fd5b6159d888615891565b96506159e660208901615891565b95506040880135945060608801359350615a02608089016158ad565b925060a0880135915060c0880135905092959891949750929550565b60008060408385031215615a30578182fd5b615a3983615891565b946020939093013593505050565b60008060008060008060c08789031215615a5f578182fd5b615a6887615891565b95506020870135945060408701359350615a84606088016158ad565b92506080870135915060a087013590509295509295509295565b60008060408385031215615ab0578182fd5b615ab983615891565b9150602083013563ffffffff81168114615ad1578182fd5b809150509250929050565b600060208284031215615aed578081fd5b81518015158114611255578182fd5b600060208284031215615b0d578081fd5b5035919050565b600060208284031215615b25578081fd5b5051919050565b60008060408385031215615b3e578182fd5b8235915061590160208401615891565b600080600060608486031215615b62578081fd5b83359250615b7260208501615891565b9150615b8060408501615891565b90509250925092565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6020808252825182820181905260009190848201906040850190845b81811015615bee5783516001600160a01b031683529284019291840191600101615bc9565b50909695505050505050565b6000602080835283518082850152825b81811015615c2657858101830151858201604001528201615c0a565b81811115615c375783604083870101525b50601f01601f1916929092016040019392505050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252600f908201526e696e76616c6964206164647265737360881b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020808252603f908201527f73686172657320616d6f756e7420646f6573206e6f74206d617463682077697460408201527f6820616d6f756e7420696e20726564656d7074696f6e20726571756573747300606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008219821115615dc757615dc7615ef6565b500190565b600060ff821660ff84168060ff03821115615de957615de9615ef6565b019392505050565b600082615e0c57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615e2b57615e2b615ef6565b500290565b60008083128015600160ff1b850184121615615e4e57615e4e615ef6565b6001600160ff1b0384018313811615615e6957615e69615ef6565b50500390565b600082821015615e8157615e81615ef6565b500390565b600181811c90821680615e9a57607f821691505b602082108114156138d857634e487b7160e01b600052602260045260246000fd5b6000600019821415615ecf57615ecf615ef6565b5060010190565b600060ff821660ff811415615eed57615eed615ef6565b60010192915050565b634e487b7160e01b600052601160045260246000fdfea264697066735822122011357ccaa1084eaf718d13d84e5694ae1f6a2593c69b9fe931213400185cbf0b64736f6c63430008040033
Deployed ByteCode
0x6080604052600436106104615760003560e01c80637ecebe001161023f578063b460af9411610139578063ce513b6f116100b6578063e14077fb1161007a578063e14077fb14610e66578063ef8b30f7146105d0578063f1127ed814610ea3578063f2fde38b14610eed578063f69e204614610f0d57600080fd5b8063ce513b6f14610dc6578063ce96cb7714610de6578063d505accf14610e06578063d905777e14610e26578063dd62ed3e14610e4657600080fd5b8063c3cda520116100fd578063c3cda52014610d6a578063c531869d14610d8a578063c5e59ec714610da6578063c63d75b6146107ec578063c6e6f592146105d057600080fd5b8063b460af9414610ce1578063b803eb6b14610d01578063b8ca3b8314610d21578063ba08765214610d37578063c1edf31914610d5757600080fd5b80639ab24eb0116101c7578063a9059cbb1161018b578063a9059cbb14610c69578063acab21e014610c89578063af02b1bc14610caa578063b39ba67714610cca578063b3d7f6b91461054957600080fd5b80639ab24eb014610bc75780639c33452314610be75780639de7025814610c07578063a457c2d714610c29578063a63b8bfb14610c4957600080fd5b80638da5cb5b1161020e5780638da5cb5b14610b005780638e539e8c14610b1e57806393aab9d514610b3e57806394bf804d14610b9257806395d89b4114610bb257600080fd5b80637ecebe0014610a315780638456cb5914610a515780638754bbc614610a665780638a11d7c914610a8657600080fd5b80633ba0b9a91161035b578063686dc24a116102d8578063715018a61161029c578063715018a614610980578063728d246314610995578063749ac1e6146109aa578063787dce3d146109ca5780637e1e23ef146109ea57600080fd5b8063686dc24a146108d65780636e553f65146108eb5780636f16b50d1461090b5780636fcfff451461092b57806370a082311461096057600080fd5b80634cdad5061161031f5780634cdad50614610549578063587cde1e1461084f5780635c19a95c146108895780635c975abb146108a9578063601b120b146108c157600080fd5b80633ba0b9a9146107ad5780633f4ba83a146107d7578063402d267d146107ec57806340550a1c1461080e57806346f751381461082e57600080fd5b806318160ddd116103e95780633644e515116103ad5780633644e515146106c957806338d52e0f146106de57806339509351146106fd5780633a46b1a81461071d5780633aa6f0ee1461073d57600080fd5b806318160ddd1461063f5780631fe45bd91461065457806323b872dd1461066b57806329c30d031461068b578063313ce567146106ad57600080fd5b806308da82061161043057806308da820614610569578063095ea7b3146105a05780630a28a477146105d057806310f26287146105f057806314f64c781461060757600080fd5b80630199c7b2146104e857806301e1d1141461051257806306fdde031461052757806307a2d13a1461054957600080fd5b366104e357333b6104a95760405162461bcd60e51b815260206004820152600d60248201526c1bdb9b1e4818dbdb9d1c9858dd609a1b60448201526064015b60405180910390fd5b604080513381523460208201527fd6717f327e0cb88b4a97a7f67a453e9258252c34937ccbdd86de7cb840e7def3910160405180910390a1005b600080fd5b3480156104f457600080fd5b506104ff6101a75481565b6040519081526020015b60405180910390f35b34801561051e57600080fd5b506104ff610f22565b34801561053357600080fd5b5061053c610f43565b6040516105099190615bfa565b34801561055557600080fd5b506104ff610564366004615afc565b610fd5565b34801561057557600080fd5b506105896105843660046158be565b610fe6565b604080519215158352602083019190915201610509565b3480156105ac57600080fd5b506105c06105bb366004615a1e565b611009565b6040519015158152602001610509565b3480156105dc57600080fd5b506104ff6105eb366004615afc565b611021565b3480156105fc57600080fd5b506104ff6101a65481565b34801561061357600080fd5b50610627610622366004615afc565b61102c565b6040516001600160a01b039091168152602001610509565b34801561064b57600080fd5b5060cb546104ff565b34801561066057600080fd5b506104ff6101a55481565b34801561067757600080fd5b506105c061068636600461597a565b611057565b34801561069757600080fd5b506106ab6106a6366004615afc565b61107b565b005b3480156106b957600080fd5b5060405160128152602001610509565b3480156106d557600080fd5b506104ff611193565b3480156106ea57600080fd5b50610194546001600160a01b0316610627565b34801561070957600080fd5b506105c0610718366004615a1e565b6111a2565b34801561072957600080fd5b506104ff610738366004615a1e565b6111e1565b34801561074957600080fd5b5061075d610758366004615afc565b61125c565b604051610509919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0918201519181019190915260c00190565b3480156107b957600080fd5b506107c2611340565b60408051928352602083019190915201610509565b3480156107e357600080fd5b506106ab61141d565b3480156107f857600080fd5b506104ff6108073660046158be565b5060001990565b34801561081a57600080fd5b506105c06108293660046158be565b611451565b34801561083a57600080fd5b5061019554610627906001600160a01b031681565b34801561085b57600080fd5b5061062761086a3660046158be565b6001600160a01b03908116600090815261016260205260409020541690565b34801561089557600080fd5b506106ab6108a43660046158be565b6114d1565b3480156108b557600080fd5b5060975460ff166105c0565b3480156108cd57600080fd5b506104ff601d81565b3480156108e257600080fd5b506104ff6114de565b3480156108f757600080fd5b506104ff610906366004615b2c565b6114f6565b34801561091757600080fd5b506106ab610926366004615b2c565b611649565b34801561093757600080fd5b5061094b6109463660046158be565b61187d565b60405163ffffffff9091168152602001610509565b34801561096c57600080fd5b506104ff61097b3660046158be565b6118a0565b34801561098c57600080fd5b506106ab6118bb565b3480156109a157600080fd5b506106ab6118ef565b3480156109b657600080fd5b506106ab6109c53660046158d8565b611924565b3480156109d657600080fd5b506106ab6109e5366004615afc565b611935565b3480156109f657600080fd5b506101a0546101a1546101a2546101a354610a119392919084565b604080519485526020850193909352918301526060820152608001610509565b348015610a3d57600080fd5b506104ff610a4c3660046158be565b611a30565b348015610a5d57600080fd5b506106ab611a4f565b348015610a7257600080fd5b506106ab610a8136600461590a565b611a81565b348015610a9257600080fd5b50610aa6610aa13660046158be565b611c9e565b604051610509919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0828101519082015260c0918201519181019190915260e00190565b348015610b0c57600080fd5b506065546001600160a01b0316610627565b348015610b2a57600080fd5b506104ff610b39366004615afc565b611d57565b348015610b4a57600080fd5b506101a9546101aa546101ab546101ac546101ad54610b6a949392919085565b604080519586526020860194909452928401919091526060830152608082015260a001610509565b348015610b9e57600080fd5b506104ff610bad366004615b2c565b611db4565b348015610bbe57600080fd5b5061053c611eff565b348015610bd357600080fd5b506104ff610be23660046158be565b611f0e565b348015610bf357600080fd5b506106ab610c02366004615a1e565b611fa5565b348015610c1357600080fd5b50610c1c6122af565b6040516105099190615bad565b348015610c3557600080fd5b506105c0610c44366004615a1e565b612311565b348015610c5557600080fd5b50610589610c643660046158be565b6123a3565b348015610c7557600080fd5b506105c0610c84366004615a1e565b6123bf565b348015610c9557600080fd5b5061019454610627906001600160a01b031681565b348015610cb657600080fd5b506107c2610cc53660046158be565b6123cd565b348015610cd657600080fd5b506104ff6101a85481565b348015610ced57600080fd5b506104ff610cfc366004615b4e565b61246f565b348015610d0d57600080fd5b506106ab610d1c3660046158be565b6124b3565b348015610d2d57600080fd5b506104ff6107d081565b348015610d4357600080fd5b506104ff610d52366004615b4e565b6126d0565b6104ff610d653660046158be565b612700565b348015610d7657600080fd5b506106ab610d85366004615a47565b6127a5565b348015610d9657600080fd5b506104ff670de0b6b3a764000081565b348015610db257600080fd5b506106ab610dc1366004615a1e565b6128db565b348015610dd257600080fd5b506107c2610de13660046158be565b612a1e565b348015610df257600080fd5b506104ff610e013660046158be565b612ab9565b348015610e1257600080fd5b506106ab610e213660046159b5565b612acc565b348015610e3257600080fd5b506104ff610e413660046158be565b612c13565b348015610e5257600080fd5b506104ff610e613660046158d8565b612c1e565b348015610e7257600080fd5b506101ae546101af546101b054610e8892919083565b60408051938452602084019290925290820152606001610509565b348015610eaf57600080fd5b50610ec3610ebe366004615a9e565b612c49565b60408051825163ffffffff1681526020928301516001600160e01b03169281019290925201610509565b348015610ef957600080fd5b506106ab610f083660046158be565b612cdc565b348015610f1957600080fd5b506106ab612d74565b6000610f2c611340565b509050610f3860cb5490565b610f40575060005b90565b606060cc8054610f5290615e86565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7e90615e86565b8015610fcb5780601f10610fa057610100808354040283529160200191610fcb565b820191906000526020600020905b815481529060010190602001808311610fae57829003601f168201915b5050505050905090565b6000610fe082612dcd565b92915050565b600080610ff561019984612df4565b9150611002610199612e16565b9050915091565b600033611017818585612e20565b5060019392505050565b6000610fe082612f44565b61019d818154811061103d57600080fd5b6000918252602090912001546001600160a01b0316905081565b600033611065858285612f61565b611070858585612fdb565b506001949350505050565b6002600154141561109e5760405162461bcd60e51b81526004016104a090615d7d565b60026001556065546001600160a01b031633146110cd5760405162461bcd60e51b81526004016104a090615ca0565b6101b054811080156110df5750600081115b61112b5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420616d6f756e7420746f20636c61696d00000000000000000060448201526064016104a0565b806101ae60020160008282546111419190615e6f565b90915550611151905033826131ba565b604080513381526020810183905243917f379da6c373c474a7957620f46a6ebd7eab654b69b9df1b748503e1487177efcc910160405180910390a25060018055565b600061119d6132d3565b905090565b33600081815260ca602090815260408083206001600160a01b038716845290915281205490919061101790829086906111dc908790615db4565b612e20565b60004382106112325760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e65640060448201526064016104a0565b6001600160a01b038316600090815261016360205260409020611255908361334e565b9392505050565b61129e6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6101a25482106112dd5760405162461bcd60e51b815260206004820152600a6024820152691b9bc81cdd58da081a5960b21b60448201526064016104a0565b50600090815261019f6020908152604091829020825160c08101845281546001600160a01b03168152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260059091015460a082015290565b60008061134c60cb5490565b6113595750600191829150565b600080600080611367613427565b919450925090506113788385615db4565b6101ae549094506113899085615db4565b93506113958185615db4565b935060006113a283613651565b91506113b090508186615db4565b6101a0546101a2549196509081101561140557600081815261019f6020526040812060048101546005909101546101a3546113eb9190615e6f565b6113f59190615e6f565b90506114018188615e6f565b9650505b8561140f60cb5490565b975097505050505050509091565b6065546001600160a01b031633146114475760405162461bcd60e51b81526004016104a090615ca0565b61144f6136a0565b565b6000805b61019d5460ff821610156114c857826001600160a01b031661019d8260ff168154811061149257634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614156114b65750600192915050565b806114c081615ed6565b915050611455565b50600092915050565b6114db3382613733565b50565b60006114e86137c4565b6101a65461119d9190615db4565b610194546040516323b872dd60e01b81526000916001600160a01b0316906323b872dd9061152c90339030908890600401615b89565b602060405180830381600087803b15801561154657600080fd5b505af115801561155a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157e9190615adc565b6115b05760405162461bcd60e51b815260206004820152600360248201526245313160e81b60448201526064016104a0565b61019454604051632e1a7d4d60e01b8152600481018590526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b1580156115f757600080fd5b505af115801561160b573d6000803e3d6000fd5b5050505060008061161a611340565b90925090508161162a8287615e11565b6116349190615df1565b92506116418486856138de565b505092915050565b6002600154141561166c5760405162461bcd60e51b81526004016104a090615d7d565b600260015560975460ff16156116945760405162461bcd60e51b81526004016104a090615c4d565b600082116116db5760405162461bcd60e51b8152602060048201526014602482015273526564656d7074696f6e3a20302073686172657360601b60448201526064016104a0565b6001600160a01b03811660009081526101a46020908152604080832033845290915290206101ab5461170c82612e16565b106117595760405162461bcd60e51b815260206004820152601c60248201527f526564656d7074696f6e3a20746f6f206d616e792070656e64696e670000000060448201526064016104a0565b336001600160a01b0383161461177457611774823385612f61565b60008061177f611340565b90925090506000816117918488615e11565b61179b9190615df1565b90506117a785876139c0565b6101a254600081815261019f6020526040812080546001600160a01b0319163317815560018101899055600281018490554260038201556101a3805460058301819055919285926117f9908490615db4565b90915550506101a2805460019190600090611815908490615db4565b90915550611825905086836139d9565b506040805189815260208101859052839133916001600160a01b038b16917ffdf3f15b057962b89bdbe4a4651fbcffc001edd8acea6d9f5317bbeaceede6fd91015b60405180910390a4505060018055505050505050565b6001600160a01b03811660009081526101636020526040812054610fe0906139e5565b6001600160a01b0316600090815260c9602052604090205490565b6065546001600160a01b031633146118e55760405162461bcd60e51b81526004016104a090615ca0565b61144f6000613a4e565b6101b1546040516001600160a01b039091169036600082376000803683855af43d806000843e818015611920578184f35b8184fd5b6119313383836000613aa0565b5050565b6065546001600160a01b0316331461195f5760405162461bcd60e51b81526004016104a090615ca0565b60008111801561197157506107d08111155b6119ac5760405162461bcd60e51b815260206004820152600c60248201526b696e76616c6964207261746560a01b60448201526064016104a0565b6101a9548114156119ed5760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd0818da185b99d95960aa1b60448201526064016104a0565b6101a981905560408051338152602081018390527fde36a2e55e70e033bfc76a70f779635cdb034d90eac53e0a2b24f6037af5edda91015b60405180910390a150565b6001600160a01b038116600090815261012f6020526040812054610fe0565b6065546001600160a01b03163314611a795760405162461bcd60e51b81526004016104a090615ca0565b61144f613d47565b600054610100900460ff16611a9c5760005460ff1615611aa0565b303b155b611b035760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104a0565b600054610100900460ff16158015611b25576000805461ffff19166101011790555b611b2d613d9f565b611b35613dce565b611b3d613dfd565b611b856040518060400160405280600a8152602001695374616b6564204b435360b01b81525060405180604001604052806004815260200163734b435360e01b815250613e2c565b611bb06040518060400160405280600a8152602001695374616b6564204b435360b01b815250613e5d565b611bb8613eb0565b611bc5610196601d613ed7565b601d611bd16101965490565b14611c115760405162461bcd60e51b815260206004820152601060248201526f696e76616c696420636170616369747960801b60448201526064016104a0565b61019480546001600160a01b03808b166001600160a01b0319928316179092556101958054928a16929091169190911790556101a98590556101aa8490556101ab8390556203f4806101ac55611c6682612cdc565b6101b180546001600160a01b0319166001600160a01b0388161790558015611c94576000805461ff00191690555b5050505050505050565b611ce76040518060e0016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b506001600160a01b03908116600090815261019e6020908152604091829020825160e081018452815490941684526001810154918401919091526002810154918301919091526003810154606083015260048101546080830152600581015460a08301526006015460c082015290565b6000438210611da85760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e65640060448201526064016104a0565b610fe06101648361334e565b6000806000611dc1611340565b909250905081611dd18287615e11565b611ddb9190615df1565b610194546040516323b872dd60e01b81529194506001600160a01b0316906323b872dd90611e1190339030908890600401615b89565b602060405180830381600087803b158015611e2b57600080fd5b505af1158015611e3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e639190615adc565b611e955760405162461bcd60e51b815260206004820152600360248201526245313160e81b60448201526064016104a0565b61019454604051632e1a7d4d60e01b8152600481018590526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b158015611edc57600080fd5b505af1158015611ef0573d6000803e3d6000fd5b505050506116418484876138de565b606060cd8054610f5290615e86565b6001600160a01b038116600090815261016360205260408120548015611f92576001600160a01b038316600090815261016360205260409020611f52600183615e6f565b81548110611f7057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015464010000000090046001600160e01b0316611f95565b60005b6001600160e01b03169392505050565b6065546001600160a01b03163314611fcf5760405162461bcd60e51b81526004016104a090615ca0565b61019554604051631015428760e21b81526001600160a01b038481166004830152909116906340550a1c9060240160206040518083038186803b15801561201557600080fd5b505afa158015612029573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204d9190615adc565b6120915760405162461bcd60e51b81526020600482015260156024820152746163746976652076616c696461746f72206f6e6c7960581b60448201526064016104a0565b6001600160a01b0382166120b75760405162461bcd60e51b81526004016104a090615c77565b6000811180156120c8575060648111155b6121055760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081dd95a59da1d60921b60448201526064016104a0565b61019d54601d1161214e5760405162461bcd60e51b8152602060048201526013602482015272746f6f206d616e792076616c696461746f727360681b60448201526064016104a0565b6001600160a01b03828116600090815261019e602052604090205416611931576040805160e0810182526001600160a01b0384811680835260208084018681526000858701818152606087018281526080880183815260a0890184815260c08a0185815297855261019e90965298909220965187546001600160a01b031916961695909517865590516001860155925160028501559151600384015592516004830155516005820155905160069091015561220b61019983613f56565b5061019d805460018101825560009182527f71880bb8535eda3be1bc3614789b84ba72ab02d5ae26ba282fa1178bb7fea1e60180546001600160a01b0319166001600160a01b0385161790556101ad805483929061226a908490615db4565b90915550506040517f09a4c0758c99f52fc2d8f37f71ca95b67c463c947ef47a32c16e9493f46a3f81906122a390339085908590615b89565b60405180910390a15050565b606061019d805480602002602001604051908101604052809291908181526020018280548015610fcb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122ea575050505050905090565b33600081815260ca602090815260408083206001600160a01b0387168452909152812054909190838110156123965760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016104a0565b6110708286868403612e20565b6000806123b261019b84612df4565b915061100261019b612e16565b600033611017818585612fdb565b6001600160a01b03811660009081526101a4602090815260408083203384529091528120819061019f825b61240183612e16565b8110156124675760006124148483613f6b565b905082600201548110612454576000818152602084905260409020600281015461243e9088615db4565b96508060010154866124509190615db4565b9550505b508061245f81615ebb565b9150506123f8565b505050915091565b60008061247b83612a1e565b9250905084811461249e5760405162461bcd60e51b81526004016104a090615d20565b6124ab3384866001613aa0565b509392505050565b6065546001600160a01b031633146124dd5760405162461bcd60e51b81526004016104a090615ca0565b61019d546001106125285760405162461bcd60e51b81526020600482015260156024820152746e6f7420656e6f7567682076616c696461746f722160581b60448201526064016104a0565b6001600160a01b03811661254e5760405162461bcd60e51b81526004016104a090615c77565b61255a61019982612df4565b156114db5761256b61019982613f77565b5061257581613f8c565b6101ae8054600090612588908490615db4565b90915550506001600160a01b038116600090815261019e60205260409020600201541561267b57610195546001600160a01b03828116600090815261019e602052604090206002015491169063ee16442e9083906125ef90670de0b6b3a764000090615df1565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561263557600080fd5b505af1158015612649573d6000803e3d6000fd5b5050506001600160a01b038216600090815261019e602052604081206002810180546003830155600490910182905555505b61268761019b82613f56565b506126918161410c565b50604080513381526001600160a01b03831660208201527f373de1e40a19b3955370231ed6a2fb9e540299dacac08e76f46f30006209fb439101611a25565b6000806126dc83612a1e565b909250905084811461249e5760405162461bcd60e51b81526004016104a090615d20565b60006001600160a01b0382166127285760405162461bcd60e51b81526004016104a090615c77565b600034116127695760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a5908185b5bdd5b9d60921b60448201526064016104a0565b600080612774611340565b90925090506000826127868334615e11565b6127909190615df1565b905061279d8534836138de565b949350505050565b834211156127f55760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e6174757265206578706972656400000060448201526064016104a0565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b03881691810191909152606081018690526080810185905260009061286f906128679060a00160405160208183030381529060405280519060200120614269565b8585856142b7565b905061287a816142df565b86146128c85760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e63650000000000000060448201526064016104a0565b6128d28188613733565b50505050505050565b6065546001600160a01b031633146129055760405162461bcd60e51b81526004016104a090615ca0565b6001600160a01b03821661292b5760405162461bcd60e51b81526004016104a090615c77565b60008111801561293c575060648111155b6129795760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081dd95a59da1d60921b60448201526064016104a0565b6001600160a01b03808316600090815261019e60205260409020805490911615612a195760018101546101ad80546000906129b5908490615e6f565b9091555050600181018290556101ad80548391906000906129d7908490615db4565b90915550506040517f59dc32f3648f08109d4de7f5122971e1c26167b086d67f6faad7e2b894c9c67890612a1090339086908690615b89565b60405180910390a15b505050565b6001600160a01b03811660009081526101a4602090815260408083203384529091528120819061019f825b612a5283612e16565b811015612467576000612a658483613f6b565b90508260020154811015612aa65760008181526020849052604090206002810154612a909088615db4565b9650806001015486612aa29190615db4565b9550505b5080612ab181615ebb565b915050612a49565b6000610fe0612ac783614306565b612dcd565b83421115612b1c5760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016104a0565b600061013054888888612b2e8c6142df565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000612b8982614269565b90506000612b99828787876142b7565b9050896001600160a01b0316816001600160a01b031614612bfc5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016104a0565b612c078a8a8a612e20565b50505050505050505050565b6000610fe082614306565b6001600160a01b03918216600090815260ca6020908152604080832093909416825291909152205490565b60408051808201909152600080825260208201526001600160a01b038316600090815261016360205260409020805463ffffffff8416908110612c9c57634e487b7160e01b600052603260045260246000fd5b60009182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b6065546001600160a01b03163314612d065760405162461bcd60e51b81526004016104a090615ca0565b6001600160a01b038116612d6b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104a0565b6114db81613a4e565b60026001541415612d975760405162461bcd60e51b81526004016104a090615d7d565b600260015560975460ff1615612dbf5760405162461bcd60e51b81526004016104a090615c4d565b612dc761433d565b60018055565b6000806000612dda611340565b909250905080612dea8386615e11565b61279d9190615df1565b6001600160a01b03811660009081526001830160205260408120541515611255565b6000610fe0825490565b6001600160a01b038316612e825760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016104a0565b6001600160a01b038216612ee35760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104a0565b6001600160a01b03838116600081815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000806000612f51611340565b909250905081612dea8286615e11565b6000612f6d8484612c1e565b90506000198114612fd55781811015612fc85760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104a0565b612fd58484848403612e20565b50505050565b6001600160a01b03831661303f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104a0565b6001600160a01b0382166130a15760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104a0565b6130ac8383836143ff565b6001600160a01b038316600090815260c96020526040902054818110156131245760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016104a0565b6001600160a01b03808516600090815260c9602052604080822085850390559185168152908120805484929061315b908490615db4565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516131a791815260200190565b60405180910390a3612fd5848484614456565b8047101561320a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016104a0565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613257576040519150601f19603f3d011682016040523d82523d6000602084013e61325c565b606091505b5050905080612a195760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016104a0565b600061119d7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61330260fb5490565b60fc546040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b8154600090815b818110156133c057600061336982846144ae565b90508486828154811061338c57634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff1611156133ac578092506133ba565b6133b7816001615db4565b91505b50613355565b811561341257846133d2600184615e6f565b815481106133f057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015464010000000090046001600160e01b0316613415565b60005b6001600160e01b031695945050505050565b60008080805b61019d5460ff821610156135e157600061019d8260ff168154811061346257634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b031680835261019e9091526040909120600201549091506134989086615db4565b6001600160a01b038216600090815261019e6020526040902060048101546003909101549196506134c891615e6f565b6134d29084615db4565b925061019560009054906101000a90046001600160a01b03166001600160a01b0316639ced7e7661019e600061019d8660ff168154811061352357634e487b7160e01b600052603260045260246000fd5b6000918252602080832091909101546001600160a01b039081168452908301939093526040918201902054905160e084901b6001600160e01b03191681529116600482015230602482015260440160206040518083038186803b15801561358957600080fd5b505afa15801561359d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135c19190615b14565b6135cb9085615db4565b93505080806135d990615ed6565b91505061342d565b5060005b6135f061019b612e16565b8160ff16101561364b57600061360b61019b60ff8416613f6b565b6001600160a01b038116600090815261019e60205260409020600301549091506136359084615db4565b925050808061364390615ed6565b9150506135e5565b50909192565b6000808261366457506000928392509050565b6101a954662386f26fc10000906136808564e8d4a51000615e11565b61368a9190615e11565b6136949190615df1565b91506110028284615e6f565b60975460ff166136e95760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016104a0565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03828116600090815261016260205260408120549091169061375b846118a0565b6001600160a01b038581166000818152610162602052604080822080546001600160a01b031916898616908117909155905194955093928616927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4612fd58284836144c9565b60008060005b61019d5460ff821610156138d8576101955461019d80546001600160a01b0390921691639ced7e769161019e916000919060ff871690811061381c57634e487b7160e01b600052603260045260246000fd5b6000918252602080832091909101546001600160a01b039081168452908301939093526040918201902054905160e084901b6001600160e01b03191681529116600482015230602482015260440160206040518083038186803b15801561388257600080fd5b505afa158015613896573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ba9190615b14565b6138c49083615db4565b9150806138d081615ed6565b9150506137ca565b50919050565b600260015414156139015760405162461bcd60e51b81526004016104a090615d7d565b600260015560975460ff16156139295760405162461bcd60e51b81526004016104a090615c4d565b816101ae600001600082825461393f9190615db4565b92505081905550816101a560008282546139599190615db4565b909155506139679050614608565b6139718382614731565b60408051838152602081018390526001600160a01b0385169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a350506001805550565b6139ca82826147bc565b612fd561016461491d83614929565b60006112558383614acc565b600063ffffffff821115613a4a5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b60648201526084016104a0565b5090565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60026001541415613ac35760405162461bcd60e51b81526004016104a090615d7d565b600260015560975460ff1615613aeb5760405162461bcd60e51b81526004016104a090615c4d565b6001600160a01b0380841660009081526101a46020908152604080832093881683529290529081209061019f9080805b613b2485612e16565b811015613b9b576000613b378683613f6b565b90508460020154811015613b885760008181526020869052604090206002810154613b629086615db4565b9450806001015484613b749190615db4565b9350613b808783614b1b565b505050613b1b565b81613b9281615ebb565b92505050613b1b565b50816101ae6001016000828254613bb29190615e6f565b90915550859050613bcc57613bc786836131ba565b613cef565b61019460009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015613c1d57600080fd5b505af1158015613c31573d6000803e3d6000fd5b50506101945460405163a9059cbb60e01b81526001600160a01b038b8116600483015260248201889052909116935063a9059cbb92506044019050602060405180830381600087803b158015613c8657600080fd5b505af1158015613c9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cbe9190615adc565b613cef5760405162461bcd60e51b8152602060048201526002602482015261453560f01b60448201526064016104a0565b866001600160a01b0316866001600160a01b0316896001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051611867929190918252602082015260400190565b60975460ff1615613d6a5760405162461bcd60e51b81526004016104a090615c4d565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586137163390565b600054610100900460ff16613dc65760405162461bcd60e51b81526004016104a090615cd5565b61144f614b27565b600054610100900460ff16613df55760405162461bcd60e51b81526004016104a090615cd5565b61144f614b57565b600054610100900460ff16613e245760405162461bcd60e51b81526004016104a090615cd5565b61144f614b7e565b600054610100900460ff16613e535760405162461bcd60e51b81526004016104a090615cd5565b6119318282614bb1565b600054610100900460ff16613e845760405162461bcd60e51b81526004016104a090615cd5565b613ea781604051806040016040528060018152602001603160f81b815250614bff565b6114db81614c40565b600054610100900460ff1661144f5760405162461bcd60e51b81526004016104a090615cd5565b8160005b82811015613f155781546001810183556000838152602090200180546001600160a01b031916905580613f0d81615ebb565b915050613edb565b5080548214612a195760405162461bcd60e51b815260206004820152600d60248201526c1c995a5b9a5d1a585b1a5e9959609a1b60448201526064016104a0565b6000611255836001600160a01b038416614acc565b60006112558383614c8f565b6000611255836001600160a01b038416614cc7565b60006001600160a01b038216613fb45760405162461bcd60e51b81526004016104a090615c77565b61019554604051634e76bf3b60e11b81526001600160a01b0384811660048301523060248301524792600092911690639ced7e769060440160206040518083038186803b15801561400457600080fd5b505afa158015614018573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061403c9190615b14565b90508061404d575060009392505050565b6101955460405163d279c19160e01b81526001600160a01b0386811660048301529091169063d279c19190602401600060405180830381600087803b15801561409557600080fd5b505af11580156140a9573d6000803e3d6000fd5b50505050600082476140bb9190615e6f565b9050806101a660008282546140d09190615db4565b9091555060009050806140e283613651565b91509150816101ae60020160008282546140fc9190615db4565b9091555090979650505050505050565b6000805b61019d5460ff8216101561426057826001600160a01b031661019d8260ff168154811061414d57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316141561424e5761019d805461417990600190615e6f565b8154811061419757634e487b7160e01b600052603260045260246000fd5b60009182526020909120015461019d80546001600160a01b039092169160ff84169081106141d557634e487b7160e01b600052603260045260246000fd5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061019d80548061422357634e487b7160e01b600052603160045260246000fd5b600082815260209020810160001990810180546001600160a01b031916905501905550600192915050565b8061425881615ed6565b915050614110565b50600192915050565b6000610fe06142766132d3565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006142c887878787614de4565b915091506142d581614ed1565b5095945050505050565b6001600160a01b038116600090815261012f602052604090208054600181018255906138d8565b6000336001600160a01b038316141561432257610fe0826118a0565b610fe061432e836118a0565b6143388433612c1e565b6150d2565b6143456150e8565b60006143576143526137c4565b613651565b6101aa546101ae54919350915061436f908390615db4565b10156143785750565b60006143826153a4565b9050806101ae600001600082825461439a9190615db4565b92505081905550806101a560008282546143b49190615db4565b909155506143c29050614608565b604080513381524260208201529081018290527f0e311a2c6dbfb0153ec3a8a5bdca09070b3e5f60768fdc10a20453f38d186873906060016122a3565b614408826118a0565b614413576000614416565b60015b61441f846118a0565b61442a57600061442d565b60015b6144379190615dcc565b60ff166101a7600082825461444c9190615e6f565b9091555050505050565b614461838383615479565b61446a826118a0565b614475576000614478565b60015b614481846118a0565b61448c57600061448f565b60015b6144999190615dcc565b60ff166101a7600082825461444c9190615db4565b60006144bd6002848418615df1565b61125590848416615db4565b816001600160a01b0316836001600160a01b0316141580156144eb5750600081115b15612a19576001600160a01b0383161561457a576001600160a01b03831660009081526101636020526040812081906145279061491d85614929565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724838360405161456f929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615612a19576001600160a01b03821660009081526101636020526040812081906145b1906154ac85614929565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a72483836040516145f9929190918252602082015260400190565b60405180910390a25050505050565b6101aa546101ae54101561461857565b60006146226154b8565b90506001600160a01b0381166146355750565b61463e81613f8c565b6101ae8054600090614651908490615db4565b90915550506101ae5460009061467090670de0b6b3a764000090615df1565b90506000614686670de0b6b3a764000083615e11565b9050806101ae600001600082825461469e9190615e6f565b90915550506001600160a01b038316600090815261019e6020526040812060020180548392906146cf908490615db4565b9091555050610195546040516336ebec7560e11b81526001600160a01b03858116600483015290911690636dd7d8ea9083906024016000604051808303818588803b15801561471d57600080fd5b505af1158015611c94573d6000803e3d6000fd5b61473b8282615635565b60cb546001600160e01b0310156147ad5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b60648201526084016104a0565b612fd56101646154ac83614929565b6001600160a01b03821661481c5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016104a0565b614828826000836143ff565b6001600160a01b038216600090815260c960205260409020548181101561489c5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016104a0565b6001600160a01b038316600090815260c960205260408120838303905560cb80548492906148cb908490615e6f565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3612a1983600084614456565b60006112558284615e6f565b8254600090819080156149825785614942600183615e6f565b8154811061496057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015464010000000090046001600160e01b0316614985565b60005b6001600160e01b0316925061499e83858763ffffffff16565b91506000811180156149ea575043866149b8600184615e6f565b815481106149d657634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16145b15614a58576149f882615728565b86614a04600184615e6f565b81548110614a2257634e487b7160e01b600052603260045260246000fd5b9060005260206000200160000160046101000a8154816001600160e01b0302191690836001600160e01b03160217905550614ac3565b856040518060400160405280614a6d436139e5565b63ffffffff168152602001614a8185615728565b6001600160e01b0390811690915282546001810184556000938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b50935093915050565b6000818152600183016020526040812054614b1357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610fe0565b506000610fe0565b60006112558383614cc7565b600054610100900460ff16614b4e5760405162461bcd60e51b81526004016104a090615cd5565b61144f33613a4e565b600054610100900460ff16612dc75760405162461bcd60e51b81526004016104a090615cd5565b600054610100900460ff16614ba55760405162461bcd60e51b81526004016104a090615cd5565b6097805460ff19169055565b600054610100900460ff16614bd85760405162461bcd60e51b81526004016104a090615cd5565b8151614beb9060cc906020850190615801565b508051612a199060cd906020840190615801565b600054610100900460ff16614c265760405162461bcd60e51b81526004016104a090615cd5565b81516020928301208151919092012060fb9190915560fc55565b600054610100900460ff16614c675760405162461bcd60e51b81526004016104a090615cd5565b507f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961013055565b6000826000018281548110614cb457634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b60008181526001830160205260408120548015614dda576000614ceb600183615e6f565b8554909150600090614cff90600190615e6f565b9050818114614d80576000866000018281548110614d2d57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905080876000018481548110614d5e57634e487b7160e01b600052603260045260246000fd5b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614d9f57634e487b7160e01b600052603160045260246000fd5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610fe0565b6000915050610fe0565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614e1b5750600090506003614ec8565b8460ff16601b14158015614e3357508460ff16601c14155b15614e445750600090506004614ec8565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614e98573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614ec157600060019250925050614ec8565b9150600090505b94509492505050565b6000816004811115614ef357634e487b7160e01b600052602160045260246000fd5b1415614efc5750565b6001816004811115614f1e57634e487b7160e01b600052602160045260246000fd5b1415614f6c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016104a0565b6002816004811115614f8e57634e487b7160e01b600052602160045260246000fd5b1415614fdc5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016104a0565b6003816004811115614ffe57634e487b7160e01b600052602160045260246000fd5b14156150575760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016104a0565b600481600481111561507957634e487b7160e01b600052602160045260246000fd5b14156114db5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016104a0565b60008183106150e15781611255565b5090919050565b60005b6150f661019b612e16565b8160ff1610156114db57600061511161019b60ff8416613f6b565b6101955460405163badca81960e01b81523060048201526001600160a01b03808416602483015292935091169063badca8199060440160206040518083038186803b15801561515f57600080fd5b505afa158015615173573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151979190615adc565b1561529a5760006151a782615791565b6001600160a01b038316600090815261019e60205260408120600101546101ad805493945090929091906151dc908490615e6f565b90915550506040805160e08101825260008082526020808301828152838501838152606085018481526080860185815260a0870186815260c088018781526001600160a01b038c8116895261019e909752988720975188546001600160a01b0319169616959095178755925160018701559051600286015551600385015551600484015551600583015591516006909101556101ae8054839290615281908490615db4565b90915550615293905061019b83613f77565b505061539e565b6001600160a01b038116600090815261019e6020526040902060030154615390576001600160a01b038116600090815261019e60205260408120600101546101ad8054919290916152ec908490615e6f565b90915550506040805160e08101825260008082526020808301828152838501838152606085018481526080860185815260a0870186815260c088018781526001600160a01b038b8116895261019e90975298909620965187546001600160a01b031916951694909417865591516001860155516002850155516003840155516004830155516005820155905160069091015561538a61019b82613f77565b5061539e565b8161539a81615ed6565b9250505b506150eb565b60008060005b61019d5460ff821610156154335761541561019e600061019d8460ff16815481106153e557634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03908116845290830193909352604090910190205416613f8c565b61541f9083615db4565b91508061542b81615ed6565b9150506153aa565b50604080513381524360208201529081018290527f6fd374a97f893367a4c9cf189b53a9d33200335b92191b4b0aa5edfd182dc4c19060600160405180910390a1919050565b6001600160a01b0383811660009081526101626020526040808220548584168352912054612a19929182169116836144c9565b60006112558284615db4565b6000806154c3613427565b50509050806000141561551f5761019d54156155165761019d6000815481106154fc57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316615519565b60005b91505090565b6001600160ff1b036000805b61019d5460ff821610156124ab57600061019e600061019d8460ff168154811061556557634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316835282019290925260400181206101ad546001820154919350906155a490633b9aca00615e11565b6155ae9190615df1565b868360020154633b9aca006155c39190615e11565b6155cd9190615df1565b6155d79190615e30565b90508481136156205780945061019d8360ff168154811061560857634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031693505b5050808061562d90615ed6565b91505061552b565b6001600160a01b03821661568b5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104a0565b615697600083836143ff565b8060cb60008282546156a99190615db4565b90915550506001600160a01b038216600090815260c96020526040812080548392906156d6908490615db4565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a361193160008383614456565b60006001600160e01b03821115613a4a5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b60648201526084016104a0565b610195546040516351cff8d960e01b81526001600160a01b03838116600483015260009247929116906351cff8d990602401600060405180830381600087803b1580156157dd57600080fd5b505af11580156157f1573d6000803e3d6000fd5b5050505080476112559190615e6f565b82805461580d90615e86565b90600052602060002090601f01602090048101928261582f5760008555615875565b82601f1061584857805160ff1916838001178555615875565b82800160010185558215615875579182015b8281111561587557825182559160200191906001019061585a565b50613a4a9291505b80821115613a4a576000815560010161587d565b80356001600160a01b03811681146158a857600080fd5b919050565b803560ff811681146158a857600080fd5b6000602082840312156158cf578081fd5b61125582615891565b600080604083850312156158ea578081fd5b6158f383615891565b915061590160208401615891565b90509250929050565b600080600080600080600060e0888a031215615924578283fd5b61592d88615891565b965061593b60208901615891565b955061594960408901615891565b9450606088013593506080880135925060a0880135915061596c60c08901615891565b905092959891949750929550565b60008060006060848603121561598e578283fd5b61599784615891565b92506159a560208501615891565b9150604084013590509250925092565b600080600080600080600060e0888a0312156159cf578283fd5b6159d888615891565b96506159e660208901615891565b95506040880135945060608801359350615a02608089016158ad565b925060a0880135915060c0880135905092959891949750929550565b60008060408385031215615a30578182fd5b615a3983615891565b946020939093013593505050565b60008060008060008060c08789031215615a5f578182fd5b615a6887615891565b95506020870135945060408701359350615a84606088016158ad565b92506080870135915060a087013590509295509295509295565b60008060408385031215615ab0578182fd5b615ab983615891565b9150602083013563ffffffff81168114615ad1578182fd5b809150509250929050565b600060208284031215615aed578081fd5b81518015158114611255578182fd5b600060208284031215615b0d578081fd5b5035919050565b600060208284031215615b25578081fd5b5051919050565b60008060408385031215615b3e578182fd5b8235915061590160208401615891565b600080600060608486031215615b62578081fd5b83359250615b7260208501615891565b9150615b8060408501615891565b90509250925092565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6020808252825182820181905260009190848201906040850190845b81811015615bee5783516001600160a01b031683529284019291840191600101615bc9565b50909695505050505050565b6000602080835283518082850152825b81811015615c2657858101830151858201604001528201615c0a565b81811115615c375783604083870101525b50601f01601f1916929092016040019392505050565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252600f908201526e696e76616c6964206164647265737360881b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020808252603f908201527f73686172657320616d6f756e7420646f6573206e6f74206d617463682077697460408201527f6820616d6f756e7420696e20726564656d7074696f6e20726571756573747300606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60008219821115615dc757615dc7615ef6565b500190565b600060ff821660ff84168060ff03821115615de957615de9615ef6565b019392505050565b600082615e0c57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615e2b57615e2b615ef6565b500290565b60008083128015600160ff1b850184121615615e4e57615e4e615ef6565b6001600160ff1b0384018313811615615e6957615e69615ef6565b50500390565b600082821015615e8157615e81615ef6565b500390565b600181811c90821680615e9a57607f821691505b602082108114156138d857634e487b7160e01b600052602260045260246000fd5b6000600019821415615ecf57615ecf615ef6565b5060010190565b600060ff821660ff811415615eed57615eed615ef6565b60010192915050565b634e487b7160e01b600052601160045260246000fdfea264697066735822122011357ccaa1084eaf718d13d84e5694ae1f6a2593c69b9fe931213400185cbf0b64736f6c63430008040033