Overview
S Balance
0 S
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
OSonicVaultCore
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { OETHVaultCore } from "./OETHVaultCore.sol"; /** * @title Origin Sonic VaultCore contract on Sonic * @author Origin Protocol Inc */ contract OSonicVaultCore is OETHVaultCore { /// @param _wS Sonic's Wrapped S token constructor(address _wS) OETHVaultCore(_wS) {} /** * @notice Instant redeem is not supported on Sonic. * Use the asynchronous `requestWithdrawal` a `claimWithdrawal` instead. */ function redeem(uint256, uint256) external override { revert("unsupported function"); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (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 Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(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); } } } }
// SPDX-License-Identifier: MIT // 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 SafeCast { /** * @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); } }
// SPDX-License-Identifier: MIT // 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 SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { 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; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Base for contracts that are managed by the Origin Protocol's Governor. * @dev Copy of the openzeppelin Ownable.sol contract with nomenclature change * from owner to governor and renounce methods removed. Does not use * Context.sol like Ownable.sol does for simplification. * @author Origin Protocol Inc */ contract Governable { // Storage position of the owner and pendingOwner of the contract // keccak256("OUSD.governor"); bytes32 private constant governorPosition = 0x7bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a; // keccak256("OUSD.pending.governor"); bytes32 private constant pendingGovernorPosition = 0x44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db; // keccak256("OUSD.reentry.status"); bytes32 private constant reentryStatusPosition = 0x53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac4535; // See OpenZeppelin ReentrancyGuard implementation uint256 constant _NOT_ENTERED = 1; uint256 constant _ENTERED = 2; event PendingGovernorshipTransfer( address indexed previousGovernor, address indexed newGovernor ); event GovernorshipTransferred( address indexed previousGovernor, address indexed newGovernor ); /** * @dev Initializes the contract setting the deployer as the initial Governor. */ constructor() { _setGovernor(msg.sender); emit GovernorshipTransferred(address(0), _governor()); } /** * @notice Returns the address of the current Governor. */ function governor() public view returns (address) { return _governor(); } /** * @dev Returns the address of the current Governor. */ function _governor() internal view returns (address governorOut) { bytes32 position = governorPosition; // solhint-disable-next-line no-inline-assembly assembly { governorOut := sload(position) } } /** * @dev Returns the address of the pending Governor. */ function _pendingGovernor() internal view returns (address pendingGovernor) { bytes32 position = pendingGovernorPosition; // solhint-disable-next-line no-inline-assembly assembly { pendingGovernor := sload(position) } } /** * @dev Throws if called by any account other than the Governor. */ modifier onlyGovernor() { require(isGovernor(), "Caller is not the Governor"); _; } /** * @notice Returns true if the caller is the current Governor. */ function isGovernor() public view returns (bool) { return msg.sender == _governor(); } function _setGovernor(address newGovernor) internal { bytes32 position = governorPosition; // solhint-disable-next-line no-inline-assembly assembly { sstore(position, newGovernor) } } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { bytes32 position = reentryStatusPosition; uint256 _reentry_status; // solhint-disable-next-line no-inline-assembly assembly { _reentry_status := sload(position) } // On the first call to nonReentrant, _notEntered will be true require(_reentry_status != _ENTERED, "Reentrant call"); // Any calls to nonReentrant after this point will fail // solhint-disable-next-line no-inline-assembly assembly { sstore(position, _ENTERED) } _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) // solhint-disable-next-line no-inline-assembly assembly { sstore(position, _NOT_ENTERED) } } function _setPendingGovernor(address newGovernor) internal { bytes32 position = pendingGovernorPosition; // solhint-disable-next-line no-inline-assembly assembly { sstore(position, newGovernor) } } /** * @notice Transfers Governance of the contract to a new account (`newGovernor`). * Can only be called by the current Governor. Must be claimed for this to complete * @param _newGovernor Address of the new Governor */ function transferGovernance(address _newGovernor) external onlyGovernor { _setPendingGovernor(_newGovernor); emit PendingGovernorshipTransfer(_governor(), _newGovernor); } /** * @notice Claim Governance of the contract to a new account (`newGovernor`). * Can only be called by the new Governor. */ function claimGovernance() external { require( msg.sender == _pendingGovernor(), "Only the pending Governor can complete the claim" ); _changeGovernor(msg.sender); } /** * @dev Change Governance of the contract to a new account (`newGovernor`). * @param _newGovernor Address of the new Governor */ function _changeGovernor(address _newGovernor) internal { require(_newGovernor != address(0), "New Governor is address(0)"); emit GovernorshipTransferred(_governor(), _newGovernor); _setGovernor(_newGovernor); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IBasicToken { function symbol() external view returns (string memory); function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IDripper { /// @notice How much funds have dripped out already and are currently // available to be sent to the vault. /// @return The amount that would be sent if a collect was called function availableFunds() external view returns (uint256); /// @notice Collect all dripped funds and send to vault. /// Recalculate new drip rate. function collect() external; /// @notice Collect all dripped funds, send to vault, recalculate new drip /// rate, and rebase mToken. function collectAndRebase() external; /// @notice Change the drip duration. Governor only. /// @param _durationSeconds the number of seconds to drip out the entire /// balance over if no collects were called during that time. function setDripDuration(uint256 _durationSeconds) external; /// @dev Transfer out ERC20 tokens held by the contract. Governor only. /// @param _asset ERC20 token address /// @param _amount amount to transfer function transferToken(address _asset, uint256 _amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IGetExchangeRateToken { function getExchangeRate() external view returns (uint256 _exchangeRate); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IOracle { /** * @dev returns the asset price in USD, in 8 decimal digits. * * The version of priceProvider deployed for OETH has 18 decimal digits */ function price(address asset) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Platform interface to integrate with lending platform like Compound, AAVE etc. */ interface IStrategy { /** * @dev Deposit the given asset to platform * @param _asset asset address * @param _amount Amount to deposit */ function deposit(address _asset, uint256 _amount) external; /** * @dev Deposit the entire balance of all supported assets in the Strategy * to the platform */ function depositAll() external; /** * @dev Withdraw given asset from Lending platform */ function withdraw( address _recipient, address _asset, uint256 _amount ) external; /** * @dev Liquidate all assets in strategy and return them to Vault. */ function withdrawAll() external; /** * @dev Returns the current balance of the given asset. */ function checkBalance(address _asset) external view returns (uint256 balance); /** * @dev Returns bool indicating whether strategy supports asset. */ function supportsAsset(address _asset) external view returns (bool); /** * @dev Collect reward tokens from the Strategy. */ function collectRewardTokens() external; /** * @dev The address array of the reward tokens for the Strategy. */ function getRewardTokenAddresses() external view returns (address[] memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /** * @title OUSD Token Contract * @dev ERC20 compatible contract for OUSD * @dev Implements an elastic supply * @author Origin Protocol Inc */ import { Governable } from "../governance/Governable.sol"; import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; contract OUSD is Governable { using SafeCast for int256; using SafeCast for uint256; /// @dev Event triggered when the supply changes /// @param totalSupply Updated token total supply /// @param rebasingCredits Updated token rebasing credits /// @param rebasingCreditsPerToken Updated token rebasing credits per token event TotalSupplyUpdatedHighres( uint256 totalSupply, uint256 rebasingCredits, uint256 rebasingCreditsPerToken ); /// @dev Event triggered when an account opts in for rebasing /// @param account Address of the account event AccountRebasingEnabled(address account); /// @dev Event triggered when an account opts out of rebasing /// @param account Address of the account event AccountRebasingDisabled(address account); /// @dev Emitted when `value` tokens are moved from one account `from` to /// another `to`. /// @param from Address of the account tokens are moved from /// @param to Address of the account tokens are moved to /// @param value Amount of tokens transferred 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. /// @param owner Address of the owner approving allowance /// @param spender Address of the spender allowance is granted to /// @param value Amount of tokens spender can transfer event Approval( address indexed owner, address indexed spender, uint256 value ); /// @dev Yield resulting from {changeSupply} that a `source` account would /// receive is directed to `target` account. /// @param source Address of the source forwarding the yield /// @param target Address of the target receiving the yield event YieldDelegated(address source, address target); /// @dev Yield delegation from `source` account to the `target` account is /// suspended. /// @param source Address of the source suspending yield forwarding /// @param target Address of the target no longer receiving yield from `source` /// account event YieldUndelegated(address source, address target); enum RebaseOptions { NotSet, StdNonRebasing, StdRebasing, YieldDelegationSource, YieldDelegationTarget } uint256[154] private _gap; // Slots to align with deployed contract uint256 private constant MAX_SUPPLY = type(uint128).max; /// @dev The amount of tokens in existence uint256 public totalSupply; mapping(address => mapping(address => uint256)) private allowances; /// @dev The vault with privileges to execute {mint}, {burn} /// and {changeSupply} address public vaultAddress; mapping(address => uint256) internal creditBalances; // the 2 storage variables below need trailing underscores to not name collide with public functions uint256 private rebasingCredits_; // Sum of all rebasing credits (creditBalances for rebasing accounts) uint256 private rebasingCreditsPerToken_; /// @dev The amount of tokens that are not rebasing - receiving yield uint256 public nonRebasingSupply; mapping(address => uint256) internal alternativeCreditsPerToken; /// @dev A map of all addresses and their respective RebaseOptions mapping(address => RebaseOptions) public rebaseState; mapping(address => uint256) private __deprecated_isUpgraded; /// @dev A map of addresses that have yields forwarded to. This is an /// inverse mapping of {yieldFrom} /// Key Account forwarding yield /// Value Account receiving yield mapping(address => address) public yieldTo; /// @dev A map of addresses that are receiving the yield. This is an /// inverse mapping of {yieldTo} /// Key Account receiving yield /// Value Account forwarding yield mapping(address => address) public yieldFrom; uint256 private constant RESOLUTION_INCREASE = 1e9; uint256[34] private __gap; // including below gap totals up to 200 /// @dev Initializes the contract and sets necessary variables. /// @param _vaultAddress Address of the vault contract /// @param _initialCreditsPerToken The starting rebasing credits per token. function initialize(address _vaultAddress, uint256 _initialCreditsPerToken) external onlyGovernor { require(_vaultAddress != address(0), "Zero vault address"); require(vaultAddress == address(0), "Already initialized"); rebasingCreditsPerToken_ = _initialCreditsPerToken; vaultAddress = _vaultAddress; } /// @dev Returns the symbol of the token, a shorter version /// of the name. function symbol() external pure virtual returns (string memory) { return "OUSD"; } /// @dev Returns the name of the token. function name() external pure virtual returns (string memory) { return "Origin Dollar"; } /// @dev Returns the number of decimals used to get its user representation. function decimals() external pure virtual returns (uint8) { return 18; } /** * @dev Verifies that the caller is the Vault contract */ modifier onlyVault() { require(vaultAddress == msg.sender, "Caller is not the Vault"); _; } /** * @return High resolution rebasingCreditsPerToken */ function rebasingCreditsPerTokenHighres() external view returns (uint256) { return rebasingCreditsPerToken_; } /** * @return Low resolution rebasingCreditsPerToken */ function rebasingCreditsPerToken() external view returns (uint256) { return rebasingCreditsPerToken_ / RESOLUTION_INCREASE; } /** * @return High resolution total number of rebasing credits */ function rebasingCreditsHighres() external view returns (uint256) { return rebasingCredits_; } /** * @return Low resolution total number of rebasing credits */ function rebasingCredits() external view returns (uint256) { return rebasingCredits_ / RESOLUTION_INCREASE; } /** * @notice Gets the balance of the specified address. * @param _account Address to query the balance of. * @return A uint256 representing the amount of base units owned by the * specified address. */ function balanceOf(address _account) public view returns (uint256) { RebaseOptions state = rebaseState[_account]; if (state == RebaseOptions.YieldDelegationSource) { // Saves a slot read when transferring to or from a yield delegating source // since we know creditBalances equals the balance. return creditBalances[_account]; } uint256 baseBalance = (creditBalances[_account] * 1e18) / _creditsPerToken(_account); if (state == RebaseOptions.YieldDelegationTarget) { // creditBalances of yieldFrom accounts equals token balances return baseBalance - creditBalances[yieldFrom[_account]]; } return baseBalance; } /** * @notice Gets the credits balance of the specified address. * @dev Backwards compatible with old low res credits per token. * @param _account The address to query the balance of. * @return (uint256, uint256) Credit balance and credits per token of the * address */ function creditsBalanceOf(address _account) external view returns (uint256, uint256) { uint256 cpt = _creditsPerToken(_account); if (cpt == 1e27) { // For a period before the resolution upgrade, we created all new // contract accounts at high resolution. Since they are not changing // as a result of this upgrade, we will return their true values return (creditBalances[_account], cpt); } else { return ( creditBalances[_account] / RESOLUTION_INCREASE, cpt / RESOLUTION_INCREASE ); } } /** * @notice Gets the credits balance of the specified address. * @param _account The address to query the balance of. * @return (uint256, uint256, bool) Credit balance, credits per token of the * address, and isUpgraded */ function creditsBalanceOfHighres(address _account) external view returns ( uint256, uint256, bool ) { return ( creditBalances[_account], _creditsPerToken(_account), true // all accounts have their resolution "upgraded" ); } // Backwards compatible view function nonRebasingCreditsPerToken(address _account) external view returns (uint256) { return alternativeCreditsPerToken[_account]; } /** * @notice Transfer tokens to a specified address. * @param _to the address to transfer to. * @param _value the amount to be transferred. * @return true on success. */ function transfer(address _to, uint256 _value) external returns (bool) { require(_to != address(0), "Transfer to zero address"); _executeTransfer(msg.sender, _to, _value); emit Transfer(msg.sender, _to, _value); return true; } /** * @notice Transfer tokens from one address to another. * @param _from The address you want to send tokens from. * @param _to The address you want to transfer to. * @param _value The amount of tokens to be transferred. * @return true on success. */ function transferFrom( address _from, address _to, uint256 _value ) external returns (bool) { require(_to != address(0), "Transfer to zero address"); uint256 userAllowance = allowances[_from][msg.sender]; require(_value <= userAllowance, "Allowance exceeded"); unchecked { allowances[_from][msg.sender] = userAllowance - _value; } _executeTransfer(_from, _to, _value); emit Transfer(_from, _to, _value); return true; } function _executeTransfer( address _from, address _to, uint256 _value ) internal { ( int256 fromRebasingCreditsDiff, int256 fromNonRebasingSupplyDiff ) = _adjustAccount(_from, -_value.toInt256()); ( int256 toRebasingCreditsDiff, int256 toNonRebasingSupplyDiff ) = _adjustAccount(_to, _value.toInt256()); _adjustGlobals( fromRebasingCreditsDiff + toRebasingCreditsDiff, fromNonRebasingSupplyDiff + toNonRebasingSupplyDiff ); } function _adjustAccount(address _account, int256 _balanceChange) internal returns (int256 rebasingCreditsDiff, int256 nonRebasingSupplyDiff) { RebaseOptions state = rebaseState[_account]; int256 currentBalance = balanceOf(_account).toInt256(); if (currentBalance + _balanceChange < 0) { revert("Transfer amount exceeds balance"); } uint256 newBalance = (currentBalance + _balanceChange).toUint256(); if (state == RebaseOptions.YieldDelegationSource) { address target = yieldTo[_account]; uint256 targetOldBalance = balanceOf(target); uint256 targetNewCredits = _balanceToRebasingCredits( targetOldBalance + newBalance ); rebasingCreditsDiff = targetNewCredits.toInt256() - creditBalances[target].toInt256(); creditBalances[_account] = newBalance; creditBalances[target] = targetNewCredits; } else if (state == RebaseOptions.YieldDelegationTarget) { uint256 newCredits = _balanceToRebasingCredits( newBalance + creditBalances[yieldFrom[_account]] ); rebasingCreditsDiff = newCredits.toInt256() - creditBalances[_account].toInt256(); creditBalances[_account] = newCredits; } else { _autoMigrate(_account); uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[ _account ]; if (alternativeCreditsPerTokenMem > 0) { nonRebasingSupplyDiff = _balanceChange; if (alternativeCreditsPerTokenMem != 1e18) { alternativeCreditsPerToken[_account] = 1e18; } creditBalances[_account] = newBalance; } else { uint256 newCredits = _balanceToRebasingCredits(newBalance); rebasingCreditsDiff = newCredits.toInt256() - creditBalances[_account].toInt256(); creditBalances[_account] = newCredits; } } } function _adjustGlobals( int256 _rebasingCreditsDiff, int256 _nonRebasingSupplyDiff ) internal { if (_rebasingCreditsDiff != 0) { rebasingCredits_ = (rebasingCredits_.toInt256() + _rebasingCreditsDiff).toUint256(); } if (_nonRebasingSupplyDiff != 0) { nonRebasingSupply = (nonRebasingSupply.toInt256() + _nonRebasingSupplyDiff).toUint256(); } } /** * @notice Function to check the amount of tokens that _owner has allowed * to `_spender`. * @param _owner The address which owns the funds. * @param _spender The address which will spend the funds. * @return The number of tokens still available for the _spender. */ function allowance(address _owner, address _spender) external view returns (uint256) { return allowances[_owner][_spender]; } /** * @notice Approve the passed address to spend the specified amount of * tokens on behalf of msg.sender. * @param _spender The address which will spend the funds. * @param _value The amount of tokens to be spent. * @return true on success. */ function approve(address _spender, uint256 _value) external returns (bool) { allowances[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } /** * @notice Creates `_amount` tokens and assigns them to `_account`, * increasing the total supply. */ function mint(address _account, uint256 _amount) external onlyVault { require(_account != address(0), "Mint to the zero address"); // Account ( int256 toRebasingCreditsDiff, int256 toNonRebasingSupplyDiff ) = _adjustAccount(_account, _amount.toInt256()); // Globals _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff); totalSupply = totalSupply + _amount; require(totalSupply < MAX_SUPPLY, "Max supply"); emit Transfer(address(0), _account, _amount); } /** * @notice Destroys `_amount` tokens from `_account`, * reducing the total supply. */ function burn(address _account, uint256 _amount) external onlyVault { require(_account != address(0), "Burn from the zero address"); if (_amount == 0) { return; } // Account ( int256 toRebasingCreditsDiff, int256 toNonRebasingSupplyDiff ) = _adjustAccount(_account, -_amount.toInt256()); // Globals _adjustGlobals(toRebasingCreditsDiff, toNonRebasingSupplyDiff); totalSupply = totalSupply - _amount; emit Transfer(_account, address(0), _amount); } /** * @dev Get the credits per token for an account. Returns a fixed amount * if the account is non-rebasing. * @param _account Address of the account. */ function _creditsPerToken(address _account) internal view returns (uint256) { uint256 alternativeCreditsPerTokenMem = alternativeCreditsPerToken[ _account ]; if (alternativeCreditsPerTokenMem != 0) { return alternativeCreditsPerTokenMem; } else { return rebasingCreditsPerToken_; } } /** * @dev Auto migrate contracts to be non rebasing, * unless they have opted into yield. * @param _account Address of the account. */ function _autoMigrate(address _account) internal { bool isContract = _account.code.length > 0; // In previous code versions, contracts would not have had their // rebaseState[_account] set to RebaseOptions.NonRebasing when migrated // therefore we check the actual accounting used on the account instead. if ( isContract && rebaseState[_account] == RebaseOptions.NotSet && alternativeCreditsPerToken[_account] == 0 ) { _rebaseOptOut(_account); } } /** * @dev Calculates credits from contract's global rebasingCreditsPerToken_, and * also balance that corresponds to those credits. The latter is important * when adjusting the contract's global nonRebasingSupply to circumvent any * possible rounding errors. * * @param _balance Balance of the account. */ function _balanceToRebasingCredits(uint256 _balance) internal view returns (uint256 rebasingCredits) { // Rounds up, because we need to ensure that accounts always have // at least the balance that they should have. // Note this should always be used on an absolute account value, // not on a possibly negative diff, because then the rounding would be wrong. return ((_balance) * rebasingCreditsPerToken_ + 1e18 - 1) / 1e18; } /** * @notice The calling account will start receiving yield after a successful call. * @param _account Address of the account. */ function governanceRebaseOptIn(address _account) external onlyGovernor { require(_account != address(0), "Zero address not allowed"); _rebaseOptIn(_account); } /** * @notice The calling account will start receiving yield after a successful call. */ function rebaseOptIn() external { _rebaseOptIn(msg.sender); } function _rebaseOptIn(address _account) internal { uint256 balance = balanceOf(_account); // prettier-ignore require( alternativeCreditsPerToken[_account] > 0 || // Accounts may explicitly `rebaseOptIn` regardless of // accounting if they have a 0 balance. creditBalances[_account] == 0 , "Account must be non-rebasing" ); RebaseOptions state = rebaseState[_account]; // prettier-ignore require( state == RebaseOptions.StdNonRebasing || state == RebaseOptions.NotSet, "Only standard non-rebasing accounts can opt in" ); uint256 newCredits = _balanceToRebasingCredits(balance); // Account rebaseState[_account] = RebaseOptions.StdRebasing; alternativeCreditsPerToken[_account] = 0; creditBalances[_account] = newCredits; // Globals _adjustGlobals(newCredits.toInt256(), -balance.toInt256()); emit AccountRebasingEnabled(_account); } /** * @notice The calling account will no longer receive yield */ function rebaseOptOut() external { _rebaseOptOut(msg.sender); } function _rebaseOptOut(address _account) internal { require( alternativeCreditsPerToken[_account] == 0, "Account must be rebasing" ); RebaseOptions state = rebaseState[_account]; require( state == RebaseOptions.StdRebasing || state == RebaseOptions.NotSet, "Only standard rebasing accounts can opt out" ); uint256 oldCredits = creditBalances[_account]; uint256 balance = balanceOf(_account); // Account rebaseState[_account] = RebaseOptions.StdNonRebasing; alternativeCreditsPerToken[_account] = 1e18; creditBalances[_account] = balance; // Globals _adjustGlobals(-oldCredits.toInt256(), balance.toInt256()); emit AccountRebasingDisabled(_account); } /** * @notice Distribute yield to users. This changes the exchange rate * between "credits" and OUSD tokens to change rebasing user's balances. * @param _newTotalSupply New total supply of OUSD. */ function changeSupply(uint256 _newTotalSupply) external onlyVault { require(totalSupply > 0, "Cannot increase 0 supply"); if (totalSupply == _newTotalSupply) { emit TotalSupplyUpdatedHighres( totalSupply, rebasingCredits_, rebasingCreditsPerToken_ ); return; } totalSupply = _newTotalSupply > MAX_SUPPLY ? MAX_SUPPLY : _newTotalSupply; uint256 rebasingSupply = totalSupply - nonRebasingSupply; // round up in the favour of the protocol rebasingCreditsPerToken_ = (rebasingCredits_ * 1e18 + rebasingSupply - 1) / rebasingSupply; require(rebasingCreditsPerToken_ > 0, "Invalid change in supply"); emit TotalSupplyUpdatedHighres( totalSupply, rebasingCredits_, rebasingCreditsPerToken_ ); } /* * @notice Send the yield from one account to another account. * Each account keeps its own balances. */ function delegateYield(address _from, address _to) external onlyGovernor { require(_from != address(0), "Zero from address not allowed"); require(_to != address(0), "Zero to address not allowed"); require(_from != _to, "Cannot delegate to self"); require( yieldFrom[_to] == address(0) && yieldTo[_to] == address(0) && yieldFrom[_from] == address(0) && yieldTo[_from] == address(0), "Blocked by existing yield delegation" ); RebaseOptions stateFrom = rebaseState[_from]; RebaseOptions stateTo = rebaseState[_to]; require( stateFrom == RebaseOptions.NotSet || stateFrom == RebaseOptions.StdNonRebasing || stateFrom == RebaseOptions.StdRebasing, "Invalid rebaseState from" ); require( stateTo == RebaseOptions.NotSet || stateTo == RebaseOptions.StdNonRebasing || stateTo == RebaseOptions.StdRebasing, "Invalid rebaseState to" ); if (alternativeCreditsPerToken[_from] == 0) { _rebaseOptOut(_from); } if (alternativeCreditsPerToken[_to] > 0) { _rebaseOptIn(_to); } uint256 fromBalance = balanceOf(_from); uint256 toBalance = balanceOf(_to); uint256 oldToCredits = creditBalances[_to]; uint256 newToCredits = _balanceToRebasingCredits( fromBalance + toBalance ); // Set up the bidirectional links yieldTo[_from] = _to; yieldFrom[_to] = _from; // Local rebaseState[_from] = RebaseOptions.YieldDelegationSource; alternativeCreditsPerToken[_from] = 1e18; creditBalances[_from] = fromBalance; rebaseState[_to] = RebaseOptions.YieldDelegationTarget; creditBalances[_to] = newToCredits; // Global int256 creditsChange = newToCredits.toInt256() - oldToCredits.toInt256(); _adjustGlobals(creditsChange, -(fromBalance).toInt256()); emit YieldDelegated(_from, _to); } /* * @notice Stop sending the yield from one account to another account. */ function undelegateYield(address _from) external onlyGovernor { // Require a delegation, which will also ensure a valid delegation require(yieldTo[_from] != address(0), "Zero address not allowed"); address to = yieldTo[_from]; uint256 fromBalance = balanceOf(_from); uint256 toBalance = balanceOf(to); uint256 oldToCredits = creditBalances[to]; uint256 newToCredits = _balanceToRebasingCredits(toBalance); // Remove the bidirectional links yieldFrom[to] = address(0); yieldTo[_from] = address(0); // Local rebaseState[_from] = RebaseOptions.StdNonRebasing; // alternativeCreditsPerToken[from] already 1e18 from `delegateYield()` creditBalances[_from] = fromBalance; rebaseState[to] = RebaseOptions.StdRebasing; // alternativeCreditsPerToken[to] already 0 from `delegateYield()` creditBalances[to] = newToCredits; // Global int256 creditsChange = newToCredits.toInt256() - oldToCredits.toInt256(); _adjustGlobals(creditsChange, fromBalance.toInt256()); emit YieldUndelegated(_from, to); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IBasicToken } from "../interfaces/IBasicToken.sol"; library Helpers { /** * @notice Fetch the `symbol()` from an ERC20 token * @dev Grabs the `symbol()` from a contract * @param _token Address of the ERC20 token * @return string Symbol of the ERC20 token */ function getSymbol(address _token) internal view returns (string memory) { string memory symbol = IBasicToken(_token).symbol(); return symbol; } /** * @notice Fetch the `decimals()` from an ERC20 token * @dev Grabs the `decimals()` from a contract and fails if * the decimal value does not live within a certain range * @param _token Address of the ERC20 token * @return uint256 Decimals of the ERC20 token */ function getDecimals(address _token) internal view returns (uint256) { uint256 decimals = IBasicToken(_token).decimals(); require( decimals >= 4 && decimals <= 18, "Token must have sufficient decimal places" ); return decimals; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Base contract any contracts that need to initialize state after deployment. * @author Origin Protocol Inc */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require( initializing || !initialized, "Initializable: contract is already initialized" ); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } uint256[50] private ______gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; // Based on StableMath from Stability Labs Pty. Ltd. // https://github.com/mstable/mStable-contracts/blob/master/contracts/shared/StableMath.sol library StableMath { using SafeMath for uint256; /** * @dev Scaling unit for use in specific calculations, * where 1 * 10**18, or 1e18 represents a unit '1' */ uint256 private constant FULL_SCALE = 1e18; /*************************************** Helpers ****************************************/ /** * @dev Adjust the scale of an integer * @param to Decimals to scale to * @param from Decimals to scale from */ function scaleBy( uint256 x, uint256 to, uint256 from ) internal pure returns (uint256) { if (to > from) { x = x.mul(10**(to - from)); } else if (to < from) { // slither-disable-next-line divide-before-multiply x = x.div(10**(from - to)); } return x; } /*************************************** Precise Arithmetic ****************************************/ /** * @dev Multiplies two precise units, and then truncates by the full scale * @param x Left hand input to multiplication * @param y Right hand input to multiplication * @return Result after multiplying the two inputs and then dividing by the shared * scale unit */ function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) { return mulTruncateScale(x, y, FULL_SCALE); } /** * @dev Multiplies two precise units, and then truncates by the given scale. For example, * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18 * @param x Left hand input to multiplication * @param y Right hand input to multiplication * @param scale Scale unit * @return Result after multiplying the two inputs and then dividing by the shared * scale unit */ function mulTruncateScale( uint256 x, uint256 y, uint256 scale ) internal pure returns (uint256) { // e.g. assume scale = fullScale // z = 10e18 * 9e17 = 9e36 uint256 z = x.mul(y); // return 9e36 / 1e18 = 9e18 return z.div(scale); } /** * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result * @param x Left hand input to multiplication * @param y Right hand input to multiplication * @return Result after multiplying the two inputs and then dividing by the shared * scale unit, rounded up to the closest base unit. */ function mulTruncateCeil(uint256 x, uint256 y) internal pure returns (uint256) { // e.g. 8e17 * 17268172638 = 138145381104e17 uint256 scaled = x.mul(y); // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17 uint256 ceil = scaled.add(FULL_SCALE.sub(1)); // e.g. 13814538111.399...e18 / 1e18 = 13814538111 return ceil.div(FULL_SCALE); } /** * @dev Precisely divides two units, by first scaling the left hand operand. Useful * for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17) * @param x Left hand input to division * @param y Right hand input to division * @return Result after multiplying the left operand by the scale, and * executing the division on the right hand input. */ function divPrecisely(uint256 x, uint256 y) internal pure returns (uint256) { // e.g. 8e18 * 1e18 = 8e36 uint256 z = x.mul(FULL_SCALE); // e.g. 8e36 / 10e18 = 8e17 return z.div(y); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import { StableMath } from "../utils/StableMath.sol"; import { VaultCore } from "./VaultCore.sol"; import { IStrategy } from "../interfaces/IStrategy.sol"; import { IDripper } from "../interfaces/IDripper.sol"; /** * @title OETH VaultCore Contract * @author Origin Protocol Inc */ contract OETHVaultCore is VaultCore { using SafeERC20 for IERC20; using StableMath for uint256; address public immutable weth; uint256 public wethAssetIndex; // For future use (because OETHBaseVaultCore inherits from this) uint256[50] private __gap; constructor(address _weth) { weth = _weth; } /** * @dev Caches WETH's index in `allAssets` variable. * Reduces gas usage by redeem by caching that. */ function cacheWETHAssetIndex() external onlyGovernor { uint256 assetCount = allAssets.length; for (uint256 i; i < assetCount; ++i) { if (allAssets[i] == weth) { wethAssetIndex = i; break; } } require(allAssets[wethAssetIndex] == weth, "Invalid WETH Asset Index"); } // @inheritdoc VaultCore // slither-disable-start reentrancy-no-eth function _mint( address _asset, uint256 _amount, uint256 _minimumOusdAmount ) internal virtual override { require(_asset == weth, "Unsupported asset for minting"); require(_amount > 0, "Amount must be greater than 0"); require( _amount >= _minimumOusdAmount, "Mint amount lower than minimum" ); emit Mint(msg.sender, _amount); // Rebase must happen before any transfers occur. if (!rebasePaused && _amount >= rebaseThreshold) { // Stream any harvested rewards (WETH) that are available to the Vault IDripper(dripper).collect(); _rebase(); } // Mint oTokens oUSD.mint(msg.sender, _amount); // Transfer the deposited coins to the vault IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount); // Give priority to the withdrawal queue for the new WETH liquidity _addWithdrawalQueueLiquidity(); // Auto-allocate if necessary if (_amount >= autoAllocateThreshold) { _allocate(); } } // slither-disable-end reentrancy-no-eth // @inheritdoc VaultCore function _calculateRedeemOutputs(uint256 _amount) internal view virtual override returns (uint256[] memory outputs) { // Overrides `VaultCore._calculateRedeemOutputs` to redeem with only // WETH instead of LST-mix. Doesn't change the function signature // for backward compatibility // Calculate redeem fee if (redeemFeeBps > 0) { uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4); _amount = _amount - redeemFee; } // Ensure that the WETH index is cached uint256 _wethAssetIndex = wethAssetIndex; require( allAssets[_wethAssetIndex] == weth, "WETH Asset index not cached" ); outputs = new uint256[](allAssets.length); outputs[_wethAssetIndex] = _amount; } // @inheritdoc VaultCore function _redeem(uint256 _amount, uint256 _minimumUnitAmount) internal virtual override { // Override `VaultCore._redeem` to simplify it. Gets rid of oracle // usage and looping through all assets for LST-mix redeem. Instead // does a simple WETH-only redeem. emit Redeem(msg.sender, _amount); if (_amount == 0) { return; } // Amount excluding fees uint256 amountMinusFee = _calculateRedeemOutputs(_amount)[ wethAssetIndex ]; require( amountMinusFee >= _minimumUnitAmount, "Redeem amount lower than minimum" ); // Is there enough WETH in the Vault available after accounting for the withdrawal queue require(_wethAvailable() >= amountMinusFee, "Liquidity error"); // Transfer WETH minus the fee to the redeemer IERC20(weth).safeTransfer(msg.sender, amountMinusFee); // Burn OETH from user (including fees) oUSD.burn(msg.sender, _amount); // Prevent insolvency _postRedeem(_amount); } /** * @notice Request an asynchronous withdrawal of WETH in exchange for OETH. * The OETH is burned on request and the WETH is transferred to the withdrawer on claim. * This request can be claimed once the withdrawal queue's `claimable` amount * is greater than or equal this request's `queued` amount. * There is a minimum of 10 minutes before a request can be claimed. After that, the request just needs * enough WETH liquidity in the Vault to satisfy all the outstanding requests to that point in the queue. * OETH is converted to WETH at 1:1. * @param _amount Amount of OETH to burn. * @return requestId Unique ID for the withdrawal request * @return queued Cumulative total of all WETH queued including already claimed requests. */ function requestWithdrawal(uint256 _amount) external virtual whenNotCapitalPaused nonReentrant returns (uint256 requestId, uint256 queued) { require(withdrawalClaimDelay > 0, "Async withdrawals not enabled"); // The check that the requester has enough OETH is done in to later burn call requestId = withdrawalQueueMetadata.nextWithdrawalIndex; queued = withdrawalQueueMetadata.queued + _amount; // Store the next withdrawal request withdrawalQueueMetadata.nextWithdrawalIndex = SafeCast.toUint128( requestId + 1 ); // Store the updated queued amount which reserves WETH in the withdrawal queue // and reduces the vault's total assets withdrawalQueueMetadata.queued = SafeCast.toUint128(queued); // Store the user's withdrawal request withdrawalRequests[requestId] = WithdrawalRequest({ withdrawer: msg.sender, claimed: false, timestamp: uint40(block.timestamp), amount: SafeCast.toUint128(_amount), queued: SafeCast.toUint128(queued) }); // Burn the user's OETH oUSD.burn(msg.sender, _amount); // Prevent withdrawal if the vault is solvent by more than the the allowed percentage _postRedeem(_amount); emit WithdrawalRequested(msg.sender, requestId, _amount, queued); } // slither-disable-start reentrancy-no-eth /** * @notice Claim a previously requested withdrawal once it is claimable. * This request can be claimed once the withdrawal queue's `claimable` amount * is greater than or equal this request's `queued` amount and 10 minutes has passed. * If the requests is not claimable, the transaction will revert with `Queue pending liquidity`. * If the request is not older than 10 minutes, the transaction will revert with `Claim delay not met`. * OETH is converted to WETH at 1:1. * @param _requestId Unique ID for the withdrawal request * @return amount Amount of WETH transferred to the withdrawer */ function claimWithdrawal(uint256 _requestId) external virtual whenNotCapitalPaused nonReentrant returns (uint256 amount) { // Try and get more liquidity if there is not enough available if ( withdrawalRequests[_requestId].queued > withdrawalQueueMetadata.claimable ) { // Stream any harvested rewards (WETH) that are available to the Vault IDripper(dripper).collect(); // Add any WETH from the Dripper to the withdrawal queue _addWithdrawalQueueLiquidity(); } amount = _claimWithdrawal(_requestId); // transfer WETH from the vault to the withdrawer IERC20(weth).safeTransfer(msg.sender, amount); // Prevent insolvency _postRedeem(amount); } // slither-disable-end reentrancy-no-eth /** * @notice Claim a previously requested withdrawals once they are claimable. * This requests can be claimed once the withdrawal queue's `claimable` amount * is greater than or equal each request's `queued` amount and 10 minutes has passed. * If one of the requests is not claimable, the whole transaction will revert with `Queue pending liquidity`. * If one of the requests is not older than 10 minutes, * the whole transaction will revert with `Claim delay not met`. * @param _requestIds Unique ID of each withdrawal request * @return amounts Amount of WETH received for each request * @return totalAmount Total amount of WETH transferred to the withdrawer */ function claimWithdrawals(uint256[] calldata _requestIds) external virtual whenNotCapitalPaused nonReentrant returns (uint256[] memory amounts, uint256 totalAmount) { // Just call the Dripper instead of looping through _requestIds to find the highest id // and checking it's queued amount is > the queue's claimable amount. // Stream any harvested rewards (WETH) that are available to the Vault IDripper(dripper).collect(); // Add any WETH from the Dripper to the withdrawal queue _addWithdrawalQueueLiquidity(); amounts = new uint256[](_requestIds.length); for (uint256 i; i < _requestIds.length; ++i) { amounts[i] = _claimWithdrawal(_requestIds[i]); totalAmount += amounts[i]; } // transfer all the claimed WETH from the vault to the withdrawer IERC20(weth).safeTransfer(msg.sender, totalAmount); // Prevent insolvency _postRedeem(totalAmount); } function _claimWithdrawal(uint256 requestId) internal returns (uint256 amount) { require(withdrawalClaimDelay > 0, "Async withdrawals not enabled"); // Load the structs from storage into memory WithdrawalRequest memory request = withdrawalRequests[requestId]; WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; require( request.timestamp + withdrawalClaimDelay <= block.timestamp, "Claim delay not met" ); // If there isn't enough reserved liquidity in the queue to claim require(request.queued <= queue.claimable, "Queue pending liquidity"); require(request.withdrawer == msg.sender, "Not requester"); require(request.claimed == false, "Already claimed"); // Store the request as claimed withdrawalRequests[requestId].claimed = true; // Store the updated claimed amount withdrawalQueueMetadata.claimed = queue.claimed + request.amount; emit WithdrawalClaimed(msg.sender, requestId, request.amount); return request.amount; } /// @notice Collects harvested rewards from the Dripper as WETH then /// adds WETH to the withdrawal queue if there is a funding shortfall. /// @dev is called from the Native Staking strategy when validator withdrawals are processed. /// It also called before any WETH is allocated to a strategy. function addWithdrawalQueueLiquidity() external { // Stream any harvested rewards (WETH) that are available to the Vault IDripper(dripper).collect(); _addWithdrawalQueueLiquidity(); } /// @dev Adds WETH to the withdrawal queue if there is a funding shortfall. /// This assumes 1 WETH equal 1 OETH. function _addWithdrawalQueueLiquidity() internal returns (uint256 addedClaimable) { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; // Check if the claimable WETH is less than the queued amount uint256 queueShortfall = queue.queued - queue.claimable; // No need to do anything is the withdrawal queue is full funded if (queueShortfall == 0) { return 0; } uint256 wethBalance = IERC20(weth).balanceOf(address(this)); // Of the claimable withdrawal requests, how much is unclaimed? // That is, the amount of WETH that is currently allocated for the withdrawal queue uint256 allocatedWeth = queue.claimable - queue.claimed; // If there is no unallocated WETH then there is nothing to add to the queue if (wethBalance <= allocatedWeth) { return 0; } uint256 unallocatedWeth = wethBalance - allocatedWeth; // the new claimable amount is the smaller of the queue shortfall or unallocated weth addedClaimable = queueShortfall < unallocatedWeth ? queueShortfall : unallocatedWeth; uint256 newClaimable = queue.claimable + addedClaimable; // Store the new claimable amount back to storage withdrawalQueueMetadata.claimable = SafeCast.toUint128(newClaimable); // emit a WithdrawalClaimable event emit WithdrawalClaimable(newClaimable, addedClaimable); } /*************************************** View Functions ****************************************/ /// @dev Calculate how much WETH in the vault is not reserved for the withdrawal queue. // That is, it is available to be redeemed or deposited into a strategy. function _wethAvailable() internal view returns (uint256 wethAvailable) { WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; // The amount of WETH that is still to be claimed in the withdrawal queue uint256 outstandingWithdrawals = queue.queued - queue.claimed; // The amount of sitting in WETH in the vault uint256 wethBalance = IERC20(weth).balanceOf(address(this)); // If there is not enough WETH in the vault to cover the outstanding withdrawals if (wethBalance <= outstandingWithdrawals) { return 0; } return wethBalance - outstandingWithdrawals; } /// @dev Get the balance of an asset held in Vault and all strategies /// less any WETH that is reserved for the withdrawal queue. /// WETH is the only asset that can return a non-zero balance. /// All other assets will return 0 even if there is some dust amounts left in the Vault. /// For example, there is 1 wei left of stETH in the OETH Vault but will return 0 in this function. /// /// If there is not enough WETH in the vault and all strategies to cover all outstanding /// withdrawal requests then return a WETH balance of 0 function _checkBalance(address _asset) internal view override returns (uint256 balance) { if (_asset != weth) { return 0; } // Get the WETH in the vault and the strategies balance = super._checkBalance(_asset); WithdrawalQueueMetadata memory queue = withdrawalQueueMetadata; // If the vault becomes insolvent enough that the total value in the vault and all strategies // is less than the outstanding withdrawals. // For example, there was a mass slashing event and most users request a withdrawal. if (balance + queue.claimed < queue.queued) { return 0; } // Need to remove WETH that is reserved for the withdrawal queue return balance + queue.claimed - queue.queued; } /** * @notice Allocate unallocated funds on Vault to strategies. **/ function allocate() external override whenNotCapitalPaused nonReentrant { // Add any unallocated WETH to the withdrawal queue first _addWithdrawalQueueLiquidity(); _allocate(); } /// @dev Allocate WETH to the default WETH strategy if there is excess to the Vault buffer. /// This is called from either `mint` or `allocate` and assumes `_addWithdrawalQueueLiquidity` /// has been called before this function. function _allocate() internal override { // No need to do anything if no default strategy for WETH address depositStrategyAddr = assetDefaultStrategies[weth]; if (depositStrategyAddr == address(0)) return; uint256 wethAvailableInVault = _wethAvailable(); // No need to do anything if there isn't any WETH in the vault to allocate if (wethAvailableInVault == 0) return; // Calculate the target buffer for the vault using the total supply uint256 totalSupply = oUSD.totalSupply(); uint256 targetBuffer = totalSupply.mulTruncate(vaultBuffer); // If available WETH in the Vault is below or equal the target buffer then there's nothing to allocate if (wethAvailableInVault <= targetBuffer) return; // The amount of assets to allocate to the default strategy uint256 allocateAmount = wethAvailableInVault - targetBuffer; IStrategy strategy = IStrategy(depositStrategyAddr); // Transfer WETH to the strategy and call the strategy's deposit function IERC20(weth).safeTransfer(address(strategy), allocateAmount); strategy.deposit(weth, allocateAmount); emit AssetAllocated(weth, depositStrategyAddr, allocateAmount); } /// @dev The total value of all WETH held by the vault and all its strategies /// less any WETH that is reserved for the withdrawal queue. /// // If there is not enough WETH in the vault and all strategies to cover all outstanding // withdrawal requests then return a total value of 0. function _totalValue() internal view override returns (uint256 value) { // As WETH is the only asset, just return the WETH balance return _checkBalance(weth); } /// @dev Only WETH is supported in the OETH Vault so return the WETH balance only /// Any ETH balances in the Vault will be ignored. /// Amounts from previously supported vault assets will also be ignored. /// For example, there is 1 wei left of stETH in the OETH Vault but is will be ignored. function _totalValueInVault() internal view override returns (uint256 value) { value = IERC20(weth).balanceOf(address(this)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title OToken VaultCore contract * @notice The Vault contract stores assets. On a deposit, OTokens will be minted and sent to the depositor. On a withdrawal, OTokens will be burned and assets will be sent to the withdrawer. The Vault accepts deposits of interest from yield bearing strategies which will modify the supply of OTokens. * @author Origin Protocol Inc */ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { StableMath } from "../utils/StableMath.sol"; import { IOracle } from "../interfaces/IOracle.sol"; import { IGetExchangeRateToken } from "../interfaces/IGetExchangeRateToken.sol"; import { IDripper } from "../interfaces/IDripper.sol"; import "./VaultInitializer.sol"; contract VaultCore is VaultInitializer { using SafeERC20 for IERC20; using StableMath for uint256; /// @dev max signed int uint256 internal constant MAX_INT = type(uint256).max; /** * @dev Verifies that the rebasing is not paused. */ modifier whenNotRebasePaused() { require(!rebasePaused, "Rebasing paused"); _; } /** * @dev Verifies that the deposits are not paused. */ modifier whenNotCapitalPaused() { require(!capitalPaused, "Capital paused"); _; } /** * @dev Verifies that the caller is the AMO strategy. */ modifier onlyOusdMetaStrategy() { require( msg.sender == ousdMetaStrategy, "Caller is not the OUSD meta strategy" ); _; } /** * @notice Deposit a supported asset and mint OTokens. * @param _asset Address of the asset being deposited * @param _amount Amount of the asset being deposited * @param _minimumOusdAmount Minimum OTokens to mint */ function mint( address _asset, uint256 _amount, uint256 _minimumOusdAmount ) external whenNotCapitalPaused nonReentrant { _mint(_asset, _amount, _minimumOusdAmount); } /** * @dev Deposit a supported asset and mint OTokens. * @param _asset Address of the asset being deposited * @param _amount Amount of the asset being deposited * @param _minimumOusdAmount Minimum OTokens to mint */ function _mint( address _asset, uint256 _amount, uint256 _minimumOusdAmount ) internal virtual { require(assets[_asset].isSupported, "Asset is not supported"); require(_amount > 0, "Amount must be greater than 0"); uint256 units = _toUnits(_amount, _asset); uint256 unitPrice = _toUnitPrice(_asset, true); uint256 priceAdjustedDeposit = (units * unitPrice) / 1e18; if (_minimumOusdAmount > 0) { require( priceAdjustedDeposit >= _minimumOusdAmount, "Mint amount lower than minimum" ); } emit Mint(msg.sender, priceAdjustedDeposit); // Rebase must happen before any transfers occur. if (priceAdjustedDeposit >= rebaseThreshold && !rebasePaused) { if (dripper != address(0)) { // Stream any harvested rewards that are available IDripper(dripper).collect(); } _rebase(); } // Mint matching amount of OTokens oUSD.mint(msg.sender, priceAdjustedDeposit); // Transfer the deposited coins to the vault IERC20 asset = IERC20(_asset); asset.safeTransferFrom(msg.sender, address(this), _amount); if (priceAdjustedDeposit >= autoAllocateThreshold) { _allocate(); } } /** * @notice Mint OTokens for a Metapool Strategy * @param _amount Amount of the asset being deposited * * Notice: can't use `nonReentrant` modifier since the `mint` function can * call `allocate`, and that can trigger `ConvexOUSDMetaStrategy` to call this function * while the execution of the `mint` has not yet completed -> causing a `nonReentrant` collision. * * Also important to understand is that this is a limitation imposed by the test suite. * Production / mainnet contracts should never be configured in a way where mint/redeem functions * that are moving funds between the Vault and end user wallets can influence strategies * utilizing this function. */ function mintForStrategy(uint256 _amount) external virtual whenNotCapitalPaused onlyOusdMetaStrategy { require(_amount < MAX_INT, "Amount too high"); emit Mint(msg.sender, _amount); // safe to cast because of the require check at the beginning of the function netOusdMintedForStrategy += int256(_amount); require( abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold, "Minted ousd surpassed netOusdMintForStrategyThreshold." ); // Mint matching amount of OTokens oUSD.mint(msg.sender, _amount); } // In memoriam /** * @notice Withdraw a supported asset and burn OTokens. * @param _amount Amount of OTokens to burn * @param _minimumUnitAmount Minimum stablecoin units to receive in return */ function redeem(uint256 _amount, uint256 _minimumUnitAmount) external virtual whenNotCapitalPaused nonReentrant { _redeem(_amount, _minimumUnitAmount); } /** * @notice Withdraw a supported asset and burn OTokens. * @param _amount Amount of OTokens to burn * @param _minimumUnitAmount Minimum stablecoin units to receive in return */ function _redeem(uint256 _amount, uint256 _minimumUnitAmount) internal virtual { // Calculate redemption outputs uint256[] memory outputs = _calculateRedeemOutputs(_amount); emit Redeem(msg.sender, _amount); // Send outputs uint256 assetCount = allAssets.length; for (uint256 i = 0; i < assetCount; ++i) { if (outputs[i] == 0) continue; address assetAddr = allAssets[i]; if (IERC20(assetAddr).balanceOf(address(this)) >= outputs[i]) { // Use Vault funds first if sufficient IERC20(assetAddr).safeTransfer(msg.sender, outputs[i]); } else { address strategyAddr = assetDefaultStrategies[assetAddr]; if (strategyAddr != address(0)) { // Nothing in Vault, but something in Strategy, send from there IStrategy strategy = IStrategy(strategyAddr); strategy.withdraw(msg.sender, assetAddr, outputs[i]); } else { // Cant find funds anywhere revert("Liquidity error"); } } } if (_minimumUnitAmount > 0) { uint256 unitTotal = 0; for (uint256 i = 0; i < outputs.length; ++i) { unitTotal += _toUnits(outputs[i], allAssets[i]); } require( unitTotal >= _minimumUnitAmount, "Redeem amount lower than minimum" ); } oUSD.burn(msg.sender, _amount); _postRedeem(_amount); } function _postRedeem(uint256 _amount) internal { // Until we can prove that we won't affect the prices of our assets // by withdrawing them, this should be here. // It's possible that a strategy was off on its asset total, perhaps // a reward token sold for more or for less than anticipated. uint256 totalUnits = 0; if (_amount >= rebaseThreshold && !rebasePaused) { totalUnits = _rebase(); } else { totalUnits = _totalValue(); } // Check that the OTokens are backed by enough assets if (maxSupplyDiff > 0) { // If there are more outstanding withdrawal requests than assets in the vault and strategies // then the available assets will be negative and totalUnits will be rounded up to zero. // As we don't know the exact shortfall amount, we will reject all redeem and withdrawals require(totalUnits > 0, "Too many outstanding requests"); // Allow a max difference of maxSupplyDiff% between // backing assets value and OUSD total supply uint256 diff = oUSD.totalSupply().divPrecisely(totalUnits); require( (diff > 1e18 ? diff - 1e18 : 1e18 - diff) <= maxSupplyDiff, "Backing supply liquidity error" ); } } /** * @notice Burn OTokens for Metapool Strategy * @param _amount Amount of OUSD to burn * * @dev Notice: can't use `nonReentrant` modifier since the `redeem` function could * require withdrawal on `ConvexOUSDMetaStrategy` and that one can call `burnForStrategy` * while the execution of the `redeem` has not yet completed -> causing a `nonReentrant` collision. * * Also important to understand is that this is a limitation imposed by the test suite. * Production / mainnet contracts should never be configured in a way where mint/redeem functions * that are moving funds between the Vault and end user wallets can influence strategies * utilizing this function. */ function burnForStrategy(uint256 _amount) external virtual whenNotCapitalPaused onlyOusdMetaStrategy { require(_amount < MAX_INT, "Amount too high"); emit Redeem(msg.sender, _amount); // safe to cast because of the require check at the beginning of the function netOusdMintedForStrategy -= int256(_amount); require( abs(netOusdMintedForStrategy) < netOusdMintForStrategyThreshold, "Attempting to burn too much OUSD." ); // Burn OTokens oUSD.burn(msg.sender, _amount); } /** * @notice Withdraw a supported asset and burn all OTokens. * @param _minimumUnitAmount Minimum stablecoin units to receive in return */ function redeemAll(uint256 _minimumUnitAmount) external whenNotCapitalPaused nonReentrant { _redeem(oUSD.balanceOf(msg.sender), _minimumUnitAmount); } /** * @notice Allocate unallocated funds on Vault to strategies. **/ function allocate() external virtual whenNotCapitalPaused nonReentrant { _allocate(); } /** * @dev Allocate unallocated funds on Vault to strategies. **/ function _allocate() internal virtual { uint256 vaultValue = _totalValueInVault(); // Nothing in vault to allocate if (vaultValue == 0) return; uint256 strategiesValue = _totalValueInStrategies(); // We have a method that does the same as this, gas optimisation uint256 calculatedTotalValue = vaultValue + strategiesValue; // We want to maintain a buffer on the Vault so calculate a percentage // modifier to multiply each amount being allocated by to enforce the // vault buffer uint256 vaultBufferModifier; if (strategiesValue == 0) { // Nothing in Strategies, allocate 100% minus the vault buffer to // strategies vaultBufferModifier = uint256(1e18) - vaultBuffer; } else { vaultBufferModifier = (vaultBuffer * calculatedTotalValue) / vaultValue; if (1e18 > vaultBufferModifier) { // E.g. 1e18 - (1e17 * 10e18)/5e18 = 8e17 // (5e18 * 8e17) / 1e18 = 4e18 allocated from Vault vaultBufferModifier = uint256(1e18) - vaultBufferModifier; } else { // We need to let the buffer fill return; } } if (vaultBufferModifier == 0) return; // Iterate over all assets in the Vault and allocate to the appropriate // strategy uint256 assetCount = allAssets.length; for (uint256 i = 0; i < assetCount; ++i) { IERC20 asset = IERC20(allAssets[i]); uint256 assetBalance = asset.balanceOf(address(this)); // No balance, nothing to do here if (assetBalance == 0) continue; // Multiply the balance by the vault buffer modifier and truncate // to the scale of the asset decimals uint256 allocateAmount = assetBalance.mulTruncate( vaultBufferModifier ); address depositStrategyAddr = assetDefaultStrategies[ address(asset) ]; if (depositStrategyAddr != address(0) && allocateAmount > 0) { IStrategy strategy = IStrategy(depositStrategyAddr); // Transfer asset to Strategy and call deposit method to // mint or take required action asset.safeTransfer(address(strategy), allocateAmount); strategy.deposit(address(asset), allocateAmount); emit AssetAllocated( address(asset), depositStrategyAddr, allocateAmount ); } } } /** * @notice Calculate the total value of assets held by the Vault and all * strategies and update the supply of OTokens. */ function rebase() external virtual nonReentrant { _rebase(); } /** * @dev Calculate the total value of assets held by the Vault and all * strategies and update the supply of OTokens, optionally sending a * portion of the yield to the trustee. * @return totalUnits Total balance of Vault in units */ function _rebase() internal whenNotRebasePaused returns (uint256) { uint256 ousdSupply = oUSD.totalSupply(); uint256 vaultValue = _totalValue(); if (ousdSupply == 0) { return vaultValue; } // Yield fee collection address _trusteeAddress = trusteeAddress; // gas savings if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) { uint256 yield = vaultValue - ousdSupply; uint256 fee = yield.mulTruncateScale(trusteeFeeBps, 1e4); require(yield > fee, "Fee must not be greater than yield"); if (fee > 0) { oUSD.mint(_trusteeAddress, fee); } emit YieldDistribution(_trusteeAddress, yield, fee); } // Only ratchet OToken supply upwards ousdSupply = oUSD.totalSupply(); // Final check should use latest value if (vaultValue > ousdSupply) { oUSD.changeSupply(vaultValue); } return vaultValue; } /** * @notice Determine the total value of assets held by the vault and its * strategies. * @return value Total value in USD/ETH (1e18) */ function totalValue() external view virtual returns (uint256 value) { value = _totalValue(); } /** * @dev Internal Calculate the total value of the assets held by the * vault and its strategies. * @return value Total value in USD/ETH (1e18) */ function _totalValue() internal view virtual returns (uint256 value) { return _totalValueInVault() + _totalValueInStrategies(); } /** * @dev Internal to calculate total value of all assets held in Vault. * @return value Total value in USD/ETH (1e18) */ function _totalValueInVault() internal view virtual returns (uint256 value) { uint256 assetCount = allAssets.length; for (uint256 y; y < assetCount; ++y) { address assetAddr = allAssets[y]; uint256 balance = IERC20(assetAddr).balanceOf(address(this)); if (balance > 0) { value += _toUnits(balance, assetAddr); } } } /** * @dev Internal to calculate total value of all assets held in Strategies. * @return value Total value in USD/ETH (1e18) */ function _totalValueInStrategies() internal view returns (uint256 value) { uint256 stratCount = allStrategies.length; for (uint256 i = 0; i < stratCount; ++i) { value = value + _totalValueInStrategy(allStrategies[i]); } } /** * @dev Internal to calculate total value of all assets held by strategy. * @param _strategyAddr Address of the strategy * @return value Total value in USD/ETH (1e18) */ function _totalValueInStrategy(address _strategyAddr) internal view returns (uint256 value) { IStrategy strategy = IStrategy(_strategyAddr); uint256 assetCount = allAssets.length; for (uint256 y; y < assetCount; ++y) { address assetAddr = allAssets[y]; if (strategy.supportsAsset(assetAddr)) { uint256 balance = strategy.checkBalance(assetAddr); if (balance > 0) { value += _toUnits(balance, assetAddr); } } } } /** * @notice Get the balance of an asset held in Vault and all strategies. * @param _asset Address of asset * @return uint256 Balance of asset in decimals of asset */ function checkBalance(address _asset) external view returns (uint256) { return _checkBalance(_asset); } /** * @notice Get the balance of an asset held in Vault and all strategies. * @param _asset Address of asset * @return balance Balance of asset in decimals of asset */ function _checkBalance(address _asset) internal view virtual returns (uint256 balance) { IERC20 asset = IERC20(_asset); balance = asset.balanceOf(address(this)); uint256 stratCount = allStrategies.length; for (uint256 i = 0; i < stratCount; ++i) { IStrategy strategy = IStrategy(allStrategies[i]); if (strategy.supportsAsset(_asset)) { balance = balance + strategy.checkBalance(_asset); } } } /** * @notice Calculate the outputs for a redeem function, i.e. the mix of * coins that will be returned */ function calculateRedeemOutputs(uint256 _amount) external view returns (uint256[] memory) { return _calculateRedeemOutputs(_amount); } /** * @dev Calculate the outputs for a redeem function, i.e. the mix of * coins that will be returned. * @return outputs Array of amounts respective to the supported assets */ function _calculateRedeemOutputs(uint256 _amount) internal view virtual returns (uint256[] memory outputs) { // We always give out coins in proportion to how many we have, // Now if all coins were the same value, this math would easy, // just take the percentage of each coin, and multiply by the // value to be given out. But if coins are worth more than $1, // then we would end up handing out too many coins. We need to // adjust by the total value of coins. // // To do this, we total up the value of our coins, by their // percentages. Then divide what we would otherwise give out by // this number. // // Let say we have 100 DAI at $1.06 and 200 USDT at $1.00. // So for every 1 DAI we give out, we'll be handing out 2 USDT // Our total output ratio is: 33% * 1.06 + 66% * 1.00 = 1.02 // // So when calculating the output, we take the percentage of // each coin, times the desired output value, divided by the // totalOutputRatio. // // For example, withdrawing: 30 OUSD: // DAI 33% * 30 / 1.02 = 9.80 DAI // USDT = 66 % * 30 / 1.02 = 19.60 USDT // // Checking these numbers: // 9.80 DAI * 1.06 = $10.40 // 19.60 USDT * 1.00 = $19.60 // // And so the user gets $10.40 + $19.60 = $30 worth of value. uint256 assetCount = allAssets.length; uint256[] memory assetUnits = new uint256[](assetCount); uint256[] memory assetBalances = new uint256[](assetCount); outputs = new uint256[](assetCount); // Calculate redeem fee if (redeemFeeBps > 0) { uint256 redeemFee = _amount.mulTruncateScale(redeemFeeBps, 1e4); _amount = _amount - redeemFee; } // Calculate assets balances and decimals once, // for a large gas savings. uint256 totalUnits = 0; for (uint256 i = 0; i < assetCount; ++i) { address assetAddr = allAssets[i]; uint256 balance = _checkBalance(assetAddr); assetBalances[i] = balance; assetUnits[i] = _toUnits(balance, assetAddr); totalUnits = totalUnits + assetUnits[i]; } // Calculate totalOutputRatio uint256 totalOutputRatio = 0; for (uint256 i = 0; i < assetCount; ++i) { uint256 unitPrice = _toUnitPrice(allAssets[i], false); uint256 ratio = (assetUnits[i] * unitPrice) / totalUnits; totalOutputRatio = totalOutputRatio + ratio; } // Calculate final outputs uint256 factor = _amount.divPrecisely(totalOutputRatio); for (uint256 i = 0; i < assetCount; ++i) { outputs[i] = (assetBalances[i] * factor) / totalUnits; } } /*************************************** Pricing ****************************************/ /** * @notice Returns the total price in 18 digit units for a given asset. * Never goes above 1, since that is how we price mints. * @param asset address of the asset * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed */ function priceUnitMint(address asset) external view returns (uint256 price) { /* need to supply 1 asset unit in asset's decimals and can not just hard-code * to 1e18 and ignore calling `_toUnits` since we need to consider assets * with the exchange rate */ uint256 units = _toUnits( uint256(1e18).scaleBy(_getDecimals(asset), 18), asset ); price = (_toUnitPrice(asset, true) * units) / 1e18; } /** * @notice Returns the total price in 18 digit unit for a given asset. * Never goes below 1, since that is how we price redeems * @param asset Address of the asset * @return price uint256: unit (USD / ETH) price for 1 unit of the asset, in 18 decimal fixed */ function priceUnitRedeem(address asset) external view returns (uint256 price) { /* need to supply 1 asset unit in asset's decimals and can not just hard-code * to 1e18 and ignore calling `_toUnits` since we need to consider assets * with the exchange rate */ uint256 units = _toUnits( uint256(1e18).scaleBy(_getDecimals(asset), 18), asset ); price = (_toUnitPrice(asset, false) * units) / 1e18; } /*************************************** Utils ****************************************/ /** * @dev Convert a quantity of a token into 1e18 fixed decimal "units" * in the underlying base (USD/ETH) used by the vault. * Price is not taken into account, only quantity. * * Examples of this conversion: * * - 1e18 DAI becomes 1e18 units (same decimals) * - 1e6 USDC becomes 1e18 units (decimal conversion) * - 1e18 rETH becomes 1.2e18 units (exchange rate conversion) * * @param _raw Quantity of asset * @param _asset Core Asset address * @return value 1e18 normalized quantity of units */ function _toUnits(uint256 _raw, address _asset) internal view returns (uint256) { UnitConversion conversion = assets[_asset].unitConversion; if (conversion == UnitConversion.DECIMALS) { return _raw.scaleBy(18, _getDecimals(_asset)); } else if (conversion == UnitConversion.GETEXCHANGERATE) { uint256 exchangeRate = IGetExchangeRateToken(_asset) .getExchangeRate(); return (_raw * exchangeRate) / 1e18; } else { revert("Unsupported conversion type"); } } /** * @dev Returns asset's unit price accounting for different asset types * and takes into account the context in which that price exists - * - mint or redeem. * * Note: since we are returning the price of the unit and not the one of the * asset (see comment above how 1 rETH exchanges for 1.2 units) we need * to make the Oracle price adjustment as well since we are pricing the * units and not the assets. * * The price also snaps to a "full unit price" in case a mint or redeem * action would be unfavourable to the protocol. * */ function _toUnitPrice(address _asset, bool isMint) internal view returns (uint256 price) { UnitConversion conversion = assets[_asset].unitConversion; price = IOracle(priceProvider).price(_asset); if (conversion == UnitConversion.GETEXCHANGERATE) { uint256 exchangeRate = IGetExchangeRateToken(_asset) .getExchangeRate(); price = (price * 1e18) / exchangeRate; } else if (conversion != UnitConversion.DECIMALS) { revert("Unsupported conversion type"); } /* At this stage the price is already adjusted to the unit * so the price checks are agnostic to underlying asset being * pegged to a USD or to an ETH or having a custom exchange rate. */ require(price <= MAX_UNIT_PRICE_DRIFT, "Vault: Price exceeds max"); require(price >= MIN_UNIT_PRICE_DRIFT, "Vault: Price under min"); if (isMint) { /* Never price a normalized unit price for more than one * unit of OETH/OUSD when minting. */ if (price > 1e18) { price = 1e18; } require(price >= MINT_MINIMUM_UNIT_PRICE, "Asset price below peg"); } else { /* Never give out more than 1 normalized unit amount of assets * for one unit of OETH/OUSD when redeeming. */ if (price < 1e18) { price = 1e18; } } } /** * @dev Get the number of decimals of a token asset * @param _asset Address of the asset * @return decimals number of decimals */ function _getDecimals(address _asset) internal view returns (uint256 decimals) { decimals = assets[_asset].decimals; require(decimals > 0, "Decimals not cached"); } /** * @notice Return the number of assets supported by the Vault. */ function getAssetCount() public view returns (uint256) { return allAssets.length; } /** * @notice Gets the vault configuration of a supported asset. * @param _asset Address of the token asset */ function getAssetConfig(address _asset) public view returns (Asset memory config) { config = assets[_asset]; } /** * @notice Return all vault asset addresses in order */ function getAllAssets() external view returns (address[] memory) { return allAssets; } /** * @notice Return the number of strategies active on the Vault. */ function getStrategyCount() external view returns (uint256) { return allStrategies.length; } /** * @notice Return the array of all strategies */ function getAllStrategies() external view returns (address[] memory) { return allStrategies; } /** * @notice Returns whether the vault supports the asset * @param _asset address of the asset * @return true if supported */ function isSupportedAsset(address _asset) external view returns (bool) { return assets[_asset].isSupported; } /** * @dev Falldown to the admin implementation * @notice This is a catch all for all functions not declared in core */ // solhint-disable-next-line no-complex-fallback fallback() external { bytes32 slot = adminImplPosition; // solhint-disable-next-line no-inline-assembly assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall( gas(), sload(slot), 0, calldatasize(), 0, 0 ) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } function abs(int256 x) private pure returns (uint256) { require(x < int256(MAX_INT), "Amount too high"); return x >= 0 ? uint256(x) : uint256(-x); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title OToken VaultInitializer contract * @notice The Vault contract initializes the vault. * @author Origin Protocol Inc */ import "./VaultStorage.sol"; contract VaultInitializer is VaultStorage { function initialize(address _priceProvider, address _oToken) external onlyGovernor initializer { require(_priceProvider != address(0), "PriceProvider address is zero"); require(_oToken != address(0), "oToken address is zero"); oUSD = OUSD(_oToken); priceProvider = _priceProvider; rebasePaused = false; capitalPaused = true; // Initial redeem fee of 0 basis points redeemFeeBps = 0; // Initial Vault buffer of 0% vaultBuffer = 0; // Initial allocate threshold of 25,000 OUSD autoAllocateThreshold = 25000e18; // Threshold for rebasing rebaseThreshold = 1000e18; // Initialize all strategies allStrategies = new address[](0); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title OToken VaultStorage contract * @notice The VaultStorage contract defines the storage for the Vault contracts * @author Origin Protocol Inc */ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { IStrategy } from "../interfaces/IStrategy.sol"; import { Governable } from "../governance/Governable.sol"; import { OUSD } from "../token/OUSD.sol"; import { Initializable } from "../utils/Initializable.sol"; import "../utils/Helpers.sol"; contract VaultStorage is Initializable, Governable { using SafeERC20 for IERC20; event AssetSupported(address _asset); event AssetRemoved(address _asset); event AssetDefaultStrategyUpdated(address _asset, address _strategy); event AssetAllocated(address _asset, address _strategy, uint256 _amount); event StrategyApproved(address _addr); event StrategyRemoved(address _addr); event Mint(address _addr, uint256 _value); event Redeem(address _addr, uint256 _value); event CapitalPaused(); event CapitalUnpaused(); event RebasePaused(); event RebaseUnpaused(); event VaultBufferUpdated(uint256 _vaultBuffer); event OusdMetaStrategyUpdated(address _ousdMetaStrategy); event RedeemFeeUpdated(uint256 _redeemFeeBps); event PriceProviderUpdated(address _priceProvider); event AllocateThresholdUpdated(uint256 _threshold); event RebaseThresholdUpdated(uint256 _threshold); event StrategistUpdated(address _address); event MaxSupplyDiffChanged(uint256 maxSupplyDiff); event YieldDistribution(address _to, uint256 _yield, uint256 _fee); event TrusteeFeeBpsChanged(uint256 _basis); event TrusteeAddressChanged(address _address); event NetOusdMintForStrategyThresholdChanged(uint256 _threshold); event SwapperChanged(address _address); event SwapAllowedUndervalueChanged(uint256 _basis); event SwapSlippageChanged(address _asset, uint256 _basis); event Swapped( address indexed _fromAsset, address indexed _toAsset, uint256 _fromAssetAmount, uint256 _toAssetAmount ); event StrategyAddedToMintWhitelist(address indexed strategy); event StrategyRemovedFromMintWhitelist(address indexed strategy); event DripperChanged(address indexed _dripper); event WithdrawalRequested( address indexed _withdrawer, uint256 indexed _requestId, uint256 _amount, uint256 _queued ); event WithdrawalClaimed( address indexed _withdrawer, uint256 indexed _requestId, uint256 _amount ); event WithdrawalClaimable(uint256 _claimable, uint256 _newClaimable); event WithdrawalClaimDelayUpdated(uint256 _newDelay); // Assets supported by the Vault, i.e. Stablecoins enum UnitConversion { DECIMALS, GETEXCHANGERATE } // Changed to fit into a single storage slot so the decimals needs to be recached struct Asset { // Note: OETHVaultCore doesn't use `isSupported` when minting, // redeeming or checking balance of assets. bool isSupported; UnitConversion unitConversion; uint8 decimals; // Max allowed slippage from the Oracle price when swapping collateral assets in basis points. // For example 40 == 0.4% slippage uint16 allowedOracleSlippageBps; } /// @dev mapping of supported vault assets to their configuration // slither-disable-next-line uninitialized-state mapping(address => Asset) internal assets; /// @dev list of all assets supported by the vault. // slither-disable-next-line uninitialized-state address[] internal allAssets; // Strategies approved for use by the Vault struct Strategy { bool isSupported; uint256 _deprecated; // Deprecated storage slot } /// @dev mapping of strategy contracts to their configuration // slither-disable-next-line uninitialized-state mapping(address => Strategy) internal strategies; /// @dev list of all vault strategies address[] internal allStrategies; /// @notice Address of the Oracle price provider contract // slither-disable-next-line uninitialized-state address public priceProvider; /// @notice pause rebasing if true bool public rebasePaused = false; /// @notice pause operations that change the OToken supply. /// eg mint, redeem, allocate, mint/burn for strategy bool public capitalPaused = true; /// @notice Redemption fee in basis points. eg 50 = 0.5% uint256 public redeemFeeBps; /// @notice Percentage of assets to keep in Vault to handle (most) withdrawals. 100% = 1e18. uint256 public vaultBuffer; /// @notice OToken mints over this amount automatically allocate funds. 18 decimals. uint256 public autoAllocateThreshold; /// @notice OToken mints over this amount automatically rebase. 18 decimals. uint256 public rebaseThreshold; /// @dev Address of the OToken token. eg OUSD or OETH. // slither-disable-next-line uninitialized-state OUSD internal oUSD; /// @dev Storage slot for the address of the VaultAdmin contract that is delegated to // keccak256("OUSD.vault.governor.admin.impl"); bytes32 constant adminImplPosition = 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9; /// @dev Address of the contract responsible for post rebase syncs with AMMs address private _deprecated_rebaseHooksAddr = address(0); /// @dev Deprecated: Address of Uniswap // slither-disable-next-line constable-states address private _deprecated_uniswapAddr = address(0); /// @notice Address of the Strategist address public strategistAddr = address(0); /// @notice Mapping of asset address to the Strategy that they should automatically // be allocated to // slither-disable-next-line uninitialized-state mapping(address => address) public assetDefaultStrategies; /// @notice Max difference between total supply and total value of assets. 18 decimals. // slither-disable-next-line uninitialized-state uint256 public maxSupplyDiff; /// @notice Trustee contract that can collect a percentage of yield address public trusteeAddress; /// @notice Amount of yield collected in basis points. eg 2000 = 20% uint256 public trusteeFeeBps; /// @dev Deprecated: Tokens that should be swapped for stablecoins address[] private _deprecated_swapTokens; uint256 constant MINT_MINIMUM_UNIT_PRICE = 0.998e18; /// @notice Metapool strategy that is allowed to mint/burn OTokens without changing collateral // slither-disable-start constable-states // slither-disable-next-line uninitialized-state address public ousdMetaStrategy; /// @notice How much OTokens are currently minted by the strategy // slither-disable-next-line uninitialized-state int256 public netOusdMintedForStrategy; /// @notice How much net total OTokens are allowed to be minted by all strategies // slither-disable-next-line uninitialized-state uint256 public netOusdMintForStrategyThreshold; // slither-disable-end constable-states uint256 constant MIN_UNIT_PRICE_DRIFT = 0.7e18; uint256 constant MAX_UNIT_PRICE_DRIFT = 1.3e18; /// @notice Collateral swap configuration. /// @dev is packed into a single storage slot to save gas. struct SwapConfig { // Contract that swaps the vault's collateral assets address swapper; // Max allowed percentage the total value can drop below the total supply in basis points. // For example 100 == 1% uint16 allowedUndervalueBps; } SwapConfig internal swapConfig = SwapConfig(address(0), 0); // List of strategies that can mint oTokens directly // Used in OETHBaseVaultCore // slither-disable-next-line uninitialized-state mapping(address => bool) public isMintWhitelistedStrategy; /// @notice Address of the Dripper contract that streams harvested rewards to the Vault /// @dev The vault is proxied so needs to be set with setDripper against the proxy contract. // slither-disable-start constable-states // slither-disable-next-line uninitialized-state address public dripper; // slither-disable-end constable-states /// Withdrawal Queue Storage ///// struct WithdrawalQueueMetadata { // cumulative total of all withdrawal requests included the ones that have already been claimed uint128 queued; // cumulative total of all the requests that can be claimed including the ones that have already been claimed uint128 claimable; // total of all the requests that have been claimed uint128 claimed; // index of the next withdrawal request starting at 0 uint128 nextWithdrawalIndex; } /// @notice Global metadata for the withdrawal queue including: /// queued - cumulative total of all withdrawal requests included the ones that have already been claimed /// claimable - cumulative total of all the requests that can be claimed including the ones already claimed /// claimed - total of all the requests that have been claimed /// nextWithdrawalIndex - index of the next withdrawal request starting at 0 // slither-disable-next-line uninitialized-state WithdrawalQueueMetadata public withdrawalQueueMetadata; struct WithdrawalRequest { address withdrawer; bool claimed; uint40 timestamp; // timestamp of the withdrawal request // Amount of oTokens to redeem. eg OETH uint128 amount; // cumulative total of all withdrawal requests including this one. // this request can be claimed when this queued amount is less than or equal to the queue's claimable amount. uint128 queued; } /// @notice Mapping of withdrawal request indices to the user withdrawal request data mapping(uint256 => WithdrawalRequest) public withdrawalRequests; /// @notice Sets a minimum delay that is required to elapse between /// requesting async withdrawals and claiming the request. /// When set to 0 async withdrawals are disabled. // slither-disable-start constable-states // slither-disable-next-line uninitialized-state uint256 public withdrawalClaimDelay; // slither-disable-end constable-states // For future use uint256[44] private __gap; /** * @notice set the implementation for the admin, this needs to be in a base class else we cannot set it * @param newImpl address of the implementation */ function setAdminImpl(address newImpl) external onlyGovernor { require( Address.isContract(newImpl), "new implementation is not a contract" ); bytes32 position = adminImplPosition; // solhint-disable-next-line no-inline-assembly assembly { sstore(position, newImpl) } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_wS","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"AllocateThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"AssetAllocated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_strategy","type":"address"}],"name":"AssetDefaultStrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_asset","type":"address"}],"name":"AssetRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_asset","type":"address"}],"name":"AssetSupported","type":"event"},{"anonymous":false,"inputs":[],"name":"CapitalPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"CapitalUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_dripper","type":"address"}],"name":"DripperChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernor","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernor","type":"address"}],"name":"GovernorshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxSupplyDiff","type":"uint256"}],"name":"MaxSupplyDiffChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"NetOusdMintForStrategyThresholdChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_ousdMetaStrategy","type":"address"}],"name":"OusdMetaStrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernor","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernor","type":"address"}],"name":"PendingGovernorshipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_priceProvider","type":"address"}],"name":"PriceProviderUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"RebasePaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_threshold","type":"uint256"}],"name":"RebaseThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"RebaseUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_redeemFeeBps","type":"uint256"}],"name":"RedeemFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_address","type":"address"}],"name":"StrategistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyAddedToMintWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_addr","type":"address"}],"name":"StrategyApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_addr","type":"address"}],"name":"StrategyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyRemovedFromMintWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_basis","type":"uint256"}],"name":"SwapAllowedUndervalueChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"_basis","type":"uint256"}],"name":"SwapSlippageChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_fromAsset","type":"address"},{"indexed":true,"internalType":"address","name":"_toAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"_fromAssetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toAssetAmount","type":"uint256"}],"name":"Swapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_address","type":"address"}],"name":"SwapperChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_address","type":"address"}],"name":"TrusteeAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_basis","type":"uint256"}],"name":"TrusteeFeeBpsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_vaultBuffer","type":"uint256"}],"name":"VaultBufferUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newDelay","type":"uint256"}],"name":"WithdrawalClaimDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_claimable","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newClaimable","type":"uint256"}],"name":"WithdrawalClaimable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_withdrawer","type":"address"},{"indexed":true,"internalType":"uint256","name":"_requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"WithdrawalClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_withdrawer","type":"address"},{"indexed":true,"internalType":"uint256","name":"_requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_queued","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_yield","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"YieldDistribution","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"addWithdrawalQueueLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetDefaultStrategies","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"autoAllocateThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnForStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cacheWETHAssetIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"calculateRedeemOutputs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"capitalPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"checkBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"}],"name":"claimWithdrawal","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_requestIds","type":"uint256[]"}],"name":"claimWithdrawals","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"totalAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dripper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllAssets","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllStrategies","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAssetConfig","outputs":[{"components":[{"internalType":"bool","name":"isSupported","type":"bool"},{"internalType":"enum VaultStorage.UnitConversion","name":"unitConversion","type":"uint8"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint16","name":"allowedOracleSlippageBps","type":"uint16"}],"internalType":"struct VaultStorage.Asset","name":"config","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategyCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_priceProvider","type":"address"},{"internalType":"address","name":"_oToken","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isGovernor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isMintWhitelistedStrategy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"isSupportedAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupplyDiff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_minimumOusdAmount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintForStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"netOusdMintForStrategyThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"netOusdMintedForStrategy","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ousdMetaStrategy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"priceUnitMint","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"priceUnitRedeem","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebasePaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebaseThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumUnitAmount","type":"uint256"}],"name":"redeemAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"requestWithdrawal","outputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"queued","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImpl","type":"address"}],"name":"setAdminImpl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategistAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalValue","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trusteeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trusteeFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wethAssetIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalClaimDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalQueueMetadata","outputs":[{"internalType":"uint128","name":"queued","type":"uint128"},{"internalType":"uint128","name":"claimable","type":"uint128"},{"internalType":"uint128","name":"claimed","type":"uint128"},{"internalType":"uint128","name":"nextWithdrawalIndex","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdrawalRequests","outputs":[{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"bool","name":"claimed","type":"bool"},{"internalType":"uint40","name":"timestamp","type":"uint40"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"queued","type":"uint128"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6037805461ffff60a01b1916600160a81b179055603d80546001600160a01b0319908116909155603e805482169055603f8054909116905560e0604052600060a081905260c052604880546001600160b01b031916905534801561006257600080fd5b50604051614240380380614240833981016040819052610081916100f1565b806100983360008051602061422083398151915255565b600080516020614220833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a36001600160a01b031660805250610121565b60006020828403121561010357600080fd5b81516001600160a01b038116811461011a57600080fd5b9392505050565b60805161407b6101a56000396000818161044101528181610961015281816109cb01528181610e1201528181611a4901528181611b270152818161231601528181612a2401528181612b6901528181612d8501528181612e8c01528181612f8f01528181612fda01528181613042015281816133d10152613780015261407b6000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c80636217f3ea1161019d578063ab80dafb116100e9578063c7af3352116100a2578063e45cc9f01161007c578063e45cc9f014610792578063e6cc54321461079b578063f8444436146107af578063fc0cfeee146107c2576102f1565b8063c7af33521461076f578063d38bfff414610777578063d4c3eea01461078a576102f1565b8063ab80dafb14610729578063abaa99161461073c578063af14052c14610744578063b888879e1461074c578063b9b17f9f1461075f578063c3b2886414610767576102f1565b80638e510b52116101565780639ee679e8116101305780639ee679e8146106c75780639fa1826e146106ef578063a0aead4d146106f8578063a403e4d514610700576102f1565b80638e510b52146105ea578063937b2581146105f35780639be918e61461069b576102f1565b80636217f3ea1461056857806367bd7ba31461057b5780636ec3ab671461059b5780637136a7a6146105bb5780637a2202f3146105ce5780637cbc2373146105d7576102f1565b80634530820a1161025c57806353ca9f24116102155780635b60f9fc116101ef5780635b60f9fc146105275780635d36b1901461053a5780635f51522614610542578063603ea03b14610555576102f1565b806353ca9f24146104f757806354c6d8581461050b578063570d8e1d14610514576102f1565b80634530820a1461046b57806345e4213b1461049e578063485cc955146104a757806348e30f54146104ba57806349c1d54d146104db57806352d38e5d146104ee576102f1565b80632acada4d116102ae5780632acada4d146103ad57806331e19cfa146103c2578063362bd1a3146103ca5780633b8fe28d146104295780633fc8cef31461043c57806344c5470714610463576102f1565b806309f6442c146103395780630c340a2414610355578063156e29f61461037557806318ce56bd146103885780631edfe3da1461039b578063207134b0146103a4575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e808015610332573d6000f35b3d6000fd5b005b61034260385481565b6040519081526020015b60405180910390f35b61035d6107d5565b6040516001600160a01b03909116815260200161034c565b6103376103833660046139b8565b6107f2565b60455461035d906001600160a01b031681565b61034260395481565b61034260435481565b6103b5610870565b60405161034c91906139eb565b603654610342565b604b54604c546103f6916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b039586168152938516602085015291841691830191909152909116606082015260800161034c565b610342610437366004613a37565b6108d2565b61035d7f000000000000000000000000000000000000000000000000000000000000000081565b61033761092d565b61048e610479366004613a37565b60496020526000908152604090205460ff1681565b604051901515815260200161034c565b610342604e5481565b6103376104b5366004613a52565b610a6d565b6104cd6104c8366004613a85565b610c6f565b60405161034c929190613b38565b60425461035d906001600160a01b031681565b610342603b5481565b60375461048e90600160a01b900460ff1681565b610342607b5481565b603f5461035d906001600160a01b031681565b610342610535366004613a37565b610e4f565b610337610e78565b610342610550366004613a37565b610f1e565b604a5461035d906001600160a01b031681565b610337610576366004613b5a565b610f2f565b61058e610589366004613b5a565b6110c1565b60405161034c9190613b73565b6105ae6105a9366004613a37565b6110cc565b60405161034c9190613b9c565b6103376105c9366004613b5a565b611172565b61034260475481565b6103376105e5366004613bf2565b61124e565b61034260415481565b610654610601366004613b5a565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a00161034c565b61048e6106a9366004613a37565b6001600160a01b031660009081526033602052604090205460ff1690565b6106da6106d5366004613b5a565b61128d565b6040805192835260208301919091520161034c565b610342603a5481565b603454610342565b61035d61070e366004613a37565b6040602081905260009182529020546001600160a01b031681565b610337610737366004613b5a565b61154a565b6103376116bc565b610337611734565b60375461035d906001600160a01b031681565b61033761177a565b6103b56117ea565b61048e61184a565b610337610785366004613a37565b61187b565b61034261191f565b61034260465481565b60375461048e90600160a81b900460ff1681565b6103426107bd366004613b5a565b611929565b6103376107d0366004613a37565b611a83565b60006107ed6000805160206140268339815191525490565b905090565b603754600160a81b900460ff16156108255760405162461bcd60e51b815260040161081c90613c14565b60405180910390fd5b600080516020614006833981519152805460011981016108575760405162461bcd60e51b815260040161081c90613c3c565b60028255610866858585611b25565b5060019055505050565b606060348054806020026020016040519081016040528092919081815260200182805480156108c857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116108aa575b5050505050905090565b6000806108fb6108f56108e485611da6565b670de0b6b3a7640000906012611e10565b84611e72565b9050670de0b6b3a764000081610912856001611fbd565b61091c9190613c7a565b6109269190613c91565b9392505050565b61093561184a565b6109515760405162461bcd60e51b815260040161081c90613cb3565b60345460005b818110156109c8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034828154811061099c5761099c613cea565b6000918252602090912001546001600160a01b0316036109c057607b8190556109c8565b600101610957565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166034607b5481548110610a0857610a08613cea565b6000918252602090912001546001600160a01b031614610a6a5760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e6465780000000000000000604482015260640161081c565b50565b610a7561184a565b610a915760405162461bcd60e51b815260040161081c90613cb3565b600054610100900460ff1680610aaa575060005460ff16155b610b0d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161081c565b600054610100900460ff16158015610b2f576000805461ffff19166101011790555b6001600160a01b038316610b855760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f000000604482015260640161081c565b6001600160a01b038216610bd45760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b604482015260640161081c565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610c5791603691613930565b508015610c6a576000805461ff00191690555b505050565b603754606090600090600160a81b900460ff1615610c9f5760405162461bcd60e51b815260040161081c90613c14565b60008051602061400683398151915280546001198101610cd15760405162461bcd60e51b815260040161081c90613c3c565b60028255604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d2557600080fd5b505af1158015610d39573d6000803e3d6000fd5b50505050610d45612290565b508467ffffffffffffffff811115610d5f57610d5f613d00565b604051908082528060200260200182016040528015610d88578160200160208202803683370190505b50935060005b85811015610e0457610db7878783818110610dab57610dab613cea565b9050602002013561246c565b858281518110610dc957610dc9613cea565b602002602001018181525050848181518110610de757610de7613cea565b602002602001015184610dfa9190613d16565b9350600101610d8e565b50610e396001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612762565b610e42836127b8565b6001825550509250929050565b600080610e616108f56108e485611da6565b9050670de0b6b3a764000081610912856000611fbd565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f135760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161081c565b610f1c3361295f565b565b6000610f2982612a20565b92915050565b603754600160a81b900460ff1615610f595760405162461bcd60e51b815260040161081c90613c14565b6045546001600160a01b03163314610f835760405162461bcd60e51b815260040161081c90613d29565b6000198110610fa45760405162461bcd60e51b815260040161081c90613d6d565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610fd5929190613d96565b60405180910390a18060466000828254610fef9190613daf565b909155505060475460465461100390612af3565b1061105a5760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b606482015260840161081c565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac9061108c9033908590600401613d96565b600060405180830381600087803b1580156110a657600080fd5b505af11580156110ba573d6000803e3d6000fd5b5050505050565b6060610f2982612b31565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff80821615158452939492939184019161010090910416600181111561113857611138613b86565b600181111561114957611149613b86565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff161561119c5760405162461bcd60e51b815260040161081c90613c14565b600080516020614006833981519152805460011981016111ce5760405162461bcd60e51b815260040161081c90613c3c565b60028255603c546040516370a0823160e01b8152336004820152611246916001600160a01b0316906370a0823190602401602060405180830381865afa15801561121c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112409190613dcf565b84612c72565b506001905550565b60405162461bcd60e51b81526020600482015260146024820152733ab739bab83837b93a32b210333ab731ba34b7b760611b604482015260640161081c565b6037546000908190600160a81b900460ff16156112bc5760405162461bcd60e51b815260040161081c90613c14565b600080516020614006833981519152805460011981016112ee5760405162461bcd60e51b815260040161081c90613c3c565b600282556000604e54116113445760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c6564000000604482015260640161081c565b604c54604b546001600160801b03600160801b9092048216955061136a91879116613d16565b925061137f61137a856001613d16565b612e19565b604c80546001600160801b03928316600160801b0292169190911790556113a583612e19565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff1691810191909152606081016113f587612e19565b6001600160801b0316815260200161140c85612e19565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906114c79033908990600401613d96565b600060405180830381600087803b1580156114e157600080fd5b505af11580156114f5573d6000803e3d6000fd5b50505050611502856127b8565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156115745760405162461bcd60e51b815260040161081c90613c14565b6045546001600160a01b0316331461159e5760405162461bcd60e51b815260040161081c90613d29565b60001981106115bf5760405162461bcd60e51b815260040161081c90613d6d565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516115f0929190613d96565b60405180910390a1806046600082825461160a9190613de8565b909155505060475460465461161e90612af3565b1061168a5760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b606482015260840161081c565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f199061108c9033908590600401613d96565b603754600160a81b900460ff16156116e65760405162461bcd60e51b815260040161081c90613c14565b600080516020614006833981519152805460011981016117185760405162461bcd60e51b815260040161081c90613c3c565b60028255611724612290565b5061172d612e82565b5060019055565b600080516020614006833981519152805460011981016117665760405162461bcd60e51b815260040161081c90613c3c565b600282556117726130aa565b505060019055565b604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156117ca57600080fd5b505af11580156117de573d6000803e3d6000fd5b50505050610a6a612290565b606060368054806020026020016040519081016040528092919081815260200182805480156108c8576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116108aa575050505050905090565b60006118626000805160206140268339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61188361184a565b61189f5760405162461bcd60e51b815260040161081c90613cb3565b6118c7817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166118e76000805160206140268339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60006107ed6133ca565b603754600090600160a81b900460ff16156119565760405162461bcd60e51b815260040161081c90613c14565b600080516020614006833981519152805460011981016119885760405162461bcd60e51b815260040161081c90613c3c565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115611a3157604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a0f57600080fd5b505af1158015611a23573d6000803e3d6000fd5b50505050611a2f612290565b505b611a3a8461246c565b9250611a706001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163385612762565b611a79836127b8565b5060019055919050565b611a8b61184a565b611aa75760405162461bcd60e51b815260040161081c90613cb3565b803b611b015760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161081c565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614611ba65760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e67000000604482015260640161081c565b60008211611bf65760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161081c565b80821015611c465760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d0000604482015260640161081c565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611c77929190613d96565b60405180910390a1603754600160a01b900460ff16158015611c9b5750603b548210155b15611d1257604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611cf057600080fd5b505af1158015611d04573d6000803e3d6000fd5b50505050611d106130aa565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611d449033908690600401613d96565b600060405180830381600087803b158015611d5e57600080fd5b505af1158015611d72573d6000803e3d6000fd5b50611d8c925050506001600160a01b0384163330856133f5565b611d94612290565b50603a548210610c6a57610c6a612e82565b6001600160a01b03811660009081526033602052604090205462010000900460ff1680611e0b5760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b604482015260640161081c565b919050565b600081831115611e4057611e39611e278385613e10565b611e3290600a613f0a565b8590613433565b9350611e6a565b81831015611e6a57611e67611e558484613e10565b611e6090600a613f0a565b859061343f565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff1681816001811115611ea657611ea6613b86565b03611ec957611ec16012611eb985611da6565b869190611e10565b915050610f29565b6001816001811115611edd57611edd613b86565b03611f6e576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f469190613dcf565b9050670de0b6b3a7640000611f5b8287613c7a565b611f659190613c91565b92505050610f29565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161081c565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea9107890602401602060405180830381865afa158015612024573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120489190613dcf565b9150600181600181111561205e5761205e613b86565b036120ee576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c79190613dcf565b9050806120dc84670de0b6b3a7640000613c7a565b6120e69190613c91565b92505061214f565b600081600181111561210257612102613b86565b1461214f5760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161081c565b67120a871cc00200008211156121a75760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d61780000000000000000604482015260640161081c565b6709b6e64a8ec600008210156121f85760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b604482015260640161081c565b821561226f57670de0b6b3a764000082111561221a57670de0b6b3a764000091505b670dd99bb65dd7000082101561226a5760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b604482015260640161081c565b611fb6565b670de0b6b3a7640000821015611fb65750670de0b6b3a76400009392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c54808416968601969096529290940416606083015260009283916122e291613f16565b6001600160801b03169050806000036122fe5760009250505090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612365573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123899190613dcf565b90506000836040015184602001516123a19190613f16565b6001600160801b031690508082116123be57600094505050505090565b60006123ca8284613e10565b90508084106123d957806123db565b835b955060008686602001516001600160801b03166123f89190613d16565b905061240381612e19565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f4633339061245b9083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e54116124bf5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c6564000000604482015260640161081c565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261258692909116613d16565b11156125ca5760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b604482015260640161081c565b80602001516001600160801b031682608001516001600160801b031611156126345760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c6971756964697479000000000000000000604482015260640161081c565b81516001600160a01b0316331461267d5760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b604482015260640161081c565b6020820151156126c15760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b604482015260640161081c565b6000848152604d602052604090819020805460ff60a01b1916600160a01b1790556060830151908201516126f59190613f35565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a350606001516001600160801b031692915050565b610c6a8363a9059cbb60e01b8484604051602401612781929190613d96565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261344b565b6000603b5482101580156127d65750603754600160a01b900460ff16155b156127ea576127e36130aa565b90506127f5565b6127f26133ca565b90505b6041541561295b576000811161284d5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e67207265717565737473000000604482015260640161081c565b60006128d082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ca9190613dcf565b9061351d565b9050604154670de0b6b3a764000082116128fb576128f682670de0b6b3a7640000613e10565b61290d565b61290d670de0b6b3a764000083613e10565b1115610c6a5760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f720000604482015260640161081c565b5050565b6001600160a01b0381166129b55760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161081c565b806001600160a01b03166129d56000805160206140268339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610a6a8160008051602061402683398151915255565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614612a6357506000919050565b612a6c82613546565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529293509190612abc9084613d16565b1015612acb5750600092915050565b805160408201516001600160801b0391821691612ae9911684613d16565b6109269190613e10565b60006000198212612b165760405162461bcd60e51b815260040161081c90613d6d565b6000821215612b2d57612b2882613f54565b610f29565b5090565b60385460609015612b6057603854600090612b509084906127106136e0565b9050612b5c8184613e10565b9250505b6000607b5490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660348281548110612ba457612ba4613cea565b6000918252602090912001546001600160a01b031614612c065760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f74206361636865640000000000604482015260640161081c565b60345467ffffffffffffffff811115612c2157612c21613d00565b604051908082528060200260200182016040528015612c4a578160200160208202803683370190505b50915082828281518110612c6057612c60613cea565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63383604051612ca3929190613d96565b60405180910390a181600003612cb7575050565b6000612cc283612b31565b607b5481518110612cd557612cd5613cea565b6020026020010151905081811015612d2f5760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d604482015260640161081c565b80612d38613702565b1015612d785760405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b604482015260640161081c565b612dac6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612762565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90612dde9033908790600401613d96565b600060405180830381600087803b158015612df857600080fd5b505af1158015612e0c573d6000803e3d6000fd5b50505050610c6a836127b8565b60006001600160801b03821115612b2d5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161081c565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166000908152604060208190529020541680612ec55750565b6000612ecf613702565b905080600003612edd575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f4b9190613dcf565b90506000612f646039548361381090919063ffffffff16565b9050808311612f735750505050565b6000612f7f8285613e10565b905084612fb66001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168284612762565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef2490613004907f0000000000000000000000000000000000000000000000000000000000000000908690600401613d96565b600060405180830381600087803b15801561301e57600080fd5b505af1158015613032573d6000803e3d6000fd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b603754600090600160a01b900460ff16156130f95760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b604482015260640161081c565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015613143573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131679190613dcf565b905060006131736133ca565b9050816000036131865791506133c79050565b6042546001600160a01b031680158015906131a057508282115b156132e25760006131b18484613e10565b905060006131ce604354612710846136e09092919063ffffffff16565b905080821161322a5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b606482015260840161081c565b801561329557603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132629086908590600401613d96565b600060405180830381600087803b15801561327c57600080fd5b505af1158015613290573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133599190613dcf565b9250828211156133c257603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b1580156133a957600080fd5b505af11580156133bd573d6000803e3d6000fd5b505050505b509150505b90565b60006107ed7f0000000000000000000000000000000000000000000000000000000000000000612a20565b6040516001600160a01b038085166024830152831660448201526064810182905261342d9085906323b872dd60e01b90608401612781565b50505050565b60006109268284613c7a565b60006109268284613c91565b60006134a0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166138259092919063ffffffff16565b805190915015610c6a57808060200190518101906134be9190613f70565b610c6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161081c565b60008061353284670de0b6b3a7640000613433565b905061353e818461343f565b949350505050565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a0823190602401602060405180830381865afa15801561358f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b39190613dcf565b60365490925060005b818110156136d8576000603682815481106135d9576135d9613cea565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa15801561362f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136539190613f70565b156136cf57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa15801561369e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136c29190613dcf565b6136cc9086613d16565b94505b506001016135bc565b505050919050565b6000806136ed8585613433565b90506136f9818461343f565b95945050505050565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c548083169585018690529290920416606083015260009283916137529190613f16565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156137c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137eb9190613dcf565b90508181116137fe576000935050505090565b6138088282613e10565b935050505090565b60006109268383670de0b6b3a76400006136e0565b606061353e848460008585843b61387e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161081c565b600080866001600160a01b0316858760405161389a9190613fb6565b60006040518083038185875af1925050503d80600081146138d7576040519150601f19603f3d011682016040523d82523d6000602084013e6138dc565b606091505b50915091506138ec8282866138f7565b979650505050505050565b60608315613906575081610926565b8251156139165782518084602001fd5b8160405162461bcd60e51b815260040161081c9190613fd2565b828054828255906000526020600020908101928215613985579160200282015b8281111561398557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613950565b50612b2d9291505b80821115612b2d576000815560010161398d565b80356001600160a01b0381168114611e0b57600080fd5b6000806000606084860312156139cd57600080fd5b6139d6846139a1565b95602085013595506040909401359392505050565b602080825282518282018190526000918401906040840190835b81811015613a2c5783516001600160a01b0316835260209384019390920191600101613a05565b509095945050505050565b600060208284031215613a4957600080fd5b610926826139a1565b60008060408385031215613a6557600080fd5b613a6e836139a1565b9150613a7c602084016139a1565b90509250929050565b60008060208385031215613a9857600080fd5b823567ffffffffffffffff811115613aaf57600080fd5b8301601f81018513613ac057600080fd5b803567ffffffffffffffff811115613ad757600080fd5b8560208260051b8401011115613aec57600080fd5b6020919091019590945092505050565b600081518084526020840193506020830160005b82811015613b2e578151865260209586019590910190600101613b10565b5093949350505050565b604081526000613b4b6040830185613afc565b90508260208301529392505050565b600060208284031215613b6c57600080fd5b5035919050565b6020815260006109266020830184613afc565b634e487b7160e01b600052602160045260246000fd5b8151151581526020820151608082019060028110613bca57634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b60008060408385031215613c0557600080fd5b50508035926020909101359150565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610f2957610f29613c64565b600082613cae57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b80820180821115610f2957610f29613c64565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6001600160a01b03929092168252602082015260400190565b8181036000831280158383131683831282161715611fb657611fb6613c64565b600060208284031215613de157600080fd5b5051919050565b8082018281126000831280158216821582161715613e0857613e08613c64565b505092915050565b81810381811115610f2957610f29613c64565b6001815b6001841115613e5e57808504811115613e4257613e42613c64565b6001841615613e5057908102905b60019390931c928002613e27565b935093915050565b600082613e7557506001610f29565b81613e8257506000610f29565b8160018114613e985760028114613ea257613ebe565b6001915050610f29565b60ff841115613eb357613eb3613c64565b50506001821b610f29565b5060208310610133831016604e8410600b8410161715613ee1575081810a610f29565b613eee6000198484613e23565b8060001904821115613f0257613f02613c64565b029392505050565b60006109268383613e66565b6001600160801b038281168282160390811115610f2957610f29613c64565b6001600160801b038181168382160190811115610f2957610f29613c64565b6000600160ff1b8201613f6957613f69613c64565b5060000390565b600060208284031215613f8257600080fd5b8151801515811461092657600080fd5b60005b83811015613fad578181015183820152602001613f95565b50506000910152565b60008251613fc8818460208701613f92565b9190910192915050565b6020815260008251806020840152613ff1816040850160208701613f92565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212202de7dbb20ec302f109ca6116b0a84f0dc4e5ad578580c8d1b1f95f186df04d0564736f6c634300081c00337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102f15760003560e01c80636217f3ea1161019d578063ab80dafb116100e9578063c7af3352116100a2578063e45cc9f01161007c578063e45cc9f014610792578063e6cc54321461079b578063f8444436146107af578063fc0cfeee146107c2576102f1565b8063c7af33521461076f578063d38bfff414610777578063d4c3eea01461078a576102f1565b8063ab80dafb14610729578063abaa99161461073c578063af14052c14610744578063b888879e1461074c578063b9b17f9f1461075f578063c3b2886414610767576102f1565b80638e510b52116101565780639ee679e8116101305780639ee679e8146106c75780639fa1826e146106ef578063a0aead4d146106f8578063a403e4d514610700576102f1565b80638e510b52146105ea578063937b2581146105f35780639be918e61461069b576102f1565b80636217f3ea1461056857806367bd7ba31461057b5780636ec3ab671461059b5780637136a7a6146105bb5780637a2202f3146105ce5780637cbc2373146105d7576102f1565b80634530820a1161025c57806353ca9f24116102155780635b60f9fc116101ef5780635b60f9fc146105275780635d36b1901461053a5780635f51522614610542578063603ea03b14610555576102f1565b806353ca9f24146104f757806354c6d8581461050b578063570d8e1d14610514576102f1565b80634530820a1461046b57806345e4213b1461049e578063485cc955146104a757806348e30f54146104ba57806349c1d54d146104db57806352d38e5d146104ee576102f1565b80632acada4d116102ae5780632acada4d146103ad57806331e19cfa146103c2578063362bd1a3146103ca5780633b8fe28d146104295780633fc8cef31461043c57806344c5470714610463576102f1565b806309f6442c146103395780630c340a2414610355578063156e29f61461037557806318ce56bd146103885780631edfe3da1461039b578063207134b0146103a4575b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9366000803760008036600084545af43d6000803e808015610332573d6000f35b3d6000fd5b005b61034260385481565b6040519081526020015b60405180910390f35b61035d6107d5565b6040516001600160a01b03909116815260200161034c565b6103376103833660046139b8565b6107f2565b60455461035d906001600160a01b031681565b61034260395481565b61034260435481565b6103b5610870565b60405161034c91906139eb565b603654610342565b604b54604c546103f6916001600160801b0380821692600160801b928390048216928183169291041684565b604080516001600160801b039586168152938516602085015291841691830191909152909116606082015260800161034c565b610342610437366004613a37565b6108d2565b61035d7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3881565b61033761092d565b61048e610479366004613a37565b60496020526000908152604090205460ff1681565b604051901515815260200161034c565b610342604e5481565b6103376104b5366004613a52565b610a6d565b6104cd6104c8366004613a85565b610c6f565b60405161034c929190613b38565b60425461035d906001600160a01b031681565b610342603b5481565b60375461048e90600160a01b900460ff1681565b610342607b5481565b603f5461035d906001600160a01b031681565b610342610535366004613a37565b610e4f565b610337610e78565b610342610550366004613a37565b610f1e565b604a5461035d906001600160a01b031681565b610337610576366004613b5a565b610f2f565b61058e610589366004613b5a565b6110c1565b60405161034c9190613b73565b6105ae6105a9366004613a37565b6110cc565b60405161034c9190613b9c565b6103376105c9366004613b5a565b611172565b61034260475481565b6103376105e5366004613bf2565b61124e565b61034260415481565b610654610601366004613b5a565b604d60205260009081526040902080546001909101546001600160a01b03821691600160a01b810460ff1691600160a81b90910464ffffffffff16906001600160801b0380821691600160801b90041685565b604080516001600160a01b039096168652931515602086015264ffffffffff909216928401929092526001600160801b03918216606084015216608082015260a00161034c565b61048e6106a9366004613a37565b6001600160a01b031660009081526033602052604090205460ff1690565b6106da6106d5366004613b5a565b61128d565b6040805192835260208301919091520161034c565b610342603a5481565b603454610342565b61035d61070e366004613a37565b6040602081905260009182529020546001600160a01b031681565b610337610737366004613b5a565b61154a565b6103376116bc565b610337611734565b60375461035d906001600160a01b031681565b61033761177a565b6103b56117ea565b61048e61184a565b610337610785366004613a37565b61187b565b61034261191f565b61034260465481565b60375461048e90600160a81b900460ff1681565b6103426107bd366004613b5a565b611929565b6103376107d0366004613a37565b611a83565b60006107ed6000805160206140268339815191525490565b905090565b603754600160a81b900460ff16156108255760405162461bcd60e51b815260040161081c90613c14565b60405180910390fd5b600080516020614006833981519152805460011981016108575760405162461bcd60e51b815260040161081c90613c3c565b60028255610866858585611b25565b5060019055505050565b606060348054806020026020016040519081016040528092919081815260200182805480156108c857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116108aa575b5050505050905090565b6000806108fb6108f56108e485611da6565b670de0b6b3a7640000906012611e10565b84611e72565b9050670de0b6b3a764000081610912856001611fbd565b61091c9190613c7a565b6109269190613c91565b9392505050565b61093561184a565b6109515760405162461bcd60e51b815260040161081c90613cb3565b60345460005b818110156109c8577f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03166034828154811061099c5761099c613cea565b6000918252602090912001546001600160a01b0316036109c057607b8190556109c8565b600101610957565b507f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03166034607b5481548110610a0857610a08613cea565b6000918252602090912001546001600160a01b031614610a6a5760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964205745544820417373657420496e6465780000000000000000604482015260640161081c565b50565b610a7561184a565b610a915760405162461bcd60e51b815260040161081c90613cb3565b600054610100900460ff1680610aaa575060005460ff16155b610b0d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161081c565b600054610100900460ff16158015610b2f576000805461ffff19166101011790555b6001600160a01b038316610b855760405162461bcd60e51b815260206004820152601d60248201527f507269636550726f76696465722061646472657373206973207a65726f000000604482015260640161081c565b6001600160a01b038216610bd45760405162461bcd60e51b81526020600482015260166024820152756f546f6b656e2061646472657373206973207a65726f60501b604482015260640161081c565b603c80546001600160a01b038481166001600160a01b031990921691909117909155603780546001600160b01b03191691851691909117600160a81b17905560006038819055603981905569054b40b1f852bda00000603a55683635c9adc5dea00000603b556040805191825260208201908190529051610c5791603691613930565b508015610c6a576000805461ff00191690555b505050565b603754606090600090600160a81b900460ff1615610c9f5760405162461bcd60e51b815260040161081c90613c14565b60008051602061400683398151915280546001198101610cd15760405162461bcd60e51b815260040161081c90613c3c565b60028255604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d2557600080fd5b505af1158015610d39573d6000803e3d6000fd5b50505050610d45612290565b508467ffffffffffffffff811115610d5f57610d5f613d00565b604051908082528060200260200182016040528015610d88578160200160208202803683370190505b50935060005b85811015610e0457610db7878783818110610dab57610dab613cea565b9050602002013561246c565b858281518110610dc957610dc9613cea565b602002602001018181525050848181518110610de757610de7613cea565b602002602001015184610dfa9190613d16565b9350600101610d8e565b50610e396001600160a01b037f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38163385612762565b610e42836127b8565b6001825550509250929050565b600080610e616108f56108e485611da6565b9050670de0b6b3a764000081610912856000611fbd565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b031614610f135760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b606482015260840161081c565b610f1c3361295f565b565b6000610f2982612a20565b92915050565b603754600160a81b900460ff1615610f595760405162461bcd60e51b815260040161081c90613c14565b6045546001600160a01b03163314610f835760405162461bcd60e51b815260040161081c90613d29565b6000198110610fa45760405162461bcd60e51b815260040161081c90613d6d565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63382604051610fd5929190613d96565b60405180910390a18060466000828254610fef9190613daf565b909155505060475460465461100390612af3565b1061105a5760405162461bcd60e51b815260206004820152602160248201527f417474656d7074696e6720746f206275726e20746f6f206d756368204f5553446044820152601760f91b606482015260840161081c565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac9061108c9033908590600401613d96565b600060405180830381600087803b1580156110a657600080fd5b505af11580156110ba573d6000803e3d6000fd5b5050505050565b6060610f2982612b31565b604080516080808201835260008083526020808401829052838501829052606084018290526001600160a01b038616825260338152908490208451928301909452835460ff80821615158452939492939184019161010090910416600181111561113857611138613b86565b600181111561114957611149613b86565b8152905462010000810460ff1660208301526301000000900461ffff1660409091015292915050565b603754600160a81b900460ff161561119c5760405162461bcd60e51b815260040161081c90613c14565b600080516020614006833981519152805460011981016111ce5760405162461bcd60e51b815260040161081c90613c3c565b60028255603c546040516370a0823160e01b8152336004820152611246916001600160a01b0316906370a0823190602401602060405180830381865afa15801561121c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112409190613dcf565b84612c72565b506001905550565b60405162461bcd60e51b81526020600482015260146024820152733ab739bab83837b93a32b210333ab731ba34b7b760611b604482015260640161081c565b6037546000908190600160a81b900460ff16156112bc5760405162461bcd60e51b815260040161081c90613c14565b600080516020614006833981519152805460011981016112ee5760405162461bcd60e51b815260040161081c90613c3c565b600282556000604e54116113445760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c6564000000604482015260640161081c565b604c54604b546001600160801b03600160801b9092048216955061136a91879116613d16565b925061137f61137a856001613d16565b612e19565b604c80546001600160801b03928316600160801b0292169190911790556113a583612e19565b604b80546001600160801b0319166001600160801b03929092169190911790556040805160a081018252338152600060208201524264ffffffffff1691810191909152606081016113f587612e19565b6001600160801b0316815260200161140c85612e19565b6001600160801b039081169091526000868152604d602090815260409182902084518154928601518685015164ffffffffff16600160a81b0264ffffffffff60a81b19911515600160a01b026001600160a81b03199095166001600160a01b0393841617949094171692909217815560608501516080909501518416600160801b029490931693909317600190920191909155603c549051632770a7eb60e21b8152911690639dc29fac906114c79033908990600401613d96565b600060405180830381600087803b1580156114e157600080fd5b505af11580156114f5573d6000803e3d6000fd5b50505050611502856127b8565b6040805186815260208101859052859133917f38e3d972947cfef94205163d483d6287ef27eb312e20cb8e0b13a49989db232e910160405180910390a3600182555050915091565b603754600160a81b900460ff16156115745760405162461bcd60e51b815260040161081c90613c14565b6045546001600160a01b0316331461159e5760405162461bcd60e51b815260040161081c90613d29565b60001981106115bf5760405162461bcd60e51b815260040161081c90613d6d565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688533826040516115f0929190613d96565b60405180910390a1806046600082825461160a9190613de8565b909155505060475460465461161e90612af3565b1061168a5760405162461bcd60e51b815260206004820152603660248201527f4d696e746564206f75736420737572706173736564206e65744f7573644d696e6044820152753a2337b929ba3930ba32b3bcaa343932b9b437b6321760511b606482015260840161081c565b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f199061108c9033908590600401613d96565b603754600160a81b900460ff16156116e65760405162461bcd60e51b815260040161081c90613c14565b600080516020614006833981519152805460011981016117185760405162461bcd60e51b815260040161081c90613c3c565b60028255611724612290565b5061172d612e82565b5060019055565b600080516020614006833981519152805460011981016117665760405162461bcd60e51b815260040161081c90613c3c565b600282556117726130aa565b505060019055565b604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156117ca57600080fd5b505af11580156117de573d6000803e3d6000fd5b50505050610a6a612290565b606060368054806020026020016040519081016040528092919081815260200182805480156108c8576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116108aa575050505050905090565b60006118626000805160206140268339815191525490565b6001600160a01b0316336001600160a01b031614905090565b61188361184a565b61189f5760405162461bcd60e51b815260040161081c90613cb3565b6118c7817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b03166118e76000805160206140268339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b60006107ed6133ca565b603754600090600160a81b900460ff16156119565760405162461bcd60e51b815260040161081c90613c14565b600080516020614006833981519152805460011981016119885760405162461bcd60e51b815260040161081c90613c3c565b60028255604b546000858152604d60205260409020600101546001600160801b03600160801b92839004811692909104161115611a3157604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611a0f57600080fd5b505af1158015611a23573d6000803e3d6000fd5b50505050611a2f612290565b505b611a3a8461246c565b9250611a706001600160a01b037f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38163385612762565b611a79836127b8565b5060019055919050565b611a8b61184a565b611aa75760405162461bcd60e51b815260040161081c90613cb3565b803b611b015760405162461bcd60e51b8152602060048201526024808201527f6e657720696d706c656d656e746174696f6e206973206e6f74206120636f6e746044820152631c9858dd60e21b606482015260840161081c565b7fa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd955565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b0316836001600160a01b031614611ba65760405162461bcd60e51b815260206004820152601d60248201527f556e737570706f7274656420617373657420666f72206d696e74696e67000000604482015260640161081c565b60008211611bf65760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640161081c565b80821015611c465760405162461bcd60e51b815260206004820152601e60248201527f4d696e7420616d6f756e74206c6f776572207468616e206d696e696d756d0000604482015260640161081c565b7f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968853383604051611c77929190613d96565b60405180910390a1603754600160a01b900460ff16158015611c9b5750603b548210155b15611d1257604a60009054906101000a90046001600160a01b03166001600160a01b031663e52253816040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611cf057600080fd5b505af1158015611d04573d6000803e3d6000fd5b50505050611d106130aa565b505b603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611d449033908690600401613d96565b600060405180830381600087803b158015611d5e57600080fd5b505af1158015611d72573d6000803e3d6000fd5b50611d8c925050506001600160a01b0384163330856133f5565b611d94612290565b50603a548210610c6a57610c6a612e82565b6001600160a01b03811660009081526033602052604090205462010000900460ff1680611e0b5760405162461bcd60e51b8152602060048201526013602482015272111958da5b585b1cc81b9bdd0818d858da1959606a1b604482015260640161081c565b919050565b600081831115611e4057611e39611e278385613e10565b611e3290600a613f0a565b8590613433565b9350611e6a565b81831015611e6a57611e67611e558484613e10565b611e6090600a613f0a565b859061343f565b93505b509192915050565b6001600160a01b038116600090815260336020526040812054610100900460ff1681816001811115611ea657611ea6613b86565b03611ec957611ec16012611eb985611da6565b869190611e10565b915050610f29565b6001816001811115611edd57611edd613b86565b03611f6e576000836001600160a01b031663e6aa216c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f469190613dcf565b9050670de0b6b3a7640000611f5b8287613c7a565b611f659190613c91565b92505050610f29565b60405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161081c565b5092915050565b6001600160a01b038281166000818152603360205260408082205460375491516315d5220f60e31b81526004810194909452919361010090920460ff169291169063aea9107890602401602060405180830381865afa158015612024573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120489190613dcf565b9150600181600181111561205e5761205e613b86565b036120ee576000846001600160a01b031663e6aa216c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c79190613dcf565b9050806120dc84670de0b6b3a7640000613c7a565b6120e69190613c91565b92505061214f565b600081600181111561210257612102613b86565b1461214f5760405162461bcd60e51b815260206004820152601b60248201527f556e737570706f7274656420636f6e76657273696f6e20747970650000000000604482015260640161081c565b67120a871cc00200008211156121a75760405162461bcd60e51b815260206004820152601860248201527f5661756c743a2050726963652065786365656473206d61780000000000000000604482015260640161081c565b6709b6e64a8ec600008210156121f85760405162461bcd60e51b81526020600482015260166024820152752b30bab63a1d10283934b1b2903ab73232b91036b4b760511b604482015260640161081c565b821561226f57670de0b6b3a764000082111561221a57670de0b6b3a764000091505b670dd99bb65dd7000082101561226a5760405162461bcd60e51b815260206004820152601560248201527441737365742070726963652062656c6f772070656760581b604482015260640161081c565b611fb6565b670de0b6b3a7640000821015611fb65750670de0b6b3a76400009392505050565b60408051608081018252604b546001600160801b03808216808452600160801b92839004821660208501819052604c54808416968601969096529290940416606083015260009283916122e291613f16565b6001600160801b03169050806000036122fe5760009250505090565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b0316906370a0823190602401602060405180830381865afa158015612365573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123899190613dcf565b90506000836040015184602001516123a19190613f16565b6001600160801b031690508082116123be57600094505050505090565b60006123ca8284613e10565b90508084106123d957806123db565b835b955060008686602001516001600160801b03166123f89190613d16565b905061240381612e19565b604b80546001600160801b03928316600160801b0292169190911790556040517fee79a0c43d3993055690b54e074b5153e8bae8d1a872b656dedb64aa8f4633339061245b9083908a90918252602082015260400190565b60405180910390a150505050505090565b600080604e54116124bf5760405162461bcd60e51b815260206004820152601d60248201527f4173796e63207769746864726177616c73206e6f7420656e61626c6564000000604482015260640161081c565b6000828152604d6020908152604091829020825160a08101845281546001600160a01b038116825260ff600160a01b82041615158285015264ffffffffff600160a81b90910481168286019081526001909301546001600160801b03808216606080860191909152600160801b92839004821660808087019190915288519081018952604b548084168252849004831697810197909752604c54808316988801989098529190960490951694840194909452604e5491519093429261258692909116613d16565b11156125ca5760405162461bcd60e51b815260206004820152601360248201527210db185a5b4819195b185e481b9bdd081b595d606a1b604482015260640161081c565b80602001516001600160801b031682608001516001600160801b031611156126345760405162461bcd60e51b815260206004820152601760248201527f51756575652070656e64696e67206c6971756964697479000000000000000000604482015260640161081c565b81516001600160a01b0316331461267d5760405162461bcd60e51b815260206004820152600d60248201526c2737ba103932b8bab2b9ba32b960991b604482015260640161081c565b6020820151156126c15760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b604482015260640161081c565b6000848152604d602052604090819020805460ff60a01b1916600160a01b1790556060830151908201516126f59190613f35565b604c80546001600160801b0319166001600160801b03928316179055606083015160405191168152849033907f2d43eb174787155132b52ddb6b346e2dca99302eac3df4466dbeff953d3c84d19060200160405180910390a350606001516001600160801b031692915050565b610c6a8363a9059cbb60e01b8484604051602401612781929190613d96565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261344b565b6000603b5482101580156127d65750603754600160a01b900460ff16155b156127ea576127e36130aa565b90506127f5565b6127f26133ca565b90505b6041541561295b576000811161284d5760405162461bcd60e51b815260206004820152601d60248201527f546f6f206d616e79206f75747374616e64696e67207265717565737473000000604482015260640161081c565b60006128d082603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ca9190613dcf565b9061351d565b9050604154670de0b6b3a764000082116128fb576128f682670de0b6b3a7640000613e10565b61290d565b61290d670de0b6b3a764000083613e10565b1115610c6a5760405162461bcd60e51b815260206004820152601e60248201527f4261636b696e6720737570706c79206c6971756964697479206572726f720000604482015260640161081c565b5050565b6001600160a01b0381166129b55760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f722069732061646472657373283029000000000000604482015260640161081c565b806001600160a01b03166129d56000805160206140268339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610a6a8160008051602061402683398151915255565b60007f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b0316826001600160a01b031614612a6357506000919050565b612a6c82613546565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c54808316958501869052929092041660608301529293509190612abc9084613d16565b1015612acb5750600092915050565b805160408201516001600160801b0391821691612ae9911684613d16565b6109269190613e10565b60006000198212612b165760405162461bcd60e51b815260040161081c90613d6d565b6000821215612b2d57612b2882613f54565b610f29565b5090565b60385460609015612b6057603854600090612b509084906127106136e0565b9050612b5c8184613e10565b9250505b6000607b5490507f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b031660348281548110612ba457612ba4613cea565b6000918252602090912001546001600160a01b031614612c065760405162461bcd60e51b815260206004820152601b60248201527f5745544820417373657420696e646578206e6f74206361636865640000000000604482015260640161081c565b60345467ffffffffffffffff811115612c2157612c21613d00565b604051908082528060200260200182016040528015612c4a578160200160208202803683370190505b50915082828281518110612c6057612c60613cea565b60200260200101818152505050919050565b7f222838db2794d11532d940e8dec38ae307ed0b63cd97c233322e221f998767a63383604051612ca3929190613d96565b60405180910390a181600003612cb7575050565b6000612cc283612b31565b607b5481518110612cd557612cd5613cea565b6020026020010151905081811015612d2f5760405162461bcd60e51b815260206004820181905260248201527f52656465656d20616d6f756e74206c6f776572207468616e206d696e696d756d604482015260640161081c565b80612d38613702565b1015612d785760405162461bcd60e51b815260206004820152600f60248201526e2634b8bab4b234ba3c9032b93937b960891b604482015260640161081c565b612dac6001600160a01b037f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38163383612762565b603c54604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90612dde9033908790600401613d96565b600060405180830381600087803b158015612df857600080fd5b505af1158015612e0c573d6000803e3d6000fd5b50505050610c6a836127b8565b60006001600160801b03821115612b2d5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161081c565b6001600160a01b037f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3881166000908152604060208190529020541680612ec55750565b6000612ecf613702565b905080600003612edd575050565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015612f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f4b9190613dcf565b90506000612f646039548361381090919063ffffffff16565b9050808311612f735750505050565b6000612f7f8285613e10565b905084612fb66001600160a01b037f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38168284612762565b6040516311f9fbc960e21b81526001600160a01b038216906347e7ef2490613004907f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38908690600401613d96565b600060405180830381600087803b15801561301e57600080fd5b505af1158015613032573d6000803e3d6000fd5b5050604080516001600160a01b037f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38811682528a1660208201529081018590527f41b99659f6ba0803f444aff29e5bf6e26dd86a3219aff92119d69710a956ba8d9250606001905060405180910390a1505050505050565b603754600090600160a01b900460ff16156130f95760405162461bcd60e51b815260206004820152600f60248201526e149958985cda5b99c81c185d5cd959608a1b604482015260640161081c565b603c54604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd9160048083019260209291908290030181865afa158015613143573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131679190613dcf565b905060006131736133ca565b9050816000036131865791506133c79050565b6042546001600160a01b031680158015906131a057508282115b156132e25760006131b18484613e10565b905060006131ce604354612710846136e09092919063ffffffff16565b905080821161322a5760405162461bcd60e51b815260206004820152602260248201527f466565206d757374206e6f742062652067726561746572207468616e207969656044820152611b1960f21b606482015260840161081c565b801561329557603c546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906132629086908590600401613d96565b600060405180830381600087803b15801561327c57600080fd5b505af1158015613290573d6000803e3d6000fd5b505050505b604080516001600160a01b0385168152602081018490529081018290527f09516ecf4a8a86e59780a9befc6dee948bc9e60a36e3be68d31ea817ee8d2c809060600160405180910390a150505b603c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133599190613dcf565b9250828211156133c257603c546040516339a7919f60e01b8152600481018490526001600160a01b03909116906339a7919f90602401600060405180830381600087803b1580156133a957600080fd5b505af11580156133bd573d6000803e3d6000fd5b505050505b509150505b90565b60006107ed7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38612a20565b6040516001600160a01b038085166024830152831660448201526064810182905261342d9085906323b872dd60e01b90608401612781565b50505050565b60006109268284613c7a565b60006109268284613c91565b60006134a0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166138259092919063ffffffff16565b805190915015610c6a57808060200190518101906134be9190613f70565b610c6a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161081c565b60008061353284670de0b6b3a7640000613433565b905061353e818461343f565b949350505050565b6040516370a0823160e01b815230600482015260009082906001600160a01b038216906370a0823190602401602060405180830381865afa15801561358f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b39190613dcf565b60365490925060005b818110156136d8576000603682815481106135d9576135d9613cea565b60009182526020909120015460405163551c457b60e11b81526001600160a01b0388811660048301529091169150819063aa388af690602401602060405180830381865afa15801561362f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136539190613f70565b156136cf57604051632fa8a91360e11b81526001600160a01b038781166004830152821690635f51522690602401602060405180830381865afa15801561369e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136c29190613dcf565b6136cc9086613d16565b94505b506001016135bc565b505050919050565b6000806136ed8585613433565b90506136f9818461343f565b95945050505050565b60408051608081018252604b546001600160801b03808216808452600160801b9283900482166020850152604c548083169585018690529290920416606083015260009283916137529190613f16565b6040516370a0823160e01b81523060048201526001600160801b039190911691506000906001600160a01b037f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3816906370a0823190602401602060405180830381865afa1580156137c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137eb9190613dcf565b90508181116137fe576000935050505090565b6138088282613e10565b935050505090565b60006109268383670de0b6b3a76400006136e0565b606061353e848460008585843b61387e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161081c565b600080866001600160a01b0316858760405161389a9190613fb6565b60006040518083038185875af1925050503d80600081146138d7576040519150601f19603f3d011682016040523d82523d6000602084013e6138dc565b606091505b50915091506138ec8282866138f7565b979650505050505050565b60608315613906575081610926565b8251156139165782518084602001fd5b8160405162461bcd60e51b815260040161081c9190613fd2565b828054828255906000526020600020908101928215613985579160200282015b8281111561398557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613950565b50612b2d9291505b80821115612b2d576000815560010161398d565b80356001600160a01b0381168114611e0b57600080fd5b6000806000606084860312156139cd57600080fd5b6139d6846139a1565b95602085013595506040909401359392505050565b602080825282518282018190526000918401906040840190835b81811015613a2c5783516001600160a01b0316835260209384019390920191600101613a05565b509095945050505050565b600060208284031215613a4957600080fd5b610926826139a1565b60008060408385031215613a6557600080fd5b613a6e836139a1565b9150613a7c602084016139a1565b90509250929050565b60008060208385031215613a9857600080fd5b823567ffffffffffffffff811115613aaf57600080fd5b8301601f81018513613ac057600080fd5b803567ffffffffffffffff811115613ad757600080fd5b8560208260051b8401011115613aec57600080fd5b6020919091019590945092505050565b600081518084526020840193506020830160005b82811015613b2e578151865260209586019590910190600101613b10565b5093949350505050565b604081526000613b4b6040830185613afc565b90508260208301529392505050565b600060208284031215613b6c57600080fd5b5035919050565b6020815260006109266020830184613afc565b634e487b7160e01b600052602160045260246000fd5b8151151581526020820151608082019060028110613bca57634e487b7160e01b600052602160045260246000fd5b8060208401525060ff604084015116604083015261ffff606084015116606083015292915050565b60008060408385031215613c0557600080fd5b50508035926020909101359150565b6020808252600e908201526d10d85c1a5d185b081c185d5cd95960921b604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610f2957610f29613c64565b600082613cae57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b80820180821115610f2957610f29613c64565b60208082526024908201527f43616c6c6572206973206e6f7420746865204f555344206d65746120737472616040820152637465677960e01b606082015260800190565b6020808252600f908201526e082dadeeadce840e8dede40d0d2ced608b1b604082015260600190565b6001600160a01b03929092168252602082015260400190565b8181036000831280158383131683831282161715611fb657611fb6613c64565b600060208284031215613de157600080fd5b5051919050565b8082018281126000831280158216821582161715613e0857613e08613c64565b505092915050565b81810381811115610f2957610f29613c64565b6001815b6001841115613e5e57808504811115613e4257613e42613c64565b6001841615613e5057908102905b60019390931c928002613e27565b935093915050565b600082613e7557506001610f29565b81613e8257506000610f29565b8160018114613e985760028114613ea257613ebe565b6001915050610f29565b60ff841115613eb357613eb3613c64565b50506001821b610f29565b5060208310610133831016604e8410600b8410161715613ee1575081810a610f29565b613eee6000198484613e23565b8060001904821115613f0257613f02613c64565b029392505050565b60006109268383613e66565b6001600160801b038281168282160390811115610f2957610f29613c64565b6001600160801b038181168382160190811115610f2957610f29613c64565b6000600160ff1b8201613f6957613f69613c64565b5060000390565b600060208284031215613f8257600080fd5b8151801515811461092657600080fd5b60005b83811015613fad578181015183820152602001613f95565b50506000910152565b60008251613fc8818460208701613f92565b9190910192915050565b6020815260008251806020840152613ff1816040850160208701613f92565b601f01601f1916919091016040019291505056fe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa26469706673582212202de7dbb20ec302f109ca6116b0a84f0dc4e5ad578580c8d1b1f95f186df04d0564736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38
-----Decoded View---------------
Arg [0] : _wS (address): 0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.