Source Code
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 23699344 | 6 days ago | 2.66703069 ETH | ||||
| Transfer | 23699344 | 6 days ago | 2.66703069 ETH | ||||
| Transfer | 23694644 | 6 days ago | 0.21197224 ETH | ||||
| Transfer | 23694644 | 6 days ago | 0.21197224 ETH | ||||
| Transfer | 23681633 | 8 days ago | 159.76845411 ETH | ||||
| Transfer | 23681633 | 8 days ago | 159.76845411 ETH | ||||
| Transfer | 23675276 | 9 days ago | 869.63552244 ETH | ||||
| Transfer | 23675276 | 9 days ago | 869.63552244 ETH | ||||
| Transfer | 23668397 | 10 days ago | 3.36255293 ETH | ||||
| Transfer | 23668397 | 10 days ago | 3.36255293 ETH | ||||
| Transfer | 23663977 | 11 days ago | 102.76175817 ETH | ||||
| Transfer | 23663977 | 11 days ago | 102.76175817 ETH | ||||
| Transfer | 23661724 | 11 days ago | 0.30858831 ETH | ||||
| Transfer | 23661724 | 11 days ago | 0.30858831 ETH | ||||
| Transfer | 23641041 | 14 days ago | 5.13851426 ETH | ||||
| Transfer | 23641041 | 14 days ago | 5.13851426 ETH | ||||
| Transfer | 23631373 | 15 days ago | 1,436.08758007 ETH | ||||
| Transfer | 23631373 | 15 days ago | 1,436.08758007 ETH | ||||
| Transfer | 23619481 | 17 days ago | 99.18852981 ETH | ||||
| Transfer | 23619481 | 17 days ago | 99.18852981 ETH | ||||
| Transfer | 23616222 | 17 days ago | 12.72594746 ETH | ||||
| Transfer | 23616222 | 17 days ago | 12.72594746 ETH | ||||
| Transfer | 23570400 | 24 days ago | 1.32272189 ETH | ||||
| Transfer | 23570400 | 24 days ago | 1.32272189 ETH | ||||
| Transfer | 23570141 | 24 days ago | 442.31123877 ETH |
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
EthOsTokenVaultEscrow
Compiler Version
v0.8.22+commit.4fc1097e
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
import {Address} from '@openzeppelin/contracts/utils/Address.sol';
import {ReentrancyGuard} from '@openzeppelin/contracts/utils/ReentrancyGuard.sol';
import {Errors} from '../libraries/Errors.sol';
import {OsTokenVaultEscrow} from './OsTokenVaultEscrow.sol';
/**
* @title EthOsTokenVaultEscrow
* @author StakeWise
* @notice Used for initiating assets exits from the vault without burning osToken on Ethereum
*/
contract EthOsTokenVaultEscrow is ReentrancyGuard, OsTokenVaultEscrow {
/**
* @notice Event emitted on assets received by the escrow
* @param sender The address of the sender
* @param value The amount of assets received
*/
event AssetsReceived(address indexed sender, uint256 value);
/**
* @dev Constructor
* @param osTokenVaultController The address of the OsTokenVaultController contract
* @param osTokenConfig The address of the OsTokenConfig contract
* @param initialOwner The address of the contract owner
* @param _authenticator The address of the OsTokenVaultEscrowAuth contract
* @param _liqThresholdPercent The liquidation threshold percent
* @param _liqBonusPercent The liquidation bonus percent
*/
constructor(
address osTokenVaultController,
address osTokenConfig,
address initialOwner,
address _authenticator,
uint64 _liqThresholdPercent,
uint256 _liqBonusPercent
)
ReentrancyGuard()
OsTokenVaultEscrow(
osTokenVaultController,
osTokenConfig,
initialOwner,
_authenticator,
_liqThresholdPercent,
_liqBonusPercent
)
{}
/**
* @dev Function for receiving assets from the vault
*/
receive() external payable {
emit AssetsReceived(msg.sender, msg.value);
}
/// @inheritdoc OsTokenVaultEscrow
function _transferAssets(address receiver, uint256 assets) internal override nonReentrant {
return Address.sendValue(payable(receiver), assets);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
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 subtraction of two unsigned integers, with an overflow flag.
*/
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.
*/
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.
*/
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.
*/
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 largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.22;
import '../interfaces/IMulticall.sol';
/**
* @title Multicall
* @author Uniswap
* @notice Adopted from https://github.com/Uniswap/v3-periphery/blob/1d69caf0d6c8cfeae9acd1f34ead30018d6e6400/contracts/base/Multicall.sol
* @notice Enables calling multiple methods in a single call to the contract
*/
abstract contract Multicall is IMulticall {
/// @inheritdoc IMulticall
function multicall(bytes[] calldata data) external override returns (bytes[] memory results) {
uint256 dataLength = data.length;
results = new bytes[](dataLength);
for (uint256 i = 0; i < dataLength; i++) {
(bool success, bytes memory result) = address(this).delegatecall(data[i]);
if (!success) {
// Next 5 lines from https://ethereum.stackexchange.com/a/83577
if (result.length < 68) revert();
assembly {
result := add(result, 0x04)
}
revert(abi.decode(result, (string)));
}
results[i] = result;
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
import {IERC5267} from '@openzeppelin/contracts/interfaces/IERC5267.sol';
/**
* @title IKeeperOracles
* @author StakeWise
* @notice Defines the interface for the KeeperOracles contract
*/
interface IKeeperOracles is IERC5267 {
/**
* @notice Event emitted on the oracle addition
* @param oracle The address of the added oracle
*/
event OracleAdded(address indexed oracle);
/**
* @notice Event emitted on the oracle removal
* @param oracle The address of the removed oracle
*/
event OracleRemoved(address indexed oracle);
/**
* @notice Event emitted on oracles config update
* @param configIpfsHash The IPFS hash of the new config
*/
event ConfigUpdated(string configIpfsHash);
/**
* @notice Function for verifying whether oracle is registered or not
* @param oracle The address of the oracle to check
* @return `true` for the registered oracle, `false` otherwise
*/
function isOracle(address oracle) external view returns (bool);
/**
* @notice Total Oracles
* @return The total number of oracles registered
*/
function totalOracles() external view returns (uint256);
/**
* @notice Function for adding oracle to the set
* @param oracle The address of the oracle to add
*/
function addOracle(address oracle) external;
/**
* @notice Function for removing oracle from the set
* @param oracle The address of the oracle to remove
*/
function removeOracle(address oracle) external;
/**
* @notice Function for updating the config IPFS hash
* @param configIpfsHash The new config IPFS hash
*/
function updateConfig(string calldata configIpfsHash) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
import {IKeeperOracles} from './IKeeperOracles.sol';
/**
* @title IKeeperRewards
* @author StakeWise
* @notice Defines the interface for the Keeper contract rewards
*/
interface IKeeperRewards is IKeeperOracles {
/**
* @notice Event emitted on rewards update
* @param caller The address of the function caller
* @param rewardsRoot The new rewards merkle tree root
* @param avgRewardPerSecond The new average reward per second
* @param updateTimestamp The update timestamp used for rewards calculation
* @param nonce The nonce used for verifying signatures
* @param rewardsIpfsHash The new rewards IPFS hash
*/
event RewardsUpdated(
address indexed caller,
bytes32 indexed rewardsRoot,
uint256 avgRewardPerSecond,
uint64 updateTimestamp,
uint64 nonce,
string rewardsIpfsHash
);
/**
* @notice Event emitted on Vault harvest
* @param vault The address of the Vault
* @param rewardsRoot The rewards merkle tree root
* @param totalAssetsDelta The Vault total assets delta since last sync. Can be negative in case of penalty/slashing.
* @param unlockedMevDelta The Vault execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults.
*/
event Harvested(
address indexed vault,
bytes32 indexed rewardsRoot,
int256 totalAssetsDelta,
uint256 unlockedMevDelta
);
/**
* @notice Event emitted on rewards min oracles number update
* @param oracles The new minimum number of oracles required to update rewards
*/
event RewardsMinOraclesUpdated(uint256 oracles);
/**
* @notice A struct containing the last synced Vault's cumulative reward
* @param assets The Vault cumulative reward earned since the start. Can be negative in case of penalty/slashing.
* @param nonce The nonce of the last sync
*/
struct Reward {
int192 assets;
uint64 nonce;
}
/**
* @notice A struct containing the last unlocked Vault's cumulative execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults.
* @param assets The shared MEV Vault's cumulative execution reward that can be withdrawn
* @param nonce The nonce of the last sync
*/
struct UnlockedMevReward {
uint192 assets;
uint64 nonce;
}
/**
* @notice A struct containing parameters for rewards update
* @param rewardsRoot The new rewards merkle root
* @param avgRewardPerSecond The new average reward per second
* @param updateTimestamp The update timestamp used for rewards calculation
* @param rewardsIpfsHash The new IPFS hash with all the Vaults' rewards for the new root
* @param signatures The concatenation of the Oracles' signatures
*/
struct RewardsUpdateParams {
bytes32 rewardsRoot;
uint256 avgRewardPerSecond;
uint64 updateTimestamp;
string rewardsIpfsHash;
bytes signatures;
}
/**
* @notice A struct containing parameters for harvesting rewards. Can only be called by Vault.
* @param rewardsRoot The rewards merkle root
* @param reward The Vault cumulative reward earned since the start. Can be negative in case of penalty/slashing.
* @param unlockedMevReward The Vault cumulative execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults.
* @param proof The proof to verify that Vault's reward is correct
*/
struct HarvestParams {
bytes32 rewardsRoot;
int160 reward;
uint160 unlockedMevReward;
bytes32[] proof;
}
/**
* @notice Previous Rewards Root
* @return The previous merkle tree root of the rewards accumulated by the Vaults
*/
function prevRewardsRoot() external view returns (bytes32);
/**
* @notice Rewards Root
* @return The latest merkle tree root of the rewards accumulated by the Vaults
*/
function rewardsRoot() external view returns (bytes32);
/**
* @notice Rewards Nonce
* @return The nonce used for updating rewards merkle tree root
*/
function rewardsNonce() external view returns (uint64);
/**
* @notice The last rewards update
* @return The timestamp of the last rewards update
*/
function lastRewardsTimestamp() external view returns (uint64);
/**
* @notice The minimum number of oracles required to update rewards
* @return The minimum number of oracles
*/
function rewardsMinOracles() external view returns (uint256);
/**
* @notice The rewards delay
* @return The delay in seconds between rewards updates
*/
function rewardsDelay() external view returns (uint256);
/**
* @notice Get last synced Vault cumulative reward
* @param vault The address of the Vault
* @return assets The last synced reward assets
* @return nonce The last synced reward nonce
*/
function rewards(address vault) external view returns (int192 assets, uint64 nonce);
/**
* @notice Get last unlocked shared MEV Vault cumulative reward
* @param vault The address of the Vault
* @return assets The last synced reward assets
* @return nonce The last synced reward nonce
*/
function unlockedMevRewards(address vault) external view returns (uint192 assets, uint64 nonce);
/**
* @notice Checks whether Vault must be harvested
* @param vault The address of the Vault
* @return `true` if the Vault requires harvesting, `false` otherwise
*/
function isHarvestRequired(address vault) external view returns (bool);
/**
* @notice Checks whether the Vault can be harvested
* @param vault The address of the Vault
* @return `true` if Vault can be harvested, `false` otherwise
*/
function canHarvest(address vault) external view returns (bool);
/**
* @notice Checks whether rewards can be updated
* @return `true` if rewards can be updated, `false` otherwise
*/
function canUpdateRewards() external view returns (bool);
/**
* @notice Checks whether the Vault has registered validators
* @param vault The address of the Vault
* @return `true` if Vault is collateralized, `false` otherwise
*/
function isCollateralized(address vault) external view returns (bool);
/**
* @notice Update rewards data
* @param params The struct containing rewards update parameters
*/
function updateRewards(RewardsUpdateParams calldata params) external;
/**
* @notice Harvest rewards. Can be called only by Vault.
* @param params The struct containing rewards harvesting parameters
* @return totalAssetsDelta The total reward/penalty accumulated by the Vault since the last sync
* @return unlockedMevDelta The Vault execution reward that can be withdrawn from shared MEV escrow. Only used by shared MEV Vaults.
* @return harvested `true` when the rewards were harvested, `false` otherwise
*/
function harvest(
HarvestParams calldata params
) external returns (int256 totalAssetsDelta, uint256 unlockedMevDelta, bool harvested);
/**
* @notice Set min number of oracles for confirming rewards update. Can only be called by the owner.
* @param _rewardsMinOracles The new min number of oracles for confirming rewards update
*/
function setRewardsMinOracles(uint256 _rewardsMinOracles) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.22;
/**
* @title Multicall
* @author Uniswap
* @notice Adopted from https://github.com/Uniswap/v3-periphery/blob/1d69caf0d6c8cfeae9acd1f34ead30018d6e6400/contracts/base/Multicall.sol
* @notice Enables calling multiple methods in a single call to the contract
*/
interface IMulticall {
/**
* @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
* @param data The encoded function data for each of the calls to make to this contract
* @return results The results from each of the calls passed in via data
*/
function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
/**
* @title IOsTokenConfig
* @author StakeWise
* @notice Defines the interface for the OsTokenConfig contract
*/
interface IOsTokenConfig {
/**
* @notice Emitted when OsToken minting and liquidating configuration values are updated
* @param vault The address of the vault to update the config for. Will be zero address if it is a default config.
* @param liqBonusPercent The new liquidation bonus percent value
* @param liqThresholdPercent The new liquidation threshold percent value
* @param ltvPercent The new loan-to-value (LTV) percent value
*/
event OsTokenConfigUpdated(
address vault,
uint128 liqBonusPercent,
uint64 liqThresholdPercent,
uint64 ltvPercent
);
/**
* @notice Emitted when the OsToken redeemer address is updated
* @param newRedeemer The address of the new redeemer
*/
event RedeemerUpdated(address newRedeemer);
/**
* @notice The OsToken minting and liquidating configuration values
* @param liqThresholdPercent The liquidation threshold percent used to calculate health factor for OsToken position
* @param liqBonusPercent The minimal bonus percent that liquidator earns on OsToken position liquidation
* @param ltvPercent The percent used to calculate how much user can mint OsToken shares
*/
struct Config {
uint128 liqBonusPercent;
uint64 liqThresholdPercent;
uint64 ltvPercent;
}
/**
* @notice The address of the OsToken redeemer
* @return The address of the redeemer
*/
function redeemer() external view returns (address);
/**
* @notice Returns the OsToken minting and liquidating configuration values for the vault
* @param vault The address of the vault to get the config for
* @return config The OsToken config for the vault
*/
function getConfig(address vault) external view returns (Config memory config);
/**
* @notice Sets the OsToken redeemer address. Can only be called by the owner.
* @param newRedeemer The address of the new redeemer
*/
function setRedeemer(address newRedeemer) external;
/**
* @notice Updates the OsToken minting and liquidating configuration values. Can only be called by the owner.
* @param vault The address of the vault. Set to zero address to update the default config.
* @param config The new OsToken configuration
*/
function updateConfig(address vault, Config memory config) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
/**
* @title IOsTokenVaultController
* @author StakeWise
* @notice Defines the interface for the OsTokenVaultController contract
*/
interface IOsTokenVaultController {
/**
* @notice Event emitted on minting shares
* @param vault The address of the Vault
* @param receiver The address that received the shares
* @param assets The number of assets collateralized
* @param shares The number of tokens the owner received
*/
event Mint(address indexed vault, address indexed receiver, uint256 assets, uint256 shares);
/**
* @notice Event emitted on burning shares
* @param vault The address of the Vault
* @param owner The address that owns the shares
* @param assets The total number of assets withdrawn
* @param shares The total number of shares burned
*/
event Burn(address indexed vault, address indexed owner, uint256 assets, uint256 shares);
/**
* @notice Event emitted on state update
* @param profitAccrued The profit accrued since the last update
* @param treasuryShares The number of shares minted for the treasury
* @param treasuryAssets The number of assets minted for the treasury
*/
event StateUpdated(uint256 profitAccrued, uint256 treasuryShares, uint256 treasuryAssets);
/**
* @notice Event emitted on capacity update
* @param capacity The amount after which the OsToken stops accepting deposits
*/
event CapacityUpdated(uint256 capacity);
/**
* @notice Event emitted on treasury address update
* @param treasury The new treasury address
*/
event TreasuryUpdated(address indexed treasury);
/**
* @notice Event emitted on fee percent update
* @param feePercent The new fee percent
*/
event FeePercentUpdated(uint16 feePercent);
/**
* @notice Event emitted on average reward per second update
* @param avgRewardPerSecond The new average reward per second
*/
event AvgRewardPerSecondUpdated(uint256 avgRewardPerSecond);
/**
* @notice Event emitted on keeper address update
* @param keeper The new keeper address
*/
event KeeperUpdated(address keeper);
/**
* @notice The OsToken capacity
* @return The amount after which the OsToken stops accepting deposits
*/
function capacity() external view returns (uint256);
/**
* @notice The DAO treasury address that receives OsToken fees
* @return The address of the treasury
*/
function treasury() external view returns (address);
/**
* @notice The fee percent (multiplied by 100)
* @return The fee percent applied by the OsToken on the rewards
*/
function feePercent() external view returns (uint64);
/**
* @notice The address that can update avgRewardPerSecond
* @return The address of the keeper contract
*/
function keeper() external view returns (address);
/**
* @notice The average reward per second used to mint OsToken rewards
* @return The average reward per second earned by the Vaults
*/
function avgRewardPerSecond() external view returns (uint256);
/**
* @notice The fee per share used for calculating the fee for every position
* @return The cumulative fee per share
*/
function cumulativeFeePerShare() external view returns (uint256);
/**
* @notice The total number of shares controlled by the OsToken
* @return The total number of shares
*/
function totalShares() external view returns (uint256);
/**
* @notice Total assets controlled by the OsToken
* @return The total amount of the underlying asset that is "managed" by OsToken
*/
function totalAssets() external view returns (uint256);
/**
* @notice Converts shares to assets
* @param assets The amount of assets to convert to shares
* @return shares The amount of shares that the OsToken would exchange for the amount of assets provided
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @notice Converts assets to shares
* @param shares The amount of shares to convert to assets
* @return assets The amount of assets that the OsToken would exchange for the amount of shares provided
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @notice Updates rewards and treasury fee checkpoint for the OsToken
*/
function updateState() external;
/**
* @notice Mint OsToken shares. Can only be called by the registered vault.
* @param receiver The address that will receive the shares
* @param shares The amount of shares to mint
* @return assets The amount of assets minted
*/
function mintShares(address receiver, uint256 shares) external returns (uint256 assets);
/**
* @notice Burn shares for withdrawn assets. Can only be called by the registered vault.
* @param owner The address that owns the shares
* @param shares The amount of shares to burn
* @return assets The amount of assets withdrawn
*/
function burnShares(address owner, uint256 shares) external returns (uint256 assets);
/**
* @notice Update treasury address. Can only be called by the owner.
* @param _treasury The new treasury address
*/
function setTreasury(address _treasury) external;
/**
* @notice Update capacity. Can only be called by the owner.
* @param _capacity The amount after which the OsToken stops accepting deposits
*/
function setCapacity(uint256 _capacity) external;
/**
* @notice Update fee percent. Can only be called by the owner. Cannot be larger than 10 000 (100%).
* @param _feePercent The new fee percent
*/
function setFeePercent(uint16 _feePercent) external;
/**
* @notice Update keeper address. Can only be called by the owner.
* @param _keeper The new keeper address
*/
function setKeeper(address _keeper) external;
/**
* @notice Updates average reward per second. Can only be called by the keeper.
* @param _avgRewardPerSecond The new average reward per second
*/
function setAvgRewardPerSecond(uint256 _avgRewardPerSecond) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
import {IMulticall} from './IMulticall.sol';
/**
* @title IOsTokenVaultEscrow
* @author StakeWise
* @notice Interface for OsTokenVaultEscrow contract
*/
interface IOsTokenVaultEscrow is IMulticall {
/**
* @notice Struct to store the escrow position details
* @param owner The address of the assets owner
* @param exitedAssets The amount of assets exited and ready to be claimed
* @param osTokenShares The amount of osToken shares
* @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee
*/
struct Position {
address owner;
uint96 exitedAssets;
uint128 osTokenShares;
uint128 cumulativeFeePerShare;
}
/**
* @notice Event emitted on position creation
* @param vault The address of the vault
* @param exitPositionTicket The exit position ticket
* @param owner The address of the assets owner
* @param osTokenShares The amount of osToken shares
* @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee
*/
event PositionCreated(
address indexed vault,
uint256 indexed exitPositionTicket,
address owner,
uint256 osTokenShares,
uint256 cumulativeFeePerShare
);
/**
* @notice Event emitted on assets exit processing
* @param vault The address of the vault
* @param caller The address of the caller
* @param exitPositionTicket The exit position ticket
* @param exitedAssets The amount of exited assets claimed
*/
event ExitedAssetsProcessed(
address indexed vault,
address indexed caller,
uint256 indexed exitPositionTicket,
uint256 exitedAssets
);
/**
* @notice Event emitted on osToken liquidation
* @param caller The address of the function caller
* @param vault The address of the vault
* @param exitPositionTicket The exit position ticket
* @param receiver The address of the receiver of the liquidated assets
* @param osTokenShares The amount of osToken shares to liquidate
* @param receivedAssets The amount of assets received
*/
event OsTokenLiquidated(
address indexed caller,
address indexed vault,
uint256 indexed exitPositionTicket,
address receiver,
uint256 osTokenShares,
uint256 receivedAssets
);
/**
* @notice Event emitted on osToken redemption
* @param caller The address of the function caller
* @param vault The address of the vault
* @param exitPositionTicket The exit position ticket
* @param receiver The address of the receiver of the redeemed assets
* @param osTokenShares The amount of osToken shares to redeem
* @param receivedAssets The amount of assets received
*/
event OsTokenRedeemed(
address indexed caller,
address indexed vault,
uint256 indexed exitPositionTicket,
address receiver,
uint256 osTokenShares,
uint256 receivedAssets
);
/**
* @notice Event emitted on exited assets claim
* @param receiver The address of the receiver of the exited assets
* @param vault The address of the vault
* @param exitPositionTicket The exit position ticket
* @param osTokenShares The amount of osToken shares burned
* @param assets The amount of assets claimed
*/
event ExitedAssetsClaimed(
address indexed receiver,
address indexed vault,
uint256 indexed exitPositionTicket,
uint256 osTokenShares,
uint256 assets
);
/**
* @notice Event emitted on liquidation configuration update
* @param liqThresholdPercent The liquidation threshold percent
* @param liqBonusPercent The liquidation bonus percent
*/
event LiqConfigUpdated(uint64 liqThresholdPercent, uint256 liqBonusPercent);
/**
* @notice Event emitted on authenticator update
* @param newAuthenticator The address of the new authenticator
*/
event AuthenticatorUpdated(address newAuthenticator);
/**
* @notice The liquidation threshold percent
* @return The liquidation threshold percent starting from which the osToken shares can be liquidated
*/
function liqThresholdPercent() external view returns (uint64);
/**
* @notice The liquidation bonus percent
* @return The liquidation bonus percent paid for liquidating the osToken shares
*/
function liqBonusPercent() external view returns (uint256);
/**
* @notice The address of the authenticator
* @return The address of the authenticator contract
*/
function authenticator() external view returns (address);
/**
* @notice Get the position details
* @param vault The address of the vault
* @param positionTicket The exit position ticket
* @return owner The address of the assets owner
* @return exitedAssets The amount of assets exited and ready to be claimed
* @return osTokenShares The amount of osToken shares
*/
function getPosition(
address vault,
uint256 positionTicket
) external view returns (address, uint256, uint256);
/**
* @notice Registers the new escrow position
* @param owner The address of the exited assets owner
* @param exitPositionTicket The exit position ticket
* @param osTokenShares The amount of osToken shares
* @param cumulativeFeePerShare The cumulative fee per share used to calculate the osToken fee
*/
function register(
address owner,
uint256 exitPositionTicket,
uint256 osTokenShares,
uint256 cumulativeFeePerShare
) external;
/**
* @notice Claims exited assets from the vault to the escrow
* @param vault The address of the vault
* @param exitPositionTicket The exit position ticket
* @param timestamp The timestamp of the exit
* @param exitQueueIndex The index of the exit in the queue
*/
function processExitedAssets(
address vault,
uint256 exitPositionTicket,
uint256 timestamp,
uint256 exitQueueIndex
) external;
/**
* @notice Claims the exited assets from the escrow to the owner. Can only be called by the position owner.
* @param vault The address of the vault
* @param exitPositionTicket The exit position ticket
* @param osTokenShares The amount of osToken shares to burn
* @return claimedAssets The amount of assets claimed
*/
function claimExitedAssets(
address vault,
uint256 exitPositionTicket,
uint256 osTokenShares
) external returns (uint256 claimedAssets);
/**
* @notice Liquidates the osToken shares
* @param vault The address of the vault
* @param exitPositionTicket The exit position ticket
* @param osTokenShares The amount of osToken shares to liquidate
* @param receiver The address of the receiver of the liquidated assets
*/
function liquidateOsToken(
address vault,
uint256 exitPositionTicket,
uint256 osTokenShares,
address receiver
) external;
/**
* @notice Redeems the osToken shares. Can only be called by the osToken redeemer.
* @param vault The address of the vault
* @param exitPositionTicket The exit position ticket
* @param osTokenShares The amount of osToken shares to redeem
* @param receiver The address of the receiver of the redeemed assets
*/
function redeemOsToken(
address vault,
uint256 exitPositionTicket,
uint256 osTokenShares,
address receiver
) external;
/**
* @notice Updates the authenticator. Can only be called by the owner.
* @param newAuthenticator The address of the new authenticator
*/
function setAuthenticator(address newAuthenticator) external;
/**
* @notice Updates the liquidation configuration. Can only be called by the owner.
* @param _liqThresholdPercent The liquidation threshold percent
* @param _liqBonusPercent The liquidation bonus percent
*/
function updateLiqConfig(uint64 _liqThresholdPercent, uint256 _liqBonusPercent) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
/**
* @title IOsTokenVaultEscrowAuth
* @author StakeWise
* @notice Interface for OsTokenVaultEscrowAuth contract
*/
interface IOsTokenVaultEscrowAuth {
/**
* @notice Check if the caller can register the exit position
* @param vault The address of the vault
* @param owner The address of the assets owner
* @param exitPositionTicket The exit position ticket
* @param osTokenShares The amount of osToken shares to burn
* @return True if the caller can register the exit position
*/
function canRegister(
address vault,
address owner,
uint256 exitPositionTicket,
uint256 osTokenShares
) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
/**
* @title IVaultState
* @author StakeWise
* @notice Defines the interface for the VaultAdmin contract
*/
interface IVaultAdmin {
/**
* @notice Event emitted on metadata ipfs hash update
* @param caller The address of the function caller
* @param metadataIpfsHash The new metadata IPFS hash
*/
event MetadataUpdated(address indexed caller, string metadataIpfsHash);
/**
* @notice The Vault admin
* @return The address of the Vault admin
*/
function admin() external view returns (address);
/**
* @notice Function for updating the metadata IPFS hash. Can only be called by Vault admin.
* @param metadataIpfsHash The new metadata IPFS hash
*/
function setMetadata(string calldata metadataIpfsHash) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
import {IVaultState} from './IVaultState.sol';
/**
* @title IVaultEnterExit
* @author StakeWise
* @notice Defines the interface for the VaultEnterExit contract
*/
interface IVaultEnterExit is IVaultState {
/**
* @notice Event emitted on deposit
* @param caller The address that called the deposit function
* @param receiver The address that received the shares
* @param assets The number of assets deposited by the caller
* @param shares The number of shares received
* @param referrer The address of the referrer
*/
event Deposited(
address indexed caller,
address indexed receiver,
uint256 assets,
uint256 shares,
address referrer
);
/**
* @notice Event emitted on redeem
* @param owner The address that owns the shares
* @param receiver The address that received withdrawn assets
* @param assets The total number of withdrawn assets
* @param shares The total number of withdrawn shares
*/
event Redeemed(address indexed owner, address indexed receiver, uint256 assets, uint256 shares);
/**
* @notice Event emitted on shares added to the exit queue
* @param owner The address that owns the shares
* @param receiver The address that will receive withdrawn assets
* @param positionTicket The exit queue ticket that was assigned to the position
* @param shares The number of shares that queued for the exit
*/
event ExitQueueEntered(
address indexed owner,
address indexed receiver,
uint256 positionTicket,
uint256 shares
);
/**
* @notice Event emitted on shares added to the V2 exit queue (deprecated)
* @param owner The address that owns the shares
* @param receiver The address that will receive withdrawn assets
* @param positionTicket The exit queue ticket that was assigned to the position
* @param shares The number of shares that queued for the exit
* @param assets The number of assets that queued for the exit
*/
event V2ExitQueueEntered(
address indexed owner,
address indexed receiver,
uint256 positionTicket,
uint256 shares,
uint256 assets
);
/**
* @notice Event emitted on claim of the exited assets
* @param receiver The address that has received withdrawn assets
* @param prevPositionTicket The exit queue ticket received after the `enterExitQueue` call
* @param newPositionTicket The new exit queue ticket in case not all the shares were withdrawn. Otherwise 0.
* @param withdrawnAssets The total number of assets withdrawn
*/
event ExitedAssetsClaimed(
address indexed receiver,
uint256 prevPositionTicket,
uint256 newPositionTicket,
uint256 withdrawnAssets
);
/**
* @notice Locks shares to the exit queue. The shares continue earning rewards until they will be burned by the Vault.
* @param shares The number of shares to lock
* @param receiver The address that will receive assets upon withdrawal
* @return positionTicket The position ticket of the exit queue. Returns uint256 max if no ticket created.
*/
function enterExitQueue(
uint256 shares,
address receiver
) external returns (uint256 positionTicket);
/**
* @notice Get the exit queue index to claim exited assets from
* @param positionTicket The exit queue position ticket to get the index for
* @return The exit queue index that should be used to claim exited assets.
* Returns -1 in case such index does not exist.
*/
function getExitQueueIndex(uint256 positionTicket) external view returns (int256);
/**
* @notice Calculates the number of shares and assets that can be claimed from the exit queue.
* @param receiver The address that will receive assets upon withdrawal
* @param positionTicket The exit queue ticket received after the `enterExitQueue` call
* @param timestamp The timestamp when the shares entered the exit queue
* @param exitQueueIndex The exit queue index at which the shares were burned. It can be looked up by calling `getExitQueueIndex`.
* @return leftTickets The number of tickets left in the queue
* @return exitedTickets The number of tickets that have already exited
* @return exitedAssets The number of assets that can be claimed
*/
function calculateExitedAssets(
address receiver,
uint256 positionTicket,
uint256 timestamp,
uint256 exitQueueIndex
) external view returns (uint256 leftTickets, uint256 exitedTickets, uint256 exitedAssets);
/**
* @notice Claims assets that were withdrawn by the Vault. It can be called only after the `enterExitQueue` call by the `receiver`.
* @param positionTicket The exit queue ticket received after the `enterExitQueue` call
* @param timestamp The timestamp when the assets entered the exit queue
* @param exitQueueIndex The exit queue index at which the shares were burned.
* It can be looked up by calling `getExitQueueIndex`.
*/
function claimExitedAssets(
uint256 positionTicket,
uint256 timestamp,
uint256 exitQueueIndex
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
import {IVaultAdmin} from './IVaultAdmin.sol';
/**
* @title IVaultFee
* @author StakeWise
* @notice Defines the interface for the VaultFee contract
*/
interface IVaultFee is IVaultAdmin {
/**
* @notice Event emitted on fee recipient update
* @param caller The address of the function caller
* @param feeRecipient The address of the new fee recipient
*/
event FeeRecipientUpdated(address indexed caller, address indexed feeRecipient);
/**
* @notice The Vault's fee recipient
* @return The address of the Vault's fee recipient
*/
function feeRecipient() external view returns (address);
/**
* @notice The Vault's fee percent in BPS
* @return The fee percent applied by the Vault on the rewards
*/
function feePercent() external view returns (uint16);
/**
* @notice Function for updating the fee recipient address. Can only be called by the admin.
* @param _feeRecipient The address of the new fee recipient
*/
function setFeeRecipient(address _feeRecipient) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
import {IKeeperRewards} from './IKeeperRewards.sol';
import {IVaultFee} from './IVaultFee.sol';
/**
* @title IVaultState
* @author StakeWise
* @notice Defines the interface for the VaultState contract
*/
interface IVaultState is IVaultFee {
/**
* @notice Event emitted on checkpoint creation
* @param shares The number of burned shares
* @param assets The amount of exited assets
*/
event CheckpointCreated(uint256 shares, uint256 assets);
/**
* @notice Event emitted on minting fee recipient shares
* @param receiver The address of the fee recipient
* @param shares The number of minted shares
* @param assets The amount of minted assets
*/
event FeeSharesMinted(address receiver, uint256 shares, uint256 assets);
/**
* @notice Event emitted when exiting assets are penalized
* @param penalty The total penalty amount
*/
event ExitingAssetsPenalized(uint256 penalty);
/**
* @notice Total assets in the Vault
* @return The total amount of the underlying asset that is "managed" by Vault
*/
function totalAssets() external view returns (uint256);
/**
* @notice Function for retrieving total shares
* @return The amount of shares in existence
*/
function totalShares() external view returns (uint256);
/**
* @notice The Vault's capacity
* @return The amount after which the Vault stops accepting deposits
*/
function capacity() external view returns (uint256);
/**
* @notice Total assets available in the Vault. They can be staked or withdrawn.
* @return The total amount of withdrawable assets
*/
function withdrawableAssets() external view returns (uint256);
/**
* @notice Queued Shares
* @return The total number of shares queued for exit
*/
function queuedShares() external view returns (uint128);
/**
* @notice Returns the number of shares held by an account
* @param account The account for which to look up the number of shares it has, i.e. its balance
* @return The number of shares held by the account
*/
function getShares(address account) external view returns (uint256);
/**
* @notice Converts assets to shares
* @param assets The amount of assets to convert to shares
* @return shares The amount of shares that the Vault would exchange for the amount of assets provided
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @notice Converts shares to assets
* @param shares The amount of shares to convert to assets
* @return assets The amount of assets that the Vault would exchange for the amount of shares provided
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @notice Check whether state update is required
* @return `true` if state update is required, `false` otherwise
*/
function isStateUpdateRequired() external view returns (bool);
/**
* @notice Updates the total amount of assets in the Vault and its exit queue
* @param harvestParams The parameters for harvesting Keeper rewards
*/
function updateState(IKeeperRewards.HarvestParams calldata harvestParams) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
/**
* @title Errors
* @author StakeWise
* @notice Contains all the custom errors
*/
library Errors {
error AccessDenied();
error InvalidShares();
error InvalidAssets();
error ZeroAddress();
error InsufficientAssets();
error CapacityExceeded();
error InvalidCapacity();
error InvalidSecurityDeposit();
error InvalidFeeRecipient();
error InvalidFeePercent();
error NotHarvested();
error NotCollateralized();
error InvalidProof();
error LowLtv();
error InvalidPosition();
error InvalidHealthFactor();
error InvalidReceivedAssets();
error InvalidTokenMeta();
error UpgradeFailed();
error InvalidValidators();
error DeadlineExpired();
error PermitInvalidSigner();
error InvalidValidatorsRegistryRoot();
error InvalidVault();
error AlreadyAdded();
error AlreadyRemoved();
error InvalidOracles();
error NotEnoughSignatures();
error InvalidOracle();
error TooEarlyUpdate();
error InvalidAvgRewardPerSecond();
error InvalidRewardsRoot();
error HarvestFailed();
error LiquidationDisabled();
error InvalidLiqThresholdPercent();
error InvalidLiqBonusPercent();
error InvalidLtvPercent();
error InvalidCheckpointIndex();
error InvalidCheckpointValue();
error MaxOraclesExceeded();
error ExitRequestNotProcessed();
error ValueNotChanged();
error InvalidWithdrawalCredentials();
error EigenPodNotFound();
error InvalidQueuedShares();
error FlashLoanFailed();
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;
import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';
import {Ownable2Step, Ownable} from '@openzeppelin/contracts/access/Ownable2Step.sol';
import {IOsTokenVaultEscrow} from '../interfaces/IOsTokenVaultEscrow.sol';
import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol';
import {IVaultEnterExit} from '../interfaces/IVaultEnterExit.sol';
import {IOsTokenConfig} from '../interfaces/IOsTokenConfig.sol';
import {IOsTokenVaultEscrowAuth} from '../interfaces/IOsTokenVaultEscrowAuth.sol';
import {Errors} from '../libraries/Errors.sol';
import {Multicall} from '../base/Multicall.sol';
/**
* @title OsTokenVaultEscrow
* @author StakeWise
* @notice Used for initiating assets exits from the vault without burning osToken
*/
abstract contract OsTokenVaultEscrow is Ownable2Step, Multicall, IOsTokenVaultEscrow {
uint256 private constant _maxPercent = 1e18;
uint256 private constant _wad = 1e18;
uint256 private constant _hfLiqThreshold = 1e18;
IOsTokenVaultController private immutable _osTokenVaultController;
IOsTokenConfig private immutable _osTokenConfig;
mapping(address vault => mapping(uint256 positionTicket => Position)) private _positions;
/// @inheritdoc IOsTokenVaultEscrow
uint256 public override liqBonusPercent;
/// @inheritdoc IOsTokenVaultEscrow
address public override authenticator;
/// @inheritdoc IOsTokenVaultEscrow
uint64 public override liqThresholdPercent;
/**
* @dev Constructor
* @param osTokenVaultController The address of the OsTokenVaultController contract
* @param osTokenConfig The address of the OsTokenConfig contract
* @param initialOwner The address of the contract owner
* @param _authenticator The address of the OsTokenVaultEscrowAuth contract
* @param _liqThresholdPercent The liquidation threshold percent
* @param _liqBonusPercent The liquidation bonus percent
*/
constructor(
address osTokenVaultController,
address osTokenConfig,
address initialOwner,
address _authenticator,
uint64 _liqThresholdPercent,
uint256 _liqBonusPercent
) Ownable(msg.sender) {
_osTokenVaultController = IOsTokenVaultController(osTokenVaultController);
_osTokenConfig = IOsTokenConfig(osTokenConfig);
updateLiqConfig(_liqThresholdPercent, _liqBonusPercent);
setAuthenticator(_authenticator);
_transferOwnership(initialOwner);
}
/// @inheritdoc IOsTokenVaultEscrow
function getPosition(
address vault,
uint256 positionTicket
) external view returns (address, uint256, uint256) {
Position memory position = _positions[vault][positionTicket];
if (position.osTokenShares != 0) {
_syncPositionFee(position);
}
return (position.owner, position.exitedAssets, position.osTokenShares);
}
/// @inheritdoc IOsTokenVaultEscrow
function register(
address owner,
uint256 exitPositionTicket,
uint256 osTokenShares,
uint256 cumulativeFeePerShare
) external override {
// check if caller has permission
if (
!IOsTokenVaultEscrowAuth(authenticator).canRegister(
msg.sender,
owner,
exitPositionTicket,
osTokenShares
)
) {
revert Errors.AccessDenied();
}
// check owner and shares are not zero
if (owner == address(0)) revert Errors.ZeroAddress();
if (osTokenShares == 0) revert Errors.InvalidShares();
// create new position
_positions[msg.sender][exitPositionTicket] = Position({
owner: owner,
exitedAssets: 0,
osTokenShares: SafeCast.toUint128(osTokenShares),
cumulativeFeePerShare: SafeCast.toUint128(cumulativeFeePerShare)
});
// emit event
emit PositionCreated(
msg.sender,
exitPositionTicket,
owner,
osTokenShares,
cumulativeFeePerShare
);
}
/// @inheritdoc IOsTokenVaultEscrow
function processExitedAssets(
address vault,
uint256 exitPositionTicket,
uint256 timestamp,
uint256 exitQueueIndex
) external override {
// get position
Position storage position = _positions[vault][exitPositionTicket];
if (position.owner == address(0)) revert Errors.InvalidPosition();
// claim exited assets
(uint256 leftTickets, , uint256 exitedAssets) = IVaultEnterExit(vault).calculateExitedAssets(
address(this),
exitPositionTicket,
timestamp,
uint256(exitQueueIndex)
);
// the exit request must be fully processed (1 ticket could be a rounding error)
if (leftTickets > 1) revert Errors.ExitRequestNotProcessed();
IVaultEnterExit(vault).claimExitedAssets(
exitPositionTicket,
timestamp,
uint256(exitQueueIndex)
);
// update position
position.exitedAssets = SafeCast.toUint96(exitedAssets);
// emit event
emit ExitedAssetsProcessed(vault, msg.sender, exitPositionTicket, exitedAssets);
}
/// @inheritdoc IOsTokenVaultEscrow
function claimExitedAssets(
address vault,
uint256 exitPositionTicket,
uint256 osTokenShares
) external override returns (uint256 claimedAssets) {
// burn osToken shares
_osTokenVaultController.burnShares(msg.sender, osTokenShares);
// fetch user position
Position memory position = _positions[vault][exitPositionTicket];
if (msg.sender != position.owner) revert Errors.AccessDenied();
// check whether position exists and there are enough osToken shares
_syncPositionFee(position);
if (position.osTokenShares == 0 || position.osTokenShares < osTokenShares) {
revert Errors.InvalidShares();
}
// calculate assets to withdraw
if (position.osTokenShares != osTokenShares) {
claimedAssets = Math.mulDiv(position.exitedAssets, osTokenShares, position.osTokenShares);
// update position osTokenShares
position.exitedAssets -= SafeCast.toUint96(claimedAssets);
position.osTokenShares -= SafeCast.toUint128(osTokenShares);
_positions[vault][exitPositionTicket] = position;
} else {
claimedAssets = position.exitedAssets;
// remove position as it is fully processed
delete _positions[vault][exitPositionTicket];
}
if (claimedAssets == 0) revert Errors.ExitRequestNotProcessed();
// transfer assets
_transferAssets(position.owner, claimedAssets);
// emit event
emit ExitedAssetsClaimed(msg.sender, vault, exitPositionTicket, osTokenShares, claimedAssets);
}
/// @inheritdoc IOsTokenVaultEscrow
function liquidateOsToken(
address vault,
uint256 exitPositionTicket,
uint256 osTokenShares,
address receiver
) external override {
uint256 receivedAssets = _redeemOsToken(
vault,
exitPositionTicket,
receiver,
osTokenShares,
true
);
emit OsTokenLiquidated(
msg.sender,
vault,
exitPositionTicket,
receiver,
osTokenShares,
receivedAssets
);
}
/// @inheritdoc IOsTokenVaultEscrow
function redeemOsToken(
address vault,
uint256 exitPositionTicket,
uint256 osTokenShares,
address receiver
) external override {
if (msg.sender != _osTokenConfig.redeemer()) revert Errors.AccessDenied();
uint256 receivedAssets = _redeemOsToken(
vault,
exitPositionTicket,
receiver,
osTokenShares,
false
);
emit OsTokenRedeemed(
msg.sender,
vault,
exitPositionTicket,
receiver,
osTokenShares,
receivedAssets
);
}
/// @inheritdoc IOsTokenVaultEscrow
function setAuthenticator(address newAuthenticator) public override onlyOwner {
if (authenticator == newAuthenticator) revert Errors.ValueNotChanged();
authenticator = newAuthenticator;
emit AuthenticatorUpdated(newAuthenticator);
}
/// @inheritdoc IOsTokenVaultEscrow
function updateLiqConfig(
uint64 _liqThresholdPercent,
uint256 _liqBonusPercent
) public override onlyOwner {
// validate liquidation threshold percent
if (_liqThresholdPercent == 0 || _liqThresholdPercent >= _maxPercent) {
revert Errors.InvalidLiqThresholdPercent();
}
// validate liquidation bonus percent
if (
_liqBonusPercent < _maxPercent ||
Math.mulDiv(_liqThresholdPercent, _liqBonusPercent, _maxPercent) > _maxPercent
) {
revert Errors.InvalidLiqBonusPercent();
}
// update config
liqThresholdPercent = _liqThresholdPercent;
liqBonusPercent = _liqBonusPercent;
// emit event
emit LiqConfigUpdated(_liqThresholdPercent, _liqBonusPercent);
}
/**
* @dev Internal function for redeeming osToken shares
* @param vault The address of the vault
* @param exitPositionTicket The position ticket of the exit queue
* @param receiver The address of the receiver of the redeemed assets
* @param osTokenShares The amount of osToken shares to redeem
* @param isLiquidation Whether the redeem is a liquidation
* @return receivedAssets The amount of assets received
*/
function _redeemOsToken(
address vault,
uint256 exitPositionTicket,
address receiver,
uint256 osTokenShares,
bool isLiquidation
) private returns (uint256 receivedAssets) {
if (receiver == address(0)) revert Errors.ZeroAddress();
// update osToken state for gas efficiency
_osTokenVaultController.updateState();
// fetch user position
Position memory position = _positions[vault][exitPositionTicket];
if (position.osTokenShares == 0) revert Errors.InvalidPosition();
_syncPositionFee(position);
// calculate received assets
if (isLiquidation) {
receivedAssets = Math.mulDiv(
_osTokenVaultController.convertToAssets(osTokenShares),
liqBonusPercent,
_maxPercent
);
} else {
receivedAssets = _osTokenVaultController.convertToAssets(osTokenShares);
}
{
// check whether received assets are valid
if (receivedAssets > position.exitedAssets) {
revert Errors.InvalidReceivedAssets();
}
if (isLiquidation) {
// check health factor violation in case of liquidation
uint256 mintedAssets = _osTokenVaultController.convertToAssets(position.osTokenShares);
if (
Math.mulDiv(
position.exitedAssets * _wad,
liqThresholdPercent,
mintedAssets * _maxPercent
) >= _hfLiqThreshold
) {
revert Errors.InvalidHealthFactor();
}
}
}
// reduce osToken supply
_osTokenVaultController.burnShares(msg.sender, osTokenShares);
// update position
position.exitedAssets -= SafeCast.toUint96(receivedAssets);
position.osTokenShares -= SafeCast.toUint128(osTokenShares);
_positions[vault][exitPositionTicket] = position;
// transfer assets to the receiver
_transferAssets(receiver, receivedAssets);
}
/**
* @dev Internal function for syncing the osToken fee
* @param position The position to sync the fee for
*/
function _syncPositionFee(Position memory position) private view {
// fetch current cumulative fee per share
uint256 cumulativeFeePerShare = _osTokenVaultController.cumulativeFeePerShare();
// check whether fee is already up to date
if (cumulativeFeePerShare == position.cumulativeFeePerShare) return;
// add treasury fee to the position
position.osTokenShares = SafeCast.toUint128(
Math.mulDiv(position.osTokenShares, cumulativeFeePerShare, position.cumulativeFeePerShare)
);
position.cumulativeFeePerShare = SafeCast.toUint128(cumulativeFeePerShare);
}
/**
* @dev Internal function for transferring assets from the Vault to the receiver
* @dev IMPORTANT: because control is transferred to the receiver, care must be
* taken to not create reentrancy vulnerabilities. The Vault must follow the checks-effects-interactions pattern:
* https://docs.soliditylang.org/en/v0.8.22/security-considerations.html#use-the-checks-effects-interactions-pattern
* @param receiver The address that will receive the assets
* @param assets The number of assets to transfer
*/
function _transferAssets(address receiver, uint256 assets) internal virtual;
}{
"viaIR": true,
"optimizer": {
"enabled": true,
"runs": 200,
"details": {
"yul": true
}
},
"evmVersion": "shanghai",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"osTokenVaultController","type":"address"},{"internalType":"address","name":"osTokenConfig","type":"address"},{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"_authenticator","type":"address"},{"internalType":"uint64","name":"_liqThresholdPercent","type":"uint64"},{"internalType":"uint256","name":"_liqBonusPercent","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ExitRequestNotProcessed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidHealthFactor","type":"error"},{"inputs":[],"name":"InvalidLiqBonusPercent","type":"error"},{"inputs":[],"name":"InvalidLiqThresholdPercent","type":"error"},{"inputs":[],"name":"InvalidPosition","type":"error"},{"inputs":[],"name":"InvalidReceivedAssets","type":"error"},{"inputs":[],"name":"InvalidShares","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"ValueNotChanged","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"AssetsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAuthenticator","type":"address"}],"name":"AuthenticatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"osTokenShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"ExitedAssetsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exitedAssets","type":"uint256"}],"name":"ExitedAssetsProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"liqThresholdPercent","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"liqBonusPercent","type":"uint256"}],"name":"LiqConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"osTokenShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"receivedAssets","type":"uint256"}],"name":"OsTokenLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"osTokenShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"receivedAssets","type":"uint256"}],"name":"OsTokenRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"osTokenShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cumulativeFeePerShare","type":"uint256"}],"name":"PositionCreated","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"authenticator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"internalType":"uint256","name":"osTokenShares","type":"uint256"}],"name":"claimExitedAssets","outputs":[{"internalType":"uint256","name":"claimedAssets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"positionTicket","type":"uint256"}],"name":"getPosition","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liqBonusPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liqThresholdPercent","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"internalType":"uint256","name":"osTokenShares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"liquidateOsToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"exitQueueIndex","type":"uint256"}],"name":"processExitedAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"internalType":"uint256","name":"osTokenShares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"redeemOsToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"exitPositionTicket","type":"uint256"},{"internalType":"uint256","name":"osTokenShares","type":"uint256"},{"internalType":"uint256","name":"cumulativeFeePerShare","type":"uint256"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAuthenticator","type":"address"}],"name":"setAuthenticator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_liqThresholdPercent","type":"uint64"},{"internalType":"uint256","name":"_liqBonusPercent","type":"uint256"}],"name":"updateLiqConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60c0346200025c57601f62001f1638819003918201601f1916830192916001600160401b03918285118486101762000260578160c092859260409788528339810103126200025c57620000528262000274565b620000606020840162000274565b916200006e85850162000274565b936200007d6060820162000274565b906080810151928316908184036200025c5760a001519360015f5533156200024557620000aa3362000289565b6001600160a01b0390811660805294851660a052620000c8620002dc565b8015801562000232575b6200022157670de0b6b3a76400008085109081156200020b575b50620001fa5760058054600160a01b600160e01b0360a09590951b94909416600160a01b600160e01b0319851681179091556004859055875191825260208201949094528491907ff8333ae7adea4c8a83c7ed352346665b55517daecce9ddb81f555e9f6c96cd6b908890a162000162620002dc565b168093821614620001e9576001600160e01b0319161781176005558251908152620001b491907f83292ae03f07801d2323041a63198dd4d11efb58fdd68f383a752b467c529f3790602090a162000289565b51611b8490816200039282396080518181816101f001528181610586015281816116760152611968015260a0518161111e0152f35b8451638c8728c760e01b8152600490fd5b865163083887e960e21b8152600490fd5b905062000219858362000309565b115f620000ec565b865163152b042360e21b8152600490fd5b50670de0b6b3a7640000811015620000d2565b8751631e4fbdf760e01b81525f6004820152602490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036200025c57565b600280546001600160a01b0319908116909155600180549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b6001546001600160a01b03163303620002f157565b60405163118cdaa760e01b8152336004820152602490fd5b90808202905f19818409908280831092039180830392146200038057670de0b6b3a764000090828211156200036e577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60405163227bc15360e01b8152600490fd5b5050670de0b6b3a76400009150049056fe60806040526004361015610022575b3615610018575f80fd5b610020611632565b005b5f3560e01c80630c4f735f146101315780630ff1ff9a1461012c578063145d7632146101275780632335c76b146101225780632b9acefa1461011d5780633a774b48146101185780633adbb5af146101135780636bf8e70e1461010e578063715018a61461010957806379ba5097146101045780638da5cb5b146100ff57806398e99bb7146100fa578063aa4fe718146100f5578063ac9650d8146100f0578063bd69176f146100eb578063e30c3978146100e65763f2fde38b0361000e5761121b565b6111f3565b6110eb565b611086565b610eca565b610d2b565b610d03565b610c81565b610c1c565b610b91565b610a9c565b6108ea565b610560565b610508565b61019b565b610161565b610144565b5f91031261014057565b5f80fd5b34610140575f366003190112610140576020600454604051908152f35b34610140575f3660031901126101405760206001600160401b0360055460a01c16604051908152f35b6001600160a01b0381160361014057565b34610140576060366003190112610140576004356101b88161018a565b60408051633b9e9f0160e21b81523360048201526044803560248084018290526001600160a01b03959194939035926020908290815f7f00000000000000000000000000000000000000000000000000000000000000008b165af18015610503576104d4575b5061025261024d836102408460018060a01b03165f52600360205260405f2090565b905f5260205260405f2090565b61131c565b8051909490610271906001600160a01b03165b6001600160a01b031690565b33036104c35761028085611660565b838501946001600160801b03958661029f82516001600160801b031690565b168381159182156104b9575b50506104a85782876102c483516001600160801b031690565b1614610450576103609061033761030d6020850199866001600160601b036102f38d516001600160601b031690565b9261030587516001600160801b031690565b1692166117d7565b9861032a61031a8b611857565b82516001600160601b0316611372565b6001600160601b03169052565b6103536103438561188a565b82516001600160801b0316611390565b6001600160801b03169052565b6103d081610382866102408760018060a01b03165f52600360205260405f2090565b8151602083015160a01b6001600160a01b0319166001600160a01b0391909116178155906001906001600160801b036040820151169060606001600160801b031991015160801b1617910155565b851561043f575161043b967fd771679d1dffa1ab8c532072cfddf3582fd9734877673490ce98426f15dfb4ce916104169088906001600160a01b03166118bd565b6118bd565b85519283526020830187905292909216913391604090a4519081529081906020820190565b0390f35b8451630e3d8e8d60e11b8152600490fd5b50945061047661046a60208701516001600160601b031690565b6001600160601b031690565b946104a3610498856102408660018060a01b03165f52600360205260405f2090565b60015f918281550155565b6103d0565b8551636edcc52360e01b8152600490fd5b109050835f6102ab565b8351634ca8886760e01b8152600490fd5b6104f59060203d6020116104fc575b6104ed81836112d2565b8101906112f3565b505f61021e565b503d6104e3565b611302565b34610140575f366003190112610140576005546040516001600160a01b039091168152602090f35b6080906003190112610140576004356105488161018a565b90602435906044359060643561055d8161018a565b90565b346101405761056e36610530565b91929091906001600160a01b03808316156108b157807f00000000000000000000000000000000000000000000000000000000000000001691823b15610140576040928351631d8557d760e01b81526004905f81838183875af1801561050357610898575b506105f561024d896102408660018060a01b03165f52600360205260405f2090565b94808601956001600160801b0361061388516001600160801b031690565b161561088a578061062661064a92611660565b8251946303d1689d60e11b958681528b818060209687938a83019190602083019252565b0381855afa801561050357610669915f9161086d575b50865490611751565b948383019661068261046a89516001600160601b031690565b871161085e57846106c09161069e8d516001600160801b031690565b908851938492839283528683019190916001600160801b036020820193169052565b0381865afa90811561050357670de0b6b3a764000091610733915f91610841575b506107046001600160601b036106fe8c516001600160601b031690565b16611934565b6001600160401b0361072b6107256005546001600160401b039060a01c1690565b93611934565b9216906117d7565b1015610833578451633b9e9f0160e21b815233918101918252602082018d905291849183919082905f90829060400103925af1988915610503576107b1610810976107df956107bd947f36d2254ece9fe37664da4738f535058024f7b2ccb3d78abe69b705c1be2876ad9d610815575b505061032a61031a89611857565b6103536103438d61188a565b6001600160a01b0386165f908152600360205260409020610382908c90610240565b6107e982886118bd565b519384931696339684604091949392606082019560018060a01b0316825260208201520152565b0390a4005b8161082b92903d106104fc576104ed81836112d2565b505f806107a3565b845163185cfc6d60e11b8152fd5b6108589150873d89116104fc576104ed81836112d2565b5f6106e1565b50845163efda1a2760e01b8152fd5b6108849150853d87116104fc576104ed81836112d2565b5f610660565b505163673f032f60e11b8152fd5b806108a56108ab926112bf565b80610136565b5f6105d3565b60405163d92e233d60e01b8152600490fd5b6080906003190112610140576004356108db8161018a565b90602435906044359060643590565b34610140576108f8366108c3565b60055491939161091290610265906001600160a01b031681565b6040805163e0eb6af360e01b81523360048201526001600160a01b03851660248201526044810186905260648101879052909591602090829060849082905afa908115610503575f91610a6d575b5015610a5c576001600160a01b03831615610a4b578015610a3a57610a357fafda9316e64488bba379a6614bcee4516ef1793ee3844298c937b46b2cae5829939495610a106109ae8461188a565b6109f76109ba8761188a565b6109e76109c561130d565b6001600160a01b038c168152935f60208601526001600160801b031686850152565b6001600160801b03166060830152565b335f908152600360205260409020610382908a90610240565b51928392339684604091949392606082019560018060a01b0316825260208201520152565b0390a3005b8451636edcc52360e01b8152600490fd5b845163d92e233d60e01b8152600490fd5b8451634ca8886760e01b8152600490fd5b610a8f915060203d602011610a95575b610a8781836112d2565b8101906113a9565b5f610960565b503d610a7d565b34610140576040806003193601126101405760043590610abb8261018a565b60018060a01b038092165f526003602052805f206024355f5260205261043b815f20926001835194610aec8661129f565b80549283168652602086019260a01c83520154906001600160601b03610b5a610b4c610b3e6001600160801b03988987168982019781895260801c6060830152610b83575b516001600160a01b031690565b93516001600160601b031690565b93516001600160801b031690565b94516001600160a01b039092168252909116602082015292909116604083015281906060820190565b610b8c81611660565b610b31565b3461014057602036600319011261014057600435610bae8161018a565b610bb6611b3a565b6005546001600160a01b039182169181168214610c0a576001600160a01b03191681176005556040519081527f83292ae03f07801d2323041a63198dd4d11efb58fdd68f383a752b467c529f3790602090a1005b604051638c8728c760e01b8152600490fd5b34610140575f36600319011261014057610c34611b3a565b600280546001600160a01b03199081169091556001805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610140575f366003190112610140576002546001600160a01b033381831603610ceb576001600160601b0360a01b8092166002556001549133908316176001553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60405163118cdaa760e01b8152336004820152602490fd5b34610140575f366003190112610140576001546040516001600160a01b039091168152602090f35b3461014057610d39366108c3565b610d5a836102408694959660018060a01b03165f52600360205260405f2090565b805490926001600160a01b0391821615610eb85760405163076b58b960e41b81523060048201526024810187905260448101869052606481018490529491169290606085608481875afa948515610503575f905f96610e83575b50600110610e7157833b156101405760405163434be96160e11b815260048101879052602481019190915260448101929092525f8260648183875af191821561050357610e2a92610e5e575b50610e0a84611857565b81546001600160a01b031660a09190911b6001600160a01b031916179055565b60405191825233917fda15728d9b7db891bd1235a1f54c14891973d2e88f4483636a7be928ccf5588c908060208101610810565b806108a5610e6b926112bf565b5f610e00565b604051630e3d8e8d60e11b8152600490fd5b60019650610ea9915060603d606011610eb1575b610ea181836112d2565b8101906113c1565b969050610db4565b503d610e97565b60405163673f032f60e11b8152600490fd5b34610140576040366003190112610140576004356001600160401b0381168082036101405760243590610efb611b3a565b80158015610fcb575b610fb957670de0b6b3a764000082818110928315610fa5575b505050610f93576005805467ffffffffffffffff60a01b191660a084901b67ffffffffffffffff60a01b161790557ff8333ae7adea4c8a83c7ed352346665b55517daecce9ddb81f555e9f6c96cd6b91610f7682600455565b604080516001600160401b039290921682526020820192909252a1005b60405163083887e960e21b8152600490fd5b610fb0929350611751565b115f8281610f1d565b60405163152b042360e21b8152600490fd5b50670de0b6b3a7640000811015610f04565b5f5b838110610fee5750505f910152565b8181015183820152602001610fdf565b9060209161101781518092818552858086019101610fdd565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106110585750505050505090565b9091929394958480611076600193603f198682030187528a51610ffe565b9801930193019194939290611048565b34610140576020366003190112610140576001600160401b036004358181116101405736602382011215610140578060040135918211610140573660248360051b830101116101405761043b9160246110df9201611570565b60405191829182611023565b34610140576110f936610530565b60405163057453a760e31b8152929391929091906001600160a01b03906020816004817f000000000000000000000000000000000000000000000000000000000000000086165afa80156105035782915f916111c4575b501633036111b257816108106111898686897ffebaeed78b2aaa8366a65cf2a811e7a20ce8c29f6563290cf5d4ece00379427897611951565b6040519384931696339684604091949392606082019560018060a01b0316825260208201520152565b604051634ca8886760e01b8152600490fd5b6111e6915060203d6020116111ec575b6111de81836112d2565b81019061161d565b5f611150565b503d6111d4565b34610140575f366003190112610140576002546040516001600160a01b039091168152602090f35b34610140576020366003190112610140576004356112388161018a565b611240611b3a565b600280546001600160a01b0319166001600160a01b039283169081179091556001549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b634e487b7160e01b5f52604160045260245ffd5b608081019081106001600160401b038211176112ba57604052565b61128b565b6001600160401b0381116112ba57604052565b90601f801991011681019081106001600160401b038211176112ba57604052565b90816020910312610140575190565b6040513d5f823e3d90fd5b6040519061131a8261129f565b565b906040516113298161129f565b82546001600160a01b038116825260a01c60208201526001909201546001600160801b038116604084015260801c6060830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160601b03918216908216039190821161138b57565b61135e565b6001600160801b03918216908216039190821161138b57565b90816020910312610140575180151581036101405790565b90816060910312610140578051916040602083015192015190565b6001600160401b0381116112ba5760051b60200190565b906113fd826113dc565b61140a60405191826112d2565b828152809261141b601f19916113dc565b01905f5b82811061142b57505050565b80606060208093850101520161141f565b634e487b7160e01b5f52603260045260245ffd5b91908110156114915760051b81013590601e19813603018212156101405701908135916001600160401b038311610140576020018236038113610140579190565b61143c565b908092918237015f815290565b6001600160401b0381116112ba57601f01601f191660200190565b3d156114e8573d906114cf826114a3565b916114dd60405193846112d2565b82523d5f602084013e565b606090565b602081830312610140578051906001600160401b038211610140570181601f8201121561014057805161151f816114a3565b9261152d60405194856112d2565b818452602082840101116101405761055d9160208085019101610fdd565b90602061055d928181520190610ffe565b80518210156114915760209160051b010190565b91909161157c836113f3565b925f5b81811061158b57505050565b5f80611598838587611450565b604093916115aa855180938193611496565b0390305af4906115b86114be565b91156115df5750906001916115cd828861155c565b526115d8818761155c565b500161157f565b90604481511061014057611619611604600492838101516024809183010191016114ed565b925162461bcd60e51b8152928392830161154b565b0390fd5b90816020910312610140575161055d8161018a565b6040513481527f09cea04c49f8b481a24e7cfff342f8b2a4ae27e595f0f3ba64ac8908efea5e0060203392a2565b60405163752a536d60e01b8152906020826004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215610503575f92611712575b5060608101906001600160801b0392836116cf84516001600160801b031690565b169182821461170b5761131a946103536117066103539585604061170696019461170086516001600160801b031690565b166117d7565b61188a565b5050505050565b61172c91925060203d6020116104fc576104ed81836112d2565b905f6116ae565b811561173d570490565b634e487b7160e01b5f52601260045260245ffd5b90808202905f19818409908280831092039180830392146117c657670de0b6b3a764000090828211156117b4577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60405163227bc15360e01b8152600490fd5b5050670de0b6b3a764000091500490565b9091828202915f198482099383808610950394808603951461184a57848311156117b457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b50509061055d9250611733565b6001600160601b039081811161186b571690565b604490604051906306dfcc6560e41b8252606060048301526024820152fd5b6001600160801b039081811161189e571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b60025f54146119225760025f5581471061190a575f918291829182916001600160a01b03165af16118ec6114be565b50156118f85760015f55565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b90670de0b6b3a76400009182810292818404149015171561138b57565b92939290916001600160a01b03808216156108b1577f00000000000000000000000000000000000000000000000000000000000000001692833b15610140576040958651631d8557d760e01b81525f81600481838a5af1801561050357611b27575b506119d561024d836102408760018060a01b03165f52600360205260405f2090565b90878201926001600160801b036119f385516001600160801b031690565b1615611b1657611a0283611660565b88516303d1689d60e11b8152600481018390529560209081886024818c5afa978815610503575f98611af7575b50879a82860190611a4a61046a83516001600160601b031690565b8a11611ae75751633b9e9f0160e21b8152336004820152602481018690529983908b9060449082905f905af19687156105035761035361034361038297611706611ab09561131a9f8f61031a906104119f9b61032a936102409d611ac9575b5050611857565b6001600160a01b03165f90815260036020526040902090565b81611adf92903d106104fc576104ed81836112d2565b505f80611aa9565b5163efda1a2760e01b8152600490fd5b611b0f919850823d84116104fc576104ed81836112d2565b965f611a2f565b885163673f032f60e11b8152600490fd5b806108a5611b34926112bf565b5f6119b3565b6001546001600160a01b03163303610ceb5756fea26469706673582212207dd2347037e024c87551c91e253c373748a83703a673442ddffcf0f878f755ef64736f6c634300081600330000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f5000306000000000000000000000000287d1e2a8de183a8bf8f2b09fa1340fbd766eb59000000000000000000000000144a98cb1cdbb23610501fe6108858d9b7d24934000000000000000000000000fc8e3e7c919b4392d9f5b27015688e49c80015f00000000000000000000000000000000000000000000000000de0375f5d1f40000000000000000000000000000000000000000000000000000de0f48c233c4000
Deployed Bytecode
0x60806040526004361015610022575b3615610018575f80fd5b610020611632565b005b5f3560e01c80630c4f735f146101315780630ff1ff9a1461012c578063145d7632146101275780632335c76b146101225780632b9acefa1461011d5780633a774b48146101185780633adbb5af146101135780636bf8e70e1461010e578063715018a61461010957806379ba5097146101045780638da5cb5b146100ff57806398e99bb7146100fa578063aa4fe718146100f5578063ac9650d8146100f0578063bd69176f146100eb578063e30c3978146100e65763f2fde38b0361000e5761121b565b6111f3565b6110eb565b611086565b610eca565b610d2b565b610d03565b610c81565b610c1c565b610b91565b610a9c565b6108ea565b610560565b610508565b61019b565b610161565b610144565b5f91031261014057565b5f80fd5b34610140575f366003190112610140576020600454604051908152f35b34610140575f3660031901126101405760206001600160401b0360055460a01c16604051908152f35b6001600160a01b0381160361014057565b34610140576060366003190112610140576004356101b88161018a565b60408051633b9e9f0160e21b81523360048201526044803560248084018290526001600160a01b03959194939035926020908290815f7f0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f50003068b165af18015610503576104d4575b5061025261024d836102408460018060a01b03165f52600360205260405f2090565b905f5260205260405f2090565b61131c565b8051909490610271906001600160a01b03165b6001600160a01b031690565b33036104c35761028085611660565b838501946001600160801b03958661029f82516001600160801b031690565b168381159182156104b9575b50506104a85782876102c483516001600160801b031690565b1614610450576103609061033761030d6020850199866001600160601b036102f38d516001600160601b031690565b9261030587516001600160801b031690565b1692166117d7565b9861032a61031a8b611857565b82516001600160601b0316611372565b6001600160601b03169052565b6103536103438561188a565b82516001600160801b0316611390565b6001600160801b03169052565b6103d081610382866102408760018060a01b03165f52600360205260405f2090565b8151602083015160a01b6001600160a01b0319166001600160a01b0391909116178155906001906001600160801b036040820151169060606001600160801b031991015160801b1617910155565b851561043f575161043b967fd771679d1dffa1ab8c532072cfddf3582fd9734877673490ce98426f15dfb4ce916104169088906001600160a01b03166118bd565b6118bd565b85519283526020830187905292909216913391604090a4519081529081906020820190565b0390f35b8451630e3d8e8d60e11b8152600490fd5b50945061047661046a60208701516001600160601b031690565b6001600160601b031690565b946104a3610498856102408660018060a01b03165f52600360205260405f2090565b60015f918281550155565b6103d0565b8551636edcc52360e01b8152600490fd5b109050835f6102ab565b8351634ca8886760e01b8152600490fd5b6104f59060203d6020116104fc575b6104ed81836112d2565b8101906112f3565b505f61021e565b503d6104e3565b611302565b34610140575f366003190112610140576005546040516001600160a01b039091168152602090f35b6080906003190112610140576004356105488161018a565b90602435906044359060643561055d8161018a565b90565b346101405761056e36610530565b91929091906001600160a01b03808316156108b157807f0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f50003061691823b15610140576040928351631d8557d760e01b81526004905f81838183875af1801561050357610898575b506105f561024d896102408660018060a01b03165f52600360205260405f2090565b94808601956001600160801b0361061388516001600160801b031690565b161561088a578061062661064a92611660565b8251946303d1689d60e11b958681528b818060209687938a83019190602083019252565b0381855afa801561050357610669915f9161086d575b50865490611751565b948383019661068261046a89516001600160601b031690565b871161085e57846106c09161069e8d516001600160801b031690565b908851938492839283528683019190916001600160801b036020820193169052565b0381865afa90811561050357670de0b6b3a764000091610733915f91610841575b506107046001600160601b036106fe8c516001600160601b031690565b16611934565b6001600160401b0361072b6107256005546001600160401b039060a01c1690565b93611934565b9216906117d7565b1015610833578451633b9e9f0160e21b815233918101918252602082018d905291849183919082905f90829060400103925af1988915610503576107b1610810976107df956107bd947f36d2254ece9fe37664da4738f535058024f7b2ccb3d78abe69b705c1be2876ad9d610815575b505061032a61031a89611857565b6103536103438d61188a565b6001600160a01b0386165f908152600360205260409020610382908c90610240565b6107e982886118bd565b519384931696339684604091949392606082019560018060a01b0316825260208201520152565b0390a4005b8161082b92903d106104fc576104ed81836112d2565b505f806107a3565b845163185cfc6d60e11b8152fd5b6108589150873d89116104fc576104ed81836112d2565b5f6106e1565b50845163efda1a2760e01b8152fd5b6108849150853d87116104fc576104ed81836112d2565b5f610660565b505163673f032f60e11b8152fd5b806108a56108ab926112bf565b80610136565b5f6105d3565b60405163d92e233d60e01b8152600490fd5b6080906003190112610140576004356108db8161018a565b90602435906044359060643590565b34610140576108f8366108c3565b60055491939161091290610265906001600160a01b031681565b6040805163e0eb6af360e01b81523360048201526001600160a01b03851660248201526044810186905260648101879052909591602090829060849082905afa908115610503575f91610a6d575b5015610a5c576001600160a01b03831615610a4b578015610a3a57610a357fafda9316e64488bba379a6614bcee4516ef1793ee3844298c937b46b2cae5829939495610a106109ae8461188a565b6109f76109ba8761188a565b6109e76109c561130d565b6001600160a01b038c168152935f60208601526001600160801b031686850152565b6001600160801b03166060830152565b335f908152600360205260409020610382908a90610240565b51928392339684604091949392606082019560018060a01b0316825260208201520152565b0390a3005b8451636edcc52360e01b8152600490fd5b845163d92e233d60e01b8152600490fd5b8451634ca8886760e01b8152600490fd5b610a8f915060203d602011610a95575b610a8781836112d2565b8101906113a9565b5f610960565b503d610a7d565b34610140576040806003193601126101405760043590610abb8261018a565b60018060a01b038092165f526003602052805f206024355f5260205261043b815f20926001835194610aec8661129f565b80549283168652602086019260a01c83520154906001600160601b03610b5a610b4c610b3e6001600160801b03988987168982019781895260801c6060830152610b83575b516001600160a01b031690565b93516001600160601b031690565b93516001600160801b031690565b94516001600160a01b039092168252909116602082015292909116604083015281906060820190565b610b8c81611660565b610b31565b3461014057602036600319011261014057600435610bae8161018a565b610bb6611b3a565b6005546001600160a01b039182169181168214610c0a576001600160a01b03191681176005556040519081527f83292ae03f07801d2323041a63198dd4d11efb58fdd68f383a752b467c529f3790602090a1005b604051638c8728c760e01b8152600490fd5b34610140575f36600319011261014057610c34611b3a565b600280546001600160a01b03199081169091556001805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b34610140575f366003190112610140576002546001600160a01b033381831603610ceb576001600160601b0360a01b8092166002556001549133908316176001553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60405163118cdaa760e01b8152336004820152602490fd5b34610140575f366003190112610140576001546040516001600160a01b039091168152602090f35b3461014057610d39366108c3565b610d5a836102408694959660018060a01b03165f52600360205260405f2090565b805490926001600160a01b0391821615610eb85760405163076b58b960e41b81523060048201526024810187905260448101869052606481018490529491169290606085608481875afa948515610503575f905f96610e83575b50600110610e7157833b156101405760405163434be96160e11b815260048101879052602481019190915260448101929092525f8260648183875af191821561050357610e2a92610e5e575b50610e0a84611857565b81546001600160a01b031660a09190911b6001600160a01b031916179055565b60405191825233917fda15728d9b7db891bd1235a1f54c14891973d2e88f4483636a7be928ccf5588c908060208101610810565b806108a5610e6b926112bf565b5f610e00565b604051630e3d8e8d60e11b8152600490fd5b60019650610ea9915060603d606011610eb1575b610ea181836112d2565b8101906113c1565b969050610db4565b503d610e97565b60405163673f032f60e11b8152600490fd5b34610140576040366003190112610140576004356001600160401b0381168082036101405760243590610efb611b3a565b80158015610fcb575b610fb957670de0b6b3a764000082818110928315610fa5575b505050610f93576005805467ffffffffffffffff60a01b191660a084901b67ffffffffffffffff60a01b161790557ff8333ae7adea4c8a83c7ed352346665b55517daecce9ddb81f555e9f6c96cd6b91610f7682600455565b604080516001600160401b039290921682526020820192909252a1005b60405163083887e960e21b8152600490fd5b610fb0929350611751565b115f8281610f1d565b60405163152b042360e21b8152600490fd5b50670de0b6b3a7640000811015610f04565b5f5b838110610fee5750505f910152565b8181015183820152602001610fdf565b9060209161101781518092818552858086019101610fdd565b601f01601f1916010190565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b8483106110585750505050505090565b9091929394958480611076600193603f198682030187528a51610ffe565b9801930193019194939290611048565b34610140576020366003190112610140576001600160401b036004358181116101405736602382011215610140578060040135918211610140573660248360051b830101116101405761043b9160246110df9201611570565b60405191829182611023565b34610140576110f936610530565b60405163057453a760e31b8152929391929091906001600160a01b03906020816004817f000000000000000000000000287d1e2a8de183a8bf8f2b09fa1340fbd766eb5986165afa80156105035782915f916111c4575b501633036111b257816108106111898686897ffebaeed78b2aaa8366a65cf2a811e7a20ce8c29f6563290cf5d4ece00379427897611951565b6040519384931696339684604091949392606082019560018060a01b0316825260208201520152565b604051634ca8886760e01b8152600490fd5b6111e6915060203d6020116111ec575b6111de81836112d2565b81019061161d565b5f611150565b503d6111d4565b34610140575f366003190112610140576002546040516001600160a01b039091168152602090f35b34610140576020366003190112610140576004356112388161018a565b611240611b3a565b600280546001600160a01b0319166001600160a01b039283169081179091556001549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b634e487b7160e01b5f52604160045260245ffd5b608081019081106001600160401b038211176112ba57604052565b61128b565b6001600160401b0381116112ba57604052565b90601f801991011681019081106001600160401b038211176112ba57604052565b90816020910312610140575190565b6040513d5f823e3d90fd5b6040519061131a8261129f565b565b906040516113298161129f565b82546001600160a01b038116825260a01c60208201526001909201546001600160801b038116604084015260801c6060830152565b634e487b7160e01b5f52601160045260245ffd5b6001600160601b03918216908216039190821161138b57565b61135e565b6001600160801b03918216908216039190821161138b57565b90816020910312610140575180151581036101405790565b90816060910312610140578051916040602083015192015190565b6001600160401b0381116112ba5760051b60200190565b906113fd826113dc565b61140a60405191826112d2565b828152809261141b601f19916113dc565b01905f5b82811061142b57505050565b80606060208093850101520161141f565b634e487b7160e01b5f52603260045260245ffd5b91908110156114915760051b81013590601e19813603018212156101405701908135916001600160401b038311610140576020018236038113610140579190565b61143c565b908092918237015f815290565b6001600160401b0381116112ba57601f01601f191660200190565b3d156114e8573d906114cf826114a3565b916114dd60405193846112d2565b82523d5f602084013e565b606090565b602081830312610140578051906001600160401b038211610140570181601f8201121561014057805161151f816114a3565b9261152d60405194856112d2565b818452602082840101116101405761055d9160208085019101610fdd565b90602061055d928181520190610ffe565b80518210156114915760209160051b010190565b91909161157c836113f3565b925f5b81811061158b57505050565b5f80611598838587611450565b604093916115aa855180938193611496565b0390305af4906115b86114be565b91156115df5750906001916115cd828861155c565b526115d8818761155c565b500161157f565b90604481511061014057611619611604600492838101516024809183010191016114ed565b925162461bcd60e51b8152928392830161154b565b0390fd5b90816020910312610140575161055d8161018a565b6040513481527f09cea04c49f8b481a24e7cfff342f8b2a4ae27e595f0f3ba64ac8908efea5e0060203392a2565b60405163752a536d60e01b8152906020826004817f0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f50003066001600160a01b03165afa918215610503575f92611712575b5060608101906001600160801b0392836116cf84516001600160801b031690565b169182821461170b5761131a946103536117066103539585604061170696019461170086516001600160801b031690565b166117d7565b61188a565b5050505050565b61172c91925060203d6020116104fc576104ed81836112d2565b905f6116ae565b811561173d570490565b634e487b7160e01b5f52601260045260245ffd5b90808202905f19818409908280831092039180830392146117c657670de0b6b3a764000090828211156117b4577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac10669940990828211900360ee1b910360121c170290565b60405163227bc15360e01b8152600490fd5b5050670de0b6b3a764000091500490565b9091828202915f198482099383808610950394808603951461184a57848311156117b457829109815f038216809204600280826003021880830282030280830282030280830282030280830282030280830282030280920290030293600183805f03040190848311900302920304170290565b50509061055d9250611733565b6001600160601b039081811161186b571690565b604490604051906306dfcc6560e41b8252606060048301526024820152fd5b6001600160801b039081811161189e571690565b604490604051906306dfcc6560e41b8252608060048301526024820152fd5b60025f54146119225760025f5581471061190a575f918291829182916001600160a01b03165af16118ec6114be565b50156118f85760015f55565b604051630a12f52160e11b8152600490fd5b60405163cd78605960e01b8152306004820152602490fd5b604051633ee5aeb560e01b8152600490fd5b90670de0b6b3a76400009182810292818404149015171561138b57565b92939290916001600160a01b03808216156108b1577f0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f50003061692833b15610140576040958651631d8557d760e01b81525f81600481838a5af1801561050357611b27575b506119d561024d836102408760018060a01b03165f52600360205260405f2090565b90878201926001600160801b036119f385516001600160801b031690565b1615611b1657611a0283611660565b88516303d1689d60e11b8152600481018390529560209081886024818c5afa978815610503575f98611af7575b50879a82860190611a4a61046a83516001600160601b031690565b8a11611ae75751633b9e9f0160e21b8152336004820152602481018690529983908b9060449082905f905af19687156105035761035361034361038297611706611ab09561131a9f8f61031a906104119f9b61032a936102409d611ac9575b5050611857565b6001600160a01b03165f90815260036020526040902090565b81611adf92903d106104fc576104ed81836112d2565b505f80611aa9565b5163efda1a2760e01b8152600490fd5b611b0f919850823d84116104fc576104ed81836112d2565b965f611a2f565b885163673f032f60e11b8152600490fd5b806108a5611b34926112bf565b5f6119b3565b6001546001600160a01b03163303610ceb5756fea26469706673582212207dd2347037e024c87551c91e253c373748a83703a673442ddffcf0f878f755ef64736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f5000306000000000000000000000000287d1e2a8de183a8bf8f2b09fa1340fbd766eb59000000000000000000000000144a98cb1cdbb23610501fe6108858d9b7d24934000000000000000000000000fc8e3e7c919b4392d9f5b27015688e49c80015f00000000000000000000000000000000000000000000000000de0375f5d1f40000000000000000000000000000000000000000000000000000de0f48c233c4000
-----Decoded View---------------
Arg [0] : osTokenVaultController (address): 0x2A261e60FB14586B474C208b1B7AC6D0f5000306
Arg [1] : osTokenConfig (address): 0x287d1e2A8dE183A8bf8f2b09Fa1340fBd766eb59
Arg [2] : initialOwner (address): 0x144a98cb1CdBb23610501fE6108858D9B7D24934
Arg [3] : _authenticator (address): 0xFc8E3E7c919b4392D9F5B27015688e49c80015f0
Arg [4] : _liqThresholdPercent (uint64): 999860000000000000
Arg [5] : _liqBonusPercent (uint256): 1000068000000000000
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000002a261e60fb14586b474c208b1b7ac6d0f5000306
Arg [1] : 000000000000000000000000287d1e2a8de183a8bf8f2b09fa1340fbd766eb59
Arg [2] : 000000000000000000000000144a98cb1cdbb23610501fe6108858d9b7d24934
Arg [3] : 000000000000000000000000fc8e3e7c919b4392d9f5b27015688e49c80015f0
Arg [4] : 0000000000000000000000000000000000000000000000000de0375f5d1f4000
Arg [5] : 0000000000000000000000000000000000000000000000000de0f48c233c4000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.