Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Generalized4626Strategy
Compiler Version
v0.8.7+commit.e28d00a7
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Generalized 4626 Strategy * @notice Investment strategy for ERC-4626 Tokenized Vaults * @author Origin Protocol Inc */ import { IERC4626 } from "../../lib/openzeppelin/interfaces/IERC4626.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC20, InitializableAbstractStrategy } from "../utils/InitializableAbstractStrategy.sol"; contract Generalized4626Strategy is InitializableAbstractStrategy { using SafeERC20 for IERC20; /// @dev Replaced with an immutable variable // slither-disable-next-line constable-states address private _deprecate_shareToken; /// @dev Replaced with an immutable variable // slither-disable-next-line constable-states address private _deprecate_assetToken; IERC20 public immutable shareToken; IERC20 public immutable assetToken; // For future use uint256[50] private __gap; /** * @param _baseConfig Base strategy config with platformAddress (ERC-4626 Vault contract), eg sfrxETH or sDAI, * and vaultAddress (OToken Vault contract), eg VaultProxy or OETHVaultProxy * @param _assetToken Address of the ERC-4626 asset token. eg frxETH or DAI */ constructor(BaseStrategyConfig memory _baseConfig, address _assetToken) InitializableAbstractStrategy(_baseConfig) { shareToken = IERC20(_baseConfig.platformAddress); assetToken = IERC20(_assetToken); } function initialize() external virtual onlyGovernor initializer { address[] memory rewardTokens = new address[](0); address[] memory assets = new address[](1); address[] memory pTokens = new address[](1); assets[0] = address(assetToken); pTokens[0] = address(platformAddress); InitializableAbstractStrategy._initialize( rewardTokens, assets, pTokens ); } /** * @dev Deposit assets by converting them to shares * @param _asset Address of asset to deposit * @param _amount Amount of asset to deposit */ function deposit(address _asset, uint256 _amount) external override onlyVault nonReentrant { _deposit(_asset, _amount); } /** * @dev Deposit assets by converting them to shares * @param _asset Address of asset to deposit * @param _amount Amount of asset to deposit */ function _deposit(address _asset, uint256 _amount) internal virtual { require(_amount > 0, "Must deposit something"); require(_asset == address(assetToken), "Unexpected asset address"); // slither-disable-next-line unused-return IERC4626(platformAddress).deposit(_amount, address(this)); emit Deposit(_asset, address(shareToken), _amount); } /** * @dev Deposit the entire balance of assetToken to gain shareToken */ function depositAll() external virtual override onlyVault nonReentrant { uint256 balance = assetToken.balanceOf(address(this)); if (balance > 0) { _deposit(address(assetToken), balance); } } /** * @dev Withdraw asset by burning shares * @param _recipient Address to receive withdrawn asset * @param _asset Address of asset to withdraw * @param _amount Amount of asset to withdraw */ function withdraw( address _recipient, address _asset, uint256 _amount ) external virtual override onlyVault nonReentrant { require(_amount > 0, "Must withdraw something"); require(_recipient != address(0), "Must specify recipient"); require(_asset == address(assetToken), "Unexpected asset address"); // slither-disable-next-line unused-return IERC4626(platformAddress).withdraw(_amount, _recipient, address(this)); emit Withdrawal(_asset, address(shareToken), _amount); } /** * @dev Internal method to respond to the addition of new asset / share tokens */ function _abstractSetPToken(address, address) internal virtual override { _approveBase(); } /** * @dev Remove all assets from platform and send them to Vault contract. */ function withdrawAll() external virtual override onlyVaultOrGovernor nonReentrant { uint256 shareBalance = shareToken.balanceOf(address(this)); uint256 assetAmount = 0; if (shareBalance > 0) { assetAmount = IERC4626(platformAddress).redeem( shareBalance, vaultAddress, address(this) ); emit Withdrawal( address(assetToken), address(shareToken), assetAmount ); } } /** * @dev Get the total asset value held in the platform * @param _asset Address of the asset * @return balance Total value of the asset in the platform */ function checkBalance(address _asset) external view virtual override returns (uint256 balance) { require(_asset == address(assetToken), "Unexpected asset address"); /* We are intentionally not counting the amount of assetToken parked on the * contract toward the checkBalance. The deposit and withdraw functions * should not result in assetToken being unused and owned by this strategy * contract. */ return IERC4626(platformAddress).maxWithdraw(address(this)); } /** * @notice Governor approves the the ERC-4626 Tokenized Vault to spend the asset. */ function safeApproveAllTokens() external override onlyGovernor { _approveBase(); } function _approveBase() internal virtual { // Approval the asset to be trasferred to the ERC-4626 Tokenized Vualt. // Used by the ERC-4626 deposit() and mint() functions // slither-disable-next-line unused-return assetToken.approve(platformAddress, type(uint256).max); } /** * @dev Retuns bool indicating whether asset is supported by strategy * @param _asset Address of the asset */ function supportsAsset(address _asset) public view virtual override returns (bool) { return _asset == address(assetToken); } /** * @notice is not supported for this strategy as the asset and * ERC-4626 Tokenized Vault are set at deploy time. * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new * contract would need to be deployed and the proxy updated. */ function setPTokenAddress(address, address) external override onlyGovernor { revert("unsupported function"); } /** * @notice is not supported for this strategy as the asset and * ERC-4626 Tokenized Vault are set at deploy time. * @dev If the ERC-4626 Tokenized Vault needed to be changed, a new * contract would need to be deployed and the proxy updated. */ function removePToken(uint256) external override onlyGovernor { 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/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// 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/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; /** * @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: MIT pragma solidity ^0.8.0; import { VaultStorage } from "../vault/VaultStorage.sol"; interface IVault { event AssetSupported(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 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 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); // Governable.sol function transferGovernance(address _newGovernor) external; function claimGovernance() external; function governor() external view returns (address); // VaultAdmin.sol function setPriceProvider(address _priceProvider) external; function priceProvider() external view returns (address); function setRedeemFeeBps(uint256 _redeemFeeBps) external; function redeemFeeBps() external view returns (uint256); function setVaultBuffer(uint256 _vaultBuffer) external; function vaultBuffer() external view returns (uint256); function setAutoAllocateThreshold(uint256 _threshold) external; function autoAllocateThreshold() external view returns (uint256); function setRebaseThreshold(uint256 _threshold) external; function rebaseThreshold() external view returns (uint256); function setStrategistAddr(address _address) external; function strategistAddr() external view returns (address); function setMaxSupplyDiff(uint256 _maxSupplyDiff) external; function maxSupplyDiff() external view returns (uint256); function setTrusteeAddress(address _address) external; function trusteeAddress() external view returns (address); function setTrusteeFeeBps(uint256 _basis) external; function trusteeFeeBps() external view returns (uint256); function ousdMetaStrategy() external view returns (address); function setSwapper(address _swapperAddr) external; function setSwapAllowedUndervalue(uint16 _percentageBps) external; function setOracleSlippage(address _asset, uint16 _allowedOracleSlippageBps) external; function supportAsset(address _asset, uint8 _supportsAsset) external; function approveStrategy(address _addr) external; function removeStrategy(address _addr) external; function setAssetDefaultStrategy(address _asset, address _strategy) external; function assetDefaultStrategies(address _asset) external view returns (address); function pauseRebase() external; function unpauseRebase() external; function rebasePaused() external view returns (bool); function pauseCapital() external; function unpauseCapital() external; function capitalPaused() external view returns (bool); function transferToken(address _asset, uint256 _amount) external; function priceUnitMint(address asset) external view returns (uint256); function priceUnitRedeem(address asset) external view returns (uint256); function withdrawAllFromStrategy(address _strategyAddr) external; function withdrawAllFromStrategies() external; function withdrawFromStrategy( address _strategyFromAddress, address[] calldata _assets, uint256[] calldata _amounts ) external; function depositToStrategy( address _strategyToAddress, address[] calldata _assets, uint256[] calldata _amounts ) external; // VaultCore.sol function mint( address _asset, uint256 _amount, uint256 _minimumOusdAmount ) external; function mintForStrategy(uint256 _amount) external; function redeem(uint256 _amount, uint256 _minimumUnitAmount) external; function burnForStrategy(uint256 _amount) external; function redeemAll(uint256 _minimumUnitAmount) external; function allocate() external; function rebase() external; function swapCollateral( address fromAsset, address toAsset, uint256 fromAssetAmount, uint256 minToAssetAmount, bytes calldata data ) external returns (uint256 toAssetAmount); function totalValue() external view returns (uint256 value); function checkBalance(address _asset) external view returns (uint256); function calculateRedeemOutputs(uint256 _amount) external view returns (uint256[] memory); function getAssetCount() external view returns (uint256); function getAssetConfig(address _asset) external view returns (VaultStorage.Asset memory config); function getAllAssets() external view returns (address[] memory); function getStrategyCount() external view returns (uint256); function swapper() external view returns (address); function allowedSwapUndervalue() external view returns (uint256); function getAllStrategies() external view returns (address[] memory); function isSupportedAsset(address _asset) external view returns (bool); function netOusdMintForStrategyThreshold() external view returns (uint256); function setOusdMetaStrategy(address _ousdMetaStrategy) external; function setNetOusdMintForStrategyThreshold(uint256 _threshold) external; function netOusdMintedForStrategy() external view returns (int256); function setDripper(address _dripper) external; function weth() external view returns (address); function cacheWETHAssetIndex() external; function wethAssetIndex() external view returns (uint256); function initialize(address, address) external; function setAdminImpl(address) external; function removeAsset(address _asset) external; // These are OETH specific functions function addWithdrawalQueueLiquidity() external; function requestWithdrawal(uint256 _amount) external returns (uint256 requestId, uint256 queued); function claimWithdrawal(uint256 requestId) external returns (uint256 amount); function claimWithdrawals(uint256[] memory requestIds) external returns (uint256[] memory amounts, uint256 totalAmount); function withdrawalQueueMetadata() external view returns (VaultStorage.WithdrawalQueueMetadata memory); function withdrawalRequests(uint256 requestId) external view returns (VaultStorage.WithdrawalRequest memory); // OETHb specific functions function addStrategyToMintWhitelist(address strategyAddr) external; function removeStrategyFromMintWhitelist(address strategyAddr) external; function isMintWhitelistedStrategy(address strategyAddr) external view returns (bool); }
// SPDX-License-Identifier: MIT 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 { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { Initializable } from "../utils/Initializable.sol"; import { InitializableERC20Detailed } from "../utils/InitializableERC20Detailed.sol"; import { StableMath } from "../utils/StableMath.sol"; import { Governable } from "../governance/Governable.sol"; /** * NOTE that this is an ERC20 token but the invariant that the sum of * balanceOf(x) for all x is not >= totalSupply(). This is a consequence of the * rebasing design. Any integrations with OUSD should be aware. */ contract OUSD is Initializable, InitializableERC20Detailed, Governable { using SafeMath for uint256; using StableMath for uint256; event TotalSupplyUpdatedHighres( uint256 totalSupply, uint256 rebasingCredits, uint256 rebasingCreditsPerToken ); event AccountRebasingEnabled(address account); event AccountRebasingDisabled(address account); enum RebaseOptions { NotSet, OptOut, OptIn } uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1 uint256 public _totalSupply; mapping(address => mapping(address => uint256)) private _allowances; address public vaultAddress = address(0); mapping(address => uint256) private _creditBalances; uint256 private _rebasingCredits; uint256 private _rebasingCreditsPerToken; // Frozen address/credits are non rebasing (value is held in contracts which // do not receive yield unless they explicitly opt in) uint256 public nonRebasingSupply; mapping(address => uint256) public nonRebasingCreditsPerToken; mapping(address => RebaseOptions) public rebaseState; mapping(address => uint256) public isUpgraded; uint256 private constant RESOLUTION_INCREASE = 1e9; function initialize( string calldata _nameArg, string calldata _symbolArg, address _vaultAddress, uint256 _initialCreditsPerToken ) external onlyGovernor initializer { InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18); _rebasingCreditsPerToken = _initialCreditsPerToken; vaultAddress = _vaultAddress; } /** * @dev Verifies that the caller is the Vault contract */ modifier onlyVault() { require(vaultAddress == msg.sender, "Caller is not the Vault"); _; } /** * @return The total supply of OUSD. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @return Low resolution rebasingCreditsPerToken */ function rebasingCreditsPerToken() public view returns (uint256) { return _rebasingCreditsPerToken / RESOLUTION_INCREASE; } /** * @return Low resolution total number of rebasing credits */ function rebasingCredits() public view returns (uint256) { return _rebasingCredits / RESOLUTION_INCREASE; } /** * @return High resolution rebasingCreditsPerToken */ function rebasingCreditsPerTokenHighres() public view returns (uint256) { return _rebasingCreditsPerToken; } /** * @return High resolution total number of rebasing credits */ function rebasingCreditsHighres() public view returns (uint256) { return _rebasingCredits; } /** * @dev 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 override returns (uint256) { if (_creditBalances[_account] == 0) return 0; return _creditBalances[_account].divPrecisely(_creditsPerToken(_account)); } /** * @dev 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) public 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 ); } } /** * @dev 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) public view returns ( uint256, uint256, bool ) { return ( _creditBalances[_account], _creditsPerToken(_account), isUpgraded[_account] == 1 ); } /** * @dev 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) public override returns (bool) { require(_to != address(0), "Transfer to zero address"); require( _value <= balanceOf(msg.sender), "Transfer greater than balance" ); _executeTransfer(msg.sender, _to, _value); emit Transfer(msg.sender, _to, _value); return true; } /** * @dev 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. */ function transferFrom( address _from, address _to, uint256 _value ) public override returns (bool) { require(_to != address(0), "Transfer to zero address"); require(_value <= balanceOf(_from), "Transfer greater than balance"); _allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub( _value ); _executeTransfer(_from, _to, _value); emit Transfer(_from, _to, _value); return true; } /** * @dev Update the count of non rebasing credits in response to a transfer * @param _from The address you want to send tokens from. * @param _to The address you want to transfer to. * @param _value Amount of OUSD to transfer */ function _executeTransfer( address _from, address _to, uint256 _value ) internal { bool isNonRebasingTo = _isNonRebasingAccount(_to); bool isNonRebasingFrom = _isNonRebasingAccount(_from); // Credits deducted and credited might be different due to the // differing creditsPerToken used by each account uint256 creditsCredited = _value.mulTruncate(_creditsPerToken(_to)); uint256 creditsDeducted = _value.mulTruncate(_creditsPerToken(_from)); _creditBalances[_from] = _creditBalances[_from].sub( creditsDeducted, "Transfer amount exceeds balance" ); _creditBalances[_to] = _creditBalances[_to].add(creditsCredited); if (isNonRebasingTo && !isNonRebasingFrom) { // Transfer to non-rebasing account from rebasing account, credits // are removed from the non rebasing tally nonRebasingSupply = nonRebasingSupply.add(_value); // Update rebasingCredits by subtracting the deducted amount _rebasingCredits = _rebasingCredits.sub(creditsDeducted); } else if (!isNonRebasingTo && isNonRebasingFrom) { // Transfer to rebasing account from non-rebasing account // Decreasing non-rebasing credits by the amount that was sent nonRebasingSupply = nonRebasingSupply.sub(_value); // Update rebasingCredits by adding the credited amount _rebasingCredits = _rebasingCredits.add(creditsCredited); } } /** * @dev 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) public view override returns (uint256) { return _allowances[_owner][_spender]; } /** * @dev Approve the passed address to spend the specified amount of tokens * on behalf of msg.sender. This method is included for ERC20 * compatibility. `increaseAllowance` and `decreaseAllowance` should be * used instead. * * Changing an allowance with this method brings the risk that someone * may transfer both the old and the new allowance - if they are both * greater than zero - if a transfer transaction is mined before the * later approve() call is mined. * @param _spender The address which will spend the funds. * @param _value The amount of tokens to be spent. */ function approve(address _spender, uint256 _value) public override returns (bool) { _allowances[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } /** * @dev Increase the amount of tokens that an owner has allowed to * `_spender`. * This method should be used instead of approve() to avoid the double * approval vulnerability described above. * @param _spender The address which will spend the funds. * @param _addedValue The amount of tokens to increase the allowance by. */ function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) { _allowances[msg.sender][_spender] = _allowances[msg.sender][_spender] .add(_addedValue); emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]); return true; } /** * @dev Decrease the amount of tokens that an owner has allowed to `_spender`. * @param _spender The address which will spend the funds. * @param _subtractedValue The amount of tokens to decrease the allowance * by. */ function decreaseAllowance(address _spender, uint256 _subtractedValue) public returns (bool) { uint256 oldValue = _allowances[msg.sender][_spender]; if (_subtractedValue >= oldValue) { _allowances[msg.sender][_spender] = 0; } else { _allowances[msg.sender][_spender] = oldValue.sub(_subtractedValue); } emit Approval(msg.sender, _spender, _allowances[msg.sender][_spender]); return true; } /** * @dev Mints new tokens, increasing totalSupply. */ function mint(address _account, uint256 _amount) external onlyVault { _mint(_account, _amount); } /** * @dev Creates `_amount` tokens and assigns them to `_account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address _account, uint256 _amount) internal nonReentrant { require(_account != address(0), "Mint to the zero address"); bool isNonRebasingAccount = _isNonRebasingAccount(_account); uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account)); _creditBalances[_account] = _creditBalances[_account].add(creditAmount); // If the account is non rebasing and doesn't have a set creditsPerToken // then set it i.e. this is a mint from a fresh contract if (isNonRebasingAccount) { nonRebasingSupply = nonRebasingSupply.add(_amount); } else { _rebasingCredits = _rebasingCredits.add(creditAmount); } _totalSupply = _totalSupply.add(_amount); require(_totalSupply < MAX_SUPPLY, "Max supply"); emit Transfer(address(0), _account, _amount); } /** * @dev Burns tokens, decreasing totalSupply. */ function burn(address account, uint256 amount) external onlyVault { _burn(account, amount); } /** * @dev Destroys `_amount` tokens from `_account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `_account` cannot be the zero address. * - `_account` must have at least `_amount` tokens. */ function _burn(address _account, uint256 _amount) internal nonReentrant { require(_account != address(0), "Burn from the zero address"); if (_amount == 0) { return; } bool isNonRebasingAccount = _isNonRebasingAccount(_account); uint256 creditAmount = _amount.mulTruncate(_creditsPerToken(_account)); uint256 currentCredits = _creditBalances[_account]; // Remove the credits, burning rounding errors if ( currentCredits == creditAmount || currentCredits - 1 == creditAmount ) { // Handle dust from rounding _creditBalances[_account] = 0; } else if (currentCredits > creditAmount) { _creditBalances[_account] = _creditBalances[_account].sub( creditAmount ); } else { revert("Remove exceeds balance"); } // Remove from the credit tallies and non-rebasing supply if (isNonRebasingAccount) { nonRebasingSupply = nonRebasingSupply.sub(_amount); } else { _rebasingCredits = _rebasingCredits.sub(creditAmount); } _totalSupply = _totalSupply.sub(_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) { if (nonRebasingCreditsPerToken[_account] != 0) { return nonRebasingCreditsPerToken[_account]; } else { return _rebasingCreditsPerToken; } } /** * @dev Is an account using rebasing accounting or non-rebasing accounting? * Also, ensure contracts are non-rebasing if they have not opted in. * @param _account Address of the account. */ function _isNonRebasingAccount(address _account) internal returns (bool) { bool isContract = Address.isContract(_account); if (isContract && rebaseState[_account] == RebaseOptions.NotSet) { _ensureRebasingMigration(_account); } return nonRebasingCreditsPerToken[_account] > 0; } /** * @dev Ensures internal account for rebasing and non-rebasing credits and * supply is updated following deployment of frozen yield change. */ function _ensureRebasingMigration(address _account) internal { if (nonRebasingCreditsPerToken[_account] == 0) { emit AccountRebasingDisabled(_account); if (_creditBalances[_account] == 0) { // Since there is no existing balance, we can directly set to // high resolution, and do not have to do any other bookkeeping nonRebasingCreditsPerToken[_account] = 1e27; } else { // Migrate an existing account: // Set fixed credits per token for this account nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken; // Update non rebasing supply nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account)); // Update credit tallies _rebasingCredits = _rebasingCredits.sub( _creditBalances[_account] ); } } } /** * @notice Enable rebasing for an account. * @dev Add a contract address to the non-rebasing exception list. The * address's balance will be part of rebases and the account will be exposed * to upside and downside. * @param _account Address of the account. */ function governanceRebaseOptIn(address _account) public nonReentrant onlyGovernor { _rebaseOptIn(_account); } /** * @dev Add a contract address to the non-rebasing exception list. The * address's balance will be part of rebases and the account will be exposed * to upside and downside. */ function rebaseOptIn() public nonReentrant { _rebaseOptIn(msg.sender); } function _rebaseOptIn(address _account) internal { require(_isNonRebasingAccount(_account), "Account has not opted out"); // Convert balance into the same amount at the current exchange rate uint256 newCreditBalance = _creditBalances[_account] .mul(_rebasingCreditsPerToken) .div(_creditsPerToken(_account)); // Decreasing non rebasing supply nonRebasingSupply = nonRebasingSupply.sub(balanceOf(_account)); _creditBalances[_account] = newCreditBalance; // Increase rebasing credits, totalSupply remains unchanged so no // adjustment necessary _rebasingCredits = _rebasingCredits.add(_creditBalances[_account]); rebaseState[_account] = RebaseOptions.OptIn; // Delete any fixed credits per token delete nonRebasingCreditsPerToken[_account]; emit AccountRebasingEnabled(_account); } /** * @dev Explicitly mark that an address is non-rebasing. */ function rebaseOptOut() public nonReentrant { require(!_isNonRebasingAccount(msg.sender), "Account has not opted in"); // Increase non rebasing supply nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender)); // Set fixed credits per token nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken; // Decrease rebasing credits, total supply remains unchanged so no // adjustment necessary _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]); // Mark explicitly opted out of rebasing rebaseState[msg.sender] = RebaseOptions.OptOut; emit AccountRebasingDisabled(msg.sender); } /** * @dev Modify the supply without minting new tokens. This uses a change in * the exchange rate between "credits" and OUSD tokens to change balances. * @param _newTotalSupply New total supply of OUSD. */ function changeSupply(uint256 _newTotalSupply) external onlyVault nonReentrant { require(_totalSupply > 0, "Cannot increase 0 supply"); if (_totalSupply == _newTotalSupply) { emit TotalSupplyUpdatedHighres( _totalSupply, _rebasingCredits, _rebasingCreditsPerToken ); return; } _totalSupply = _newTotalSupply > MAX_SUPPLY ? MAX_SUPPLY : _newTotalSupply; _rebasingCreditsPerToken = _rebasingCredits.divPrecisely( _totalSupply.sub(nonRebasingSupply) ); require(_rebasingCreditsPerToken > 0, "Invalid change in supply"); _totalSupply = _rebasingCredits .divPrecisely(_rebasingCreditsPerToken) .add(nonRebasingSupply); emit TotalSupplyUpdatedHighres( _totalSupply, _rebasingCredits, _rebasingCreditsPerToken ); } }
// 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; /** * @title Base contract for vault strategies. * @author Origin Protocol Inc */ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Initializable } from "../utils/Initializable.sol"; import { Governable } from "../governance/Governable.sol"; import { IVault } from "../interfaces/IVault.sol"; abstract contract InitializableAbstractStrategy is Initializable, Governable { using SafeERC20 for IERC20; event PTokenAdded(address indexed _asset, address _pToken); event PTokenRemoved(address indexed _asset, address _pToken); event Deposit(address indexed _asset, address _pToken, uint256 _amount); event Withdrawal(address indexed _asset, address _pToken, uint256 _amount); event RewardTokenCollected( address recipient, address rewardToken, uint256 amount ); event RewardTokenAddressesUpdated( address[] _oldAddresses, address[] _newAddresses ); event HarvesterAddressesUpdated( address _oldHarvesterAddress, address _newHarvesterAddress ); /// @notice Address of the underlying platform address public immutable platformAddress; /// @notice Address of the OToken vault address public immutable vaultAddress; /// @dev Replaced with an immutable variable // slither-disable-next-line constable-states address private _deprecated_platformAddress; /// @dev Replaced with an immutable // slither-disable-next-line constable-states address private _deprecated_vaultAddress; /// @notice asset => pToken (Platform Specific Token Address) mapping(address => address) public assetToPToken; /// @notice Full list of all assets supported by the strategy address[] internal assetsMapped; // Deprecated: Reward token address // slither-disable-next-line constable-states address private _deprecated_rewardTokenAddress; // Deprecated: now resides in Harvester's rewardTokenConfigs // slither-disable-next-line constable-states uint256 private _deprecated_rewardLiquidationThreshold; /// @notice Address of the Harvester contract allowed to collect reward tokens address public harvesterAddress; /// @notice Address of the reward tokens. eg CRV, BAL, CVX, AURA address[] public rewardTokenAddresses; /* Reserved for future expansion. Used to be 100 storage slots * and has decreased to accommodate: * - harvesterAddress * - rewardTokenAddresses */ int256[98] private _reserved; struct BaseStrategyConfig { address platformAddress; // Address of the underlying platform address vaultAddress; // Address of the OToken's Vault } /** * @param _config The platform and OToken vault addresses */ constructor(BaseStrategyConfig memory _config) { platformAddress = _config.platformAddress; vaultAddress = _config.vaultAddress; } /** * @dev Internal initialize function, to set up initial internal state * @param _rewardTokenAddresses Address of reward token for platform * @param _assets Addresses of initial supported assets * @param _pTokens Platform Token corresponding addresses */ function _initialize( address[] memory _rewardTokenAddresses, address[] memory _assets, address[] memory _pTokens ) internal { rewardTokenAddresses = _rewardTokenAddresses; uint256 assetCount = _assets.length; require(assetCount == _pTokens.length, "Invalid input arrays"); for (uint256 i = 0; i < assetCount; ++i) { _setPTokenAddress(_assets[i], _pTokens[i]); } } /** * @notice Collect accumulated reward token and send to Vault. */ function collectRewardTokens() external virtual onlyHarvester nonReentrant { _collectRewardTokens(); } /** * @dev Default implementation that transfers reward tokens to the Harvester * Implementing strategies need to add custom logic to collect the rewards. */ function _collectRewardTokens() internal virtual { uint256 rewardTokenCount = rewardTokenAddresses.length; for (uint256 i = 0; i < rewardTokenCount; ++i) { IERC20 rewardToken = IERC20(rewardTokenAddresses[i]); uint256 balance = rewardToken.balanceOf(address(this)); if (balance > 0) { emit RewardTokenCollected( harvesterAddress, address(rewardToken), balance ); rewardToken.safeTransfer(harvesterAddress, balance); } } } /** * @dev Verifies that the caller is the Vault. */ modifier onlyVault() { require(msg.sender == vaultAddress, "Caller is not the Vault"); _; } /** * @dev Verifies that the caller is the Harvester. */ modifier onlyHarvester() { require(msg.sender == harvesterAddress, "Caller is not the Harvester"); _; } /** * @dev Verifies that the caller is the Vault or Governor. */ modifier onlyVaultOrGovernor() { require( msg.sender == vaultAddress || msg.sender == governor(), "Caller is not the Vault or Governor" ); _; } /** * @dev Verifies that the caller is the Vault, Governor, or Strategist. */ modifier onlyVaultOrGovernorOrStrategist() { require( msg.sender == vaultAddress || msg.sender == governor() || msg.sender == IVault(vaultAddress).strategistAddr(), "Caller is not the Vault, Governor, or Strategist" ); _; } /** * @notice Set the reward token addresses. Any old addresses will be overwritten. * @param _rewardTokenAddresses Array of reward token addresses */ function setRewardTokenAddresses(address[] calldata _rewardTokenAddresses) external onlyGovernor { uint256 rewardTokenCount = _rewardTokenAddresses.length; for (uint256 i = 0; i < rewardTokenCount; ++i) { require( _rewardTokenAddresses[i] != address(0), "Can not set an empty address as a reward token" ); } emit RewardTokenAddressesUpdated( rewardTokenAddresses, _rewardTokenAddresses ); rewardTokenAddresses = _rewardTokenAddresses; } /** * @notice Get the reward token addresses. * @return address[] the reward token addresses. */ function getRewardTokenAddresses() external view returns (address[] memory) { return rewardTokenAddresses; } /** * @notice Provide support for asset by passing its pToken address. * This method can only be called by the system Governor * @param _asset Address for the asset * @param _pToken Address for the corresponding platform token */ function setPTokenAddress(address _asset, address _pToken) external virtual onlyGovernor { _setPTokenAddress(_asset, _pToken); } /** * @notice Remove a supported asset by passing its index. * This method can only be called by the system Governor * @param _assetIndex Index of the asset to be removed */ function removePToken(uint256 _assetIndex) external virtual onlyGovernor { require(_assetIndex < assetsMapped.length, "Invalid index"); address asset = assetsMapped[_assetIndex]; address pToken = assetToPToken[asset]; if (_assetIndex < assetsMapped.length - 1) { assetsMapped[_assetIndex] = assetsMapped[assetsMapped.length - 1]; } assetsMapped.pop(); assetToPToken[asset] = address(0); emit PTokenRemoved(asset, pToken); } /** * @notice Provide support for asset by passing its pToken address. * Add to internal mappings and execute the platform specific, * abstract method `_abstractSetPToken` * @param _asset Address for the asset * @param _pToken Address for the corresponding platform token */ function _setPTokenAddress(address _asset, address _pToken) internal { require(assetToPToken[_asset] == address(0), "pToken already set"); require( _asset != address(0) && _pToken != address(0), "Invalid addresses" ); assetToPToken[_asset] = _pToken; assetsMapped.push(_asset); emit PTokenAdded(_asset, _pToken); _abstractSetPToken(_asset, _pToken); } /** * @notice Transfer token to governor. Intended for recovering tokens stuck in * strategy contracts, i.e. mistaken sends. * @param _asset Address for the asset * @param _amount Amount of the asset to transfer */ function transferToken(address _asset, uint256 _amount) public virtual onlyGovernor { require(!supportsAsset(_asset), "Cannot transfer supported asset"); IERC20(_asset).safeTransfer(governor(), _amount); } /** * @notice Set the Harvester contract that can collect rewards. * @param _harvesterAddress Address of the harvester contract. */ function setHarvesterAddress(address _harvesterAddress) external onlyGovernor { emit HarvesterAddressesUpdated(harvesterAddress, _harvesterAddress); harvesterAddress = _harvesterAddress; } /*************************************** Abstract ****************************************/ function _abstractSetPToken(address _asset, address _pToken) internal virtual; function safeApproveAllTokens() external virtual; /** * @notice Deposit an amount of assets into the platform * @param _asset Address for the asset * @param _amount Units of asset to deposit */ function deposit(address _asset, uint256 _amount) external virtual; /** * @notice Deposit all supported assets in this strategy contract to the platform */ function depositAll() external virtual; /** * @notice Withdraw an `amount` of assets from the platform and * send to the `_recipient`. * @param _recipient Address to which the asset should be sent * @param _asset Address of the asset * @param _amount Units of asset to withdraw */ function withdraw( address _recipient, address _asset, uint256 _amount ) external virtual; /** * @notice Withdraw all supported assets from platform and * sends to the OToken's Vault. */ function withdrawAll() external virtual; /** * @notice Get the total asset value held in the platform. * This includes any interest that was generated since depositing. * @param _asset Address of the asset * @return balance Total value of the asset in the platform */ function checkBalance(address _asset) external view virtual returns (uint256 balance); /** * @notice Check if an asset is supported. * @param _asset Address of the asset * @return bool Whether asset is supported */ function supportsAsset(address _asset) public view virtual returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @dev Optional functions from the ERC20 standard. * Converted from openzeppelin/contracts/token/ERC20/ERC20Detailed.sol * @author Origin Protocol Inc */ abstract contract InitializableERC20Detailed is IERC20 { // Storage gap to skip storage from prior to OUSD reset uint256[100] private _____gap; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of * these values are immutable: they can only be set once during * construction. * @notice To avoid variable shadowing appended `Arg` after arguments name. */ function _initialize( string memory nameArg, string memory symbolArg, uint8 decimalsArg ) internal { _name = nameArg; _symbol = symbolArg; _decimals = decimalsArg; } /** * @notice Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @notice Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @notice Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } }
// 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; /** * @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); // 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; //keccak256("OUSD.vault.governor.admin.impl"); bytes32 constant adminImplPosition = 0xa2bd3d3cf188a41358c8b401076eb59066b09dec5775650c0de4c55187d17bd9; // Address of the contract responsible for post rebase syncs with AMMs address private _deprecated_rebaseHooksAddr = address(0); // 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; // For future use uint256[45] 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) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw( uint256 assets, address receiver, address owner ) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem( uint256 shares, address receiver, address owner ) external returns (uint256 assets); }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"components":[{"internalType":"address","name":"platformAddress","type":"address"},{"internalType":"address","name":"vaultAddress","type":"address"}],"internalType":"struct InitializableAbstractStrategy.BaseStrategyConfig","name":"_baseConfig","type":"tuple"},{"internalType":"address","name":"_assetToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_pToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Deposit","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":"address","name":"_oldHarvesterAddress","type":"address"},{"indexed":false,"internalType":"address","name":"_newHarvesterAddress","type":"address"}],"name":"HarvesterAddressesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_pToken","type":"address"}],"name":"PTokenAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_pToken","type":"address"}],"name":"PTokenRemoved","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":"_oldAddresses","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"_newAddresses","type":"address[]"}],"name":"RewardTokenAddressesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardTokenCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"address","name":"_pToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetToPToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"checkBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardTokenAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvesterAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isGovernor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"removePToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokenAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"safeApproveAllTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_harvesterAddress","type":"address"}],"name":"setHarvesterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"setPTokenAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_rewardTokenAddresses","type":"address[]"}],"name":"setRewardTokenAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shareToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"supportsAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101006040523480156200001257600080fd5b50604051620024de380380620024de8339810160408190526200003591620000ea565b816200004e33600080516020620024be83398151915255565b600080516020620024be833981519152546040516001600160a01b03909116906000907fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a908290a380516001600160601b0319606091821b8116608052602090920151811b821660a0529251831b811660c052911b1660e0526200017c565b80516001600160a01b0381168114620000e557600080fd5b919050565b6000808284036060811215620000ff57600080fd5b60408112156200010e57600080fd5b50604080519081016001600160401b03811182821017156200014057634e487b7160e01b600052604160045260246000fd5b6040526200014e84620000cd565b81526200015e60208501620000cd565b602082015291506200017360408401620000cd565b90509250929050565b60805160601c60a05160601c60c05160601c60e05160601c61224d620002716000396000818161020e01528181610329015281816104a50152818161071a0152818161094201528181610c58015281816110cb015281816112c9015281816113580152818161148901526118d20152600081816102b301528181610b0001528181610ca3015281816111d101526115870152600081816102350152818161054b01528181610a1601528181610baa01528181610fb7015261123e0152600081816103b70152818161077e0152818161099601528181610bd801528181611146015281816114f401526118a2015261224d6000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80638129fc1c116100de578063c2e1e3f411610097578063d9caed1211610071578063d9caed121461039f578063dbe55e56146103b2578063de5f6268146103d9578063f6ca71b0146103e157600080fd5b8063c2e1e3f414610371578063c7af335214610384578063d38bfff41461038c57600080fd5b80638129fc1c146102e8578063853828b6146102f05780639136616a146102f857806396d538bb14610306578063aa388af614610319578063ad1728cb1461036957600080fd5b806347e7ef241161014b5780635f515226116101255780635f5152261461027a57806367c7066c1461029b5780636c9fa59e146102ae5780637b2d9b2c146102d557600080fd5b806347e7ef24146102575780635a063f631461026a5780635d36b1901461027257600080fd5b80630c340a24146101935780630ed57b3a146101b85780630fc3b4c4146101cd5780631072cbea146101f65780631083f76114610209578063430bf08a14610230575b600080fd5b61019b6103f6565b6040516001600160a01b0390911681526020015b60405180910390f35b6101cb6101c6366004611e0b565b610413565b005b61019b6101db366004611df0565b6035602052600090815260409020546001600160a01b031681565b6101cb610204366004611e7a565b61047f565b61019b7f000000000000000000000000000000000000000000000000000000000000000081565b61019b7f000000000000000000000000000000000000000000000000000000000000000081565b6101cb610265366004611e7a565b610540565b6101cb6105d1565b6101cb610670565b61028d610288366004611df0565b610716565b6040519081526020016101af565b60395461019b906001600160a01b031681565b61019b7f000000000000000000000000000000000000000000000000000000000000000081565b61019b6102e3366004611f3b565b610806565b6101cb610830565b6101cb610a0b565b6101cb6101c6366004611f3b565b6101cb610314366004611ea4565b610cf8565b610359610327366004611df0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b60405190151581526020016101af565b6101cb610e1e565b6101cb61037f366004611df0565b610e4a565b610359610ed7565b6101cb61039a366004611df0565b610f08565b6101cb6103ad366004611e3e565b610fac565b61019b7f000000000000000000000000000000000000000000000000000000000000000081565b6101cb611233565b6103e9611385565b6040516101af9190611f89565b600061040e6000805160206121f88339815191525490565b905090565b61041b610ed7565b6104405760405162461bcd60e51b8152600401610437906120d6565b60405180910390fd5b60405162461bcd60e51b81526020600482015260146024820152733ab739bab83837b93a32b210333ab731ba34b7b760611b6044820152606401610437565b610487610ed7565b6104a35760405162461bcd60e51b8152600401610437906120d6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811690831614156105205760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610437565b61053c61052b6103f6565b6001600160a01b03841690836113e7565b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105885760405162461bcd60e51b81526004016104379061209f565b6000805160206121d8833981519152805460028114156105ba5760405162461bcd60e51b815260040161043790612144565b600282556105c8848461143e565b50600190555050565b6039546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610437565b6000805160206121d88339815191528054600281141561065d5760405162461bcd60e51b815260040161043790612144565b600282556106696115e3565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461070b5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610437565b6107143361170f565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146107695760405162461bcd60e51b81526004016104379061210d565b60405163ce96cb7760e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ce96cb779060240160206040518083038186803b1580156107c857600080fd5b505afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108009190611f54565b92915050565b603a818154811061081657600080fd5b6000918252602090912001546001600160a01b0316905081565b610838610ed7565b6108545760405162461bcd60e51b8152600401610437906120d6565b600054610100900460ff168061086d575060005460ff16155b6108d05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610437565b600054610100900460ff161580156108f2576000805461ffff19166101011790555b6040805160008082526001602080840182815260608501865293949293928501908036833750506040805160018082528183019092529293506000929150602080830190803683370190505090507f000000000000000000000000000000000000000000000000000000000000000082600081518110610974576109746121c1565b60200260200101906001600160a01b031690816001600160a01b0316815250507f0000000000000000000000000000000000000000000000000000000000000000816000815181106109c8576109c86121c1565b60200260200101906001600160a01b031690816001600160a01b0316815250506109f38383836117d0565b5050508015610a08576000805461ff00191690555b50565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610a5a5750610a456103f6565b6001600160a01b0316336001600160a01b0316145b610ab25760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610437565b6000805160206121d883398151915280546002811415610ae45760405162461bcd60e51b815260040161043790612144565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015610b4a57600080fd5b505afa158015610b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b829190611f54565b905060008115610cee57604051635d043b2960e11b8152600481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301523060448301527f0000000000000000000000000000000000000000000000000000000000000000169063ba08765290606401602060405180830381600087803b158015610c1c57600080fd5b505af1158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c549190611f54565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63987f000000000000000000000000000000000000000000000000000000000000000083604051610ce59291906001600160a01b03929092168252602082015260400190565b60405180910390a25b5050600182555050565b610d00610ed7565b610d1c5760405162461bcd60e51b8152600401610437906120d6565b8060005b81811015610dcf576000848483818110610d3c57610d3c6121c1565b9050602002016020810190610d519190611df0565b6001600160a01b03161415610dbf5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610437565b610dc881612198565b9050610d20565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc603a8484604051610e0493929190611fd6565b60405180910390a1610e18603a8484611d07565b50505050565b610e26610ed7565b610e425760405162461bcd60e51b8152600401610437906120d6565b61071461188b565b610e52610ed7565b610e6e5760405162461bcd60e51b8152600401610437906120d6565b603954604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a1603980546001600160a01b0319166001600160a01b0392909216919091179055565b6000610eef6000805160206121f88339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610f10610ed7565b610f2c5760405162461bcd60e51b8152600401610437906120d6565b610f54817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610f746000805160206121f88339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610ff45760405162461bcd60e51b81526004016104379061209f565b6000805160206121d8833981519152805460028114156110265760405162461bcd60e51b815260040161043790612144565b600282556000831161107a5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610437565b6001600160a01b0385166110c95760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610437565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161461111a5760405162461bcd60e51b81526004016104379061210d565b604051632d182be560e21b8152600481018490526001600160a01b0386811660248301523060448301527f0000000000000000000000000000000000000000000000000000000000000000169063b460af9490606401602060405180830381600087803b15801561118a57600080fd5b505af115801561119e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c29190611f54565b50604080516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081168252602082018690528616917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a25060019055505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461127b5760405162461bcd60e51b81526004016104379061209f565b6000805160206121d8833981519152805460028114156112ad5760405162461bcd60e51b815260040161043790612144565b600282556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b15801561131357600080fd5b505afa158015611327573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134b9190611f54565b9050801561137d5761137d7f00000000000000000000000000000000000000000000000000000000000000008261143e565b505060019055565b6060603a8054806020026020016040519081016040528092919081815260200182805480156113dd57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113bf575b5050505050905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261143990849061194e565b505050565b600081116114875760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610437565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316146114d85760405162461bcd60e51b81526004016104379061210d565b604051636e553f6560e01b8152600481018290523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636e553f6590604401602060405180830381600087803b15801561154057600080fd5b505af1158015611554573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115789190611f54565b50604080516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081168252602082018490528416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b603a5460005b8181101561053c576000603a8281548110611606576116066121c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561165457600080fd5b505afa158015611668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168c9190611f54565b905080156116fc57603954604080516001600160a01b039283168152918416602083015281018290527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a16039546116fc906001600160a01b038481169116836113e7565b50508061170890612198565b90506115e9565b6001600160a01b0381166117655760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610437565b806001600160a01b03166117856000805160206121f88339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610a08816000805160206121f883398151915255565b82516117e390603a906020860190611d6a565b5081518151811461182d5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610437565b60005b818110156118845761187484828151811061184d5761184d6121c1565b6020026020010151848381518110611867576118676121c1565b6020026020010151611a20565b61187d81612198565b9050611830565b5050505050565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401602060405180830381600087803b15801561191657600080fd5b505af115801561192a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a089190611f19565b60006119a3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b859092919063ffffffff16565b80519091501561143957808060200190518101906119c19190611f19565b6114395760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610437565b6001600160a01b038281166000908152603560205260409020541615611a7d5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610437565b6001600160a01b03821615801590611a9d57506001600160a01b03811615155b611add5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610437565b6001600160a01b03828116600081815260356020908152604080832080549587166001600160a01b031996871681179091556036805460018101825594527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a261053c8282611b9e565b6060611b948484600085611ba6565b90505b9392505050565b61053c61188b565b606082471015611c075760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610437565b843b611c555760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610437565b600080866001600160a01b03168587604051611c719190611f6d565b60006040518083038185875af1925050503d8060008114611cae576040519150601f19603f3d011682016040523d82523d6000602084013e611cb3565b606091505b5091509150611cc3828286611cce565b979650505050505050565b60608315611cdd575081611b97565b825115611ced5782518084602001fd5b8160405162461bcd60e51b8152600401610437919061206c565b828054828255906000526020600020908101928215611d5a579160200282015b82811115611d5a5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190611d27565b50611d66929150611dbf565b5090565b828054828255906000526020600020908101928215611d5a579160200282015b82811115611d5a57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190611d8a565b5b80821115611d665760008155600101611dc0565b80356001600160a01b0381168114611deb57600080fd5b919050565b600060208284031215611e0257600080fd5b611b9782611dd4565b60008060408385031215611e1e57600080fd5b611e2783611dd4565b9150611e3560208401611dd4565b90509250929050565b600080600060608486031215611e5357600080fd5b611e5c84611dd4565b9250611e6a60208501611dd4565b9150604084013590509250925092565b60008060408385031215611e8d57600080fd5b611e9683611dd4565b946020939093013593505050565b60008060208385031215611eb757600080fd5b823567ffffffffffffffff80821115611ecf57600080fd5b818501915085601f830112611ee357600080fd5b813581811115611ef257600080fd5b8660208260051b8501011115611f0757600080fd5b60209290920196919550909350505050565b600060208284031215611f2b57600080fd5b81518015158114611b9757600080fd5b600060208284031215611f4d57600080fd5b5035919050565b600060208284031215611f6657600080fd5b5051919050565b60008251611f7f81846020870161216c565b9190910192915050565b6020808252825182820181905260009190848201906040850190845b81811015611fca5783516001600160a01b031683529284019291840191600101611fa5565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156120205781546001600160a01b031684529284019260019182019101611ffb565b505050838103828501528481528590820160005b86811015612060576001600160a01b0361204d84611dd4565b1682529183019190830190600101612034565b50979650505050505050565b602081526000825180602084015261208b81604085016020870161216c565b601f01601f19169190910160400192915050565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526018908201527f556e657870656374656420617373657420616464726573730000000000000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60005b8381101561218757818101518382015260200161216f565b83811115610e185750506000910152565b60006000198214156121ba57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220ab01c759f671f6efaed4d2015a4632468fd19f1905870c673eae948d83711fa364736f6c634300080700337bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4a000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f70000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061018e5760003560e01c80638129fc1c116100de578063c2e1e3f411610097578063d9caed1211610071578063d9caed121461039f578063dbe55e56146103b2578063de5f6268146103d9578063f6ca71b0146103e157600080fd5b8063c2e1e3f414610371578063c7af335214610384578063d38bfff41461038c57600080fd5b80638129fc1c146102e8578063853828b6146102f05780639136616a146102f857806396d538bb14610306578063aa388af614610319578063ad1728cb1461036957600080fd5b806347e7ef241161014b5780635f515226116101255780635f5152261461027a57806367c7066c1461029b5780636c9fa59e146102ae5780637b2d9b2c146102d557600080fd5b806347e7ef24146102575780635a063f631461026a5780635d36b1901461027257600080fd5b80630c340a24146101935780630ed57b3a146101b85780630fc3b4c4146101cd5780631072cbea146101f65780631083f76114610209578063430bf08a14610230575b600080fd5b61019b6103f6565b6040516001600160a01b0390911681526020015b60405180910390f35b6101cb6101c6366004611e0b565b610413565b005b61019b6101db366004611df0565b6035602052600090815260409020546001600160a01b031681565b6101cb610204366004611e7a565b61047f565b61019b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b61019b7f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f7081565b6101cb610265366004611e7a565b610540565b6101cb6105d1565b6101cb610670565b61028d610288366004611df0565b610716565b6040519081526020016101af565b60395461019b906001600160a01b031681565b61019b7f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb81565b61019b6102e3366004611f3b565b610806565b6101cb610830565b6101cb610a0b565b6101cb6101c6366004611f3b565b6101cb610314366004611ea4565b610cf8565b610359610327366004611df0565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0390811691161490565b60405190151581526020016101af565b6101cb610e1e565b6101cb61037f366004611df0565b610e4a565b610359610ed7565b6101cb61039a366004611df0565b610f08565b6101cb6103ad366004611e3e565b610fac565b61019b7f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb81565b6101cb611233565b6103e9611385565b6040516101af9190611f89565b600061040e6000805160206121f88339815191525490565b905090565b61041b610ed7565b6104405760405162461bcd60e51b8152600401610437906120d6565b60405180910390fd5b60405162461bcd60e51b81526020600482015260146024820152733ab739bab83837b93a32b210333ab731ba34b7b760611b6044820152606401610437565b610487610ed7565b6104a35760405162461bcd60e51b8152600401610437906120d6565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0390811690831614156105205760405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f74207472616e7366657220737570706f72746564206173736574006044820152606401610437565b61053c61052b6103f6565b6001600160a01b03841690836113e7565b5050565b336001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f7016146105885760405162461bcd60e51b81526004016104379061209f565b6000805160206121d8833981519152805460028114156105ba5760405162461bcd60e51b815260040161043790612144565b600282556105c8848461143e565b50600190555050565b6039546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820152601b60248201527f43616c6c6572206973206e6f74207468652048617276657374657200000000006044820152606401610437565b6000805160206121d88339815191528054600281141561065d5760405162461bcd60e51b815260040161043790612144565b600282556106696115e3565b5060019055565b7f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db546001600160a01b0316336001600160a01b03161461070b5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79207468652070656e64696e6720476f7665726e6f722063616e20636f60448201526f6d706c6574652074686520636c61696d60801b6064820152608401610437565b6107143361170f565b565b60007f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316826001600160a01b0316146107695760405162461bcd60e51b81526004016104379061210d565b60405163ce96cb7760e01b81523060048201527f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb6001600160a01b03169063ce96cb779060240160206040518083038186803b1580156107c857600080fd5b505afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108009190611f54565b92915050565b603a818154811061081657600080fd5b6000918252602090912001546001600160a01b0316905081565b610838610ed7565b6108545760405162461bcd60e51b8152600401610437906120d6565b600054610100900460ff168061086d575060005460ff16155b6108d05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610437565b600054610100900460ff161580156108f2576000805461ffff19166101011790555b6040805160008082526001602080840182815260608501865293949293928501908036833750506040805160018082528183019092529293506000929150602080830190803683370190505090507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4882600081518110610974576109746121c1565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb816000815181106109c8576109c86121c1565b60200260200101906001600160a01b031690816001600160a01b0316815250506109f38383836117d0565b5050508015610a08576000805461ff00191690555b50565b336001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f70161480610a5a5750610a456103f6565b6001600160a01b0316336001600160a01b0316145b610ab25760405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865205661756c74206f7220476f7665726044820152623737b960e91b6064820152608401610437565b6000805160206121d883398151915280546002811415610ae45760405162461bcd60e51b815260040161043790612144565b600282556040516370a0823160e01b81523060048201526000907f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb6001600160a01b0316906370a082319060240160206040518083038186803b158015610b4a57600080fd5b505afa158015610b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b829190611f54565b905060008115610cee57604051635d043b2960e11b8152600481018390526001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f70811660248301523060448301527f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb169063ba08765290606401602060405180830381600087803b158015610c1c57600080fd5b505af1158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c549190611f54565b90507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b03167f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63987f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb83604051610ce59291906001600160a01b03929092168252602082015260400190565b60405180910390a25b5050600182555050565b610d00610ed7565b610d1c5760405162461bcd60e51b8152600401610437906120d6565b8060005b81811015610dcf576000848483818110610d3c57610d3c6121c1565b9050602002016020810190610d519190611df0565b6001600160a01b03161415610dbf5760405162461bcd60e51b815260206004820152602e60248201527f43616e206e6f742073657420616e20656d70747920616464726573732061732060448201526d30903932bbb0b932103a37b5b2b760911b6064820152608401610437565b610dc881612198565b9050610d20565b507f04c0b9649497d316554306e53678d5f5f5dbc3a06f97dec13ff4cfe98b986bbc603a8484604051610e0493929190611fd6565b60405180910390a1610e18603a8484611d07565b50505050565b610e26610ed7565b610e425760405162461bcd60e51b8152600401610437906120d6565b61071461188b565b610e52610ed7565b610e6e5760405162461bcd60e51b8152600401610437906120d6565b603954604080516001600160a01b03928316815291831660208301527fe48386b84419f4d36e0f96c10cc3510b6fb1a33795620c5098b22472bbe90796910160405180910390a1603980546001600160a01b0319166001600160a01b0392909216919091179055565b6000610eef6000805160206121f88339815191525490565b6001600160a01b0316336001600160a01b031614905090565b610f10610ed7565b610f2c5760405162461bcd60e51b8152600401610437906120d6565b610f54817f44c4d30b2eaad5130ad70c3ba6972730566f3e6359ab83e800d905c61b1c51db55565b806001600160a01b0316610f746000805160206121f88339815191525490565b6001600160a01b03167fa39cc5eb22d0f34d8beaefee8a3f17cc229c1a1d1ef87a5ad47313487b1c4f0d60405160405180910390a350565b336001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f701614610ff45760405162461bcd60e51b81526004016104379061209f565b6000805160206121d8833981519152805460028114156110265760405162461bcd60e51b815260040161043790612144565b600282556000831161107a5760405162461bcd60e51b815260206004820152601760248201527f4d75737420776974686472617720736f6d657468696e670000000000000000006044820152606401610437565b6001600160a01b0385166110c95760405162461bcd60e51b8152602060048201526016602482015275135d5cdd081cdc1958da599e481c9958da5c1a595b9d60521b6044820152606401610437565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316846001600160a01b03161461111a5760405162461bcd60e51b81526004016104379061210d565b604051632d182be560e21b8152600481018490526001600160a01b0386811660248301523060448301527f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb169063b460af9490606401602060405180830381600087803b15801561118a57600080fd5b505af115801561119e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c29190611f54565b50604080516001600160a01b037f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb81168252602082018690528616917f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398910160405180910390a25060019055505050565b336001600160a01b037f000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f70161461127b5760405162461bcd60e51b81526004016104379061209f565b6000805160206121d8833981519152805460028114156112ad5760405162461bcd60e51b815260040161043790612144565b600282556040516370a0823160e01b81523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a082319060240160206040518083038186803b15801561131357600080fd5b505afa158015611327573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061134b9190611f54565b9050801561137d5761137d7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488261143e565b505060019055565b6060603a8054806020026020016040519081016040528092919081815260200182805480156113dd57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113bf575b5050505050905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261143990849061194e565b505050565b600081116114875760405162461bcd60e51b81526020600482015260166024820152754d757374206465706f73697420736f6d657468696e6760501b6044820152606401610437565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316826001600160a01b0316146114d85760405162461bcd60e51b81526004016104379061210d565b604051636e553f6560e01b8152600481018290523060248201527f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb6001600160a01b031690636e553f6590604401602060405180830381600087803b15801561154057600080fd5b505af1158015611554573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115789190611f54565b50604080516001600160a01b037f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb81168252602082018490528416917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62910160405180910390a25050565b603a5460005b8181101561053c576000603a8281548110611606576116066121c1565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b15801561165457600080fd5b505afa158015611668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168c9190611f54565b905080156116fc57603954604080516001600160a01b039283168152918416602083015281018290527ff6c07a063ed4e63808eb8da7112d46dbcd38de2b40a73dbcc9353c5a94c723539060600160405180910390a16039546116fc906001600160a01b038481169116836113e7565b50508061170890612198565b90506115e9565b6001600160a01b0381166117655760405162461bcd60e51b815260206004820152601a60248201527f4e657720476f7665726e6f7220697320616464726573732830290000000000006044820152606401610437565b806001600160a01b03166117856000805160206121f88339815191525490565b6001600160a01b03167fc7c0c772add429241571afb3805861fb3cfa2af374534088b76cdb4325a87e9a60405160405180910390a3610a08816000805160206121f883398151915255565b82516117e390603a906020860190611d6a565b5081518151811461182d5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420696e7075742061727261797360601b6044820152606401610437565b60005b818110156118845761187484828151811061184d5761184d6121c1565b6020026020010151848381518110611867576118676121c1565b6020026020010151611a20565b61187d81612198565b9050611830565b5050505050565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb8116600483015260001960248301527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48169063095ea7b390604401602060405180830381600087803b15801561191657600080fd5b505af115801561192a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a089190611f19565b60006119a3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b859092919063ffffffff16565b80519091501561143957808060200190518101906119c19190611f19565b6114395760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610437565b6001600160a01b038281166000908152603560205260409020541615611a7d5760405162461bcd60e51b81526020600482015260126024820152711c151bdad95b88185b1c9958591e481cd95d60721b6044820152606401610437565b6001600160a01b03821615801590611a9d57506001600160a01b03811615155b611add5760405162461bcd60e51b8152602060048201526011602482015270496e76616c69642061646472657373657360781b6044820152606401610437565b6001600160a01b03828116600081815260356020908152604080832080549587166001600160a01b031996871681179091556036805460018101825594527f4a11f94e20a93c79f6ec743a1954ec4fc2c08429ae2122118bf234b2185c81b890930180549095168417909455925190815290917fef6485b84315f9b1483beffa32aae9a0596890395e3d7521f1c5fbb51790e765910160405180910390a261053c8282611b9e565b6060611b948484600085611ba6565b90505b9392505050565b61053c61188b565b606082471015611c075760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610437565b843b611c555760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610437565b600080866001600160a01b03168587604051611c719190611f6d565b60006040518083038185875af1925050503d8060008114611cae576040519150601f19603f3d011682016040523d82523d6000602084013e611cb3565b606091505b5091509150611cc3828286611cce565b979650505050505050565b60608315611cdd575081611b97565b825115611ced5782518084602001fd5b8160405162461bcd60e51b8152600401610437919061206c565b828054828255906000526020600020908101928215611d5a579160200282015b82811115611d5a5781546001600160a01b0319166001600160a01b03843516178255602090920191600190910190611d27565b50611d66929150611dbf565b5090565b828054828255906000526020600020908101928215611d5a579160200282015b82811115611d5a57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190611d8a565b5b80821115611d665760008155600101611dc0565b80356001600160a01b0381168114611deb57600080fd5b919050565b600060208284031215611e0257600080fd5b611b9782611dd4565b60008060408385031215611e1e57600080fd5b611e2783611dd4565b9150611e3560208401611dd4565b90509250929050565b600080600060608486031215611e5357600080fd5b611e5c84611dd4565b9250611e6a60208501611dd4565b9150604084013590509250925092565b60008060408385031215611e8d57600080fd5b611e9683611dd4565b946020939093013593505050565b60008060208385031215611eb757600080fd5b823567ffffffffffffffff80821115611ecf57600080fd5b818501915085601f830112611ee357600080fd5b813581811115611ef257600080fd5b8660208260051b8501011115611f0757600080fd5b60209290920196919550909350505050565b600060208284031215611f2b57600080fd5b81518015158114611b9757600080fd5b600060208284031215611f4d57600080fd5b5035919050565b600060208284031215611f6657600080fd5b5051919050565b60008251611f7f81846020870161216c565b9190910192915050565b6020808252825182820181905260009190848201906040850190845b81811015611fca5783516001600160a01b031683529284019291840191600101611fa5565b50909695505050505050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156120205781546001600160a01b031684529284019260019182019101611ffb565b505050838103828501528481528590820160005b86811015612060576001600160a01b0361204d84611dd4565b1682529183019190830190600101612034565b50979650505050505050565b602081526000825180602084015261208b81604085016020870161216c565b601f01601f19169190910160400192915050565b60208082526017908201527f43616c6c6572206973206e6f7420746865205661756c74000000000000000000604082015260600190565b6020808252601a908201527f43616c6c6572206973206e6f742074686520476f7665726e6f72000000000000604082015260600190565b60208082526018908201527f556e657870656374656420617373657420616464726573730000000000000000604082015260600190565b6020808252600e908201526d1499595b9d1c985b9d0818d85b1b60921b604082015260600190565b60005b8381101561218757818101518382015260200161216f565b83811115610e185750506000910152565b60006000198214156121ba57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fdfe53bf423e48ed90e97d02ab0ebab13b2a235a6bfbe9c321847d5c175333ac45357bea13895fa79d2831e0a9e28edede30099005a50d652d8957cf8a607ee6ca4aa2646970667358221220ab01c759f671f6efaed4d2015a4632468fd19f1905870c673eae948d83711fa364736f6c63430008070033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f70000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
-----Decoded View---------------
Arg [0] : _baseConfig (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : _assetToken (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000beef01735c132ada46aa9aa4c54623caa92a64cb
Arg [1] : 000000000000000000000000e75d77b1865ae93c7eaa3040b038d7aa7bc02f70
Arg [2] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.