Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Contract Name:
ProxyAdmin
Compiler Version
v0.8.25+commit.b61c2a91
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol)
pragma solidity ^0.8.0;
import "./TransparentUpgradeableProxy.sol";
import "../../access/Ownable.sol";
/**
* @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
* explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
*/
contract ProxyAdmin is Ownable {
constructor (address initialOwner) Ownable(initialOwner) {}
/**
* @dev Returns the current implementation of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("implementation()")) == 0x5c60da1b
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
require(success);
return abi.decode(returndata, (address));
}
/**
* @dev Returns the current admin of `proxy`.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
// We need to manually run the static call since the getter cannot be flagged as view
// bytes4(keccak256("admin()")) == 0xf851a440
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
require(success);
return abi.decode(returndata, (address));
}
/**
* @dev Changes the admin of `proxy` to `newAdmin`.
*
* Requirements:
*
* - This contract must be the current admin of `proxy`.
*/
function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
proxy.changeAdmin(newAdmin);
}
/**
* @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
proxy.upgradeTo(implementation);
}
/**
* @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
* {TransparentUpgradeableProxy-upgradeToAndCall}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
*/
function upgradeAndCall(
TransparentUpgradeableProxy proxy,
address implementation,
bytes memory data
) public payable virtual onlyOwner {
proxy.upgradeToAndCall{value: msg.value}(implementation, data);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorInterface {
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
function latestRound() external view returns (uint256);
function getAnswer(uint256 roundId) external view returns (int256);
function getTimestamp(uint256 roundId) external view returns (uint256);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./AggregatorInterface.sol";
import "./AggregatorV3Interface.sol";
interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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.
*
* By default, the owner account will be the one that deploys the contract. 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 Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function __Ownable2Step_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable2Step_init_unchained() internal onlyInitializing {
}
/**
* @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();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev 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 {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @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 {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract 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 v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
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.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
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 (rounding == Rounding.Up && 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 down.
*
* 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted 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
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
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
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
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
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
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
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted 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
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
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
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
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
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
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
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
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
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
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
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
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
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
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
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
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
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
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
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
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
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
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
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted 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
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
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
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
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
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
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
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted 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
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
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
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
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
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
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
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted 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
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
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
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
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
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
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
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted 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
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
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
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
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
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import "./IAccessControlManagerV8.sol";
/**
* @title AccessControlledV8
* @author Venus
* @notice This contract is helper between access control manager and actual contract. This contract further inherited by other contract (using solidity 0.8.13)
* to integrate access controlled mechanism. It provides initialise methods and verifying access methods.
*/
abstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {
/// @notice Access control manager contract
IAccessControlManagerV8 private _accessControlManager;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
/// @notice Emitted when access control manager contract address is changed
event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);
/// @notice Thrown when the action is prohibited by AccessControlManager
error Unauthorized(address sender, address calledContract, string methodSignature);
function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {
__Ownable2Step_init();
__AccessControlled_init_unchained(accessControlManager_);
}
function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {
_setAccessControlManager(accessControlManager_);
}
/**
* @notice Sets the address of AccessControlManager
* @dev Admin function to set address of AccessControlManager
* @param accessControlManager_ The new address of the AccessControlManager
* @custom:event Emits NewAccessControlManager event
* @custom:access Only Governance
*/
function setAccessControlManager(address accessControlManager_) external onlyOwner {
_setAccessControlManager(accessControlManager_);
}
/**
* @notice Returns the address of the access control manager contract
*/
function accessControlManager() external view returns (IAccessControlManagerV8) {
return _accessControlManager;
}
/**
* @dev Internal function to set address of AccessControlManager
* @param accessControlManager_ The new address of the AccessControlManager
*/
function _setAccessControlManager(address accessControlManager_) internal {
require(address(accessControlManager_) != address(0), "invalid acess control manager address");
address oldAccessControlManager = address(_accessControlManager);
_accessControlManager = IAccessControlManagerV8(accessControlManager_);
emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);
}
/**
* @notice Reverts if the call is not allowed by AccessControlManager
* @param signature Method signature
*/
function _checkAccessAllowed(string memory signature) internal view {
bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);
if (!isAllowedToCall) {
revert Unauthorized(msg.sender, address(this), signature);
}
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./IAccessControlManagerV8.sol";
/**
* @title AccessControlManager
* @author Venus
* @dev This contract is a wrapper of OpenZeppelin AccessControl extending it in a way to standartize access control within Venus Smart Contract Ecosystem.
* @notice Access control plays a crucial role in the Venus governance model. It is used to restrict functions so that they can only be called from one
* account or list of accounts (EOA or Contract Accounts).
*
* The implementation of `AccessControlManager`(https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/AccessControlManager.sol)
* inherits the [Open Zeppelin AccessControl](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol)
* contract as a base for role management logic. There are two role types: admin and granular permissions.
*
* ## Granular Roles
*
* Granular roles are built by hashing the contract address and its function signature. For example, given contract `Foo` with function `Foo.bar()` which
* is guarded by ACM, calling `giveRolePermission` for account B do the following:
*
* 1. Compute `keccak256(contractFooAddress,functionSignatureBar)`
* 1. Add the computed role to the roles of account B
* 1. Account B now can call `ContractFoo.bar()`
*
* ## Admin Roles
*
* Admin roles allow for an address to call a function signature on any contract guarded by the `AccessControlManager`. This is particularly useful for
* contracts created by factories.
*
* For Admin roles a null address is hashed in place of the contract address (`keccak256(0x0000000000000000000000000000000000000000,functionSignatureBar)`.
*
* In the previous example, giving account B the admin role, account B will have permissions to call the `bar()` function on any contract that is guarded by
* ACM, not only contract A.
*
* ## Protocol Integration
*
* All restricted functions in Venus Protocol use a hook to ACM in order to check if the caller has the right permission to call the guarded function.
* `AccessControlledV5` and `AccessControlledV8` abstract contract makes this integration easier. They call ACM's external method
* `isAllowedToCall(address caller, string functionSig)`. Here is an example of how `setCollateralFactor` function in `Comptroller` is integrated with ACM:
```
contract Comptroller is [...] AccessControlledV8 {
[...]
function setCollateralFactor(VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external {
_checkAccessAllowed("setCollateralFactor(address,uint256,uint256)");
[...]
}
}
```
*/
contract AccessControlManager is AccessControl, IAccessControlManagerV8 {
/// @notice Emitted when an account is given a permission to a certain contract function
/// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and
/// can call any contract function with this signature
event PermissionGranted(address account, address contractAddress, string functionSig);
/// @notice Emitted when an account is revoked a permission to a certain contract function
event PermissionRevoked(address account, address contractAddress, string functionSig);
constructor() {
// Grant the contract deployer the default admin role: it will be able
// to grant and revoke any roles
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
/**
* @notice Gives a function call permission to one single account
* @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE
* @param contractAddress address of contract for which call permissions will be granted
* @dev if contractAddress is zero address, the account can access the specified function
* on **any** contract managed by this ACL
* @param functionSig signature e.g. "functionName(uint256,bool)"
* @param accountToPermit account that will be given access to the contract function
* @custom:event Emits a {RoleGranted} and {PermissionGranted} events.
*/
function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {
bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));
grantRole(role, accountToPermit);
emit PermissionGranted(accountToPermit, contractAddress, functionSig);
}
/**
* @notice Revokes an account's permission to a particular function call
* @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE
* May emit a {RoleRevoked} event.
* @param contractAddress address of contract for which call permissions will be revoked
* @param functionSig signature e.g. "functionName(uint256,bool)"
* @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.
*/
function revokeCallPermission(
address contractAddress,
string calldata functionSig,
address accountToRevoke
) public {
bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));
revokeRole(role, accountToRevoke);
emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);
}
/**
* @notice Verifies if the given account can call a contract's guarded function
* @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender
* @param account for which call permissions will be checked
* @param functionSig restricted function signature e.g. "functionName(uint256,bool)"
* @return false if the user account cannot call the particular contract function
*
*/
function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {
bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));
if (hasRole(role, account)) {
return true;
} else {
role = keccak256(abi.encodePacked(address(0), functionSig));
return hasRole(role, account);
}
}
/**
* @notice Verifies if the given account can call a contract's guarded function
* @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.
* @param account for which call permissions will be checked against
* @param contractAddress address of the restricted contract
* @param functionSig signature of the restricted function e.g. "functionName(uint256,bool)"
* @return false if the user account cannot call the particular contract function
*/
function hasPermission(
address account,
address contractAddress,
string calldata functionSig
) public view returns (bool) {
bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));
return hasRole(role, account);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.25;
import "@openzeppelin/contracts/access/IAccessControl.sol";
/**
* @title IAccessControlManagerV8
* @author Venus
* @notice Interface implemented by the `AccessControlManagerV8` contract.
*/
interface IAccessControlManagerV8 is IAccessControl {
function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;
function revokeCallPermission(
address contractAddress,
string calldata functionSig,
address accountToRevoke
) external;
function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);
function hasPermission(
address account,
address contractAddress,
string calldata functionSig
) external view returns (bool);
}// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.25; /// @dev Base unit for computations, usually used in scaling (multiplications, divisions) uint256 constant EXP_SCALE = 1e18; /// @dev A unit (literal one) in EXP_SCALE, usually used in additions/subtractions uint256 constant MANTISSA_ONE = EXP_SCALE; /// @dev The approximate number of seconds per year uint256 constant SECONDS_PER_YEAR = 31_536_000;
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
/// @notice Thrown if the supplied address is a zero address where it is not allowed
error ZeroAddressNotAllowed();
/// @notice Thrown if the supplied value is 0 where it is not allowed
error ZeroValueNotAllowed();
/// @notice Checks if the provided address is nonzero, reverts otherwise
/// @param address_ Address to check
/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address
function ensureNonzeroAddress(address address_) pure {
if (address_ == address(0)) {
revert ZeroAddressNotAllowed();
}
}
/// @notice Checks if the provided value is nonzero, reverts otherwise
/// @param value_ Value to check
/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0
function ensureNonzeroValue(uint256 value_) pure {
if (value_ == 0) {
revert ZeroValueNotAllowed();
}
}// SPDX-License-Identifier: UNLICENSED pragma solidity >0.0.0; import '@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol';
// SPDX-License-Identifier: UNLICENSED pragma solidity >0.0.0; import 'hardhat-deploy/solc_0.8/openzeppelin/proxy/transparent/ProxyAdmin.sol';
// SPDX-License-Identifier: UNLICENSED pragma solidity >0.0.0; import 'hardhat-deploy/solc_0.8/proxy/OptimizedTransparentUpgradeableProxy.sol';
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.25;
interface FeedRegistryInterface {
function latestRoundDataByName(
string memory base,
string memory quote
)
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function decimalsByName(string memory base, string memory quote) external view returns (uint8);
}pragma solidity 0.8.25;
interface IAccountantWithRateProviders {
function getRate() external view returns (uint256);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface IAnkrBNB {
function sharesToBonds(uint256 amount) external view returns (uint256);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface IEtherFiLiquidityPool {
function amountForShare(uint256 _share) external view returns (uint256);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface IPendlePtOracle {
function getPtToAssetRate(address market, uint32 duration) external view returns (uint256);
function getOracleState(
address market,
uint32 duration
)
external
view
returns (bool increaseCardinalityRequired, uint16 cardinalityRequired, bool oldestObservationSatisfied);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface IPStakePool {
struct Data {
uint256 totalWei;
uint256 poolTokenSupply;
}
/**
* @dev The current exchange rate for converting stkBNB to BNB.
*/
function exchangeRate() external view returns (Data memory);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface ISFrax {
function convertToAssets(uint256 shares) external view returns (uint256);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface ISfrxEthFraxOracle {
function getPrices() external view returns (bool _isbadData, uint256 _priceLow, uint256 _priceHigh);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface IStaderStakeManager {
function convertBnbXToBnb(uint256 _amount) external view returns (uint256);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.25;
interface IStETH {
function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface ISynclubStakeManager {
function convertSnBnbToBnb(uint256 _amount) external view returns (uint256);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
interface IWBETH {
function exchangeRate() external view returns (uint256);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.25;
interface OracleInterface {
function getPrice(address asset) external view returns (uint256);
}
interface ResilientOracleInterface is OracleInterface {
function updatePrice(address vToken) external;
function updateAssetPrice(address asset) external;
function getUnderlyingPrice(address vToken) external view returns (uint256);
}
interface TwapInterface is OracleInterface {
function updateTwap(address asset) external returns (uint256);
}
interface BoundValidatorInterface {
function validatePriceWithAnchorPrice(
address asset,
uint256 reporterPrice,
uint256 anchorPrice
) external view returns (bool);
}// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: 2022 Venus
pragma solidity ^0.8.25;
interface PublicResolverInterface {
function addr(bytes32 node) external view returns (address payable);
}// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2021 Pyth Data Foundation
pragma solidity ^0.8.25;
contract PythStructs {
// A price with a degree of uncertainty, represented as a price +- a confidence interval.
//
// The confidence interval roughly corresponds to the standard error of a normal distribution.
// Both the price and confidence are stored in a fixed-point numeric representation,
// `x * (10^expo)`, where `expo` is the exponent.
//
// Please refer to the documentation at https://docs.pyth.network/consumers/best-practices for how
// to how this price safely.
struct Price {
// Price
int64 price;
// Confidence interval around the price
uint64 conf;
// Price exponent
int32 expo;
// Unix timestamp describing when the price was published
uint256 publishTime;
}
// PriceFeed represents a current aggregate price from pyth publisher feeds.
struct PriceFeed {
// The price ID.
bytes32 id;
// Latest available price
Price price;
// Latest available exponentially-weighted moving average price
Price emaPrice;
}
}
/// @title Consume prices from the Pyth Network (https://pyth.network/).
/// @dev Please refer to the guidance at https://docs.pyth.network/consumers/best-practices
/// for how to consume prices safely.
/// @author Pyth Data Association
interface IPyth {
/// @dev Emitted when an update for price feed with `id` is processed successfully.
/// @param id The Pyth Price Feed ID.
/// @param fresh True if the price update is more recent and stored.
/// @param chainId ID of the source chain that the batch price update containing this price.
/// This value comes from Wormhole, and you can find the corresponding chains
/// at https://docs.wormholenetwork.com/wormhole/contracts.
/// @param sequenceNumber Sequence number of the batch price update containing this price.
/// @param lastPublishTime Publish time of the previously stored price.
/// @param publishTime Publish time of the given price update.
/// @param price Price of the given price update.
/// @param conf Confidence interval of the given price update.
event PriceFeedUpdate(
bytes32 indexed id,
bool indexed fresh,
uint16 chainId,
uint64 sequenceNumber,
uint256 lastPublishTime,
uint256 publishTime,
int64 price,
uint64 conf
);
/// @dev Emitted when a batch price update is processed successfully.
/// @param chainId ID of the source chain that the batch price update comes from.
/// @param sequenceNumber Sequence number of the batch price update.
/// @param batchSize Number of prices within the batch price update.
/// @param freshPricesInBatch Number of prices that were more recent and were stored.
event BatchPriceFeedUpdate(uint16 chainId, uint64 sequenceNumber, uint256 batchSize, uint256 freshPricesInBatch);
/// @dev Emitted when a call to `updatePriceFeeds` is processed successfully.
/// @param sender Sender of the call (`msg.sender`).
/// @param batchCount Number of batches that this function processed.
/// @param fee Amount of paid fee for updating the prices.
event UpdatePriceFeeds(address indexed sender, uint256 batchCount, uint256 fee);
/// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time
function getValidTimePeriod() external view returns (uint256 validTimePeriod);
/// @notice Returns the price and confidence interval.
/// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds.
/// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPrice(bytes32 id) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price and confidence interval.
/// @dev Reverts if the EMA price is not available.
/// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPrice(bytes32 id) external view returns (PythStructs.Price memory price);
/// @notice Returns the price of a price feed without any sanity checks.
/// @dev This function returns the most recent price update in this contract without any recency checks.
/// This function is unsafe as the returned price update may be arbitrarily far in the past.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getPrice` or `getPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceUnsafe(bytes32 id) external view returns (PythStructs.Price memory price);
/// @notice Returns the price that is no older than `age` seconds of the current time.
/// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceNoOlderThan(bytes32 id, uint256 age) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.
/// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.
/// However, if the price is not recent this function returns the latest available price.
///
/// The returned price can be from arbitrarily far in the past; this function makes no guarantees that
/// the returned price is recent or useful for any particular application.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceUnsafe(bytes32 id) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds
/// of the current time.
/// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceNoOlderThan(bytes32 id, uint256 age) external view returns (PythStructs.Price memory price);
/// @notice Update price feeds with given update messages.
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
/// Prices will be updated if they are more recent than the current stored prices.
/// The call will succeed even if the update is not the most recent.
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
function updatePriceFeeds(bytes[] calldata updateData) external payable;
/// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is
/// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the
/// given `publishTimes` for the price feeds and does not read the actual price
/// update publish time within `updateData`.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
///
/// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime
/// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have
/// a newer or equal publish time than the given publish time, it will reject the transaction to save gas.
/// Otherwise, it calls updatePriceFeeds method to update the prices.
///
/// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`
function updatePriceFeedsIfNecessary(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64[] calldata publishTimes
) external payable;
/// @notice Returns the required fee to update an array of price updates.
/// @param updateDataSize Number of price updates.
/// @return feeAmount The required fee in Wei.
function getUpdateFee(uint256 updateDataSize) external view returns (uint256 feeAmount);
}
abstract contract AbstractPyth is IPyth {
/// @notice Returns the price feed with given id.
/// @dev Reverts if the price does not exist.
/// @param id The Pyth Price Feed ID of which to fetch the PriceFeed.
function queryPriceFeed(bytes32 id) public view virtual returns (PythStructs.PriceFeed memory priceFeed);
/// @notice Returns true if a price feed with the given id exists.
/// @param id The Pyth Price Feed ID of which to check its existence.
function priceFeedExists(bytes32 id) public view virtual returns (bool exists);
function getValidTimePeriod() public view virtual override returns (uint256 validTimePeriod);
function getPrice(bytes32 id) external view override returns (PythStructs.Price memory price) {
return getPriceNoOlderThan(id, getValidTimePeriod());
}
function getEmaPrice(bytes32 id) external view override returns (PythStructs.Price memory price) {
return getEmaPriceNoOlderThan(id, getValidTimePeriod());
}
function getPriceUnsafe(bytes32 id) public view override returns (PythStructs.Price memory price) {
PythStructs.PriceFeed memory priceFeed = queryPriceFeed(id);
return priceFeed.price;
}
function getPriceNoOlderThan(
bytes32 id,
uint256 age
) public view override returns (PythStructs.Price memory price) {
price = getPriceUnsafe(id);
require(diff(block.timestamp, price.publishTime) <= age, "no price available which is recent enough");
return price;
}
function getEmaPriceUnsafe(bytes32 id) public view override returns (PythStructs.Price memory price) {
PythStructs.PriceFeed memory priceFeed = queryPriceFeed(id);
return priceFeed.emaPrice;
}
function getEmaPriceNoOlderThan(
bytes32 id,
uint256 age
) public view override returns (PythStructs.Price memory price) {
price = getEmaPriceUnsafe(id);
require(diff(block.timestamp, price.publishTime) <= age, "no ema price available which is recent enough");
return price;
}
function diff(uint256 x, uint256 y) internal pure returns (uint256) {
if (x > y) {
return x - y;
} else {
return y - x;
}
}
// Access modifier is overridden to public to be able to call it locally.
function updatePriceFeeds(bytes[] calldata updateData) public payable virtual override;
function updatePriceFeedsIfNecessary(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64[] calldata publishTimes
) external payable override {
require(priceIds.length == publishTimes.length, "priceIds and publishTimes arrays should have same length");
bool updateNeeded = false;
for (uint256 i = 0; i < priceIds.length; ) {
if (!priceFeedExists(priceIds[i]) || queryPriceFeed(priceIds[i]).price.publishTime < publishTimes[i]) {
updateNeeded = true;
break;
}
unchecked {
i++;
}
}
require(updateNeeded, "no prices in the submitted batch have fresh prices, so this update will have no effect");
updatePriceFeeds(updateData);
}
}// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: 2022 Venus
pragma solidity ^0.8.25;
interface SIDRegistryInterface {
function resolver(bytes32 node) external view returns (address);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.25;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface VBep20Interface is IERC20Metadata {
/**
* @notice Underlying asset for this VToken
*/
function underlying() external view returns (address);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { IAnkrBNB } from "../interfaces/IAnkrBNB.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
/**
* @title AnkrBNBOracle
* @author Venus
* @notice This oracle fetches the price of ankrBNB asset
*/
contract AnkrBNBOracle is CorrelatedTokenOracle {
/// @notice This is used as token address of BNB on BSC
address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address ankrBNB,
address resilientOracle
) CorrelatedTokenOracle(ankrBNB, NATIVE_TOKEN_ADDR, resilientOracle) {}
/**
* @notice Fetches the amount of BNB for 1 ankrBNB
* @return amount The amount of BNB for ankrBNB
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return IAnkrBNB(CORRELATED_TOKEN).sharesToBonds(EXP_SCALE);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../interfaces/VBep20Interface.sol";
import "../interfaces/SIDRegistryInterface.sol";
import "../interfaces/FeedRegistryInterface.sol";
import "../interfaces/PublicResolverInterface.sol";
import "../interfaces/OracleInterface.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol";
import "../interfaces/OracleInterface.sol";
/**
* @title BinanceOracle
* @author Venus
* @notice This oracle fetches price of assets from Binance.
*/
contract BinanceOracle is AccessControlledV8, OracleInterface {
/// @notice Used to fetch feed registry address.
address public sidRegistryAddress;
/// @notice Set this as asset address for BNB. This is the underlying address for vBNB
address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
/// @notice Max stale period configuration for assets
mapping(string => uint256) public maxStalePeriod;
/// @notice Override symbols to be compatible with Binance feed registry
mapping(string => string) public symbols;
/// @notice Used to fetch price of assets used directly when space ID is not supported by current chain.
address public feedRegistryAddress;
/// @notice Emits when asset stale period is updated.
event MaxStalePeriodAdded(string indexed asset, uint256 maxStalePeriod);
/// @notice Emits when symbol of the asset is updated.
event SymbolOverridden(string indexed symbol, string overriddenSymbol);
/// @notice Emits when address of feed registry is updated.
event FeedRegistryUpdated(address indexed oldFeedRegistry, address indexed newFeedRegistry);
/**
* @notice Checks whether an address is null or not
*/
modifier notNullAddress(address someone) {
if (someone == address(0)) revert("can't be zero address");
_;
}
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Sets the contracts required to fetch prices
* @param _sidRegistryAddress Address of SID registry
* @param _accessControlManager Address of the access control manager contract
*/
function initialize(address _sidRegistryAddress, address _accessControlManager) external initializer {
sidRegistryAddress = _sidRegistryAddress;
__AccessControlled_init(_accessControlManager);
}
/**
* @notice Used to set the max stale period of an asset
* @param symbol The symbol of the asset
* @param _maxStalePeriod The max stake period
*/
function setMaxStalePeriod(string memory symbol, uint256 _maxStalePeriod) external {
_checkAccessAllowed("setMaxStalePeriod(string,uint256)");
if (_maxStalePeriod == 0) revert("stale period can't be zero");
if (bytes(symbol).length == 0) revert("symbol cannot be empty");
maxStalePeriod[symbol] = _maxStalePeriod;
emit MaxStalePeriodAdded(symbol, _maxStalePeriod);
}
/**
* @notice Used to override a symbol when fetching price
* @param symbol The symbol to override
* @param overrideSymbol The symbol after override
*/
function setSymbolOverride(string calldata symbol, string calldata overrideSymbol) external {
_checkAccessAllowed("setSymbolOverride(string,string)");
if (bytes(symbol).length == 0) revert("symbol cannot be empty");
symbols[symbol] = overrideSymbol;
emit SymbolOverridden(symbol, overrideSymbol);
}
/**
* @notice Used to set feed registry address when current chain does not support space ID.
* @param newfeedRegistryAddress Address of new feed registry.
*/
function setFeedRegistryAddress(
address newfeedRegistryAddress
) external notNullAddress(newfeedRegistryAddress) onlyOwner {
if (sidRegistryAddress != address(0)) revert("sidRegistryAddress must be zero");
emit FeedRegistryUpdated(feedRegistryAddress, newfeedRegistryAddress);
feedRegistryAddress = newfeedRegistryAddress;
}
/**
* @notice Uses Space ID to fetch the feed registry address
* @return feedRegistryAddress Address of binance oracle feed registry.
*/
function getFeedRegistryAddress() public view returns (address) {
bytes32 nodeHash = 0x94fe3821e0768eb35012484db4df61890f9a6ca5bfa984ef8ff717e73139faff;
SIDRegistryInterface sidRegistry = SIDRegistryInterface(sidRegistryAddress);
address publicResolverAddress = sidRegistry.resolver(nodeHash);
PublicResolverInterface publicResolver = PublicResolverInterface(publicResolverAddress);
return publicResolver.addr(nodeHash);
}
/**
* @notice Gets the price of a asset from the binance oracle
* @param asset Address of the asset
* @return Price in USD
*/
function getPrice(address asset) public view returns (uint256) {
string memory symbol;
uint256 decimals;
if (asset == BNB_ADDR) {
symbol = "BNB";
decimals = 18;
} else {
IERC20Metadata token = IERC20Metadata(asset);
symbol = token.symbol();
decimals = token.decimals();
}
string memory overrideSymbol = symbols[symbol];
if (bytes(overrideSymbol).length != 0) {
symbol = overrideSymbol;
}
return _getPrice(symbol, decimals);
}
function _getPrice(string memory symbol, uint256 decimals) internal view returns (uint256) {
FeedRegistryInterface feedRegistry;
if (sidRegistryAddress != address(0)) {
// If sidRegistryAddress is available, fetch feedRegistryAddress from sidRegistry
feedRegistry = FeedRegistryInterface(getFeedRegistryAddress());
} else {
// Use feedRegistry directly if sidRegistryAddress is not available
feedRegistry = FeedRegistryInterface(feedRegistryAddress);
}
(, int256 answer, , uint256 updatedAt, ) = feedRegistry.latestRoundDataByName(symbol, "USD");
if (answer <= 0) revert("invalid binance oracle price");
if (block.timestamp < updatedAt) revert("updatedAt exceeds block time");
uint256 deltaTime;
unchecked {
deltaTime = block.timestamp - updatedAt;
}
if (deltaTime > maxStalePeriod[symbol]) revert("binance oracle price expired");
uint256 decimalDelta = feedRegistry.decimalsByName(symbol, "USD");
return (uint256(answer) * (10 ** (18 - decimalDelta))) * (10 ** (18 - decimals));
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { IStaderStakeManager } from "../interfaces/IStaderStakeManager.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
/**
* @title BNBxOracle
* @author Venus
* @notice This oracle fetches the price of BNBx asset
*/
contract BNBxOracle is CorrelatedTokenOracle {
/// @notice This is used as token address of BNB on BSC
address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
/// @notice Address of StakeManager
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IStaderStakeManager public immutable STAKE_MANAGER;
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address stakeManager,
address bnbx,
address resilientOracle
) CorrelatedTokenOracle(bnbx, NATIVE_TOKEN_ADDR, resilientOracle) {
ensureNonzeroAddress(stakeManager);
STAKE_MANAGER = IStaderStakeManager(stakeManager);
}
/**
* @notice Fetches the amount of BNB for 1 BNBx
* @return price The amount of BNB for BNBx
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return STAKE_MANAGER.convertBnbXToBnb(EXP_SCALE);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "../interfaces/VBep20Interface.sol";
import "../interfaces/OracleInterface.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol";
/**
* @title BoundValidator
* @author Venus
* @notice The BoundValidator contract is used to validate prices fetched from two different sources.
* Each asset has an upper and lower bound ratio set in the config. In order for a price to be valid
* it must fall within this range of the validator price.
*/
contract BoundValidator is AccessControlledV8, BoundValidatorInterface {
struct ValidateConfig {
/// @notice asset address
address asset;
/// @notice Upper bound of deviation between reported price and anchor price,
/// beyond which the reported price will be invalidated
uint256 upperBoundRatio;
/// @notice Lower bound of deviation between reported price and anchor price,
/// below which the reported price will be invalidated
uint256 lowerBoundRatio;
}
/// @notice validation configs by asset
mapping(address => ValidateConfig) public validateConfigs;
/// @notice Emit this event when new validation configs are added
event ValidateConfigAdded(address indexed asset, uint256 indexed upperBound, uint256 indexed lowerBound);
/// @notice Constructor for the implementation contract. Sets immutable variables.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initializes the owner of the contract
* @param accessControlManager_ Address of the access control manager contract
*/
function initialize(address accessControlManager_) external initializer {
__AccessControlled_init(accessControlManager_);
}
/**
* @notice Add multiple validation configs at the same time
* @param configs Array of validation configs
* @custom:access Only Governance
* @custom:error Zero length error is thrown if length of the config array is 0
* @custom:event Emits ValidateConfigAdded for each validation config that is successfully set
*/
function setValidateConfigs(ValidateConfig[] memory configs) external {
uint256 length = configs.length;
if (length == 0) revert("invalid validate config length");
for (uint256 i; i < length; ) {
setValidateConfig(configs[i]);
unchecked {
++i;
}
}
}
/**
* @notice Add a single validation config
* @param config Validation config struct
* @custom:access Only Governance
* @custom:error Null address error is thrown if asset address is null
* @custom:error Range error thrown if bound ratio is not positive
* @custom:error Range error thrown if lower bound is greater than or equal to upper bound
* @custom:event Emits ValidateConfigAdded when a validation config is successfully set
*/
function setValidateConfig(ValidateConfig memory config) public {
_checkAccessAllowed("setValidateConfig(ValidateConfig)");
if (config.asset == address(0)) revert("asset can't be zero address");
if (config.upperBoundRatio == 0 || config.lowerBoundRatio == 0) revert("bound must be positive");
if (config.upperBoundRatio <= config.lowerBoundRatio) revert("upper bound must be higher than lowner bound");
validateConfigs[config.asset] = config;
emit ValidateConfigAdded(config.asset, config.upperBoundRatio, config.lowerBoundRatio);
}
/**
* @notice Test reported asset price against anchor price
* @param asset asset address
* @param reportedPrice The price to be tested
* @custom:error Missing error thrown if asset config is not set
* @custom:error Price error thrown if anchor price is not valid
*/
function validatePriceWithAnchorPrice(
address asset,
uint256 reportedPrice,
uint256 anchorPrice
) public view virtual override returns (bool) {
if (validateConfigs[asset].upperBoundRatio == 0) revert("validation config not exist");
if (anchorPrice == 0) revert("anchor price is not valid");
return _isWithinAnchor(asset, reportedPrice, anchorPrice);
}
/**
* @notice Test whether the reported price is within the valid bounds
* @param asset Asset address
* @param reportedPrice The price to be tested
* @param anchorPrice The reported price must be within the the valid bounds of this price
*/
function _isWithinAnchor(address asset, uint256 reportedPrice, uint256 anchorPrice) private view returns (bool) {
if (reportedPrice != 0) {
// we need to multiply anchorPrice by 1e18 to make the ratio 18 decimals
uint256 anchorRatio = (anchorPrice * 1e18) / reportedPrice;
uint256 upperBoundAnchorRatio = validateConfigs[asset].upperBoundRatio;
uint256 lowerBoundAnchorRatio = validateConfigs[asset].lowerBoundRatio;
return anchorRatio <= upperBoundAnchorRatio && anchorRatio >= lowerBoundAnchorRatio;
}
return false;
}
// BoundValidator is to get inherited, so it's a good practice to add some storage gaps like
// OpenZepplin proposed in their contracts: https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
// solhint-disable-next-line
uint256[49] private __gap;
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "../interfaces/VBep20Interface.sol";
import "../interfaces/OracleInterface.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol";
/**
* @title ChainlinkOracle
* @author Venus
* @notice This oracle fetches prices of assets from the Chainlink oracle.
*/
contract ChainlinkOracle is AccessControlledV8, OracleInterface {
struct TokenConfig {
/// @notice Underlying token address, which can't be a null address
/// @notice Used to check if a token is supported
/// @notice 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB address for native tokens
/// (e.g BNB for BNB chain, ETH for Ethereum network)
address asset;
/// @notice Chainlink feed address
address feed;
/// @notice Price expiration period of this asset
uint256 maxStalePeriod;
}
/// @notice Set this as asset address for native token on each chain.
/// This is the underlying address for vBNB on BNB chain or an underlying asset for a native market on any chain.
address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
/// @notice Manually set an override price, useful under extenuating conditions such as price feed failure
mapping(address => uint256) public prices;
/// @notice Token config by assets
mapping(address => TokenConfig) public tokenConfigs;
/// @notice Emit when a price is manually set
event PricePosted(address indexed asset, uint256 previousPriceMantissa, uint256 newPriceMantissa);
/// @notice Emit when a token config is added
event TokenConfigAdded(address indexed asset, address feed, uint256 maxStalePeriod);
modifier notNullAddress(address someone) {
if (someone == address(0)) revert("can't be zero address");
_;
}
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initializes the owner of the contract
* @param accessControlManager_ Address of the access control manager contract
*/
function initialize(address accessControlManager_) external initializer {
__AccessControlled_init(accessControlManager_);
}
/**
* @notice Manually set the price of a given asset
* @param asset Asset address
* @param price Asset price in 18 decimals
* @custom:access Only Governance
* @custom:event Emits PricePosted event on succesfully setup of asset price
*/
function setDirectPrice(address asset, uint256 price) external notNullAddress(asset) {
_checkAccessAllowed("setDirectPrice(address,uint256)");
uint256 previousPriceMantissa = prices[asset];
prices[asset] = price;
emit PricePosted(asset, previousPriceMantissa, price);
}
/**
* @notice Add multiple token configs at the same time
* @param tokenConfigs_ config array
* @custom:access Only Governance
* @custom:error Zero length error thrown, if length of the array in parameter is 0
*/
function setTokenConfigs(TokenConfig[] memory tokenConfigs_) external {
if (tokenConfigs_.length == 0) revert("length can't be 0");
uint256 numTokenConfigs = tokenConfigs_.length;
for (uint256 i; i < numTokenConfigs; ) {
setTokenConfig(tokenConfigs_[i]);
unchecked {
++i;
}
}
}
/**
* @notice Add single token config. asset & feed cannot be null addresses and maxStalePeriod must be positive
* @param tokenConfig Token config struct
* @custom:access Only Governance
* @custom:error NotNullAddress error is thrown if asset address is null
* @custom:error NotNullAddress error is thrown if token feed address is null
* @custom:error Range error is thrown if maxStale period of token is not greater than zero
* @custom:event Emits TokenConfigAdded event on succesfully setting of the token config
*/
function setTokenConfig(
TokenConfig memory tokenConfig
) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.feed) {
_checkAccessAllowed("setTokenConfig(TokenConfig)");
if (tokenConfig.maxStalePeriod == 0) revert("stale period can't be zero");
tokenConfigs[tokenConfig.asset] = tokenConfig;
emit TokenConfigAdded(tokenConfig.asset, tokenConfig.feed, tokenConfig.maxStalePeriod);
}
/**
* @notice Gets the price of a asset from the chainlink oracle
* @param asset Address of the asset
* @return Price in USD from Chainlink or a manually set price for the asset
*/
function getPrice(address asset) public view virtual returns (uint256) {
uint256 decimals;
if (asset == NATIVE_TOKEN_ADDR) {
decimals = 18;
} else {
IERC20Metadata token = IERC20Metadata(asset);
decimals = token.decimals();
}
return _getPriceInternal(asset, decimals);
}
/**
* @notice Gets the Chainlink price for a given asset
* @param asset address of the asset
* @param decimals decimals of the asset
* @return price Asset price in USD or a manually set price of the asset
*/
function _getPriceInternal(address asset, uint256 decimals) internal view returns (uint256 price) {
uint256 tokenPrice = prices[asset];
if (tokenPrice != 0) {
price = tokenPrice;
} else {
price = _getChainlinkPrice(asset);
}
uint256 decimalDelta = 18 - decimals;
return price * (10 ** decimalDelta);
}
/**
* @notice Get the Chainlink price for an asset, revert if token config doesn't exist
* @dev The precision of the price feed is used to ensure the returned price has 18 decimals of precision
* @param asset Address of the asset
* @return price Price in USD, with 18 decimals of precision
* @custom:error NotNullAddress error is thrown if the asset address is null
* @custom:error Price error is thrown if the Chainlink price of asset is not greater than zero
* @custom:error Timing error is thrown if current timestamp is less than the last updatedAt timestamp
* @custom:error Timing error is thrown if time difference between current time and last updated time
* is greater than maxStalePeriod
*/
function _getChainlinkPrice(
address asset
) private view notNullAddress(tokenConfigs[asset].asset) returns (uint256) {
TokenConfig memory tokenConfig = tokenConfigs[asset];
AggregatorV3Interface feed = AggregatorV3Interface(tokenConfig.feed);
// note: maxStalePeriod cannot be 0
uint256 maxStalePeriod = tokenConfig.maxStalePeriod;
// Chainlink USD-denominated feeds store answers at 8 decimals, mostly
uint256 decimalDelta = 18 - feed.decimals();
(, int256 answer, , uint256 updatedAt, ) = feed.latestRoundData();
if (answer <= 0) revert("chainlink price must be positive");
if (block.timestamp < updatedAt) revert("updatedAt exceeds block time");
uint256 deltaTime;
unchecked {
deltaTime = block.timestamp - updatedAt;
}
if (deltaTime > maxStalePeriod) revert("chainlink price expired");
return uint256(answer) * (10 ** decimalDelta);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { OracleInterface } from "../../interfaces/OracleInterface.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/**
* @title CorrelatedTokenOracle
* @notice This oracle fetches the price of a token that is correlated to another token.
*/
abstract contract CorrelatedTokenOracle is OracleInterface {
/// @notice Address of the correlated token
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address public immutable CORRELATED_TOKEN;
/// @notice Address of the underlying token
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address public immutable UNDERLYING_TOKEN;
/// @notice Address of Resilient Oracle
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
OracleInterface public immutable RESILIENT_ORACLE;
/// @notice Thrown if the token address is invalid
error InvalidTokenAddress();
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address correlatedToken, address underlyingToken, address resilientOracle) {
ensureNonzeroAddress(correlatedToken);
ensureNonzeroAddress(underlyingToken);
ensureNonzeroAddress(resilientOracle);
CORRELATED_TOKEN = correlatedToken;
UNDERLYING_TOKEN = underlyingToken;
RESILIENT_ORACLE = OracleInterface(resilientOracle);
}
/**
* @notice Fetches the price of the correlated token
* @param asset Address of the correlated token
* @return price The price of the correlated token in scaled decimal places
*/
function getPrice(address asset) external view override returns (uint256) {
if (asset != CORRELATED_TOKEN) revert InvalidTokenAddress();
// get underlying token amount for 1 correlated token scaled by underlying token decimals
uint256 underlyingAmount = _getUnderlyingAmount();
// oracle returns (36 - asset decimal) scaled price
uint256 underlyingUSDPrice = RESILIENT_ORACLE.getPrice(UNDERLYING_TOKEN);
IERC20Metadata token = IERC20Metadata(CORRELATED_TOKEN);
uint256 decimals = token.decimals();
// underlyingAmount (for 1 correlated token) * underlyingUSDPrice / decimals(correlated token)
return (underlyingAmount * underlyingUSDPrice) / (10 ** decimals);
}
/**
* @notice Gets the underlying amount for correlated token
* @return underlyingAmount Amount of underlying token
*/
function _getUnderlyingAmount() internal view virtual returns (uint256);
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "../../interfaces/FeedRegistryInterface.sol";
contract MockBinanceFeedRegistry is FeedRegistryInterface {
mapping(string => uint256) public assetPrices;
function setAssetPrice(string memory base, uint256 price) external {
assetPrices[base] = price;
}
function latestRoundDataByName(
string memory base,
string memory quote
)
external
view
override
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
{
quote;
return (0, int256(assetPrices[base]), 0, block.timestamp - 10, 0);
}
function decimalsByName(string memory base, string memory quote) external view override returns (uint8) {
return 8;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { OracleInterface } from "../../interfaces/OracleInterface.sol";
contract MockBinanceOracle is OwnableUpgradeable, OracleInterface {
mapping(address => uint256) public assetPrices;
constructor() {}
function initialize() public initializer {}
function setPrice(address asset, uint256 price) external {
assetPrices[asset] = price;
}
function getPrice(address token) public view returns (uint256) {
return assetPrices[token];
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { OracleInterface } from "../../interfaces/OracleInterface.sol";
contract MockChainlinkOracle is OwnableUpgradeable, OracleInterface {
mapping(address => uint256) public assetPrices;
//set price in 6 decimal precision
constructor() {}
function initialize() public initializer {
__Ownable_init();
}
function setPrice(address asset, uint256 price) external {
assetPrices[asset] = price;
}
//https://compound.finance/docs/prices
function getPrice(address token) public view returns (uint256) {
return assetPrices[token];
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "../../interfaces/IPendlePtOracle.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MockPendlePtOracle is IPendlePtOracle, Ownable {
mapping(address => mapping(uint32 => uint256)) public ptToAssetRate;
constructor() Ownable() {}
function setPtToAssetRate(address market, uint32 duration, uint256 rate) external onlyOwner {
ptToAssetRate[market][duration] = rate;
}
function getPtToAssetRate(address market, uint32 duration) external view returns (uint256) {
return ptToAssetRate[market][duration];
}
function getOracleState(
address market,
uint32 duration
)
external
view
returns (bool increaseCardinalityRequired, uint16 cardinalityRequired, bool oldestObservationSatisfied)
{
return (false, 0, true);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { IPyth } from "../PythOracle.sol";
import { OracleInterface } from "../../interfaces/OracleInterface.sol";
contract MockPythOracle is OwnableUpgradeable {
mapping(address => uint256) public assetPrices;
/// @notice the actual pyth oracle address fetch & store the prices
IPyth public underlyingPythOracle;
//set price in 6 decimal precision
constructor() {}
function initialize(address underlyingPythOracle_) public initializer {
__Ownable_init();
if (underlyingPythOracle_ == address(0)) revert("pyth oracle cannot be zero address");
underlyingPythOracle = IPyth(underlyingPythOracle_);
}
function setPrice(address asset, uint256 price) external {
assetPrices[asset] = price;
}
//https://compound.finance/docs/prices
function getPrice(address token) public view returns (uint256) {
return assetPrices[token];
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "../../interfaces/ISfrxEthFraxOracle.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MockSfrxEthFraxOracle is ISfrxEthFraxOracle, Ownable {
bool public isBadData;
uint256 public priceLow;
uint256 public priceHigh;
constructor() Ownable() {}
function setPrices(bool _isBadData, uint256 _priceLow, uint256 _priceHigh) external onlyOwner {
isBadData = _isBadData;
priceLow = _priceLow;
priceHigh = _priceHigh;
}
function getPrices() external view override returns (bool, uint256, uint256) {
return (isBadData, priceLow, priceHigh);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
import { OracleInterface } from "../interfaces/OracleInterface.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/**
* @title OneJumpOracle
* @author Venus
* @notice This oracle fetches the price of an asset in through an intermediate asset
*/
contract OneJumpOracle is CorrelatedTokenOracle {
/// @notice Address of the intermediate oracle
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
OracleInterface public immutable INTERMEDIATE_ORACLE;
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address correlatedToken,
address underlyingToken,
address resilientOracle,
address intermediateOracle
) CorrelatedTokenOracle(correlatedToken, underlyingToken, resilientOracle) {
ensureNonzeroAddress(intermediateOracle);
INTERMEDIATE_ORACLE = OracleInterface(intermediateOracle);
}
/**
* @notice Fetches the amount of the underlying token for 1 correlated token, using the intermediate oracle
* @return amount The amount of the underlying token for 1 correlated token scaled by the underlying token decimals
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
uint256 underlyingDecimals = IERC20Metadata(UNDERLYING_TOKEN).decimals();
uint256 correlatedDecimals = IERC20Metadata(CORRELATED_TOKEN).decimals();
uint256 underlyingAmount = INTERMEDIATE_ORACLE.getPrice(CORRELATED_TOKEN);
return (underlyingAmount * (10 ** correlatedDecimals)) / (10 ** (36 - underlyingDecimals));
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { IPendlePtOracle } from "../interfaces/IPendlePtOracle.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { ensureNonzeroAddress, ensureNonzeroValue } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
/**
* @title PendleOracle
* @author Venus
* @notice This oracle fetches the price of a pendle token
*/
contract PendleOracle is CorrelatedTokenOracle {
/// @notice Address of the PT oracle
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IPendlePtOracle public immutable PT_ORACLE;
/// @notice Address of the market
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address public immutable MARKET;
/// @notice Twap duration for the oracle
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
uint32 public immutable TWAP_DURATION;
/// @notice Thrown if the duration is invalid
error InvalidDuration();
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address market,
address ptOracle,
address ptToken,
address underlyingToken,
address resilientOracle,
uint32 twapDuration
) CorrelatedTokenOracle(ptToken, underlyingToken, resilientOracle) {
ensureNonzeroAddress(market);
ensureNonzeroAddress(ptOracle);
ensureNonzeroValue(twapDuration);
MARKET = market;
PT_ORACLE = IPendlePtOracle(ptOracle);
TWAP_DURATION = twapDuration;
(bool increaseCardinalityRequired, , bool oldestObservationSatisfied) = PT_ORACLE.getOracleState(
MARKET,
TWAP_DURATION
);
if (increaseCardinalityRequired || !oldestObservationSatisfied) {
revert InvalidDuration();
}
}
/**
* @notice Fetches the amount of underlying token for 1 pendle token
* @return amount The amount of underlying token for pendle token
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return PT_ORACLE.getPtToAssetRate(MARKET, TWAP_DURATION);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/math/SignedMath.sol";
import "../interfaces/PythInterface.sol";
import "../interfaces/OracleInterface.sol";
import "../interfaces/VBep20Interface.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol";
/**
* @title PythOracle
* @author Venus
* @notice PythOracle contract reads prices from actual Pyth oracle contract which accepts, verifies and stores
* the updated prices from external sources
*/
contract PythOracle is AccessControlledV8, OracleInterface {
// To calculate 10 ** n(which is a signed type)
using SignedMath for int256;
// To cast int64/int8 types from Pyth to unsigned types
using SafeCast for int256;
struct TokenConfig {
bytes32 pythId;
address asset;
uint64 maxStalePeriod;
}
/// @notice Exponent scale (decimal precision) of prices
uint256 public constant EXP_SCALE = 1e18;
/// @notice Set this as asset address for BNB. This is the underlying for vBNB
address public constant BNB_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
/// @notice The actual pyth oracle address fetch & store the prices
IPyth public underlyingPythOracle;
/// @notice Token configs by asset address
mapping(address => TokenConfig) public tokenConfigs;
/// @notice Emit when setting a new pyth oracle address
event PythOracleSet(address indexed oldPythOracle, address indexed newPythOracle);
/// @notice Emit when a token config is added
event TokenConfigAdded(address indexed asset, bytes32 indexed pythId, uint64 indexed maxStalePeriod);
modifier notNullAddress(address someone) {
if (someone == address(0)) revert("can't be zero address");
_;
}
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initializes the owner of the contract and sets required contracts
* @param underlyingPythOracle_ Address of the Pyth oracle
* @param accessControlManager_ Address of the access control manager contract
*/
function initialize(
address underlyingPythOracle_,
address accessControlManager_
) external initializer notNullAddress(underlyingPythOracle_) {
__AccessControlled_init(accessControlManager_);
underlyingPythOracle = IPyth(underlyingPythOracle_);
emit PythOracleSet(address(0), underlyingPythOracle_);
}
/**
* @notice Batch set token configs
* @param tokenConfigs_ Token config array
* @custom:access Only Governance
* @custom:error Zero length error is thrown if length of the array in parameter is 0
*/
function setTokenConfigs(TokenConfig[] memory tokenConfigs_) external {
if (tokenConfigs_.length == 0) revert("length can't be 0");
uint256 numTokenConfigs = tokenConfigs_.length;
for (uint256 i; i < numTokenConfigs; ) {
setTokenConfig(tokenConfigs_[i]);
unchecked {
++i;
}
}
}
/**
* @notice Set the underlying Pyth oracle contract address
* @param underlyingPythOracle_ Pyth oracle contract address
* @custom:access Only Governance
* @custom:error NotNullAddress error thrown if underlyingPythOracle_ address is zero
* @custom:event Emits PythOracleSet event with address of Pyth oracle.
*/
function setUnderlyingPythOracle(
IPyth underlyingPythOracle_
) external notNullAddress(address(underlyingPythOracle_)) {
_checkAccessAllowed("setUnderlyingPythOracle(address)");
IPyth oldUnderlyingPythOracle = underlyingPythOracle;
underlyingPythOracle = underlyingPythOracle_;
emit PythOracleSet(address(oldUnderlyingPythOracle), address(underlyingPythOracle_));
}
/**
* @notice Set single token config. `maxStalePeriod` cannot be 0 and `asset` cannot be a null address
* @param tokenConfig Token config struct
* @custom:access Only Governance
* @custom:error Range error is thrown if max stale period is zero
* @custom:error NotNullAddress error is thrown if asset address is null
*/
function setTokenConfig(TokenConfig memory tokenConfig) public notNullAddress(tokenConfig.asset) {
_checkAccessAllowed("setTokenConfig(TokenConfig)");
if (tokenConfig.maxStalePeriod == 0) revert("max stale period cannot be 0");
tokenConfigs[tokenConfig.asset] = tokenConfig;
emit TokenConfigAdded(tokenConfig.asset, tokenConfig.pythId, tokenConfig.maxStalePeriod);
}
/**
* @notice Gets the price of a asset from the pyth oracle
* @param asset Address of the asset
* @return Price in USD
*/
function getPrice(address asset) public view returns (uint256) {
uint256 decimals;
if (asset == BNB_ADDR) {
decimals = 18;
} else {
IERC20Metadata token = IERC20Metadata(asset);
decimals = token.decimals();
}
return _getPriceInternal(asset, decimals);
}
function _getPriceInternal(address asset, uint256 decimals) internal view returns (uint256) {
TokenConfig storage tokenConfig = tokenConfigs[asset];
if (tokenConfig.asset == address(0)) revert("asset doesn't exist");
// if the price is expired after it's compared against `maxStalePeriod`, the following call will revert
PythStructs.Price memory priceInfo = underlyingPythOracle.getPriceNoOlderThan(
tokenConfig.pythId,
tokenConfig.maxStalePeriod
);
uint256 price = int256(priceInfo.price).toUint256();
if (price == 0) revert("invalid pyth oracle price");
// the price returned from Pyth is price ** 10^expo, which is the real dollar price of the assets
// we need to multiply it by 1e18 to make the price 18 decimals
if (priceInfo.expo > 0) {
return price * EXP_SCALE * (10 ** int256(priceInfo.expo).toUint256()) * (10 ** (18 - decimals));
} else {
return ((price * EXP_SCALE) / (10 ** int256(-priceInfo.expo).toUint256())) * (10 ** (18 - decimals));
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
import { ChainlinkOracle } from "./ChainlinkOracle.sol";
import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
/**
@title Sequencer Chain Link Oracle
@notice Oracle to fetch price using chainlink oracles on L2s with sequencer
*/
contract SequencerChainlinkOracle is ChainlinkOracle {
/// @notice L2 Sequencer feed
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
AggregatorV3Interface public immutable sequencer;
/// @notice L2 Sequencer grace period
uint256 public constant GRACE_PERIOD_TIME = 3600;
/**
@notice Contract constructor
@param _sequencer L2 sequencer
@custom:oz-upgrades-unsafe-allow constructor
*/
constructor(AggregatorV3Interface _sequencer) ChainlinkOracle() {
require(address(_sequencer) != address(0), "zero address");
sequencer = _sequencer;
}
/// @inheritdoc ChainlinkOracle
function getPrice(address asset) public view override returns (uint) {
if (!isSequencerActive()) revert("L2 sequencer unavailable");
return super.getPrice(asset);
}
function isSequencerActive() internal view returns (bool) {
// answer from oracle is a variable with a value of either 1 or 0
// 0: The sequencer is up
// 1: The sequencer is down
// startedAt: This timestamp indicates when the sequencer changed status
(, int256 answer, uint256 startedAt, , ) = sequencer.latestRoundData();
if (block.timestamp - startedAt <= GRACE_PERIOD_TIME || answer == 1) return false;
return true;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { ISFrax } from "../interfaces/ISFrax.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
/**
* @title SFraxOracle
* @author Venus
* @notice This oracle fetches the price of sFrax
*/
contract SFraxOracle is CorrelatedTokenOracle {
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address sFrax,
address frax,
address resilientOracle
) CorrelatedTokenOracle(sFrax, frax, resilientOracle) {}
/**
* @notice Fetches the amount of FRAX for 1 sFrax
* @return amount The amount of FRAX for sFrax
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return ISFrax(CORRELATED_TOKEN).convertToAssets(EXP_SCALE);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { ISfrxEthFraxOracle } from "../interfaces/ISfrxEthFraxOracle.sol";
import { ensureNonzeroAddress, ensureNonzeroValue } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
import { AccessControlledV8 } from "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol";
import { OracleInterface } from "../interfaces/OracleInterface.sol";
/**
* @title SFrxETHOracle
* @author Venus
* @notice This oracle fetches the price of sfrxETH
*/
contract SFrxETHOracle is AccessControlledV8, OracleInterface {
/// @notice Address of SfrxEthFraxOracle
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
ISfrxEthFraxOracle public immutable SFRXETH_FRAX_ORACLE;
/// @notice Address of sfrxETH
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address public immutable SFRXETH;
/// @notice Maximum allowed price difference
uint256 public maxAllowedPriceDifference;
/// @notice Emits when the maximum allowed price difference is updated
event MaxAllowedPriceDifferenceUpdated(uint256 oldMaxAllowedPriceDifference, uint256 newMaxAllowedPriceDifference);
/// @notice Thrown if the price data is invalid
error BadPriceData();
/// @notice Thrown if the price difference exceeds the allowed limit
error PriceDifferenceExceeded();
/// @notice Thrown if the token address is invalid
error InvalidTokenAddress();
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
/// @custom:error ZeroAddressNotAllowed is thrown when `_sfrxEthFraxOracle` or `_sfrxETH` are the zero address
constructor(address _sfrxEthFraxOracle, address _sfrxETH) {
ensureNonzeroAddress(_sfrxEthFraxOracle);
ensureNonzeroAddress(_sfrxETH);
SFRXETH_FRAX_ORACLE = ISfrxEthFraxOracle(_sfrxEthFraxOracle);
SFRXETH = _sfrxETH;
_disableInitializers();
}
/**
* @notice Sets the contracts required to fetch prices
* @param _accessControlManager Address of the access control manager contract
* @param _maxAllowedPriceDifference Maximum allowed price difference
* @custom:error ZeroValueNotAllowed is thrown if `_maxAllowedPriceDifference` is zero
*/
function initialize(address _accessControlManager, uint256 _maxAllowedPriceDifference) external initializer {
ensureNonzeroValue(_maxAllowedPriceDifference);
__AccessControlled_init(_accessControlManager);
maxAllowedPriceDifference = _maxAllowedPriceDifference;
}
/**
* @notice Sets the maximum allowed price difference
* @param _maxAllowedPriceDifference Maximum allowed price difference
* @custom:error ZeroValueNotAllowed is thrown if `_maxAllowedPriceDifference` is zero
*/
function setMaxAllowedPriceDifference(uint256 _maxAllowedPriceDifference) external {
_checkAccessAllowed("setMaxAllowedPriceDifference(uint256)");
ensureNonzeroValue(_maxAllowedPriceDifference);
emit MaxAllowedPriceDifferenceUpdated(maxAllowedPriceDifference, _maxAllowedPriceDifference);
maxAllowedPriceDifference = _maxAllowedPriceDifference;
}
/**
* @notice Fetches the USD price of sfrxETH
* @param asset Address of the sfrxETH token
* @return price The price scaled by 1e18
* @custom:error InvalidTokenAddress is thrown when the `asset` is not the sfrxETH token (`SFRXETH`)
* @custom:error BadPriceData is thrown if the `SFRXETH_FRAX_ORACLE` oracle informs it has bad data
* @custom:error ZeroValueNotAllowed is thrown if the prices (low or high, in USD) are zero
* @custom:error PriceDifferenceExceeded is thrown if priceHigh/priceLow is greater than `maxAllowedPriceDifference`
*/
function getPrice(address asset) external view returns (uint256) {
if (asset != SFRXETH) revert InvalidTokenAddress();
(bool isBadData, uint256 priceLow, uint256 priceHigh) = SFRXETH_FRAX_ORACLE.getPrices();
if (isBadData) revert BadPriceData();
// calculate price in USD
uint256 priceHighInUSD = (EXP_SCALE ** 2) / priceLow;
uint256 priceLowInUSD = (EXP_SCALE ** 2) / priceHigh;
ensureNonzeroValue(priceHighInUSD);
ensureNonzeroValue(priceLowInUSD);
// validate price difference
uint256 difference = (priceHighInUSD * EXP_SCALE) / priceLowInUSD;
if (difference > maxAllowedPriceDifference) revert PriceDifferenceExceeded();
// calculate and return average price
return (priceHighInUSD + priceLowInUSD) / 2;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { ISynclubStakeManager } from "../interfaces/ISynclubStakeManager.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
/**
* @title SlisBNBOracle
* @author Venus
* @notice This oracle fetches the price of slisBNB asset
*/
contract SlisBNBOracle is CorrelatedTokenOracle {
/// @notice This is used as token address of BNB on BSC
address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
/// @notice Address of StakeManager
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
ISynclubStakeManager public immutable STAKE_MANAGER;
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address stakeManager,
address slisBNB,
address resilientOracle
) CorrelatedTokenOracle(slisBNB, NATIVE_TOKEN_ADDR, resilientOracle) {
ensureNonzeroAddress(stakeManager);
STAKE_MANAGER = ISynclubStakeManager(stakeManager);
}
/**
* @notice Fetches the amount of BNB for 1 slisBNB
* @return amount The amount of BNB for slisBNB
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return STAKE_MANAGER.convertSnBnbToBnb(EXP_SCALE);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { IPStakePool } from "../interfaces/IPStakePool.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
/**
* @title StkBNBOracle
* @author Venus
* @notice This oracle fetches the price of stkBNB asset
*/
contract StkBNBOracle is CorrelatedTokenOracle {
/// @notice This is used as token address of BNB on BSC
address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
/// @notice Address of StakePool
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IPStakePool public immutable STAKE_POOL;
/// @notice Thrown if the pool token supply is zero
error PoolTokenSupplyIsZero();
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address stakePool,
address stkBNB,
address resilientOracle
) CorrelatedTokenOracle(stkBNB, NATIVE_TOKEN_ADDR, resilientOracle) {
ensureNonzeroAddress(stakePool);
STAKE_POOL = IPStakePool(stakePool);
}
/**
* @notice Fetches the amount of BNB for 1 stkBNB
* @return price The amount of BNB for stkBNB
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
IPStakePool.Data memory exchangeRateData = STAKE_POOL.exchangeRate();
if (exchangeRateData.poolTokenSupply == 0) {
revert PoolTokenSupplyIsZero();
}
return (exchangeRateData.totalWei * EXP_SCALE) / exchangeRateData.poolTokenSupply;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { IWBETH } from "../interfaces/IWBETH.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
/**
* @title WBETHOracle
* @author Venus
* @notice This oracle fetches the price of wBETH asset
*/
contract WBETHOracle is CorrelatedTokenOracle {
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address wbeth,
address eth,
address resilientOracle
) CorrelatedTokenOracle(wbeth, eth, resilientOracle) {}
/**
* @notice Fetches the amount of ETH for 1 wBETH
* @return amount The amount of ETH for wBETH
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return IWBETH(CORRELATED_TOKEN).exchangeRate();
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { IAccountantWithRateProviders } from "../interfaces/IAccountantWithRateProviders.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
/**
* @title WeETHAccountantOracle
* @author Venus
* @notice This oracle fetches the price of ether.fi restaked token
*/
contract WeETHAccountantOracle is CorrelatedTokenOracle {
/// @notice Address of AccountantWithRateProviders
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IAccountantWithRateProviders public immutable ACCOUNTANT;
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address accountant,
address LRT,
address WETH,
address resilientOracle
) CorrelatedTokenOracle(LRT, WETH, resilientOracle) {
ensureNonzeroAddress(accountant);
ACCOUNTANT = IAccountantWithRateProviders(accountant);
}
/**
* @notice Gets the WETH for 1 LRT
* @return amount Amount of WETH
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return ACCOUNTANT.getRate();
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { IEtherFiLiquidityPool } from "../interfaces/IEtherFiLiquidityPool.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
/**
* @title WeETHOracle
* @author Venus
* @notice This oracle fetches the price of weETH
*/
contract WeETHOracle is CorrelatedTokenOracle {
/// @notice Address of Liqiudity pool
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IEtherFiLiquidityPool public immutable LIQUIDITY_POOL;
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address liquidityPool,
address weETH,
address eETH,
address resilientOracle
) CorrelatedTokenOracle(weETH, eETH, resilientOracle) {
ensureNonzeroAddress(liquidityPool);
LIQUIDITY_POOL = IEtherFiLiquidityPool(liquidityPool);
}
/**
* @notice Gets the eETH for 1 weETH
* @return amount Amount of eETH
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return LIQUIDITY_POOL.amountForShare(EXP_SCALE);
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { OracleInterface } from "../interfaces/OracleInterface.sol";
import { IStETH } from "../interfaces/IStETH.sol";
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
/**
* @title WstETHOracle
* @author Venus
* @notice Depending on the equivalence flag price is either based on assumption that 1 stETH = 1 ETH
* or the price of stETH/USD (secondary market price) is obtained from the oracle.
*/
contract WstETHOracle is OracleInterface {
/// @notice A flag assuming 1:1 price equivalence between stETH/ETH
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
bool public immutable ASSUME_STETH_ETH_EQUIVALENCE;
/// @notice Address of stETH
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IStETH public immutable STETH;
/// @notice Address of wstETH
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address public immutable WSTETH_ADDRESS;
/// @notice Address of WETH
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address public immutable WETH_ADDRESS;
/// @notice Address of Resilient Oracle
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
OracleInterface public immutable RESILIENT_ORACLE;
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address wstETHAddress,
address wETHAddress,
address stETHAddress,
address resilientOracleAddress,
bool assumeEquivalence
) {
ensureNonzeroAddress(wstETHAddress);
ensureNonzeroAddress(wETHAddress);
ensureNonzeroAddress(stETHAddress);
ensureNonzeroAddress(resilientOracleAddress);
WSTETH_ADDRESS = wstETHAddress;
WETH_ADDRESS = wETHAddress;
STETH = IStETH(stETHAddress);
RESILIENT_ORACLE = OracleInterface(resilientOracleAddress);
ASSUME_STETH_ETH_EQUIVALENCE = assumeEquivalence;
}
/**
* @notice Gets the USD price of wstETH asset
* @dev Depending on the equivalence flag price is either based on assumption that 1 stETH = 1 ETH
* or the price of stETH/USD (secondary market price) is obtained from the oracle
* @param asset Address of wstETH
* @return wstETH Price in USD scaled by 1e18
*/
function getPrice(address asset) public view returns (uint256) {
if (asset != WSTETH_ADDRESS) revert("wrong wstETH address");
// get stETH amount for 1 wstETH scaled by 1e18
uint256 stETHAmount = STETH.getPooledEthByShares(1 ether);
// price is scaled 1e18 (oracle returns 36 - asset decimal scale)
uint256 stETHUSDPrice = RESILIENT_ORACLE.getPrice(ASSUME_STETH_ETH_EQUIVALENCE ? WETH_ADDRESS : address(STETH));
// stETHAmount (for 1 wstETH) * stETHUSDPrice / 1e18
return (stETHAmount * stETHUSDPrice) / EXP_SCALE;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import { IStETH } from "../interfaces/IStETH.sol";
import { CorrelatedTokenOracle } from "./common/CorrelatedTokenOracle.sol";
import { EXP_SCALE } from "@venusprotocol/solidity-utilities/contracts/constants.sol";
/**
* @title WstETHOracleV2
* @author Venus
* @notice This oracle fetches the price of wstETH
*/
contract WstETHOracleV2 is CorrelatedTokenOracle {
/// @notice Constructor for the implementation contract.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address wstETH,
address stETH,
address resilientOracle
) CorrelatedTokenOracle(wstETH, stETH, resilientOracle) {}
/**
* @notice Gets the stETH for 1 wstETH
* @return amount Amount of stETH
*/
function _getUnderlyingAmount() internal view override returns (uint256) {
return IStETH(UNDERLYING_TOKEN).getPooledEthByShares(EXP_SCALE);
}
}// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: 2022 Venus
pragma solidity 0.8.25;
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "./interfaces/VBep20Interface.sol";
import "./interfaces/OracleInterface.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV8.sol";
/**
* @title ResilientOracle
* @author Venus
* @notice The Resilient Oracle is the main contract that the protocol uses to fetch prices of assets.
*
* DeFi protocols are vulnerable to price oracle failures including oracle manipulation and incorrectly
* reported prices. If only one oracle is used, this creates a single point of failure and opens a vector
* for attacking the protocol.
*
* The Resilient Oracle uses multiple sources and fallback mechanisms to provide accurate prices and protect
* the protocol from oracle attacks. Currently it includes integrations with Chainlink, Pyth, Binance Oracle
* and TWAP (Time-Weighted Average Price) oracles. TWAP uses PancakeSwap as the on-chain price source.
*
* For every market (vToken) we configure the main, pivot and fallback oracles. The oracles are configured per
* vToken's underlying asset address. The main oracle oracle is the most trustworthy price source, the pivot
* oracle is used as a loose sanity checker and the fallback oracle is used as a backup price source.
*
* To validate prices returned from two oracles, we use an upper and lower bound ratio that is set for every
* market. The upper bound ratio represents the deviation between reported price (the price that’s being
* validated) and the anchor price (the price we are validating against) above which the reported price will
* be invalidated. The lower bound ratio presents the deviation between reported price and anchor price below
* which the reported price will be invalidated. So for oracle price to be considered valid the below statement
* should be true:
```
anchorRatio = anchorPrice/reporterPrice
isValid = anchorRatio <= upperBoundAnchorRatio && anchorRatio >= lowerBoundAnchorRatio
```
* In most cases, Chainlink is used as the main oracle, TWAP or Pyth oracles are used as the pivot oracle depending
* on which supports the given market and Binance oracle is used as the fallback oracle. For some markets we may
* use Pyth or TWAP as the main oracle if the token price is not supported by Chainlink or Binance oracles.
*
* For a fetched price to be valid it must be positive and not stagnant. If the price is invalid then we consider the
* oracle to be stagnant and treat it like it's disabled.
*/
contract ResilientOracle is PausableUpgradeable, AccessControlledV8, ResilientOracleInterface {
/**
* @dev Oracle roles:
* **main**: The most trustworthy price source
* **pivot**: Price oracle used as a loose sanity checker
* **fallback**: The backup source when main oracle price is invalidated
*/
enum OracleRole {
MAIN,
PIVOT,
FALLBACK
}
struct TokenConfig {
/// @notice asset address
address asset;
/// @notice `oracles` stores the oracles based on their role in the following order:
/// [main, pivot, fallback],
/// It can be indexed with the corresponding enum OracleRole value
address[3] oracles;
/// @notice `enableFlagsForOracles` stores the enabled state
/// for each oracle in the same order as `oracles`
bool[3] enableFlagsForOracles;
}
uint256 public constant INVALID_PRICE = 0;
/// @notice Native market address
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address public immutable nativeMarket;
/// @notice VAI address
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address public immutable vai;
/// @notice Set this as asset address for Native token on each chain.This is the underlying for vBNB (on bsc)
/// and can serve as any underlying asset of a market that supports native tokens
address public constant NATIVE_TOKEN_ADDR = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;
/// @notice Bound validator contract address
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
BoundValidatorInterface public immutable boundValidator;
mapping(address => TokenConfig) private tokenConfigs;
event TokenConfigAdded(
address indexed asset,
address indexed mainOracle,
address indexed pivotOracle,
address fallbackOracle
);
/// Event emitted when an oracle is set
event OracleSet(address indexed asset, address indexed oracle, uint256 indexed role);
/// Event emitted when an oracle is enabled or disabled
event OracleEnabled(address indexed asset, uint256 indexed role, bool indexed enable);
/**
* @notice Checks whether an address is null or not
*/
modifier notNullAddress(address someone) {
if (someone == address(0)) revert("can't be zero address");
_;
}
/**
* @notice Checks whether token config exists by checking whether asset is null address
* @dev address can't be null, so it's suitable to be used to check the validity of the config
* @param asset asset address
*/
modifier checkTokenConfigExistence(address asset) {
if (tokenConfigs[asset].asset == address(0)) revert("token config must exist");
_;
}
/// @notice Constructor for the implementation contract. Sets immutable variables.
/// @dev nativeMarketAddress can be address(0) if on the chain we do not support native market
/// (e.g vETH on ethereum would not be supported, only vWETH)
/// @param nativeMarketAddress The address of a native market (for bsc it would be vBNB address)
/// @param vaiAddress The address of the VAI token (if there is VAI on the deployed chain).
/// Set to address(0) of VAI is not existent.
/// @param _boundValidator Address of the bound validator contract
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address nativeMarketAddress,
address vaiAddress,
BoundValidatorInterface _boundValidator
) notNullAddress(address(_boundValidator)) {
nativeMarket = nativeMarketAddress;
vai = vaiAddress;
boundValidator = _boundValidator;
_disableInitializers();
}
/**
* @notice Initializes the contract admin and sets the BoundValidator contract address
* @param accessControlManager_ Address of the access control manager contract
*/
function initialize(address accessControlManager_) external initializer {
__AccessControlled_init(accessControlManager_);
__Pausable_init();
}
/**
* @notice Pauses oracle
* @custom:access Only Governance
*/
function pause() external {
_checkAccessAllowed("pause()");
_pause();
}
/**
* @notice Unpauses oracle
* @custom:access Only Governance
*/
function unpause() external {
_checkAccessAllowed("unpause()");
_unpause();
}
/**
* @notice Batch sets token configs
* @param tokenConfigs_ Token config array
* @custom:access Only Governance
* @custom:error Throws a length error if the length of the token configs array is 0
*/
function setTokenConfigs(TokenConfig[] memory tokenConfigs_) external {
if (tokenConfigs_.length == 0) revert("length can't be 0");
uint256 numTokenConfigs = tokenConfigs_.length;
for (uint256 i; i < numTokenConfigs; ) {
setTokenConfig(tokenConfigs_[i]);
unchecked {
++i;
}
}
}
/**
* @notice Sets oracle for a given asset and role.
* @dev Supplied asset **must** exist and main oracle may not be null
* @param asset Asset address
* @param oracle Oracle address
* @param role Oracle role
* @custom:access Only Governance
* @custom:error Null address error if main-role oracle address is null
* @custom:error NotNullAddress error is thrown if asset address is null
* @custom:error TokenConfigExistance error is thrown if token config is not set
* @custom:event Emits OracleSet event with asset address, oracle address and role of the oracle for the asset
*/
function setOracle(
address asset,
address oracle,
OracleRole role
) external notNullAddress(asset) checkTokenConfigExistence(asset) {
_checkAccessAllowed("setOracle(address,address,uint8)");
if (oracle == address(0) && role == OracleRole.MAIN) revert("can't set zero address to main oracle");
tokenConfigs[asset].oracles[uint256(role)] = oracle;
emit OracleSet(asset, oracle, uint256(role));
}
/**
* @notice Enables/ disables oracle for the input asset. Token config for the input asset **must** exist
* @dev Configuration for the asset **must** already exist and the asset cannot be 0 address
* @param asset Asset address
* @param role Oracle role
* @param enable Enabled boolean of the oracle
* @custom:access Only Governance
* @custom:error NotNullAddress error is thrown if asset address is null
* @custom:error TokenConfigExistance error is thrown if token config is not set
*/
function enableOracle(
address asset,
OracleRole role,
bool enable
) external notNullAddress(asset) checkTokenConfigExistence(asset) {
_checkAccessAllowed("enableOracle(address,uint8,bool)");
tokenConfigs[asset].enableFlagsForOracles[uint256(role)] = enable;
emit OracleEnabled(asset, uint256(role), enable);
}
/**
* @notice Updates the TWAP pivot oracle price.
* @dev This function should always be called before calling getUnderlyingPrice
* @param vToken vToken address
*/
function updatePrice(address vToken) external override {
address asset = _getUnderlyingAsset(vToken);
(address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);
if (pivotOracle != address(0) && pivotOracleEnabled) {
//if pivot oracle is not TwapOracle it will revert so we need to catch the revert
try TwapInterface(pivotOracle).updateTwap(asset) {} catch {}
}
}
/**
* @notice Updates the pivot oracle price. Currently using TWAP
* @dev This function should always be called before calling getPrice
* @param asset asset address
*/
function updateAssetPrice(address asset) external {
(address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);
if (pivotOracle != address(0) && pivotOracleEnabled) {
//if pivot oracle is not TwapOracle it will revert so we need to catch the revert
try TwapInterface(pivotOracle).updateTwap(asset) {} catch {}
}
}
/**
* @dev Gets token config by asset address
* @param asset asset address
* @return tokenConfig Config for the asset
*/
function getTokenConfig(address asset) external view returns (TokenConfig memory) {
return tokenConfigs[asset];
}
/**
* @notice Gets price of the underlying asset for a given vToken. Validation flow:
* - Check if the oracle is paused globally
* - Validate price from main oracle against pivot oracle
* - Validate price from fallback oracle against pivot oracle if the first validation failed
* - Validate price from main oracle against fallback oracle if the second validation failed
* In the case that the pivot oracle is not available but main price is available and validation is successful,
* main oracle price is returned.
* @param vToken vToken address
* @return price USD price in scaled decimal places.
* @custom:error Paused error is thrown when resilent oracle is paused
* @custom:error Invalid resilient oracle price error is thrown if fetched prices from oracle is invalid
*/
function getUnderlyingPrice(address vToken) external view override returns (uint256) {
if (paused()) revert("resilient oracle is paused");
address asset = _getUnderlyingAsset(vToken);
return _getPrice(asset);
}
/**
* @notice Gets price of the asset
* @param asset asset address
* @return price USD price in scaled decimal places.
* @custom:error Paused error is thrown when resilent oracle is paused
* @custom:error Invalid resilient oracle price error is thrown if fetched prices from oracle is invalid
*/
function getPrice(address asset) external view override returns (uint256) {
if (paused()) revert("resilient oracle is paused");
return _getPrice(asset);
}
/**
* @notice Sets/resets single token configs.
* @dev main oracle **must not** be a null address
* @param tokenConfig Token config struct
* @custom:access Only Governance
* @custom:error NotNullAddress is thrown if asset address is null
* @custom:error NotNullAddress is thrown if main-role oracle address for asset is null
* @custom:event Emits TokenConfigAdded event when the asset config is set successfully by the authorized account
*/
function setTokenConfig(
TokenConfig memory tokenConfig
) public notNullAddress(tokenConfig.asset) notNullAddress(tokenConfig.oracles[uint256(OracleRole.MAIN)]) {
_checkAccessAllowed("setTokenConfig(TokenConfig)");
tokenConfigs[tokenConfig.asset] = tokenConfig;
emit TokenConfigAdded(
tokenConfig.asset,
tokenConfig.oracles[uint256(OracleRole.MAIN)],
tokenConfig.oracles[uint256(OracleRole.PIVOT)],
tokenConfig.oracles[uint256(OracleRole.FALLBACK)]
);
}
/**
* @notice Gets oracle and enabled status by asset address
* @param asset asset address
* @param role Oracle role
* @return oracle Oracle address based on role
* @return enabled Enabled flag of the oracle based on token config
*/
function getOracle(address asset, OracleRole role) public view returns (address oracle, bool enabled) {
oracle = tokenConfigs[asset].oracles[uint256(role)];
enabled = tokenConfigs[asset].enableFlagsForOracles[uint256(role)];
}
function _getPrice(address asset) internal view returns (uint256) {
uint256 pivotPrice = INVALID_PRICE;
// Get pivot oracle price, Invalid price if not available or error
(address pivotOracle, bool pivotOracleEnabled) = getOracle(asset, OracleRole.PIVOT);
if (pivotOracleEnabled && pivotOracle != address(0)) {
try OracleInterface(pivotOracle).getPrice(asset) returns (uint256 pricePivot) {
pivotPrice = pricePivot;
} catch {}
}
// Compare main price and pivot price, return main price and if validation was successful
// note: In case pivot oracle is not available but main price is available and
// validation is successful, the main oracle price is returned.
(uint256 mainPrice, bool validatedPivotMain) = _getMainOraclePrice(
asset,
pivotPrice,
pivotOracleEnabled && pivotOracle != address(0)
);
if (mainPrice != INVALID_PRICE && validatedPivotMain) return mainPrice;
// Compare fallback and pivot if main oracle comparision fails with pivot
// Return fallback price when fallback price is validated successfully with pivot oracle
(uint256 fallbackPrice, bool validatedPivotFallback) = _getFallbackOraclePrice(asset, pivotPrice);
if (fallbackPrice != INVALID_PRICE && validatedPivotFallback) return fallbackPrice;
// Lastly compare main price and fallback price
if (
mainPrice != INVALID_PRICE &&
fallbackPrice != INVALID_PRICE &&
boundValidator.validatePriceWithAnchorPrice(asset, mainPrice, fallbackPrice)
) {
return mainPrice;
}
revert("invalid resilient oracle price");
}
/**
* @notice Gets a price for the provided asset
* @dev This function won't revert when price is 0, because the fallback oracle may still be
* able to fetch a correct price
* @param asset asset address
* @param pivotPrice Pivot oracle price
* @param pivotEnabled If pivot oracle is not empty and enabled
* @return price USD price in scaled decimals
* e.g. asset decimals is 8 then price is returned as 10**18 * 10**(18-8) = 10**28 decimals
* @return pivotValidated Boolean representing if the validation of main oracle price
* and pivot oracle price were successful
* @custom:error Invalid price error is thrown if main oracle fails to fetch price of the asset
* @custom:error Invalid price error is thrown if main oracle is not enabled or main oracle
* address is null
*/
function _getMainOraclePrice(
address asset,
uint256 pivotPrice,
bool pivotEnabled
) internal view returns (uint256, bool) {
(address mainOracle, bool mainOracleEnabled) = getOracle(asset, OracleRole.MAIN);
if (mainOracleEnabled && mainOracle != address(0)) {
try OracleInterface(mainOracle).getPrice(asset) returns (uint256 mainOraclePrice) {
if (!pivotEnabled) {
return (mainOraclePrice, true);
}
if (pivotPrice == INVALID_PRICE) {
return (mainOraclePrice, false);
}
return (
mainOraclePrice,
boundValidator.validatePriceWithAnchorPrice(asset, mainOraclePrice, pivotPrice)
);
} catch {
return (INVALID_PRICE, false);
}
}
return (INVALID_PRICE, false);
}
/**
* @dev This function won't revert when the price is 0 because getPrice checks if price is > 0
* @param asset asset address
* @return price USD price in 18 decimals
* @return pivotValidated Boolean representing if the validation of fallback oracle price
* and pivot oracle price were successfull
* @custom:error Invalid price error is thrown if fallback oracle fails to fetch price of the asset
* @custom:error Invalid price error is thrown if fallback oracle is not enabled or fallback oracle
* address is null
*/
function _getFallbackOraclePrice(address asset, uint256 pivotPrice) private view returns (uint256, bool) {
(address fallbackOracle, bool fallbackEnabled) = getOracle(asset, OracleRole.FALLBACK);
if (fallbackEnabled && fallbackOracle != address(0)) {
try OracleInterface(fallbackOracle).getPrice(asset) returns (uint256 fallbackOraclePrice) {
if (pivotPrice == INVALID_PRICE) {
return (fallbackOraclePrice, false);
}
return (
fallbackOraclePrice,
boundValidator.validatePriceWithAnchorPrice(asset, fallbackOraclePrice, pivotPrice)
);
} catch {
return (INVALID_PRICE, false);
}
}
return (INVALID_PRICE, false);
}
/**
* @dev This function returns the underlying asset of a vToken
* @param vToken vToken address
* @return asset underlying asset address
*/
function _getUnderlyingAsset(address vToken) private view notNullAddress(vToken) returns (address asset) {
if (vToken == nativeMarket) {
asset = NATIVE_TOKEN_ADDR;
} else if (vToken == vai) {
asset = vai;
} else {
asset = VBep20Interface(vToken).underlying();
}
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlManager.sol";
contract AccessControlManagerScenario is AccessControlManager {}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract BEP20Harness is ERC20 {
uint8 public decimalsInternal = 18;
constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) {
decimalsInternal = decimals_;
}
function faucet(uint256 amount) external {
_mint(msg.sender, amount);
}
function decimals() public view virtual override returns (uint8) {
return decimalsInternal;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IAnkrBNB } from "../interfaces/IAnkrBNB.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MockAnkrBNB is ERC20, Ownable, IAnkrBNB {
uint8 private immutable _decimals;
uint256 public exchangeRate;
constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) Ownable() {
_decimals = decimals_;
}
function faucet(uint256 amount) external {
_mint(msg.sender, amount);
}
function setSharesToBonds(uint256 rate) external onlyOwner {
exchangeRate = rate;
}
function sharesToBonds(uint256 amount) external view override returns (uint256) {
return (amount * exchangeRate) / (10 ** uint256(_decimals));
}
function decimals() public view virtual override(ERC20, IAnkrBNB) returns (uint8) {
return _decimals;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "../interfaces/IEtherFiLiquidityPool.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MockEtherFiLiquidityPool is IEtherFiLiquidityPool, Ownable {
/// @notice The amount of eETH per weETH scaled by 1e18
uint256 public amountPerShare;
constructor() Ownable() {}
function setAmountPerShare(uint256 _amountPerShare) external onlyOwner {
amountPerShare = _amountPerShare;
}
function amountForShare(uint256 _share) external view override returns (uint256) {
return (_share * amountPerShare) / 1e18;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "../interfaces/PythInterface.sol";
contract MockPyth is AbstractPyth {
mapping(bytes32 => PythStructs.PriceFeed) priceFeeds;
uint64 sequenceNumber;
uint256 singleUpdateFeeInWei;
uint256 validTimePeriod;
constructor(uint256 _validTimePeriod, uint256 _singleUpdateFeeInWei) {
singleUpdateFeeInWei = _singleUpdateFeeInWei;
validTimePeriod = _validTimePeriod;
}
// simply update price feeds
function updatePriceFeedsHarness(PythStructs.PriceFeed[] calldata feeds) external {
require(feeds.length > 0, "feeds length must > 0");
for (uint256 i = 0; i < feeds.length; ) {
priceFeeds[feeds[i].id] = feeds[i];
unchecked {
++i;
}
}
}
// Takes an array of encoded price feeds and stores them.
// You can create this data either by calling createPriceFeedData or
// by using web3.js or ethers abi utilities.
function updatePriceFeeds(bytes[] calldata updateData) public payable override {
uint256 requiredFee = getUpdateFee(updateData.length);
require(msg.value >= requiredFee, "Insufficient paid fee amount");
if (msg.value > requiredFee) {
(bool success, ) = payable(msg.sender).call{ value: msg.value - requiredFee }("");
require(success, "failed to transfer update fee");
}
uint256 freshPrices = 0;
// Chain ID is id of the source chain that the price update comes from. Since it is just a mock contract
// We set it to 1.
uint16 chainId = 1;
for (uint256 i = 0; i < updateData.length; ) {
PythStructs.PriceFeed memory priceFeed = abi.decode(updateData[i], (PythStructs.PriceFeed));
bool fresh = false;
uint256 lastPublishTime = priceFeeds[priceFeed.id].price.publishTime;
if (lastPublishTime < priceFeed.price.publishTime) {
// Price information is more recent than the existing price information.
fresh = true;
priceFeeds[priceFeed.id] = priceFeed;
freshPrices += 1;
}
emit PriceFeedUpdate(
priceFeed.id,
fresh,
chainId,
sequenceNumber,
priceFeed.price.publishTime,
lastPublishTime,
priceFeed.price.price,
priceFeed.price.conf
);
unchecked {
i++;
}
}
// In the real contract, the input of this function contains multiple batches that each contain multiple prices.
// This event is emitted when a batch is processed. In this mock contract we consider
// there is only one batch of prices.
// Each batch has (chainId, sequenceNumber) as it's unique identifier. Here chainId
// is set to 1 and an increasing sequence number is used.
emit BatchPriceFeedUpdate(chainId, sequenceNumber, updateData.length, freshPrices);
sequenceNumber += 1;
// There is only 1 batch of prices
emit UpdatePriceFeeds(msg.sender, 1, requiredFee);
}
function queryPriceFeed(bytes32 id) public view override returns (PythStructs.PriceFeed memory priceFeed) {
require(priceFeeds[id].id != 0, "no price feed found for the given price id");
return priceFeeds[id];
}
function priceFeedExists(bytes32 id) public view override returns (bool) {
return (priceFeeds[id].id != 0);
}
function getValidTimePeriod() public view override returns (uint256) {
return validTimePeriod;
}
function getUpdateFee(uint256 updateDataSize) public view override returns (uint256 feeAmount) {
return singleUpdateFeeInWei * updateDataSize;
}
function createPriceFeedUpdateData(
bytes32 id,
int64 price,
uint64 conf,
int32 expo,
int64 emaPrice,
uint64 emaConf,
uint64 publishTime
) public pure returns (bytes memory priceFeedData) {
PythStructs.PriceFeed memory priceFeed;
priceFeed.id = id;
priceFeed.price.price = price;
priceFeed.price.conf = conf;
priceFeed.price.expo = expo;
priceFeed.price.publishTime = publishTime;
priceFeed.emaPrice.price = emaPrice;
priceFeed.emaPrice.conf = emaConf;
priceFeed.emaPrice.expo = expo;
priceFeed.emaPrice.publishTime = publishTime;
priceFeedData = abi.encode(priceFeed);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { ISFrax } from "../interfaces/ISFrax.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MockSFrax is ERC20, Ownable, ISFrax {
uint8 private immutable _decimals;
uint256 public exchangeRate;
constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) Ownable() {
_decimals = decimals_;
}
function faucet(uint256 amount) external {
_mint(msg.sender, amount);
}
function setRate(uint256 rate) external onlyOwner {
exchangeRate = rate;
}
function convertToAssets(uint256 shares) external view override returns (uint256) {
return (shares * exchangeRate) / (10 ** uint256(_decimals));
}
function decimals() public view virtual override(ERC20, ISFrax) returns (uint8) {
return _decimals;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "../interfaces/OracleInterface.sol";
contract MockSimpleOracle is OracleInterface {
mapping(address => uint256) public prices;
constructor() {
//
}
function getUnderlyingPrice(address vToken) external view returns (uint256) {
return prices[vToken];
}
function getPrice(address asset) external view returns (uint256) {
return prices[asset];
}
function setPrice(address vToken, uint256 price) public {
prices[vToken] = price;
}
}
contract MockBoundValidator is BoundValidatorInterface {
mapping(address => bool) public validateResults;
bool public twapUpdated;
constructor() {
//
}
function validatePriceWithAnchorPrice(
address vToken,
uint256 reporterPrice,
uint256 anchorPrice
) external view returns (bool) {
return validateResults[vToken];
}
function validateAssetPriceWithAnchorPrice(
address asset,
uint256 reporterPrice,
uint256 anchorPrice
) external view returns (bool) {
return validateResults[asset];
}
function setValidateResult(address token, bool pass) public {
validateResults[token] = pass;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol";
/**
* @title MockV3Aggregator
* @notice Based on the FluxAggregator contract
* @notice Use this contract when you need to test
* other contract's ability to read data from an
* aggregator contract, but how the aggregator got
* its answer is unimportant
*/
contract MockV3Aggregator is AggregatorV2V3Interface {
uint256 public constant version = 0;
uint8 public decimals;
int256 public latestAnswer;
uint256 public latestTimestamp;
uint256 public latestRound;
mapping(uint256 => int256) public getAnswer;
mapping(uint256 => uint256) public getTimestamp;
mapping(uint256 => uint256) private getStartedAt;
constructor(uint8 _decimals, int256 _initialAnswer) {
decimals = _decimals;
updateAnswer(_initialAnswer);
}
function getRoundData(
uint80 _roundId
)
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
{
return (_roundId, getAnswer[_roundId], getStartedAt[_roundId], getTimestamp[_roundId], _roundId);
}
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
{
return (
uint80(latestRound),
getAnswer[latestRound],
getStartedAt[latestRound],
getTimestamp[latestRound],
uint80(latestRound)
);
}
function description() external pure returns (string memory) {
return "v0.6/tests/MockV3Aggregator.sol";
}
function updateAnswer(int256 _answer) public {
latestAnswer = _answer;
latestTimestamp = block.timestamp;
latestRound++;
getAnswer[latestRound] = _answer;
getTimestamp[latestRound] = block.timestamp;
getStartedAt[latestRound] = block.timestamp;
}
function updateRoundData(uint80 _roundId, int256 _answer, uint256 _timestamp, uint256 _startedAt) public {
latestRound = _roundId;
latestAnswer = _answer;
latestTimestamp = _timestamp;
getAnswer[latestRound] = _answer;
getTimestamp[latestRound] = _timestamp;
getStartedAt[latestRound] = _startedAt;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IWBETH } from "../interfaces/IWBETH.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MockWBETH is ERC20, Ownable, IWBETH {
uint8 private immutable _decimals;
uint256 public override exchangeRate;
constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) Ownable() {
_decimals = decimals_;
}
function faucet(uint256 amount) external {
_mint(msg.sender, amount);
}
function setExchangeRate(uint256 rate) external onlyOwner {
exchangeRate = rate;
}
function decimals() public view virtual override(ERC20, IWBETH) returns (uint8) {
return _decimals;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
// a library for performing various math operations
library Math {
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x < y ? x : y;
}
// babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}
// range: [0, 2**112 - 1]
// resolution: 1 / 2**112
library UQ112x112 {
//solhint-disable-next-line state-visibility
uint224 constant Q112 = 2 ** 112;
// encode a uint112 as a UQ112x112
function encode(uint112 y) internal pure returns (uint224 z) {
z = uint224(y) * Q112; // never overflows
}
// divide a UQ112x112 by a uint112, returning a UQ112x112
function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
z = x / uint224(y);
}
}
contract PancakePairHarness {
using UQ112x112 for uint224;
address public token0;
address public token1;
uint112 private reserve0; // uses single storage slot, accessible via getReserves
uint112 private reserve1; // uses single storage slot, accessible via getReserves
uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves
uint256 public price0CumulativeLast;
uint256 public price1CumulativeLast;
uint256 public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
// called once by the factory at time of deployment
function initialize(address _token0, address _token1) external {
token0 = _token0;
token1 = _token1;
}
// update reserves and, on the first call per block, price accumulators
function update(uint256 balance0, uint256 balance1, uint112 _reserve0, uint112 _reserve1) external {
require(balance0 <= type(uint112).max && balance1 <= type(uint112).max, "PancakeV2: OVERFLOW");
uint32 blockTimestamp = uint32(block.timestamp % 2 ** 32);
unchecked {
uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
// * never overflows, and + overflow is desired
price0CumulativeLast += uint256(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
price1CumulativeLast += uint256(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
}
}
reserve0 = uint112(balance0);
reserve1 = uint112(balance1);
blockTimestampLast = blockTimestamp;
}
function currentBlockTimestamp() external view returns (uint32) {
return uint32(block.timestamp % 2 ** 32);
}
function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
_reserve0 = reserve0;
_reserve1 = reserve1;
_blockTimestampLast = blockTimestampLast;
}
}// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.8.25;
import "./BEP20Harness.sol";
contract VBEP20Harness is BEP20Harness {
/**
* @notice Underlying asset for this VToken
*/
address public underlying;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals,
address underlying_
) BEP20Harness(name_, symbol_, decimals) {
underlying = underlying_;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor (address initialOwner) {
_transferOwnership(initialOwner);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)
pragma solidity ^0.8.0;
import "../Proxy.sol";
import "./ERC1967Upgrade.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
* function call, and allows initializating the storage of the proxy like a Solidity constructor.
*/
constructor(address _logic, bytes memory _data) payable {
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
_upgradeToAndCall(_logic, _data, false);
}
/**
* @dev Returns the current implementation address.
*/
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view virtual returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract");
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overriden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.0;
import "../ERC1967/ERC1967Proxy.sol";
/**
* @dev This contract implements a proxy that is upgradeable by an admin.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches one of the admin functions exposed by the proxy itself.
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
* "admin cannot fallback to proxy target".
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation.
*
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
* you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
*/
contract TransparentUpgradeableProxy is ERC1967Proxy {
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
*/
constructor(
address _logic,
address admin_,
bytes memory _data
) payable ERC1967Proxy(_logic, _data) {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_changeAdmin(admin_);
}
/**
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
*/
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
/**
* @dev Returns the current admin.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function admin() external ifAdmin returns (address admin_) {
admin_ = _getAdmin();
}
/**
* @dev Returns the current implementation.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function implementation() external ifAdmin returns (address implementation_) {
implementation_ = _implementation();
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
*/
function changeAdmin(address newAdmin) external virtual ifAdmin {
_changeAdmin(newAdmin);
}
/**
* @dev Upgrade the implementation of the proxy.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeToAndCall(newImplementation, bytes(""), false);
}
/**
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
* proxied contract.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeToAndCall(newImplementation, data, true);
}
/**
* @dev Returns the current admin.
*/
function _admin() internal view virtual returns (address) {
return _getAdmin();
}
/**
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
*/
function _beforeFallback() internal virtual override {
require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.0;
import "../openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
/**
* @dev This contract implements a proxy that is upgradeable by an admin.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches one of the admin functions exposed by the proxy itself.
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
* "admin cannot fallback to proxy target".
*
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
* to sudden errors when trying to call a function from the proxy implementation.
*
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
* you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
*/
contract OptimizedTransparentUpgradeableProxy is ERC1967Proxy {
address internal immutable _ADMIN;
/**
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
* optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
*/
constructor(
address _logic,
address admin_,
bytes memory _data
) payable ERC1967Proxy(_logic, _data) {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_ADMIN = admin_;
// still store it to work with EIP-1967
bytes32 slot = _ADMIN_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, admin_)
}
emit AdminChanged(address(0), admin_);
}
/**
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
*/
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
/**
* @dev Returns the current admin.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function admin() external ifAdmin returns (address admin_) {
admin_ = _getAdmin();
}
/**
* @dev Returns the current implementation.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function implementation() external ifAdmin returns (address implementation_) {
implementation_ = _implementation();
}
/**
* @dev Upgrade the implementation of the proxy.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeToAndCall(newImplementation, bytes(""), false);
}
/**
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
* proxied contract.
*
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
*/
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeToAndCall(newImplementation, data, true);
}
/**
* @dev Returns the current admin.
*/
function _admin() internal view virtual returns (address) {
return _getAdmin();
}
/**
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
*/
function _beforeFallback() internal virtual override {
require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
function _getAdmin() internal view virtual override returns (address) {
return _ADMIN;
}
}{
"optimizer": {
"enabled": true,
"runs": 200,
"details": {
"yul": true
}
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"changeProxyAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"}],"name":"getProxyAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"}],"name":"getProxyImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"implementation","type":"address"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TransparentUpgradeableProxy","name":"proxy","type":"address"},{"internalType":"address","name":"implementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
6080604052348015600f57600080fd5b506040516107e43803806107e4833981016040819052602c91608a565b80603481603a565b505060b8565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215609b57600080fd5b81516001600160a01b038116811460b157600080fd5b9392505050565b61071d806100c76000396000f3fe60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead1461016457600080fd5b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b3660046104ed565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d1610215565b005b3480156100df57600080fd5b506100d16100ee366004610511565b610254565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f366004610560565b6102de565b34801561013057600080fd5b506100d161013f366004610511565b61036f565b34801561015057600080fd5b506100d161015f3660046104ed565b6103c7565b34801561017057600080fd5b506100a061017f3660046104ed565b610462565b6000806000836001600160a01b03166040516101aa90635c60da1b60e01b815260040190565b600060405180830381855afa9150503d80600081146101e5576040519150601f19603f3d011682016040523d82523d6000602084013e6101ea565b606091505b5091509150816101f957600080fd5b8080602001905181019061020d9190610636565b949350505050565b6000546001600160a01b031633146102485760405162461bcd60e51b815260040161023f90610653565b60405180910390fd5b6102526000610488565b565b6000546001600160a01b0316331461027e5760405162461bcd60e51b815260040161023f90610653565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b1580156102c257600080fd5b505af11580156102d6573d6000803e3d6000fd5b505050505050565b6000546001600160a01b031633146103085760405162461bcd60e51b815260040161023f90610653565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906103389086908690600401610688565b6000604051808303818588803b15801561035157600080fd5b505af1158015610365573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b031633146103995760405162461bcd60e51b815260040161023f90610653565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe6906024016102a8565b6000546001600160a01b031633146103f15760405162461bcd60e51b815260040161023f90610653565b6001600160a01b0381166104565760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161023f565b61045f81610488565b50565b6000806000836001600160a01b03166040516101aa906303e1469160e61b815260040190565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038116811461045f57600080fd5b6000602082840312156104ff57600080fd5b813561050a816104d8565b9392505050565b6000806040838503121561052457600080fd5b823561052f816104d8565b9150602083013561053f816104d8565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561057557600080fd5b8335610580816104d8565b92506020840135610590816104d8565b9150604084013567ffffffffffffffff808211156105ad57600080fd5b818601915086601f8301126105c157600080fd5b8135818111156105d3576105d361054a565b604051601f8201601f19908116603f011681019083821181831017156105fb576105fb61054a565b8160405282815289602084870101111561061457600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561064857600080fd5b815161050a816104d8565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60018060a01b03831681526000602060406020840152835180604085015260005b818110156106c5578581018301518582016060015282016106a9565b506000606082860101526060601f19601f83011685010192505050939250505056fea264697066735822122030f52ef7e16587f148a9f5ca0dbcadc434f9288a9162f8ab87307aa33db8fc4364736f6c63430008190033000000000000000000000000df3b635d2b535f906bb02abb22aed71346e36a00
Deployed Bytecode
0x60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead1461016457600080fd5b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b3660046104ed565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d1610215565b005b3480156100df57600080fd5b506100d16100ee366004610511565b610254565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f366004610560565b6102de565b34801561013057600080fd5b506100d161013f366004610511565b61036f565b34801561015057600080fd5b506100d161015f3660046104ed565b6103c7565b34801561017057600080fd5b506100a061017f3660046104ed565b610462565b6000806000836001600160a01b03166040516101aa90635c60da1b60e01b815260040190565b600060405180830381855afa9150503d80600081146101e5576040519150601f19603f3d011682016040523d82523d6000602084013e6101ea565b606091505b5091509150816101f957600080fd5b8080602001905181019061020d9190610636565b949350505050565b6000546001600160a01b031633146102485760405162461bcd60e51b815260040161023f90610653565b60405180910390fd5b6102526000610488565b565b6000546001600160a01b0316331461027e5760405162461bcd60e51b815260040161023f90610653565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b1580156102c257600080fd5b505af11580156102d6573d6000803e3d6000fd5b505050505050565b6000546001600160a01b031633146103085760405162461bcd60e51b815260040161023f90610653565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906103389086908690600401610688565b6000604051808303818588803b15801561035157600080fd5b505af1158015610365573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b031633146103995760405162461bcd60e51b815260040161023f90610653565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe6906024016102a8565b6000546001600160a01b031633146103f15760405162461bcd60e51b815260040161023f90610653565b6001600160a01b0381166104565760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161023f565b61045f81610488565b50565b6000806000836001600160a01b03166040516101aa906303e1469160e61b815260040190565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038116811461045f57600080fd5b6000602082840312156104ff57600080fd5b813561050a816104d8565b9392505050565b6000806040838503121561052457600080fd5b823561052f816104d8565b9150602083013561053f816104d8565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561057557600080fd5b8335610580816104d8565b92506020840135610590816104d8565b9150604084013567ffffffffffffffff808211156105ad57600080fd5b818601915086601f8301126105c157600080fd5b8135818111156105d3576105d361054a565b604051601f8201601f19908116603f011681019083821181831017156105fb576105fb61054a565b8160405282815289602084870101111561061457600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561064857600080fd5b815161050a816104d8565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60018060a01b03831681526000602060406020840152835180604085015260005b818110156106c5578581018301518582016060015282016106a9565b506000606082860101526060601f19601f83011685010192505050939250505056fea264697066735822122030f52ef7e16587f148a9f5ca0dbcadc434f9288a9162f8ab87307aa33db8fc4364736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000df3b635d2b535f906bb02abb22aed71346e36a00
-----Decoded View---------------
Arg [0] : initialOwner (address): 0xdf3b635d2b535f906BB02abb22AED71346E36a00
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000df3b635d2b535f906bb02abb22aed71346e36a00
Deployed Bytecode Sourcemap
435:2470:90:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;701:437;;;;;;;;;;-1:-1:-1;701:437:90;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;661:32:96;;;643:51;;631:2;616:18;701:437:90;;;;;;;1689:101:84;;;;;;;;;;;;;:::i;:::-;;1891:148:90;;;;;;;;;;-1:-1:-1;1891:148:90;;;;;:::i;:::-;;:::i;1057:85:84:-;;;;;;;;;;-1:-1:-1;1103:7:84;1129:6;-1:-1:-1;;;;;1129:6:84;1057:85;;2659:244:90;;;;;;:::i;:::-;;:::i;2244:149::-;;;;;;;;;;-1:-1:-1;2244:149:90;;;;;:::i;:::-;;:::i;1939:198:84:-;;;;;;;;;;-1:-1:-1;1939:198:84;;;;;:::i;:::-;;:::i;1298:419:90:-;;;;;;;;;;-1:-1:-1;1298:419:90;;;;;:::i;:::-;;:::i;701:437::-;797:7;974:12;988:23;1023:5;-1:-1:-1;;;;;1015:25:90;:40;;;;-1:-1:-1;;;3104:33:96;;3162:1;3153:11;;2903:267;1015:40:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;973:82;;;;1073:7;1065:16;;;;;;1109:10;1098:33;;;;;;;;;;;;:::i;:::-;1091:40;701:437;-1:-1:-1;;;;701:437:90:o;1689:101:84:-;1103:7;1129:6;-1:-1:-1;;;;;1129:6:84;719:10:93;1269:23:84;1261:68;;;;-1:-1:-1;;;1261:68:84;;;;;;;:::i;:::-;;;;;;;;;1753:30:::1;1780:1;1753:18;:30::i;:::-;1689:101::o:0;1891:148:90:-;1103:7:84;1129:6;-1:-1:-1;;;;;1129:6:84;719:10:93;1269:23:84;1261:68;;;;-1:-1:-1;;;1261:68:84;;;;;;;:::i;:::-;2005:27:90::1;::::0;-1:-1:-1;;;2005:27:90;;-1:-1:-1;;;;;661:32:96;;;2005:27:90::1;::::0;::::1;643:51:96::0;2005:17:90;::::1;::::0;::::1;::::0;616:18:96;;2005:27:90::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;1891:148:::0;;:::o;2659:244::-;1103:7:84;1129:6;-1:-1:-1;;;;;1129:6:84;719:10:93;1269:23:84;1261:68;;;;-1:-1:-1;;;1261:68:84;;;;;;;:::i;:::-;2834:62:90::1;::::0;-1:-1:-1;;;2834:62:90;;-1:-1:-1;;;;;2834:22:90;::::1;::::0;::::1;::::0;2864:9:::1;::::0;2834:62:::1;::::0;2875:14;;2891:4;;2834:62:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;2659:244:::0;;;:::o;2244:149::-;1103:7:84;1129:6;-1:-1:-1;;;;;1129:6:84;719:10:93;1269:23:84;1261:68;;;;-1:-1:-1;;;1261:68:84;;;;;;;:::i;:::-;2355:31:90::1;::::0;-1:-1:-1;;;2355:31:90;;-1:-1:-1;;;;;661:32:96;;;2355:31:90::1;::::0;::::1;643:51:96::0;2355:15:90;::::1;::::0;::::1;::::0;616:18:96;;2355:31:90::1;497:203:96::0;1939:198:84;1103:7;1129:6;-1:-1:-1;;;;;1129:6:84;719:10:93;1269:23:84;1261:68;;;;-1:-1:-1;;;1261:68:84;;;;;;;:::i;:::-;-1:-1:-1;;;;;2027:22:84;::::1;2019:73;;;::::0;-1:-1:-1;;;2019:73:84;;4679:2:96;2019:73:84::1;::::0;::::1;4661:21:96::0;4718:2;4698:18;;;4691:30;4757:34;4737:18;;;4730:62;-1:-1:-1;;;4808:18:96;;;4801:36;4854:19;;2019:73:84::1;4477:402:96::0;2019:73:84::1;2102:28;2121:8;2102:18;:28::i;:::-;1939:198:::0;:::o;1298:419:90:-;1385:7;1553:12;1567:23;1602:5;-1:-1:-1;;;;;1594:25:90;:40;;;;-1:-1:-1;;;5085:33:96;;5143:1;5134:11;;4884:267;2291:187:84;2364:16;2383:6;;-1:-1:-1;;;;;2399:17:84;;;-1:-1:-1;;;;;;2399:17:84;;;;;;2431:40;;2383:6;;;;;;;2431:40;;2364:16;2431:40;2354:124;2291:187;:::o;14:160:96:-;-1:-1:-1;;;;;118:31:96;;108:42;;98:70;;164:1;161;154:12;179:313;275:6;328:2;316:9;307:7;303:23;299:32;296:52;;;344:1;341;334:12;296:52;383:9;370:23;402:60;456:5;402:60;:::i;:::-;481:5;179:313;-1:-1:-1;;;179:313:96:o;705:483::-;810:6;818;871:2;859:9;850:7;846:23;842:32;839:52;;;887:1;884;877:12;839:52;926:9;913:23;945:60;999:5;945:60;:::i;:::-;1024:5;-1:-1:-1;1081:2:96;1066:18;;1053:32;1094:62;1053:32;1094:62;:::i;:::-;1175:7;1165:17;;;705:483;;;;;:::o;1193:127::-;1254:10;1249:3;1245:20;1242:1;1235:31;1285:4;1282:1;1275:15;1309:4;1306:1;1299:15;1325:1292;1448:6;1456;1464;1517:2;1505:9;1496:7;1492:23;1488:32;1485:52;;;1533:1;1530;1523:12;1485:52;1572:9;1559:23;1591:60;1645:5;1591:60;:::i;:::-;1670:5;-1:-1:-1;1727:2:96;1712:18;;1699:32;1740:62;1699:32;1740:62;:::i;:::-;1821:7;-1:-1:-1;1879:2:96;1864:18;;1851:32;1902:18;1932:14;;;1929:34;;;1959:1;1956;1949:12;1929:34;1997:6;1986:9;1982:22;1972:32;;2042:7;2035:4;2031:2;2027:13;2023:27;2013:55;;2064:1;2061;2054:12;2013:55;2100:2;2087:16;2122:2;2118;2115:10;2112:36;;;2128:18;;:::i;:::-;2203:2;2197:9;2171:2;2257:13;;-1:-1:-1;;2253:22:96;;;2277:2;2249:31;2245:40;2233:53;;;2301:18;;;2321:22;;;2298:46;2295:72;;;2347:18;;:::i;:::-;2387:10;2383:2;2376:22;2422:2;2414:6;2407:18;2462:7;2457:2;2452;2448;2444:11;2440:20;2437:33;2434:53;;;2483:1;2480;2473:12;2434:53;2539:2;2534;2530;2526:11;2521:2;2513:6;2509:15;2496:46;2584:1;2579:2;2574;2566:6;2562:15;2558:24;2551:35;2605:6;2595:16;;;;;;;1325:1292;;;;;:::o;3175:288::-;3253:6;3306:2;3294:9;3285:7;3281:23;3277:32;3274:52;;;3322:1;3319;3312:12;3274:52;3354:9;3348:16;3373:60;3427:5;3373:60;:::i;3468:356::-;3670:2;3652:21;;;3689:18;;;3682:30;3748:34;3743:2;3728:18;;3721:62;3815:2;3800:18;;3468:356::o;3829:643::-;4033:1;4029;4024:3;4020:11;4016:19;4008:6;4004:32;3993:9;3986:51;3967:4;4056:2;4094;4089;4078:9;4074:18;4067:30;4126:6;4120:13;4169:6;4164:2;4153:9;4149:18;4142:34;4194:1;4204:140;4218:6;4215:1;4212:13;4204:140;;;4313:14;;;4309:23;;4303:30;4279:17;;;4298:2;4275:26;4268:66;4233:10;;4204:140;;;4208:3;4393:1;4388:2;4379:6;4368:9;4364:22;4360:31;4353:42;4463:2;4456;4452:7;4447:2;4439:6;4435:15;4431:29;4420:9;4416:45;4412:54;4404:62;;;;3829:643;;;;;:::o
Swarm Source
ipfs://30f52ef7e16587f148a9f5ca0dbcadc434f9288a9162f8ab87307aa33db8fc43
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.