Contract Name:
xRenzoDepositNativeBridge
Contract Source Code:
// 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 OR Apache-2.0
pragma solidity >=0.6.11;
library TypeCasts {
// alignment preserving cast
function addressToBytes32(address _addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(_addr)));
}
// alignment preserving cast
function bytes32ToAddress(bytes32 _buf) internal pure returns (address) {
require(
uint256(_buf) <= uint256(type(uint160).max),
"TypeCasts: bytes32ToAddress overflow"
);
return address(uint160(uint256(_buf)));
}
}
// 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.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @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) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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 v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
// 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) (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) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
// 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 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
*
* 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: UNLICENSED
pragma solidity ^0.8.0;
interface IWeth {
function deposit() external payable;
function withdraw(uint256 value) external;
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IxRenzoDeposit {
function deposit(
IERC20 _token,
uint256 _amountIn,
uint256 _minOut,
uint256 _deadline
) external returns (uint256);
function sweep(IERC20 _token) external payable;
function updatePrice(uint256 price, uint256 timestamp) external;
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
interface IRenzoOracleL2 {
function getMintRate() external view returns (uint256, uint256);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
struct Quote {
address token; // address(0) for the native token
uint256 amount;
}
interface IValueTransferBridge {
/**
* @notice Transfer value to another domain
* @param _destination The destination domain of the message
* @param _recipient The message recipient address on `destination`
* @param _amount The amount to send to the recipient
* @return messageId The identifier of the dispatched message.
*/
function transferRemote(
uint32 _destination,
bytes32 _recipient,
uint256 _amount
) external payable returns (bytes32);
/**
* @notice Provide the value transfer quote
* @param _destination The destination domain of the message
* @param _recipient The message recipient address on `destination`
* @param _amount The amount to send to the recipient
* @return quotes Indicate how much of each token to approve and/or send.
* @dev Good practice is to use the first entry of the quotes for the native currency (i.e. ETH)
*/
function quoteTransferRemote(
uint32 _destination,
bytes32 _recipient,
uint256 _amount
) external view returns (Quote[] memory quotes);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import "./xRenzoDepositNativeBridgeStorage.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {
OwnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {
IERC20MetadataUpgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import "../../Errors/Errors.sol";
import "../xERC20/interfaces/IXERC20.sol";
import "../Connext/core/IWeth.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "../../RateProvider/IRateProvider.sol";
import "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol";
/**
* @author Renzo
* @title xRenzoDeposit Contract
* @dev Tokens are sent to this contract via deposit, xezETH is minted for the user,
* and funds are batched and bridged down to the L1 for depositing into the Renzo Protocol.
* Any ezETH minted on the L1 will be locked in the lockbox for unwrapping at a later time with xezETH.
* @notice Allows L2 minting of xezETH tokens in exchange for deposited assets
*/
contract xRenzoDepositNativeBridge is
Initializable,
OwnableUpgradeable,
ReentrancyGuardUpgradeable,
IRateProvider,
xRenzoDepositNativeBridgeStorageV2
{
using TypeCasts for address;
using SafeERC20 for IERC20;
/// @dev - This contract expects all tokens to have 18 decimals for pricing
uint8 public constant EXPECTED_DECIMALS = 18;
/// @dev - Fee basis point, 100 basis point = 1 %
uint32 public constant FEE_BASIS = 10000;
IERC20 public constant ETH_NATIVE_TOKEN_ADDRESS =
IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
uint256 public constant MIN_DUST_BRIDGE = 500000 gwei;
event PriceUpdated(uint256 price, uint256 timestamp);
event Deposit(address indexed user, uint256 amountIn, uint256 amountOut);
event BridgeSwept(address token, uint256 amount, address sweeper);
event ReceiverPriceFeedUpdated(address newReceiver, address oldReceiver);
event SweeperBridgeFeeCollected(address sweeper, address token, uint256 feeCollected);
event BridgeFeeShareUpdated(uint256 oldBridgeFeeShare, uint256 newBridgeFeeShare);
event FlatBridgeFeeUpdated(uint256 oldFlatBridgeFee, uint256 newFlatBridgeFee);
event SweepBatchSizeUpdated(uint256 oldSweepBatchSize, uint256 newSweepBatchSize);
event TokenSupportUpdated(
address token,
bool supported,
address oracle,
address valueTransferBridge
);
event TokenTimeDiscountUpdated(address token, uint256 oldDiscount, uint256 newDiscount);
event BridgeFeeCollectorUpdated(address oldBridgeFeeCollector, address newBridgeFeeCollector);
/// @dev Prevents implementation contract from being initialized.
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initializes the contract with initial vars
* @dev All tokens are expected to have 18 decimals
* @param _currentPrice Initializes it with an initial price of ezETH to ETH
* @param _xezETH L2 ezETH token
* @param _weth WETH token for wrapping ETH - can be 0x0 if not supported
* @param _receiver Renzo Receiver middleware contract for price feed
* @param _mainnetDestinationDomain The mainnet destination domain to receive bridge funds
* @param _mainnetRecipient The contract on mainnet to receive bridge funds
* @param _bridgeFeeCollector The address to collect bridge fees - is sent funds as they are collected
*/
function initialize(
uint256 _currentPrice,
IERC20 _xezETH,
IWeth _weth,
address _receiver,
uint32 _mainnetDestinationDomain,
address _mainnetRecipient,
address _bridgeFeeCollector
) public initializer {
// Initialize inherited classes
__Ownable_init();
__ReentrancyGuard_init();
// Verify valid non zero values
if (
_currentPrice == 0 ||
address(_xezETH) == address(0) ||
address(_weth) == address(0) ||
address(_receiver) == address(0) ||
_mainnetDestinationDomain == 0 ||
_mainnetRecipient == address(0) ||
_bridgeFeeCollector == address(0)
) {
revert InvalidZeroInput();
}
// Verify all tokens have 18 decimals
uint8 decimals = IERC20MetadataUpgradeable(address(_xezETH)).decimals();
if (decimals != EXPECTED_DECIMALS) {
revert InvalidTokenDecimals(EXPECTED_DECIMALS, decimals);
}
decimals = IERC20MetadataUpgradeable(address(_weth)).decimals();
if (decimals != EXPECTED_DECIMALS) {
revert InvalidTokenDecimals(EXPECTED_DECIMALS, decimals);
}
// Initialize the price and timestamp
lastPrice = _currentPrice;
lastPriceTimestamp = block.timestamp;
// Set xezETH address
xezETH = _xezETH;
// Set WETH address
weth = _weth;
// Set price receiver contract address
receiver = _receiver;
// Set the destination domain and recipient
mainnetDestinationDomain = _mainnetDestinationDomain;
mainnetRecipient = _mainnetRecipient;
// set bridge Fee Share 0.05% where 100 basis point = 1%
bridgeFeeShare = 5;
//set sweep batch size to 32 ETH
sweepBatchSize = 32 ether;
// Set the bridge fee collector
bridgeFeeCollector = _bridgeFeeCollector;
}
/**
* @notice Accepts deposit for the user in the native asset and mints xezETH
* @dev This function allows anyone to call and deposit the native asset for xezETH
* ezETH will be immediately minted based on the current price
* @param _minOut Minimum number of xezETH to accept to ensure slippage minimums
* @param _deadline latest timestamp to accept this transaction
* @return uint256 Amount of xezETH minted to calling account
*/
function depositETH(
uint256 _minOut,
uint256 _deadline
) external payable nonReentrant returns (uint256) {
if (msg.value == 0) {
revert InvalidZeroInput();
}
// Calculate bridgeFee for deposit amount
uint256 bridgeFee = getBridgeFeeShare(msg.value);
// Send the eth fee to the bridgeFeeCollector
if (bridgeFee > 0) {
bool success = payable(bridgeFeeCollector).send(bridgeFee);
if (!success) revert TransferFailed();
emit SweeperBridgeFeeCollected(
bridgeFeeCollector,
address(ETH_NATIVE_TOKEN_ADDRESS),
bridgeFee
);
}
// Remaining amount after bridge fee
uint256 remainingAmount = msg.value - bridgeFee;
// Sanity check amount
if (remainingAmount == 0) {
revert InvalidZeroInput();
}
// Deposit remaining amount to mint xezETH
return _deposit(ETH_NATIVE_TOKEN_ADDRESS, remainingAmount, _minOut, _deadline);
}
/**
* @notice Accepts deposit for the user in depositToken and mints xezETH
* @dev This funcion allows anyone to call and deposit collateral for xezETH
* ezETH will be immediately minted based on the current price
* Funds will be held until sweep() is called.
* User calling this function should first approve the tokens to be pulled via transferFrom
* @param _amountIn Amount of tokens to deposit
* @param _minOut Minimum number of xezETH to accept to ensure slippage minimums
* @param _deadline latest timestamp to accept this transaction
* @return uint256 Amount of xezETH minted to calling account
*/
function deposit(
IERC20 _token,
uint256 _amountIn,
uint256 _minOut,
uint256 _deadline
) external nonReentrant returns (uint256) {
// Verify the amount is valid
if (_amountIn == 0) {
revert InvalidZeroInput();
}
// Transfer deposit tokens from user to this contract
_token.safeTransferFrom(msg.sender, address(this), _amountIn);
// calculate bridgeFee for deposit amount
uint256 bridgeFee = getBridgeFeeShare(_amountIn);
// Send the fee to the bridgeFeeCollector
if (bridgeFee > 0) {
_token.safeTransfer(bridgeFeeCollector, bridgeFee);
emit SweeperBridgeFeeCollected(bridgeFeeCollector, address(_token), bridgeFee);
}
// subtract from _amountIn
_amountIn -= bridgeFee;
// Get the ETH value of the token
uint256 tokenEthValue = _getTokenEthValue(_token, _amountIn);
if (tokenEthValue == 0) {
revert InvalidZeroOutput();
}
// Special Case if the token is WETH... unwrap to ETH
if (_token == IERC20(address(weth))) {
// Unwrap WETH to ETH
weth.withdraw(_amountIn);
}
return _deposit(_token, tokenEthValue, _minOut, _deadline);
}
/**
* @notice Internal function to trade deposit tokens
* @dev Deposit Tokens should be available in the contract before calling this function
* @param _token Address of the token to be deposited
* @param _tokenEthValue Amount of value priced in ETH
* @param _minOut Minimum number of xezETH to accept to ensure slippage minimums
* @param _deadline latest timestamp to accept this transaction
* @return uint256 Amount of xezETH minted to calling account
*/
function _deposit(
IERC20 _token,
uint256 _tokenEthValue,
uint256 _minOut,
uint256 _deadline
) internal returns (uint256) {
// Verify the token is supported
if (!depositTokenSupported[_token]) {
revert InvalidTokenReceived();
}
// Discount the value based on the time it takes to be sent across the bridge
uint256 timeBasedDiscount = _getTokenTimeBasedDiscount(_token, _tokenEthValue);
_tokenEthValue -= timeBasedDiscount;
// Fetch price and timestamp of ezETH from the configured price feed
(uint256 lastPrice, uint256 lastPriceTimestamp) = getMintRate();
// Verify the price is not stale
if (block.timestamp > lastPriceTimestamp + 1 days) {
revert OraclePriceExpired();
}
// Calculate the amount of xezETH to mint - assumes 18 decimals for price and token
uint256 xezETHAmount = (1e18 * _tokenEthValue) / lastPrice;
// Check that the user will get the minimum amount of xezETH
if (xezETHAmount < _minOut) {
revert InsufficientOutputAmount();
}
// Verify the deadline has not passed
if (block.timestamp > _deadline) {
revert InvalidTimestamp(_deadline);
}
// Mint xezETH to the user
IXERC20(address(xezETH)).mint(msg.sender, xezETHAmount);
// Emit the event and return amount minted
emit Deposit(msg.sender, _tokenEthValue, xezETHAmount);
return xezETHAmount;
}
/**
* @notice Gets the ETH value of the deposit token
* @dev Assumes oracle price is in ETH and is 18 decimals
* @return uint256 ETH Value
*/
function _getTokenEthValue(IERC20 _token, uint256 _amount) internal view returns (uint256) {
AggregatorV3Interface oracle = tokenOracleLookup[_token];
if (address(oracle) == address(0x0)) revert OracleNotFound();
(, int256 price, , uint256 timestamp, ) = oracle.latestRoundData();
if (block.timestamp > timestamp + 1 days) revert OraclePriceExpired();
if (price <= 0) revert InvalidOraclePrice();
// Calculate the value of the token in ETH - assumes both token and price are 18 decimals
return (_amount * uint256(price)) / 1e18;
}
/**
* @notice Function returns bridge fee share for deposit - includes percentage and flat fee
* @param _amountIn deposit amount in terms of ETH
*/
function getBridgeFeeShare(uint256 _amountIn) public view returns (uint256) {
// deduct bridge Fee share
if (_amountIn < sweepBatchSize) {
return ((_amountIn * bridgeFeeShare) / FEE_BASIS) + flatBridgeFee;
} else {
return ((sweepBatchSize * bridgeFeeShare) / FEE_BASIS) + flatBridgeFee;
}
}
/**
* @notice Gets the time based discount for the token amount
* @dev If the token takes 7 days to get across the bridge, the value will not be earning yield for 7 days so it must be discounted.
* The discount should include any staking and restaking yields that the token would have earned.
* @param _token address of the token
* @param _tokenEthValue ETH value of the token
* @return uint256 amount to be discounted by
*/
function _getTokenTimeBasedDiscount(
IERC20 _token,
uint256 _tokenEthValue
) internal view returns (uint256) {
// Calculate the time based discount
return (tokenTimeDiscountBasisPoints[_token] * _tokenEthValue) / FEE_BASIS;
}
/**
* @notice Fetch the price of ezETH from configured price feeds
*/
function getMintRate() public view returns (uint256, uint256) {
// revert if PriceFeedNotAvailable
if (receiver == address(0)) revert PriceFeedNotAvailable();
return (lastPrice, lastPriceTimestamp);
}
/**
* @notice Updates the price feed
* @dev This function will receive the price feed and timestamp from the L1 through CCIPReceiver middleware contract.
* It should verify the origin of the call and only allow permissioned source to call.
* @param _price The price of ezETH sent via L1.
* @param _timestamp The timestamp at which L1 sent the price.
*/
function updatePrice(uint256 _price, uint256 _timestamp) external override {
if (msg.sender != receiver) revert InvalidSender(receiver, msg.sender);
_updatePrice(_price, _timestamp);
}
/**
* @notice Updates the price feed from the Owner account
* @dev Sets the last price and timestamp
* @param price price of ezETH to ETH - 18 decimal precision
*/
function updatePriceByOwner(uint256 price) external onlyOwner {
return _updatePrice(price, block.timestamp);
}
/**
* @notice Internal function to update price
* @dev Sanity checks input values and updates prices
* @param _price Current price of ezETH to ETH - 18 decimal precision
* @param _timestamp The timestamp of the price update
*/
function _updatePrice(uint256 _price, uint256 _timestamp) internal {
_beforeUpdatePrice(_price, _timestamp);
// Update values and emit event
lastPrice = _price;
lastPriceTimestamp = _timestamp;
emit PriceUpdated(_price, _timestamp);
}
function _beforeUpdatePrice(uint256 _price, uint256 _timestamp) internal view {
// Check for 0
if (_price == 0) {
revert InvalidZeroInput();
}
// check for undercollateralized price - < 1
if (_price < 1 ether) {
revert InvalidOraclePrice();
}
// Check for price divergence - more than 1%
if (
(_price > lastPrice && (_price - lastPrice) > (lastPrice / 100)) ||
(_price < lastPrice && (lastPrice - _price) > (lastPrice / 100))
) {
revert InvalidOraclePrice();
}
// Do not allow older price timestamps
if (_timestamp <= lastPriceTimestamp) {
revert InvalidTimestamp(_timestamp);
}
// Do not allow future timestamps
if (_timestamp > block.timestamp) {
revert InvalidTimestamp(_timestamp);
}
}
/**
* @notice This function will take the balance of an asset in the contract and bridge it down to the L1
* @dev The L1 contract will unwrap, deposit in Renzo, and lock up the ezETH in the lockbox on L1
* The caller will estimate and pay the gas for the bridge call
* @param _token Address of token to be swept to L1
*/
function sweep(IERC20 _token) public payable nonReentrant {
// Verify it is a supported token
if (!depositTokenSupported[_token]) {
revert InvalidTokenReceived();
}
// Get the balance of the asset in the contract
uint256 balance = _token.balanceOf(address(this));
// If there is not enough to bridge balance, revert
if (balance <= MIN_DUST_BRIDGE) {
revert InsufficientOutputAmount();
}
// Approve the token and route it to mainnet
_token.safeIncreaseAllowance(address(valueTransferBridges[_token]), balance);
// Include the msg.value to pay any bridge fees
valueTransferBridges[_token].transferRemote{ value: msg.value }(
mainnetDestinationDomain,
mainnetRecipient.addressToBytes32(),
balance
);
// Emit the event
emit BridgeSwept(address(_token), balance, msg.sender);
}
/**
* @notice This function will take the balance ETH in the contract and bridge it down to the L1
* @dev The L1 contract will deposit in Renzo, and lock up the ezETH in the lockbox on L1
* The caller will estimate and pay the gas for the bridge call
*/
function sweepETH() public payable nonReentrant {
// Verify Native ETH is supported
if (!depositTokenSupported[ETH_NATIVE_TOKEN_ADDRESS]) {
revert InvalidTokenReceived();
}
// Get the balance of ETH in the contract minus the gas value
uint256 valueToSend = address(this).balance - msg.value;
// If there is not enough to bridge balance, revert
if (valueToSend <= MIN_DUST_BRIDGE) {
revert InsufficientOutputAmount();
}
// Send the full ETH available but specify the amount that should be bridged
valueTransferBridges[ETH_NATIVE_TOKEN_ADDRESS].transferRemote{
value: address(this).balance
}(mainnetDestinationDomain, mainnetRecipient.addressToBytes32(), valueToSend);
// Emit the event
emit BridgeSwept(address(ETH_NATIVE_TOKEN_ADDRESS), valueToSend, msg.sender);
}
/**
* @notice Exposes the price via getRate()
* @dev This is required for a balancer pool to get the price of ezETH
* @return uint256 .
*/
function getRate() external view override returns (uint256) {
(uint256 _lastPrice, uint256 _lastPriceTimestamp) = getMintRate();
if (block.timestamp > _lastPriceTimestamp + 1 days) {
revert OraclePriceExpired();
}
return _lastPrice;
}
/**
* @notice Allows the owner to set the support for a deposit asset
* @dev Checks the token for 0 anb verifies the oracle is set properly if adding support
* @param _token EC20 token
* @param _supported Indicates if the token is supported for a deposit asset
* @param _tokenOracle If supported, the oracle for the token to get pricing in ETH
* @param _valueTransferBridge Middleware contract used to transfer asset through configured bridge
*/
function setSupportedToken(
IERC20 _token,
bool _supported,
AggregatorV3Interface _tokenOracle,
IValueTransferBridge _valueTransferBridge
) external onlyOwner {
// Verify the token is not 0
if (address(_token) == address(0)) revert InvalidZeroInput();
// Verify the token is 18 decimals if it is not ETH
if (
address(_token) != address(ETH_NATIVE_TOKEN_ADDRESS) &&
IERC20MetadataUpgradeable(address(_token)).decimals() != 18
) revert InvalidTokenDecimals(18, IERC20MetadataUpgradeable(address(_token)).decimals());
// Update support value
depositTokenSupported[_token] = _supported;
// If support is being added, verify the oracle
if (_supported) {
if (address(_tokenOracle) == address(0)) revert InvalidZeroInput();
// Verify that the pricing of the oracle is to 18 decimals - pricing calculations will be off otherwise
if (_tokenOracle.decimals() != 18)
revert InvalidTokenDecimals(18, _tokenOracle.decimals());
// Set the oracle lookup
tokenOracleLookup[_token] = _tokenOracle;
if (address(_valueTransferBridge) == address(0)) {
revert InvalidZeroInput();
}
// Set the value transfer bridge
valueTransferBridges[_token] = _valueTransferBridge;
} else {
// If not supported, set the oracle to 0
tokenOracleLookup[_token] = AggregatorV3Interface(address(0));
// If not supported, set the value transfer bridge to 0
valueTransferBridges[_token] = IValueTransferBridge(address(0));
}
// Emit the event
emit TokenSupportUpdated(
address(_token),
_supported,
address(_tokenOracle),
address(_valueTransferBridge)
);
}
/**
* @notice Sweeps accidental ETH value sent to the contract
* @dev Restricted to be called by the Owner only.
* @param _amount amount of native asset
* @param _to destination address
*/
function recoverNative(uint256 _amount, address _to) external onlyOwner {
payable(_to).transfer(_amount);
}
/**
* @notice Sweeps accidental ERC20 value sent to the contract
* @dev Restricted to be called by the Owner only.
* @param _token address of the ERC20 token
* @param _amount amount of ERC20 token
* @param _to destination address
*/
function recoverERC20(address _token, uint256 _amount, address _to) external onlyOwner {
IERC20(_token).safeTransfer(_to, _amount);
}
/******************************
* Admin/OnlyOwner functions
*****************************/
/**
* @notice This function sets/updates the Bridge Fee Collector address
* @dev This should be permissioned call (onlyOwner)
* @param _bridgeFeeCollector new Bridge fee collector address
*/
function setBridgeFeeCollector(address _bridgeFeeCollector) external onlyOwner {
if (_bridgeFeeCollector == address(0)) revert InvalidZeroInput();
emit BridgeFeeCollectorUpdated(bridgeFeeCollector, _bridgeFeeCollector);
bridgeFeeCollector = _bridgeFeeCollector;
}
/**
* @notice This function sets/updates the Receiver Price Feed Middleware for ezETH
* @dev This should be permissioned call (onlyOnwer), can be set to address(0) for not configured
* @param _receiver Receiver address
*/
function setReceiverPriceFeed(address _receiver) external onlyOwner {
emit ReceiverPriceFeedUpdated(_receiver, receiver);
receiver = _receiver;
}
/**
* @notice This function updates the BridgeFeeShare for depositors (must be <= 1% i.e. 100 bps)
* @dev This should be a permissioned call (onlyOnwer)
* @param _newShare new Bridge fee share in basis points where 100 basis points = 1%
* @param _newFlatFee new flat fee charged for each deposit in addition to the % fee - in token units
*/
function updateBridgeFeeShare(uint256 _newShare, uint256 _newFlatFee) external onlyOwner {
if (_newShare > 100) revert InvalidBridgeFeeShare(_newShare);
emit BridgeFeeShareUpdated(bridgeFeeShare, _newShare);
bridgeFeeShare = _newShare;
emit FlatBridgeFeeUpdated(flatBridgeFee, _newFlatFee);
flatBridgeFee = _newFlatFee;
}
/**
* @notice This function updates the Sweep Batch Size (must be >= 32 ETH)
* @dev This should be a permissioned call (onlyOwner)
* @param _newBatchSize new batch size for sweeping
*/
function updateSweepBatchSize(uint256 _newBatchSize) external onlyOwner {
if (_newBatchSize < 32 ether) revert InvalidSweepBatchSize(_newBatchSize);
emit SweepBatchSizeUpdated(sweepBatchSize, _newBatchSize);
sweepBatchSize = _newBatchSize;
}
/**
* @notice Updates the time based discount bps per token
* @dev This should be a permissioned call (onlyOwner)
* @param _token address of the token
* @param _discount time based discount in basis points where 100 basis points = 1%
*/
function updateTokenTimeDiscount(IERC20 _token, uint256 _discount) external onlyOwner {
// Verify the token is supported
if (!depositTokenSupported[_token]) {
revert InvalidTokenReceived();
}
// The discount should not be greater than 1%
if (_discount > 100) revert OverMaxBasisPoints();
// Get the discount currently set
uint256 oldDiscount = tokenTimeDiscountBasisPoints[_token];
// Update the discount and emit event
tokenTimeDiscountBasisPoints[_token] = _discount;
emit TokenTimeDiscountUpdated(address(_token), oldDiscount, _discount);
}
/**
* @notice Fallback function to handle ETH sent to the contract from unwrapping WETH
* @dev Warning: users should not send ETH directly to this contract!
*/
receive() external payable {}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import "./IxRenzoDeposit.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./Oracle/IRenzoOracleL2.sol";
import "../Connext/core/IWeth.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "./ValueTransfer/IValueTransferBridge.sol";
abstract contract xRenzoDepositNativeBridgeStorageV1 is IxRenzoDeposit {
/// @notice The last timestamp the price was updated
uint256 public lastPriceTimestamp;
/// @notice The last price that was updated - denominated in ETH with 18 decimal precision
uint256 public lastPrice;
/// @notice The xezETH token address
IERC20 public xezETH;
/// @notice The receiver middleware contract address
address public receiver;
/// @notice The contract address where the bridge call should be sent on mainnet ETH
address public bridgeTargetAddress;
// bridge fee in basis points 100 basis points = 1%
uint256 public bridgeFeeShare;
// Batch size for sweeping
uint256 public sweepBatchSize;
// WETH token for wrapping ETH
IWeth public weth;
/// @dev Contracts that routes funds down to mainnet per token
mapping(IERC20 => IValueTransferBridge) public valueTransferBridges;
/// @dev The mainnet destination domain to receive bridge funds
uint32 public mainnetDestinationDomain;
/// @dev The contract on mainnet to receive bridge funds
address public mainnetRecipient;
// @dev Mapping of supported tokens
mapping(IERC20 => bool) public depositTokenSupported;
// @dev Mapping of token to oracle lookup
mapping(IERC20 => AggregatorV3Interface) public tokenOracleLookup;
// @dev Bridge fees are sent to the bridge fee collector
address public bridgeFeeCollector;
// @dev The mapping of token to time based discount in basis points - 100 basis points = 1%
mapping(IERC20 => uint256) public tokenTimeDiscountBasisPoints;
}
abstract contract xRenzoDepositNativeBridgeStorageV2 is xRenzoDepositNativeBridgeStorageV1 {
/// @dev A flat amount charged to each deposit in addition to the % fee (optional)
uint256 public flatBridgeFee;
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.4 <0.9.0;
interface IXERC20 {
/**
* @notice Emits when a lockbox is set
*
* @param _lockbox The address of the lockbox
*/
event LockboxSet(address _lockbox);
/**
* @notice Emits when a limit is set
*
* @param _mintingLimit The updated minting limit we are setting to the bridge
* @param _burningLimit The updated burning limit we are setting to the bridge
* @param _bridge The address of the bridge we are setting the limit too
*/
event BridgeLimitsSet(uint256 _mintingLimit, uint256 _burningLimit, address indexed _bridge);
/**
* @notice Reverts when a user with too low of a limit tries to call mint/burn
*/
error IXERC20_NotHighEnoughLimits();
/**
* @notice Reverts when caller is not the factory
*/
error IXERC20_NotFactory();
/**
* @notice Reverts when mint or burn value is 0
*/
error IXERC20_INVALID_0_VALUE();
/**
* @notice Contains the full minting and burning data for a particular bridge
*
* @param minterParams The minting parameters for the bridge
* @param burnerParams The burning parameters for the bridge
*/
struct Bridge {
BridgeParameters minterParams;
BridgeParameters burnerParams;
}
/**
* @notice Contains the mint or burn parameters for a bridge
*
* @param timestamp The timestamp of the last mint/burn
* @param ratePerSecond The rate per second of the bridge
* @param maxLimit The max limit of the bridge
* @param currentLimit The current limit of the bridge
*/
struct BridgeParameters {
uint256 timestamp;
uint256 ratePerSecond;
uint256 maxLimit;
uint256 currentLimit;
}
/**
* @notice Sets the lockbox address
*
* @param _lockbox The address of the lockbox
*/
function setLockbox(address _lockbox) external;
/**
* @notice Updates the limits of any bridge
* @dev Can only be called by the owner
* @param _mintingLimit The updated minting limit we are setting to the bridge
* @param _burningLimit The updated burning limit we are setting to the bridge
* @param _bridge The address of the bridge we are setting the limits too
*/
function setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) external;
/**
* @notice Returns the max limit of a minter
*
* @param _minter The minter we are viewing the limits of
* @return _limit The limit the minter has
*/
function mintingMaxLimitOf(address _minter) external view returns (uint256 _limit);
/**
* @notice Returns the max limit of a bridge
*
* @param _bridge the bridge we are viewing the limits of
* @return _limit The limit the bridge has
*/
function burningMaxLimitOf(address _bridge) external view returns (uint256 _limit);
/**
* @notice Returns the current limit of a minter
*
* @param _minter The minter we are viewing the limits of
* @return _limit The limit the minter has
*/
function mintingCurrentLimitOf(address _minter) external view returns (uint256 _limit);
/**
* @notice Returns the current limit of a bridge
*
* @param _bridge the bridge we are viewing the limits of
* @return _limit The limit the bridge has
*/
function burningCurrentLimitOf(address _bridge) external view returns (uint256 _limit);
/**
* @notice Mints tokens for a user
* @dev Can only be called by a minter
* @param _user The address of the user who needs tokens minted
* @param _amount The amount of tokens being minted
*/
function mint(address _user, uint256 _amount) external;
/**
* @notice Burns tokens for a user
* @dev Can only be called by a minter
* @param _user The address of the user who needs tokens burned
* @param _amount The amount of tokens being burned
*/
function burn(address _user, uint256 _amount) external;
function owner() external view returns (address);
function balanceOf(address _user) external view returns (uint256);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
/// @dev Error for 0x0 address inputs
error InvalidZeroInput();
/// @dev Error for already added items to a list
error AlreadyAdded();
/// @dev Error for not found items in a list
error NotFound();
/// @dev Error for hitting max TVL
error MaxTVLReached();
/// @dev Error for caller not having permissions
error NotRestakeManagerAdmin();
/// @dev Error for call not coming from deposit queue contract
error NotDepositQueue();
/// @dev Error for contract being paused
error ContractPaused();
/// @dev Error for exceeding max basis points (100%)
error OverMaxBasisPoints();
/// @dev Error for invalid token decimals for collateral tokens (must be 18)
error InvalidTokenDecimals(uint8 expected, uint8 actual);
/// @dev Error when withdraw is already completed
error WithdrawAlreadyCompleted();
/// @dev Error when a different address tries to complete withdraw
error NotOriginalWithdrawCaller(address expectedCaller);
/// @dev Error when caller does not have OD admin role
error NotOperatorDelegatorAdmin();
/// @dev Error when caller does not have Oracle Admin role
error NotOracleAdmin();
/// @dev Error when caller is not RestakeManager contract
error NotRestakeManager();
/// @dev Errror when caller does not have ETH Restake Admin role
error NotNativeEthRestakeAdmin();
/// @dev Error when delegation address was already set - cannot be set again
error DelegateAddressAlreadySet();
/// @dev Error when caller does not have ERC20 Rewards Admin role
error NotERC20RewardsAdmin();
/// @dev Error when sending ETH fails
error TransferFailed();
/// @dev Error when caller does not have ETH Minter Burner Admin role
error NotEzETHMinterBurner();
/// @dev Error when caller does not have Token Admin role
error NotTokenAdmin();
/// @dev Error when price oracle is not configured
error OracleNotFound();
/// @dev Error when price oracle data is stale
error OraclePriceExpired();
/// @dev Error when array lengths do not match
error MismatchedArrayLengths();
/// @dev Error when caller does not have Deposit Withdraw Pauser role
error NotDepositWithdrawPauser();
/// @dev Error when an individual token TVL is over the max
error MaxTokenTVLReached();
/// @dev Error when Oracle price is invalid
error InvalidOraclePrice();
/// @dev Error when calling an invalid function
error NotImplemented();
/// @dev Error when calculating token amounts is invalid
error InvalidTokenAmount();
/// @dev Error when timestamp is invalid - likely in the past
error InvalidTimestamp(uint256 timestamp);
/// @dev Error when trade does not meet minimum output amount
error InsufficientOutputAmount();
/// @dev Error when the token received over the bridge is not the one expected
error InvalidTokenReceived();
/// @dev Error when the origin address is not whitelisted
error InvalidOrigin();
/// @dev Error when the sender is not expected
error InvalidSender(address expectedSender, address actualSender);
/// @dev error when function returns 0 amount
error InvalidZeroOutput();
/// @dev error when xRenzoBridge does not have enough balance to pay for fee
error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees);
/// @dev error when source chain is not expected
error InvalidSourceChain(uint64 expectedCCIPChainSelector, uint64 actualCCIPChainSelector);
/// @dev Error when an unauthorized address tries to call the bridge function on the L2
error UnauthorizedBridgeSweeper();
/// @dev Error when caller does not have BRIDGE_ADMIN role
error NotBridgeAdmin();
/// @dev Error when caller does not have PRICE_FEED_SENDER role
error NotPriceFeedSender();
/// @dev Error for connext price Feed unauthorised call
error UnAuthorisedCall();
/// @dev Error for no price feed configured on L2
error PriceFeedNotAvailable();
/// @dev Error for invalid bridge fee share configuration
error InvalidBridgeFeeShare(uint256 bridgeFee);
/// @dev Error for invalid sweep batch size
error InvalidSweepBatchSize(uint256 batchSize);
/// @dev Error when caller does not have Withdraw Queue admin role
error NotWithdrawQueueAdmin();
/// @dev Error when caller try to withdraw more than Buffer
error NotEnoughWithdrawBuffer();
/// @dev Error when caller try to claim withdraw before cooldown period
error EarlyClaim();
/// @dev Error when caller try to withdraw for unsupported asset
error UnsupportedWithdrawAsset();
/// @dev Error when caller try to claim invalidWithdrawIndex
error InvalidWithdrawIndex();
/// @dev Error when TVL was expected to be 0
error InvalidTVL();
/// @dev Error when incorrect BeaconChainStrategy is set for LST in completeQueuedWithdrawal
error IncorrectStrategy();
/// @dev Error when adding new OperatorDelegator which is not delegated
error OperatoDelegatorNotDelegated();
/// @dev Error when emergency tracking already tracked withdrawal
error WithdrawalAlreadyTracked();
/// @dev Error when emergency tracking already completed withdrawal
error WithdrawalAlreadyCompleted();
/// @dev Error when caller does not have Emergency Withdraw Tracking Admin role
error NotEmergencyWithdrawTrackingAdmin();
/// @dev Error when strategy does not have specified underlying
error InvalidStrategy();
/// @dev Error when strategy already set and hold non zero token balance
error NonZeroUnderlyingStrategyExist();
/// @dev Error when caller tried to claim queued withdrawal when not filled
error QueuedWithdrawalNotFilled();
/// @dev Error when caller does not have EigenLayerRewardsAdmin role
error NotEigenLayerRewardsAdmin();
/// @dev Error when rewardsDestination is not configured while trying to claim
error RewardsDestinationNotConfigured();
/// @dev Error when WETHUnwrapper is not configured while trying to claim WETH restaking rewards
error WETHUnwrapperNotConfigured();
/// @dev Error when currentCheckpoint is not accounted by OperatorDelegator
error CheckpointAlreadyActive();
/// @dev Error when specified checkpoint is already recorded
error CheckpointAlreadyRecorded();
/// @dev Error when caller does not have Emergency Checkpoint Tracking admin role
error NotEmergencyCheckpointTrackingAdmin();
/// @dev Error when last completed checkpoint on EigenPod is not recorded in OperatorDelegator
error CheckpointNotRecorded();
/// @dev Error when non pauser tries to change pause state
error NotPauser();
/// @dev Error when user tried to withdraw asset more than available in protocol collateral
error NotEnoughCollateralValue();
/// @dev Error when admin tries to disable asset withdraw queue which is not enabled
error WithdrawQueueNotEnabled();
/// @dev Error when admin tries to enable erc20 withdraw queue for IS_NATIVE address
error IsNativeAddressNotAllowed();
/// @dev Error when admin tried to complete queued withdrawal with receiveAsShares
error OnlyReceiveAsTokenAllowed();
/// @dev Error when Withdrawal is not queued
error WithdrawalNotQueued();
/// @dev Error when admin tries to track Withdraw of different staker
error InvalidStakerAddress();
/// @dev Error when caller does not have Emergency track AVS ETH slashing admin role
error NotEmergencyTrackAVSEthSlashingAdmin();
/// @dev Error when below the limit
error BelowAllowedLimit();
/// @dev Error when gas refund address is not set in DepositQueue
error GasRefundAddressNotSet();
/// @dev Error when withdraw requests are paused.
error WithdrawRequestPaused();
/// @dev Error when withdraw claims are paused.
error ClaimPaused();
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity 0.8.27;
interface IRateProvider {
function getRate() external view returns (uint256);
}