Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/interfaces/IERC1363.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
"
},
"@openzeppelin/contracts/interfaces/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
"
},
"@openzeppelin/contracts/interfaces/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
"
},
"@openzeppelin/contracts/interfaces/IERC20Metadata.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
"
},
"@openzeppelin/contracts/interfaces/IERC4626.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
"
},
"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
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);
}
"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}
"
},
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 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 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, 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.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @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.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @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 silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
"
},
"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}
"
},
"@openzeppelin/contracts/token/ERC721/IERC721.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC-721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
"
},
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* 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[ERC 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);
}
"
},
"contracts/interfaces/IApp.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.28;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IApp is IERC20 {
function mint(address account_, uint256 amount_) external;
function burn(uint256 amount) external;
}
"
},
"contracts/interfaces/IAppConvertibles.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.28;
pragma abicoder v2;
import "./IApp.sol";
import "./IAppOracle.sol";
import "./IOracleV2.sol";
import "./IPermissionedERC20.sol";
import "./IPermissionedERC20Factory.sol";
import "@openzeppelin/contracts/interfaces/IERC4626.sol";
import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
/// @title IAppConvertibles Interface
/// @author RZR Protocol
/// @notice Interface for the RZR Convertibles system
interface IAppConvertibles is IERC721Enumerable {
/// @notice Position data structure for convertible positions
/// @param amountStaked Amount of loan tokens staked in this position
/// @param amountConvertible Amount of RZR tokens convertible in this position
/// @param fixedInterestRate Fixed interest rate per second for this position
/// @param fixedInterestClaimed Amount of interest claimed by user
/// @param lockDuration Lock duration for this position
/// @param lockStartTime Timestamp when the lock period started
/// @param priceConversion Price at which conversion can occur
/// @param priceEntry Price when the position was created
struct Position {
IERC4626 asset;
uint256 amountStaked;
uint256 amountConvertible;
uint256 stakingPower;
uint256 fixedInterestRate;
uint256 fixedInterestClaimed;
uint256 lockDuration;
uint256 lockStartTime;
uint256 priceConversion;
uint256 priceEntry;
}
/// @notice Contract configuration variables
/// @param minConversionPremium Minimum conversion premium (in basis points)
/// @param maxConversionPremium Maximum conversion premium (in basis points)
/// @param minFixedInterestRate Minimum fixed interest rate per second
/// @param maxFixedInterestRate Maximum fixed interest rate per second
struct Variables {
IPermissionedERC20 trackingToken;
uint256 minConversionPremium;
uint256 maxConversionPremium;
uint256 minFixedInterestRate;
uint256 maxFixedInterestRate;
uint256 debtCap;
}
/// @notice Emitted when a user creates a new convertible position
/// @param user The address of the user who staked
/// @param tokenId The NFT token ID for the new position
/// @param amountStaked Amount of loan tokens staked
/// @param amountConvertible Amount of RZR tokens convertible
/// @param lockDuration Lock duration for the position
/// @param priceEntry Price when the position was created
/// @param priceConversion Price at which conversion can occur
/// @param fixedInterestPerSecond Fixed interest rate per second
event Staked(
address indexed user,
uint256 indexed tokenId,
uint256 amountStaked,
uint256 amountConvertible,
uint256 lockDuration,
uint256 priceEntry,
uint256 priceConversion,
uint256 fixedInterestPerSecond
);
/// @notice Emitted when a user converts their convertible position to RZR tokens
/// @param user The address of the user who converted
/// @param tokenId The NFT token ID that was converted
/// @param amountStaked Amount of loan tokens that were staked
/// @param amountConvertible Amount of RZR tokens that were convertible
/// @param twapPrice The TWAP price that triggered the conversion
event Converted(
address indexed user,
uint256 indexed tokenId,
uint256 amountStaked,
uint256 amountConvertible,
uint256 twapPrice
);
/// @notice Emitted when a user redeems their convertible position for loan tokens + interest
/// @param user The address of the user who redeemed
/// @param tokenId The NFT token ID that was redeemed
/// @param amountStaked Amount of loan tokens that were staked
/// @param amountConvertible Amount of RZR tokens that were convertible
/// @param interestAccumulated Amount of interest accumulated and paid out
event Redeemed(
address indexed user,
uint256 indexed tokenId,
uint256 amountStaked,
uint256 amountConvertible,
uint256 interestAccumulated
);
/// @notice Emitted when governance updates the contract variables
/// @param loanToken The loan token that was enabled
/// @param minConversionPremium New minimum conversion premium
/// @param maxConversionPremium New maximum conversion premium
/// @param minFixedInterestRate New minimum fixed interest rate per second
/// @param maxFixedInterestRate New maximum fixed interest rate per second
/// @param debtCap New maximum debt of convertible positions
event VariablesUpdated(
IERC20 indexed loanToken,
uint256 minConversionPremium,
uint256 maxConversionPremium,
uint256 minFixedInterestRate,
uint256 maxFixedInterestRate,
uint256 debtCap
);
/// @notice Emitted when a convertible NFT is transferred between addresses
/// @param from The address transferring the position
/// @param to The address receiving the position
/// @param tokenId The NFT token ID being transferred
/// @param amountStaked Amount of loan tokens staked in the position
/// @param amountConvertible Amount of RZR tokens convertible in the position
event PositionTransferred(
address indexed from,
address indexed to,
uint256 indexed tokenId,
uint256 amountStaked,
uint256 amountConvertible
);
/// @notice Emitted when a convertible position is split into two positions
/// @param user The address of the user who split the position
/// @param originalTokenId The original NFT token ID
/// @param newTokenId The new NFT token ID created from the split
/// @param originalAmountStaked Total amount staked in the original position
/// @param newAmountStaked Amount staked in the new position
/// @param originalAmountConvertible Total amount convertible in the original position
/// @param newAmountConvertible newAmountConvertible Amount convertible in the new position
/// @param percentageE18 The percentage used for the split (in basis points)
event PositionSplit(
address indexed user,
uint256 indexed originalTokenId,
uint256 indexed newTokenId,
uint256 originalAmountStaked,
uint256 newAmountStaked,
uint256 originalAmountConvertible,
uint256 newAmountConvertible,
uint256 percentageE18
);
/// @notice Emitted when a user claims interest from a convertible position
/// @param user The address of the user who claimed interest
/// @param tokenId The NFT token ID that the interest was claimed from
/// @param interestClaimed interestClaimed Amount of interest claimed
event InterestClaimed(address indexed user, uint256 indexed tokenId, uint256 interestClaimed);
/// @notice Emitted when a token is enabled
/// @param token The token that was enabled
event TokenEnabled(address indexed token);
/// @notice Get the claimable interest for a convertible position
/// @param tokenId The NFT token ID that the interest was claimed from
/// @return interestClaimable interestClaimable Amount of interest claimable
/// @return totalInterestClaimed Total amount of interest claimed
function claimableInterest(uint256 tokenId)
external
view
returns (uint256 interestClaimable, uint256 totalInterestClaimed);
/// @notice Claim interest from a convertible position
/// @param tokenId The NFT token ID to claim interest from
/// @param unwrap4626 Whether to unwrap the interest from the 4626 vault
/// @return interestClaimed interestClaimed Amount of interest claimed
/// @return totalInterestClaimed Total amount of interest claimed
function claimInterest(uint256 tokenId, bool unwrap4626)
external
returns (uint256 interestClaimed, uint256 totalInterestClaimed);
/// @notice Maximum lock duration for convertible positions (4 years)
/// @return value The maximum lock duration in seconds
function MAX_LOCK_DURATION() external view returns (uint256 value);
/// @notice Minimum lock duration for convertible positions (30 days)
/// @return value The minimum lock duration in seconds
function MIN_LOCK_DURATION() external view returns (uint256 value);
/// @notice Maximum age of oracle price data before considered stale (1 day)
/// @return value The maximum oracle staleness period in seconds
function MAX_ORACLE_STALENESS() external view returns (uint256 value);
/// @notice Minimum bond duration for convertible positions (7 days)
/// @return value The minimum bond duration in seconds
function MIN_BOND_DURATION() external view returns (uint256 value);
/// @notice The RZR token contract
/// @return rzr rzr The RZR token contract address
function rzr() external view returns (IApp rzr);
/// @notice The tracking token for loan positions
/// @return stakingPowerToken stakingPowerToken The loan tracking token contract address
function stakingPowerToken() external view returns (IPermissionedERC20 stakingPowerToken);
/// @notice The tracking token for RZR convertible positions
/// @return rzrTrackingToken rzrTrackingToken The RZR tracking token contract address
function rzrTrackingToken() external view returns (IPermissionedERC20 rzrTrackingToken);
/// @notice The oracle contract for price feeds
/// @return oracle The oracle contract address
function oracle() external view returns (IAppOracle oracle);
/// @notice The TWAP oracle contract for conversion price validation
/// @return twapOracle The TWAP oracle contract address
function twapOracle() external view returns (IOracleV2 twapOracle);
/// @notice The spot oracle contract for conversion price validation
/// @return spotOracle The spot oracle contract address
function spotOracle() external view returns (IOracleV2 spotOracle);
/// @notice The last issued token ID
/// @return lastId The most recent token ID
function lastId() external view returns (uint256 lastId);
/// @notice The factory contract for creating permissioned ERC20 tokens
/// @return factory factory The factory contract address
function factory() external view returns (IPermissionedERC20Factory factory);
/// @notice Total amount of loan tokens staked across all positions
/// @return totalStaked The total staked amount
function totalStaked(address loanToken) external view returns (uint256 totalStaked);
/// @notice Total amount of RZR tokens convertible across all positions
/// @return totalConvertible The total convertible amount
function totalConvertible() external view returns (uint256 totalConvertible);
/// @notice Contract variables for conversion premiums and interest rates
/// @param _loanToken The loan token that was enabled
/// @return vars The contract variables
function variables(IERC20 _loanToken) external view returns (Variables memory vars);
/// @notice Get position details for a specific token ID
/// @param tokenId The NFT token ID
/// @return position The position details
function positions(uint256 tokenId) external view returns (Position memory position);
/// @notice Initialize the convertibles contract
/// @param _rzr The RZR token contract address
/// @param _oracle The oracle contract address for price feeds
/// @param _spotOracle The spot oracle contract address
/// @param _twapOracle The TWAP oracle contract address
/// @param _authority The authority contract address
function initialize(
address _rzr,
address _oracle,
address _spotOracle,
address _twapOracle,
address _authority,
address _factory
) external;
/// @notice Enable a new loan token for convertible positions
/// @param loanToken The loan token to enable
/// @param _minConversionPremium Minimum conversion premium (in basis points)
/// @param _maxConversionPremium Maximum conversion premium (in basis points)
/// @param _minFixedInterestRate Minimum fixed interest rate per second
/// @param _maxFixedInterestRate Maximum fixed interest rate per second
/// @param _debtCap Maximum debt of convertible positions
function enableToken(
IERC20Metadata loanToken,
uint256 _minConversionPremium,
uint256 _maxConversionPremium,
uint256 _minFixedInterestRate,
uint256 _maxFixedInterestRate,
uint256 _debtCap
) external;
/// @notice Set contract variables (governance only)
/// @param _loanToken The loan token that was enabled
/// @param _minConversionPremium Minimum conversion premium (in basis points)
/// @param _maxConversionPremium Maximum conversion premium (in basis points)
/// @param _minFixedInterestRate Minimum fixed interest rate per second
/// @param _maxFixedInterestRate Maximum fixed interest rate per second
/// @param _debtCap Maximum debt of convertible positions
function setVariables(
IERC20 _loanToken,
uint256 _minConversionPremium,
uint256 _maxConversionPremium,
uint256 _minFixedInterestRate,
uint256 _maxFixedInterestRate,
uint256 _debtCap
) external;
/// @notice Create a new convertible position by staking loan tokens
/// @param amount Amount of loan tokens to stake
/// @param lockDuration Duration to lock the position (must be between MIN and MAX)
/// @param receiver The address to receive the convertible position
/// @return tokenId The NFT token ID for the new position
/// @return conversionPrice Price at which conversion can occur
/// @return conversionAmount Amount of RZR tokens convertible
/// @return fixedInterestRate Fixed interest rate per second
/// @return fixedInterestRateAmount Fixed interest rate amount
/// @return stakingPower Amount of staking power tokens received
function stake(IERC20 loanToken, uint256 amount, uint256 lockDuration, address receiver)
external
returns (
uint256 tokenId,
uint256 conversionPrice,
uint256 conversionAmount,
uint256 fixedInterestRate,
uint256 fixedInterestRateAmount,
uint256 stakingPower
);
/// @notice Convert a convertible position to RZR tokens
/// @param tokenId The NFT token ID to convert
function convert(uint256 tokenId) external;
/// @notice Redeem a convertible position for loan tokens + accumulated interest
/// @param tokenId The NFT token ID to redeem
/// @param unwrap4626 Whether to unwrap the loan tokens from the 4626 vault
function redeem(uint256 tokenId, bool unwrap4626) external;
/// @notice Split a convertible position into two positions
/// @param tokenId The NFT token ID to split
/// @param percentageE18 The percentage to split (0-1e18 representing 0-100%)
function split(uint256 tokenId, uint256 percentageE18) external;
/// @notice Calculate conversion terms for a given amount and lock duration
/// @param loanToken The loan token that was enabled
/// @param amountLoan Amount of loan tokens to stake
/// @param lockDuration Duration to lock the position
/// @return conversionPrice Price at which conversion can occur
/// @return conversionAmount Amount of RZR tokens convertible
/// @return fixedInterestRate Fixed interest rate per second
function getOfferings(IERC20 loanToken, uint256 amountLoan, uint256 lockDuration)
external
view
returns (uint256 conversionPrice, uint256 conversionAmount, uint256 fixedInterestRate);
/// @notice Executes a function on the contract
/// @param target The target contract
/// @param data The data to execute
function execute(address target, bytes memory data) external;
}
"
},
"contracts/interfaces/IAppOracle.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.28;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface IAppOracle {
event OracleUpdated(address indexed token, address indexed oracle, uint256 maxStaleness);
event FloorPriceUpdated(uint256 oldPrice, uint256 newPrice);
event PriceFetched(
address indexed token, uint256 amount, uint256 rzrAmount, uint256 usdAmount, uint256 lastUpdatedAt
);
// Errors
error OracleNotFound(address token);
error OracleAlreadyExists(address token);
error OracleInactive(address token);
error InvalidOracleAddress();
error InvalidTokenAddress();
/// @notice Initializes the AppOracle contract
/// @dev This function is only callable once
/// @param _authority The address of the authority contract
/// @param _app The address of the app contract
function initialize(address _authority, address _app) external;
/**
* @notice Update the oracle for a token
* @param token The token address
* @param oracle The oracle contract
*/
function updateOracle(address token, address oracle, uint256 maxStaleness) external;
/**
* @notice Get the price for a token
* @param token The token address
* @return rzrAmount The token price in RZR
* @return usdAmount The token price in USD
* @return lastUpdatedAt The timestamp of the last update
*/
function getPrice(address token)
external
view
returns (uint256 rzrAmount, uint256 usdAmount, uint256 lastUpdatedAt);
/**
* @notice Get the price for a token in RZR for an amount
* @param token The token address
* @param amount The amount of the token
* @return rzrAmount The token price in RZR for the amount
* @return usdAmount The token price in USD for the amount
* @return lastUpdatedAt The timestamp of the last update
*/
function getPriceForAmount(address token, uint256 amount)
external
view
returns (uint256 rzrAmount, uint256 usdAmount, uint256 lastUpdatedAt);
/**
* @notice Get the price for a token in RZR for an amount in the floor price
* @param token The token address
* @param amount The amount of the token
* @return rzrAmount The token price in RZR for the amount
* @return usdAmount The token price in USD for the amount
* @return lastUpdatedAt The timestamp of the last update
*/
function getPriceForAmountInFloor(address token, uint256 amount)
external
view
returns (uint256 rzrAmount, uint256 usdAmount, uint256 lastUpdatedAt);
/**
* @notice Get the floor price for RZR
* @return price The RZR floor price
*/
function getTokenPrice() external view returns (uint256);
/**
* @notice Set the floor price for RZR
* @param newFloorPrice The new RZR price
*/
function setTokenPrice(uint256 newFloorPrice) external;
}
"
},
"contracts/interfaces/IAppReferrals.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.28;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IAppReferrals {
struct ClaimRewardsInput {
address user;
uint256 amount;
bytes32[] proofs;
}
// Events
event ReferralCodeRegistered(address indexed referrer, bytes8 code);
event ReferralRegistered(address indexed referred, bytes8 indexed referrerCode);
event RewardsClaimed(address indexed user, uint256 amount, bytes32 root);
event ReferralStaked(address indexed user, uint256 amount, uint256 declaredValue, bytes8 referralCode);
event ReferralBondBought(address indexed user, uint256 payout, bytes8 referralCode);
event ReferralStakedIntoLST(address indexed user, uint256 amount, bytes8 referralCode);
event MerkleServerSet(address indexed merkleServer);
event MerkleRootSet(bytes32 indexed merkleRoot);
// Functions
/// @notice Initializes the contract
/// @param _rzr The address of the rzr contract
/// @param _usdr The address of the usdr contract
/// @param _bond4626 The address of the bond4626 contract
/// @param _usdtreasury The address of the usdtreasury contract
/// @param _appTreasury The address of the app treasury contract
/// @param _staking The address of the staking contract
/// @param _staking4626 The address of the staking4626 contract
/// @param _authority The address of the authority
/// @param _allowReferralCodeRegistration The flag to allow referral code registration
function initialize(
address _rzr,
address _usdr,
address _bond4626,
address _usdtreasury,
address _appTreasury,
address _staking,
address _staking4626,
address _authority,
bool _allowReferralCodeRegistration
) external;
/// @notice Gets the referral code for a user
/// @param _user The user to get the referral code for
/// @return referrerCode The referral code for the user
function userToReferralCode(address _user) external view returns (bytes8 referrerCode);
/// @notice Gets the user for a referral code
/// @param _code The referral code to get the user for
/// @return user The user for the referral code
function referralCodeToUser(bytes8 _code) external view returns (address user);
/// @notice Sets the merkle server
/// @param _merkleServer The merkle server address
function setMerkleServer(address _merkleServer) external;
/// @notice Sets the merkle root for the current week
/// @param _merkleRoot The merkle root for the week
function setMerkleRoot(bytes32 _merkleRoot) external;
/// @notice Claims rewards using a merkle proof
/// @param inputs The inputs for the rewards to claim
/// @dev The proofs are the two parts of the merkle proof
function claimRewards(ClaimRewardsInput[] calldata inputs) external;
/// @notice Registers a referral code for the caller
function registerReferralCode(bytes8 code) external;
/// @notice Registers a referral code for the given referrer
/// @param _code The referral code to register
/// @param _referrer The referrer to register the referral code for
function registerReferralCodeFor(bytes8 _code, address _referrer) external;
/// @notice Gets all referrals for a referrer
/// @param referrer The referrer to get referrals for
/// @return referrals Array of addresses that were referred
function getReferrals(address referrer) external view returns (address[] memory referrals);
/// @notice Stakes RZR tokens with a referral code
/// @param amount The amount of RZR tokens to stake
/// @param declaredValue The declared value of the stake
/// @param _referralCode The referral code to use
/// @param _to The address to stake for
/// @return tokenId_ The ID of the created stake position NFT
/// @return taxPaid_ The amount of tax paid
function stakeWithReferral(uint256 amount, uint256 declaredValue, bytes8 _referralCode, address _to)
external
returns (uint256 tokenId_, uint256 taxPaid_);
/// @notice Stakes RZR tokens with a referral code into the LST
/// @param amount The amount of RZR tokens to stake
/// @param _referralCode The referral code to use
/// @param _to The address to stake for
/// @return minted The amount of tokens minted
function stakeIntoLSTWithReferral(uint256 amount, bytes8 _referralCode, address _to)
external
returns (uint256 minted);
/// @notice Buys a bond with a referral code
/// @param _amount The amount of USDR tokens to buy
/// @param _referralCode The referral code to use
/// @param _to The address to buy the bond for
/// @return payout The amount of RZR tokens received
function bondWithReferral(
uint256 _amount,
bytes8 _referralCode,
address _to
) external returns (uint256 payout);
}
"
},
"contracts/interfaces/IAppStaking.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.28;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./ITotalSupplyOracle.sol";
/// @title IAppStaking
/// @notice Interface for the staking system that allows users to stake RZR tokens and earn rewards
/// @dev This interface extends IERC721Enumerable to provide NFT functionality for staking positions
interface IAppStaking is IERC721Enumerable {
// Structs
/// @notice Represents a staking position
/// @param amount Amount of RZR tokens staked in the position
/// @p
Submitted on: 2025-11-06 13:09:10
Comments
Log in to comment.
No comments yet.