Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/periphery/LeverageTokenDeploymentBatcher.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Dependency imports
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {UnsafeUpgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
// Internal imports
import {ILeverageManager} from "../interfaces/ILeverageManager.sol";
import {ILeverageToken} from "../interfaces/ILeverageToken.sol";
import {ILeverageTokenDeploymentBatcher} from "../interfaces/periphery/ILeverageTokenDeploymentBatcher.sol";
import {IMorphoLendingAdapter} from "../interfaces/IMorphoLendingAdapter.sol";
import {IMorphoLendingAdapterFactory} from "../interfaces/IMorphoLendingAdapterFactory.sol";
import {IRebalanceAdapter} from "../interfaces/IRebalanceAdapter.sol";
import {RebalanceAdapter} from "../rebalance/RebalanceAdapter.sol";
import {ActionData, LeverageTokenConfig} from "../types/DataTypes.sol";
/**
* @dev The LeverageTokenDeploymentBatcher is a periphery contract that can be used to batch deployment of a LeverageToken
* with a deposit of collateral into the LeverageToken. This is highly recommended to avoid inflation attacks from front-running
* the initial deposit into the LeverageToken.
*
* @custom:contact security@seamlessprotocol.com
*/
contract LeverageTokenDeploymentBatcher is ILeverageTokenDeploymentBatcher {
/// @inheritdoc ILeverageTokenDeploymentBatcher
ILeverageManager public immutable leverageManager;
/// @inheritdoc ILeverageTokenDeploymentBatcher
IMorphoLendingAdapterFactory public immutable morphoLendingAdapterFactory;
/// @notice Constructor
/// @param _leverageManager The LeverageManager contract
constructor(ILeverageManager _leverageManager, IMorphoLendingAdapterFactory _morphoLendingAdapterFactory) {
leverageManager = _leverageManager;
morphoLendingAdapterFactory = _morphoLendingAdapterFactory;
}
/// @inheritdoc ILeverageTokenDeploymentBatcher
function deployLeverageTokenAndDeposit(
LeverageTokenDeploymentParams memory leverageTokenDeploymentParams,
MorphoLendingAdapterDeploymentParams memory lendingAdapterDeploymentParams,
RebalanceAdapterDeploymentParams memory rebalanceAdapterDeploymentParams,
uint256 collateral,
uint256 minShares
) public returns (ILeverageToken, ActionData memory) {
IMorphoLendingAdapter lendingAdapter = morphoLendingAdapterFactory.deployAdapter(
lendingAdapterDeploymentParams.morphoMarketId,
address(this),
salt(msg.sender, lendingAdapterDeploymentParams.baseSalt)
);
RebalanceAdapter.RebalanceAdapterInitParams memory rebalanceAdapterInitParams = RebalanceAdapter
.RebalanceAdapterInitParams({
owner: rebalanceAdapterDeploymentParams.owner,
authorizedCreator: address(this),
leverageManager: leverageManager,
minCollateralRatio: rebalanceAdapterDeploymentParams.minCollateralRatio,
targetCollateralRatio: rebalanceAdapterDeploymentParams.targetCollateralRatio,
maxCollateralRatio: rebalanceAdapterDeploymentParams.maxCollateralRatio,
auctionDuration: rebalanceAdapterDeploymentParams.auctionDuration,
initialPriceMultiplier: rebalanceAdapterDeploymentParams.initialPriceMultiplier,
minPriceMultiplier: rebalanceAdapterDeploymentParams.minPriceMultiplier,
preLiquidationCollateralRatioThreshold: rebalanceAdapterDeploymentParams.preLiquidationCollateralRatioThreshold,
rebalanceReward: rebalanceAdapterDeploymentParams.rebalanceReward
});
IRebalanceAdapter rebalanceAdapter = IRebalanceAdapter(
UnsafeUpgrades.deployUUPSProxy(
rebalanceAdapterDeploymentParams.implementation,
abi.encodeCall(RebalanceAdapter.initialize, (rebalanceAdapterInitParams))
)
);
LeverageTokenConfig memory leverageTokenConfig = LeverageTokenConfig({
lendingAdapter: lendingAdapter,
rebalanceAdapter: IRebalanceAdapter(rebalanceAdapter),
mintTokenFee: leverageTokenDeploymentParams.mintTokenFee,
redeemTokenFee: leverageTokenDeploymentParams.redeemTokenFee
});
ILeverageToken leverageToken = leverageManager.createNewLeverageToken(
leverageTokenConfig,
leverageTokenDeploymentParams.leverageTokenName,
leverageTokenDeploymentParams.leverageTokenSymbol
);
IERC20 collateralAsset = leverageTokenConfig.lendingAdapter.getCollateralAsset();
SafeERC20.safeTransferFrom(collateralAsset, msg.sender, address(this), collateral);
SafeERC20.forceApprove(collateralAsset, address(leverageManager), collateral);
ActionData memory depositData = leverageManager.deposit(leverageToken, collateral, minShares);
// Transfer shares and debt received from the deposit to the sender
SafeERC20.safeTransfer(leverageToken, msg.sender, depositData.shares);
SafeERC20.safeTransfer(leverageTokenConfig.lendingAdapter.getDebtAsset(), msg.sender, depositData.debt);
return (leverageToken, depositData);
}
/// @notice Given the `sender` and `baseSalt`, return the salt that will be used for deployment.
/// @param sender The address of the sender.
/// @param baseSalt The user-provided base salt.
function salt(address sender, bytes32 baseSalt) internal pure returns (bytes32) {
return keccak256(abi.encode(sender, baseSalt));
}
}
"
},
"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/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);
}
"
},
"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.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 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);
}
}
"
},
"lib/openzeppelin-foundry-upgrades/src/Upgrades.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import {Vm} from "forge-std/Vm.sol";
import {Options} from "./Options.sol";
import {Core} from "./internal/Core.sol";
import {Utils} from "./internal/Utils.sol";
/**
* @dev Library for deploying and managing upgradeable contracts from Forge scripts or tests.
*
* NOTE: Requires OpenZeppelin Contracts v5 or higher.
*/
library Upgrades {
/**
* @dev Deploys a UUPS proxy using the given contract as the implementation.
*
* @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param initializerData Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @param opts Common options
* @return Proxy address
*/
function deployUUPSProxy(
string memory contractName,
bytes memory initializerData,
Options memory opts
) internal returns (address) {
address impl = deployImplementation(contractName, opts);
return Core.deploy("ERC1967Proxy.sol:ERC1967Proxy", abi.encode(impl, initializerData), opts);
}
/**
* @dev Deploys a UUPS proxy using the given contract as the implementation.
*
* @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param initializerData Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @return Proxy address
*/
function deployUUPSProxy(string memory contractName, bytes memory initializerData) internal returns (address) {
Options memory opts;
return deployUUPSProxy(contractName, initializerData, opts);
}
/**
* @dev Deploys a transparent proxy using the given contract as the implementation.
*
* @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param initialOwner Address to set as the owner of the ProxyAdmin contract which gets deployed by the proxy
* @param initializerData Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @param opts Common options
* @return Proxy address
*/
function deployTransparentProxy(
string memory contractName,
address initialOwner,
bytes memory initializerData,
Options memory opts
) internal returns (address) {
if (!opts.unsafeSkipAllChecks && !opts.unsafeSkipProxyAdminCheck && Core.inferProxyAdmin(initialOwner)) {
revert(
string.concat(
"`initialOwner` must not be a ProxyAdmin contract. If the contract at address ",
Vm(Utils.CHEATCODE_ADDRESS).toString(initialOwner),
" is not a ProxyAdmin contract and you are sure that this contract is able to call functions on an actual ProxyAdmin, skip this check with the `unsafeSkipProxyAdminCheck` option."
)
);
}
address impl = deployImplementation(contractName, opts);
return
Core.deploy(
"TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy",
abi.encode(impl, initialOwner, initializerData),
opts
);
}
/**
* @dev Deploys a transparent proxy using the given contract as the implementation.
*
* @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param initialOwner Address to set as the owner of the ProxyAdmin contract which gets deployed by the proxy
* @param initializerData Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @return Proxy address
*/
function deployTransparentProxy(
string memory contractName,
address initialOwner,
bytes memory initializerData
) internal returns (address) {
Options memory opts;
return deployTransparentProxy(contractName, initialOwner, initializerData, opts);
}
/**
* @dev Upgrades a proxy to a new implementation contract. Only supported for UUPS or transparent proxies.
*
* Requires that either the `referenceContract` option is set, or the new implementation contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* @param proxy Address of the proxy to upgrade
* @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param data Encoded call data of an arbitrary function to call during the upgrade process, or empty if no function needs to be called during the upgrade
* @param opts Common options
*/
function upgradeProxy(address proxy, string memory contractName, bytes memory data, Options memory opts) internal {
Core.upgradeProxy(proxy, contractName, data, opts);
}
/**
* @dev Upgrades a proxy to a new implementation contract. Only supported for UUPS or transparent proxies.
*
* Requires that either the `referenceContract` option is set, or the new implementation contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* @param proxy Address of the proxy to upgrade
* @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param data Encoded call data of an arbitrary function to call during the upgrade process, or empty if no function needs to be called during the upgrade
*/
function upgradeProxy(address proxy, string memory contractName, bytes memory data) internal {
Options memory opts;
Core.upgradeProxy(proxy, contractName, data, opts);
}
/**
* @notice For tests only. If broadcasting in scripts, use the `--sender <ADDRESS>` option with `forge script` instead.
*
* @dev Upgrades a proxy to a new implementation contract. Only supported for UUPS or transparent proxies.
*
* Requires that either the `referenceContract` option is set, or the new implementation contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* This function provides an additional `tryCaller` parameter to test an upgrade using a specific caller address.
* Use this if you encounter `OwnableUnauthorizedAccount` errors in your tests.
*
* @param proxy Address of the proxy to upgrade
* @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param data Encoded call data of an arbitrary function to call during the upgrade process, or empty if no function needs to be called during the upgrade
* @param opts Common options
* @param tryCaller Address to use as the caller of the upgrade function. This should be the address that owns the proxy or its ProxyAdmin.
*/
function upgradeProxy(
address proxy,
string memory contractName,
bytes memory data,
Options memory opts,
address tryCaller
) internal {
Core.upgradeProxy(proxy, contractName, data, opts, tryCaller);
}
/**
* @notice For tests only. If broadcasting in scripts, use the `--sender <ADDRESS>` option with `forge script` instead.
*
* @dev Upgrades a proxy to a new implementation contract. Only supported for UUPS or transparent proxies.
*
* Requires that either the `referenceContract` option is set, or the new implementation contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* This function provides an additional `tryCaller` parameter to test an upgrade using a specific caller address.
* Use this if you encounter `OwnableUnauthorizedAccount` errors in your tests.
*
* @param proxy Address of the proxy to upgrade
* @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param data Encoded call data of an arbitrary function to call during the upgrade process, or empty if no function needs to be called during the upgrade
* @param tryCaller Address to use as the caller of the upgrade function. This should be the address that owns the proxy or its ProxyAdmin.
*/
function upgradeProxy(address proxy, string memory contractName, bytes memory data, address tryCaller) internal {
Options memory opts;
Core.upgradeProxy(proxy, contractName, data, opts, tryCaller);
}
/**
* @dev Deploys an upgradeable beacon using the given contract as the implementation.
*
* @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param initialOwner Address to set as the owner of the UpgradeableBeacon contract which gets deployed
* @param opts Common options
* @return Beacon address
*/
function deployBeacon(
string memory contractName,
address initialOwner,
Options memory opts
) internal returns (address) {
address impl = deployImplementation(contractName, opts);
return Core.deploy("UpgradeableBeacon.sol:UpgradeableBeacon", abi.encode(impl, initialOwner), opts);
}
/**
* @dev Deploys an upgradeable beacon using the given contract as the implementation.
*
* @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param initialOwner Address to set as the owner of the UpgradeableBeacon contract which gets deployed
* @return Beacon address
*/
function deployBeacon(string memory contractName, address initialOwner) internal returns (address) {
Options memory opts;
return deployBeacon(contractName, initialOwner, opts);
}
/**
* @dev Upgrades a beacon to a new implementation contract.
*
* Requires that either the `referenceContract` option is set, or the new implementation contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* @param beacon Address of the beacon to upgrade
* @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param opts Common options
*/
function upgradeBeacon(address beacon, string memory contractName, Options memory opts) internal {
Core.upgradeBeacon(beacon, contractName, opts);
}
/**
* @dev Upgrades a beacon to a new implementation contract.
*
* Requires that either the `referenceContract` option is set, or the new implementation contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* @param beacon Address of the beacon to upgrade
* @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
*/
function upgradeBeacon(address beacon, string memory contractName) internal {
Options memory opts;
Core.upgradeBeacon(beacon, contractName, opts);
}
/**
* @notice For tests only. If broadcasting in scripts, use the `--sender <ADDRESS>` option with `forge script` instead.
*
* @dev Upgrades a beacon to a new implementation contract.
*
* Requires that either the `referenceContract` option is set, or the new implementation contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* This function provides an additional `tryCaller` parameter to test an upgrade using a specific caller address.
* Use this if you encounter `OwnableUnauthorizedAccount` errors in your tests.
*
* @param beacon Address of the beacon to upgrade
* @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param opts Common options
* @param tryCaller Address to use as the caller of the upgrade function. This should be the address that owns the beacon.
*/
function upgradeBeacon(
address beacon,
string memory contractName,
Options memory opts,
address tryCaller
) internal {
Core.upgradeBeacon(beacon, contractName, opts, tryCaller);
}
/**
* @notice For tests only. If broadcasting in scripts, use the `--sender <ADDRESS>` option with `forge script` instead.
*
* @dev Upgrades a beacon to a new implementation contract.
*
* Requires that either the `referenceContract` option is set, or the new implementation contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* This function provides an additional `tryCaller` parameter to test an upgrade using a specific caller address.
* Use this if you encounter `OwnableUnauthorizedAccount` errors in your tests.
*
* @param beacon Address of the beacon to upgrade
* @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param tryCaller Address to use as the caller of the upgrade function. This should be the address that owns the beacon.
*/
function upgradeBeacon(address beacon, string memory contractName, address tryCaller) internal {
Options memory opts;
Core.upgradeBeacon(beacon, contractName, opts, tryCaller);
}
/**
* @dev Deploys a beacon proxy using the given beacon and call data.
*
* @param beacon Address of the beacon to use
* @param data Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @return Proxy address
*/
function deployBeaconProxy(address beacon, bytes memory data) internal returns (address) {
Options memory opts;
return deployBeaconProxy(beacon, data, opts);
}
/**
* @dev Deploys a beacon proxy using the given beacon and call data.
*
* @param beacon Address of the beacon to use
* @param data Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @param opts Common options
* @return Proxy address
*/
function deployBeaconProxy(address beacon, bytes memory data, Options memory opts) internal returns (address) {
return Core.deploy("BeaconProxy.sol:BeaconProxy", abi.encode(beacon, data), opts);
}
/**
* @dev Validates an implementation contract, but does not deploy it.
*
* @param contractName Name of the contract to validate, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param opts Common options
*/
function validateImplementation(string memory contractName, Options memory opts) internal {
Core.validateImplementation(contractName, opts);
}
/**
* @dev Validates and deploys an implementation contract, and returns its address.
*
* @param contractName Name of the contract to deploy, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param opts Common options
* @return Address of the implementation contract
*/
function deployImplementation(string memory contractName, Options memory opts) internal returns (address) {
return Core.deployImplementation(contractName, opts);
}
/**
* @dev Validates a new implementation contract in comparison with a reference contract, but does not deploy it.
*
* Requires that either the `referenceContract` option is set, or the contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* @param contractName Name of the contract to validate, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param opts Common options
*/
function validateUpgrade(string memory contractName, Options memory opts) internal {
Core.validateUpgrade(contractName, opts);
}
/**
* @dev Validates a new implementation contract in comparison with a reference contract, deploys the new implementation contract,
* and returns its address.
*
* Requires that either the `referenceContract` option is set, or the contract has a `@custom:oz-upgrades-from <reference>` annotation.
*
* Use this method to prepare an upgrade to be run from an admin address you do not control directly or cannot use from your deployment environment.
*
* @param contractName Name of the contract to deploy, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory
* @param opts Common options
* @return Address of the new implementation contract
*/
function prepareUpgrade(string memory contractName, Options memory opts) internal returns (address) {
return Core.prepareUpgrade(contractName, opts);
}
/**
* @dev Gets the admin address of a transparent proxy from its ERC1967 admin storage slot.
*
* @param proxy Address of a transparent proxy
* @return Admin address
*/
function getAdminAddress(address proxy) internal view returns (address) {
return Core.getAdminAddress(proxy);
}
/**
* @dev Gets the implementation address of a transparent or UUPS proxy from its ERC1967 implementation storage slot.
*
* @param proxy Address of a transparent or UUPS proxy
* @return Implementation address
*/
function getImplementationAddress(address proxy) internal view returns (address) {
return Core.getImplementationAddress(proxy);
}
/**
* @dev Gets the beacon address of a beacon proxy from its ERC1967 beacon storage slot.
*
* @param proxy Address of a beacon proxy
* @return Beacon address
*/
function getBeaconAddress(address proxy) internal view returns (address) {
return Core.getBeaconAddress(proxy);
}
}
/**
* @dev Library for deploying and managing upgradeable contracts from Forge tests, without validations.
*
* Can be used with `forge coverage`. Requires implementation contracts to be instantiated first.
* Does not require `--ffi` and does not require a clean compilation before each run.
*
* Not supported for OpenZeppelin Defender deployments.
*
* WARNING: Not recommended for use in Forge scripts.
* `UnsafeUpgrades` does not validate whether your contracts are upgrade safe or whether new implementations are compatible with previous ones.
* Use `Upgrades` if you want validations to be run.
*
* NOTE: Requires OpenZeppelin Contracts v5 or higher.
*/
library UnsafeUpgrades {
/**
* @dev Deploys a UUPS proxy using the given contract address as the implementation.
*
* @param impl Address of the contract to use as the implementation
* @param initializerData Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @return Proxy address
*/
function deployUUPSProxy(address impl, bytes memory initializerData) internal returns (address) {
return address(new ERC1967Proxy(impl, initializerData));
}
/**
* @dev Deploys a transparent proxy using the given contract address as the implementation.
*
* @param impl Address of the contract to use as the implementation
* @param initialOwner Address to set as the owner of the ProxyAdmin contract which gets deployed by the proxy
* @param initializerData Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @return Proxy address
*/
function deployTransparentProxy(
address impl,
address initialOwner,
bytes memory initializerData
) internal returns (address) {
return address(new TransparentUpgradeableProxy(impl, initialOwner, initializerData));
}
/**
* @dev Upgrades a proxy to a new implementation contract address. Only supported for UUPS or transparent proxies.
*
* @param proxy Address of the proxy to upgrade
* @param newImpl Address of the new implementation contract to upgrade to
* @param data Encoded call data of an arbitrary function to call during the upgrade process, or empty if no function needs to be called during the upgrade
*/
function upgradeProxy(address proxy, address newImpl, bytes memory data) internal {
Core.upgradeProxyTo(proxy, newImpl, data);
}
/**
* @notice For tests only. If broadcasting in scripts, use the `--sender <ADDRESS>` option with `forge script` instead.
*
* @dev Upgrades a proxy to a new implementation contract address. Only supported for UUPS or transparent proxies.
*
* This function provides an additional `tryCaller` parameter to test an upgrade using a specific caller address.
* Use this if you encounter `OwnableUnauthorizedAccount` errors in your tests.
*
* @param proxy Address of the proxy to upgrade
* @param newImpl Address of the new implementation contract to upgrade to
* @param data Encoded call data of an arbitrary function to call during the upgrade process, or empty if no function needs to be called during the upgrade
* @param tryCaller Address to use as the caller of the upgrade function. This should be the address that owns the proxy or its ProxyAdmin.
*/
function upgradeProxy(address proxy, address newImpl, bytes memory data, address tryCaller) internal {
Core.upgradeProxyTo(proxy, newImpl, data, tryCaller);
}
/**
* @dev Deploys an upgradeable beacon using the given contract address as the implementation.
*
* @param impl Address of the contract to use as the implementation
* @param initialOwner Address to set as the owner of the UpgradeableBeacon contract which gets deployed
* @return Beacon address
*/
function deployBeacon(address impl, address initialOwner) internal returns (address) {
return address(new UpgradeableBeacon(impl, initialOwner));
}
/**
* @dev Upgrades a beacon to a new implementation contract address.
*
* @param beacon Address of the beacon to upgrade
* @param newImpl Address of the new implementation contract to upgrade to
*/
function upgradeBeacon(address beacon, address newImpl) internal {
Core.upgradeBeaconTo(beacon, newImpl);
}
/**
* @notice For tests only. If broadcasting in scripts, use the `--sender <ADDRESS>` option with `forge script` instead.
*
* @dev Upgrades a beacon to a new implementation contract address.
*
* This function provides an additional `tryCaller` parameter to test an upgrade using a specific caller address.
* Use this if you encounter `OwnableUnauthorizedAccount` errors in your tests.
*
* @param beacon Address of the beacon to upgrade
* @param newImpl Address of the new implementation contract to upgrade to
* @param tryCaller Address to use as the caller of the upgrade function. This should be the address that owns the beacon.
*/
function upgradeBeacon(address beacon, address newImpl, address tryCaller) internal {
Core.upgradeBeaconTo(beacon, newImpl, tryCaller);
}
/**
* @dev Deploys a beacon proxy using the given beacon and call data.
*
* @param beacon Address of the beacon to use
* @param data Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required
* @return Proxy address
*/
function deployBeaconProxy(address beacon, bytes memory data) internal returns (address) {
return address(new BeaconProxy(beacon, data));
}
/**
* @dev Gets the admin address of a transparent proxy from its ERC1967 admin storage slot.
*
* @param proxy Address of a transparent proxy
* @return Admin address
*/
function getAdminAddress(address proxy) internal view returns (address) {
return Core.getAdminAddress(proxy);
}
/**
* @dev Gets the implementation address of a transparent or UUPS proxy from its ERC1967 implementation storage slot.
*
* @param proxy Address of a transparent or UUPS proxy
* @return Implementation address
*/
function getImplementationAddress(address proxy) internal view returns (address) {
return Core.getImplementationAddress(proxy);
}
/**
* @dev Gets the beacon address of a beacon proxy from its ERC1967 beacon storage slot.
*
* @param proxy Address of a beacon proxy
* @return Beacon address
*/
function getBeaconAddress(address proxy) internal view returns (address) {
return Core.getBeaconAddress(proxy);
}
}
"
},
"src/interfaces/ILeverageManager.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
// Dependency imports
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
// Internal imports
import {IFeeManager} from "./IFeeManager.sol";
import {IRebalanceAdapterBase} from "./IRebalanceAdapterBase.sol";
import {ILeverageToken} from "./ILeverageToken.sol";
import {IBeaconProxyFactory} from "./IBeaconProxyFactory.sol";
import {ILendingAdapter} from "./ILendingAdapter.sol";
import {ActionData, LeverageTokenState, RebalanceAction, LeverageTokenConfig} from "src/types/DataTypes.sol";
interface ILeverageManager is IFeeManager {
/// @notice Error thrown when someone tries to set zero address for collateral or debt asset when creating a LeverageToken
error InvalidLeverageTokenAssets();
/// @notice Error thrown when collateral ratios are invalid for an action
error InvalidCollateralRatios();
/// @notice Error thrown when slippage is too high during mint/redeem
/// @param actual The actual amount of tokens received
/// @param expected The expected amount of tokens to receive
error SlippageTooHigh(uint256 actual, uint256 expected);
/// @notice Error thrown when caller is not authorized to rebalance
/// @param token The LeverageToken to rebalance
/// @param caller The caller of the rebalance function
error NotRebalancer(ILeverageToken token, address caller);
/// @notice Error thrown when a LeverageToken's initial collateral ratio is invalid (must be greater than the base ratio)
/// @param initialCollateralRatio The initial collateral ratio that is invalid
error InvalidLeverageTokenInitialCollateralRatio(uint256 initialCollateralRatio);
/// @notice Error thrown when a LeverageToken's state after rebalance is invalid
/// @param token The LeverageToken that has invalid state after rebalance
error InvalidLeverageTokenStateAfterRebalance(ILeverageToken token);
/// @notice Event emitted when the LeverageManager is initialized
/// @param leverageTokenFactory The factory for creating new LeverageTokens
event LeverageManagerInitialized(IBeaconProxyFactory leverageTokenFactory);
/// @notice Error thrown when attempting to rebalance a LeverageToken that is not eligible for rebalance
error LeverageTokenNotEligibleForRebalance();
/// @notice Event emitted when a new LeverageToken is created
/// @param token The new LeverageToken
/// @param collateralAsset The collateral asset of the LeverageToken
/// @param debtAsset The debt asset of the LeverageToken
/// @param config The config of the LeverageToken
event LeverageTokenCreated(
ILeverageToken indexed token, IERC20 collateralAsset, IERC20 debtAsset, LeverageTokenConfig config
);
/// @notice Event emitted when a user mints LeverageToken shares
/// @param token The LeverageToken
/// @param sender The sender of the mint
/// @param actionData The action data of the mint
event Mint(ILeverageToken indexed token, address indexed sender, ActionData actionData);
/// @notice Event emitted when a user rebalances a LeverageToken
/// @param token The LeverageToken
/// @param sender The sender of the rebalance
/// @param stateBefore The state of the LeverageToken before the rebalance
/// @param stateAfter The state of the LeverageToken after the rebalance
/// @param actions The actions that were taken
event Rebalance(
ILeverageToken indexed token,
address indexed sender,
LeverageTokenState stateBefore,
LeverageTokenState stateAfter,
RebalanceAction[] actions
);
/// @notice Event emitted when a user redeems LeverageToken shares
/// @param token The LeverageToken
/// @param sender The sender of the redeem
/// @param actionData The action data of the redeem
event Redeem(ILeverageToken indexed token, address indexed sender, ActionData actionData);
/// @notice Returns the base collateral ratio
/// @return baseRatio Base collateral ratio
function BASE_RATIO() external view returns (uint256);
/// @notice Converts an amount of collateral to an amount of debt for a LeverageToken, based on the current
/// collateral ratio of the LeverageToken
/// @param token LeverageToken to convert collateral to debt for
/// @param collateral Amount of collateral to convert to debt
/// @param rounding Rounding mode to use for the conversion
/// @return debt Amount of debt that correspond to the collateral
/// @dev For deposits/mints, Math.Rounding.Floor should be used. For withdraws/redeems, Math.Rounding.Ceil should be used.
function convertCollateralToDebt(ILeverageToken token, uint256 collateral, Math.Rounding rounding)
external
view
returns (uint256 debt);
/// @notice Converts an amount of collateral to an amount of shares for a LeverageToken, based on the current
/// collateral ratio of the LeverageToken
/// @param token LeverageToken to convert collateral to shares for
/// @param collateral Amount of collateral to convert to shares
/// @param rounding Rounding mode to use for the conversion
/// @return shares Amount of shares that correspond to the collateral
/// @dev For deposits/mints, Math.Rounding.Floor should be used. For withdraws/redeems, Math.Rounding.Ceil should be used.
function convertCollateralToShares(ILeverageToken token, uint256 collateral, Math.Rounding rounding)
external
view
returns (uint256 shares);
/// @notice Converts an amount of debt to an amount of collateral for a LeverageToken, based on the current
/// collateral ratio of the LeverageToken
/// @param token LeverageToken to convert debt to collateral for
/// @param debt Amount of debt to convert to collateral
/// @param rounding Rounding mode to use for the conversion
/// @return collateral Amount of collateral that correspond to the debt amount
/// @dev For deposits/mints, Math.Rounding.Ceil should be used. For withdraws/redeems, Math.Rounding.Floor should be used.
function convertDebtToCollateral(ILeverageToken token, uint256 debt, Math.Rounding rounding)
external
view
returns (uint256 collateral);
/// @notice Converts an amount of shares to an amount of collateral for a LeverageToken, based on the current
/// collateral ratio of the LeverageToken
/// @param token LeverageToken to convert shares to collateral for
/// @param shares Amount of shares to convert to collateral
/// @param rounding Rounding mode to use for the conversion
/// @return collateral Amount of collateral that correspond to the shares
/// @dev For deposits/mints, Math.Rounding.Ceil should be used. For withdraws/redeems, Math.Rounding.Floor should be used.
function convertSharesToCollateral(ILeverageToken token, uint256 shares, Math.Rounding rounding)
external
view
returns (uint256 collateral);
/// @notice Converts an amount of shares to an amount of debt for a LeverageToken, based on the current
/// collateral ratio of the LeverageToken
/// @param token LeverageToken to convert shares to debt for
/// @param shares Amount of shares to convert to debt
/// @param rounding Rounding mode to use for the conversion
/// @return debt Amount of debt that correspond to the shares
/// @dev For deposits/mints, Math.Rounding.Floor should be used. For withdraws/redeems, Math.Rounding.Ceil should be used.
function convertSharesToDebt(ILeverageToken token, uint256 shares, Math.Rounding rounding)
external
view
returns (uint256 debt);
/// @notice Converts an amount of shares to an amount of equity in collateral asset for a LeverageToken, based on the
/// price oracle used by the underlying lending adapter and state of the LeverageToken
/// @param token LeverageToken to convert shares to equity in collateral asset for
/// @param shares Amount of shares to convert to equity in collateral asset
/// @return equityInCollateralAsset Amount of equity in collateral asset that correspond to the shares
function convertToAssets(ILeverageToken token, uint256 shares)
external
view
returns (uint256 equityInCollateralAsset);
/// @notice Converts an amount of equity in collateral asset to an amount of shares for a LeverageToken, based on the
/// price oracle used by the underlying lending adapter and state of the LeverageToken
/// @param token LeverageToken to convert equity in collateral asset to shares for
/// @param equityInCollateralAsset Amount of equity in collateral asset to convert to shares
/// @return shares Amount of shares that correspond to the equity in collateral asset
function convertToShares(ILeverageToken token, uint256 equityInCollateralAsset)
external
view
returns (uint256 shares);
/// @notice Returns the factory for creating new LeverageTokens
/// @return factory Factory for creating new LeverageTokens
function getLeverageTokenFactory() external view returns (IBeaconProxyFactory factory);
/// @notice Returns the lending adapter for a LeverageToken
/// @param token LeverageToken to get lending adapter for
/// @return adapter Lending adapter for the LeverageToken
function getLeverageTokenLendingAdapter(ILeverageToken token) external view returns (ILendingAdapter adapter);
/// @notice Returns the collateral asset for a LeverageToken
/// @param token LeverageToken to get collateral asset for
/// @return collateralAsset Collateral asset for the LeverageToken
function getLeverageTokenCollateralAsset(ILeverageToken token) external view returns (IERC20 collateralAsset);
/// @notice Returns the debt asset for a LeverageToken
/// @param token LeverageToken to get debt asset for
/// @return debtAsset Debt asset for the LeverageToken
function getLeverageTokenDebtAsset(ILeverageToken token) external view returns (IERC20 debtAsset);
/// @notice Returns the rebalance adapter for a LeverageToken
/// @param token LeverageToken to get the rebalance adapter for
/// @return adapter Rebalance adapter for the LeverageToken
function getLeverageTokenRebalanceAdapter(ILeverageToken token)
external
view
returns (IRebalanceAdapterBase adapter);
/// @notice Returns the entire configuration for a LeverageToken
/// @param token LeverageToken to get config for
/// @return config LeverageToken configuration
function getLeverageTokenConfig(ILeverageToken token) external view returns (LeverageTokenConfig memory config);
/// @notice Returns the initial collateral ratio for a LeverageToken
/// @param token LeverageToken to get initial collateral ratio for
/// @return initialCollateralRatio Initial collateral ratio for the LeverageToken
/// @dev Initial collateral ratio is followed when the LeverageToken has no shares and on mints when debt is 0.
function getLeverageTokenInitialCollateralRatio(ILeverageToken token)
external
view
returns (uint256 initialCollateralRatio);
/// @notice Returns all data required to describe current LeverageToken state - collateral, debt, equity and collateral ratio
/// @param token LeverageToken to query state for
/// @return state LeverageToken state
function getLeverageTokenState(ILeverageToken token) external view returns (LeverageTokenState memory state);
/// @notice Previews deposit function call and returns all required data
/// @param token LeverageToken to preview deposit for
/// @param collateral Amount of collateral to deposit
/// @return previewData Preview data for deposit
/// - collateral Amount of collateral that will be added to the LeverageToken and sent to the receiver
/// - debt Amount of debt that will be borrowed and sent to the receiver
/// - shares Amount of shares that will be minted to the receiver
/// - tokenFee Amount of shares that will be charged for the deposit that are given to the LeverageToken
/// - treasuryFee Amount of shares that will be charged for the deposit that are given to the treasury
/// @dev Sender should approve leverage manager to spend collateral amount of collateral asset
function previewDeposit(ILeverageToken token, uint256 collateral) external view returns (ActionData memory);
/// @notice Previews mint function call and returns all required data
/// @param token LeverageToken to preview mint for
/// @param shares Amount of shares to mint
/// @return previewData Preview data for mint
/// - collateral Amount of collateral that will be added to the LeverageToken and sent to the receiver
/// - debt Amount of debt that will be borrowed and sent to the receiver
/// - shares Amount of shares that will be minted to the receiver
/// - tokenFee Amount of shares that will be charged for the mint that are given to the LeverageToken
/// - treasuryFee Amount of shares that will be charged for the mint that are given to the treasury
/// @dev Sender should approve leverage manager to spend collateral amount of collateral asset
function previewMint(ILeverageToken token, uint256 shares) external view returns (ActionData memory);
/// @notice Previews redeem function call and returns all required data
/// @param token LeverageToken to preview redeem for
/// @param shares Amount of shares to redeem
/// @return previewData Preview data for redeem
/// - collateral Amount of collateral that will be removed from the LeverageToken and sent to the sender
/// - debt Amount of debt that will be taken from sender and repaid to the LeverageToken
/// - shares Amount of shares that will be burned from sender
/// - tokenFee Amount of shares that will be charged for the redeem that are given to the LeverageToken
/// - treasuryFee Amount of shares that will be charged for the redeem that are given to the treasury
/// @dev Sender should approve LeverageManager to spend debt amount of debt asset
function previewRedeem(ILeverageToken token, uint256 shares) external view returns (ActionData memory);
/// @notice Previews withdraw function call and returns all required data
/// @param token LeverageToken to preview withdraw for
/// @param collateral Amount of collateral to withdraw
/// @return previewData Preview data for withdraw
/// - collateral Amount of collateral that will be removed from the LeverageToken and sent to the sender
/// - debt Amount of debt that will be taken from sender and repaid to the LeverageToken
/// - shares Amount of shares that will be burned from sender
/// - tokenFee Amount of shares that will be charged for the redeem that are given to the LeverageToken
/// - treasuryFee Amount of shares that will be charged for the redeem that are given to the treasury
/// @dev Sender should approve LeverageManager to spend debt amount of debt asset
function previewWithdraw(ILeverageToken token, uint256 collateral) external view returns (ActionData memory);
/// @notice Creates a new LeverageToken with the given config
/// @param config Configuration of the LeverageToken
/// @param name Name of the LeverageToken
/// @param symbol Symbol of the LeverageToken
/// @return token Address of the new LeverageToken
function createNewLeverageToken(LeverageTokenConfig memory config, string memory name, string memory symbol)
external
returns (ILeverageToken token);
/// @notice Deposits collateral into a LeverageToken and mints shares to the sender
/// @param token LeverageToken to deposit into
/// @param collateral Amount of collateral to deposit
/// @param minShares Minimum number of shares to mint
/// @return depositData Action data for the deposit
/// - collateral Amount of collateral that was added, including any fees
/// - debt Amount of debt that was added
/// - shares Amount of shares minted to the sender
/// - tokenFee Amount of shares that was charged for the deposit that are given to the LeverageToken
/// - treasuryFee Amount of shares that was charged for the deposit that are given to the treasury
/// @dev Sender should approve leverage manager to spend collateral amount of collateral asset
function deposit(ILeverageToken token, uint256 collateral, uint256 minShares)
external
returns (ActionData memory);
/// @notice Mints shares of a LeverageToken to the sender
/// @param token LeverageToken to mint shares for
/// @param shares Amount of shares to mint
/// @param maxCollateral Maximum amount of collateral to use for minting
/// @return mintData Action data for the mint
/// - collateral Amount of collateral that was added, including any fees
/// - debt Amount of debt that was added
/// - shares Amount of shares minted to the sender
/// - tokenFee Amount of shares that was charged for the mint that are given to the LeverageToken
/// - treasuryFee Amount of shares that was charged for the mint that are given to the treasury
/// @dev Sender should approve leverage manager to spend collateral amount of collateral asset, which can be
/// previewed with previewMint
function mint(ILeverageToken token, uint256 shares, uint256 maxCollateral) external returns (ActionData memory);
/// @notice Redeems equity from a LeverageToken and burns shares from sender
/// @param token The LeverageToken to redeem from
/// @param shares The amount of shares to redeem
/// @param minCollateral The minimum amount of collateral to receive
/// @return actionData Data about the redeem
/// - collateral Amount of collateral that was removed from LeverageToken and sent to sender
/// - debt Amount of debt that was repaid to LeverageToken, taken from sender
/// - shares Amount of the sender's shares that were burned for the redeem
/// - tokenFee Amount of shares that was charged for the redeem that are given to the LeverageToken
/// - treasuryFee Amount of shares that was charged for the redeem that are given to the treasury
function redeem(ILeverageToken token, uint256 shares, uint256 minCollateral)
external
returns (ActionData memory actionData);
/// @notice Rebalances a LeverageToken based on provided actions
/// @param leverageToken LeverageToken to rebalance
/// @param actions Rebalance actions to execute (add collateral, remove collateral, borrow or repay)
/// @param tokenIn Token to transfer in. Transfer from caller to the LeverageManager contract
/// @param tokenOut Token to transfer out. Transfer from the LeverageManager contract to caller
//
Submitted on: 2025-10-10 16:41:13
Comments
Log in to comment.
No comments yet.