Skip to content

Extract VaultValidators, VaultOsToken to libraries #107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 11, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions contracts/base/ERC20Upgradeable.sol
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {IERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol';
import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
import {Errors} from '../libraries/Errors.sol';
import {EIP712Utils} from '../libraries/EIP712Utils.sol';

/**
* @title ERC20 Upgradeable
@@ -128,18 +129,7 @@ abstract contract ERC20Upgradeable is Initializable, IERC20Permit, IERC20, IERC2
* @dev This function is used to compute the hash of the EIP712 typed data
*/
function _computeDomainSeparator() private view returns (bytes32) {
return
keccak256(
abi.encode(
keccak256(
'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
),
keccak256(bytes(name)),
keccak256('1'),
block.chainid,
address(this)
)
);
return EIP712Utils.computeDomainSeparator(name, address(this));
}

/**
3 changes: 1 addition & 2 deletions contracts/interfaces/IVaultEthStaking.sol
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@

pragma solidity ^0.8.22;

import {IVaultState} from './IVaultState.sol';
import {IVaultValidators} from './IVaultValidators.sol';
import {IVaultEnterExit} from './IVaultEnterExit.sol';
import {IKeeperRewards} from './IKeeperRewards.sol';
@@ -13,7 +12,7 @@ import {IVaultMev} from './IVaultMev.sol';
* @author StakeWise
* @notice Defines the interface for the VaultEthStaking contract
*/
interface IVaultEthStaking is IVaultState, IVaultValidators, IVaultEnterExit, IVaultMev {
interface IVaultEthStaking is IVaultValidators, IVaultEnterExit, IVaultMev {
/**
* @notice Deposit ETH to the Vault
* @param receiver The address that will receive Vault's shares
23 changes: 14 additions & 9 deletions contracts/interfaces/IVaultState.sol
Original file line number Diff line number Diff line change
@@ -57,16 +57,21 @@ interface IVaultState is IVaultFee {
function withdrawableAssets() external view returns (uint256);

/**
* @notice Queued Shares
* @return The total number of shares queued for exit
* @notice Get exit queue data
* @return queuedShares The number of shares in the exit queue
* @return unclaimedAssets The amount of unclaimed assets in the exit queue
* @return totalExitingAssets The total amount of exiting assets
* @return totalTickets The total number of tickets in the exit queue
*/
function queuedShares() external view returns (uint128);

/**
* @notice Total Exiting Assets (deprecated)
* @return The total number of assets queued for exit
*/
function totalExitingAssets() external view returns (uint128);
function getExitQueueData()
external
view
returns (
uint128 queuedShares,
uint128 unclaimedAssets,
uint128 totalExitingAssets,
uint256 totalTickets
);

/**
* @notice Returns the number of shares held by an account
35 changes: 35 additions & 0 deletions contracts/libraries/EIP712Utils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.22;

/**
* @title EIP712Utils
* @author StakeWise
* @notice Includes functionality for calculating EIP712 hashes
*/
library EIP712Utils {
/**
* @notice Computes the hash of the EIP712 typed data
* @dev This function is used to compute the hash of the EIP712 typed data
* @param name The name of the domain
* @param verifyingContract The address of the verifying contract
* @return The hash of the EIP712 typed data
*/
function computeDomainSeparator(
string memory name,
address verifyingContract
) external view returns (bytes32) {
return
keccak256(
abi.encode(
keccak256(
'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
),
keccak256(bytes(name)),
keccak256('1'),
block.chainid,
verifyingContract
)
);
}
}
4 changes: 2 additions & 2 deletions contracts/libraries/ExitQueue.sol
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ library ExitQueue {
function getCheckpointIndex(
History storage self,
uint256 positionTicket
) internal view returns (uint256) {
) external view returns (uint256) {
uint256 high = self.checkpoints.length;
uint256 low;
while (low < high) {
@@ -83,7 +83,7 @@ library ExitQueue {
uint256 checkpointIdx,
uint256 positionTicket,
uint256 positionShares
) internal view returns (uint256 burnedShares, uint256 exitedAssets) {
) external view returns (uint256 burnedShares, uint256 exitedAssets) {
uint256 length = self.checkpoints.length;
// there are no exited assets for such checkpoint index or no shares to burn
if (checkpointIdx >= length || positionShares == 0) return (0, 0);
86 changes: 86 additions & 0 deletions contracts/libraries/OsTokenUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.22;

import {Math} from '@openzeppelin/contracts/utils/math/Math.sol';
import {IOsTokenConfig} from '../interfaces/IOsTokenConfig.sol';
import {IOsTokenVaultController} from '../interfaces/IOsTokenVaultController.sol';
import {Errors} from './Errors.sol';

/**
* @title OsTokenUtils
* @author StakeWise
* @notice Includes functionality for handling osToken redemptions
*/
library OsTokenUtils {
uint256 private constant _wad = 1e18;
uint256 private constant _hfLiqThreshold = 1e18;
uint256 private constant _maxPercent = 1e18;
uint256 private constant _disabledLiqThreshold = type(uint64).max;

/**
* @dev Struct for storing redemption data
* @param mintedAssets The amount of minted assets
* @param depositedAssets The amount of deposited assets
* @param redeemedOsTokenShares The amount of redeemed osToken shares
* @param availableAssets The amount of available assets
* @param isLiquidation Whether the redemption is a liquidation
*/
struct RedemptionData {
uint256 mintedAssets;
uint256 depositedAssets;
uint256 redeemedOsTokenShares;
uint256 availableAssets;
bool isLiquidation;
}

/**
* @dev Calculates the amount of received assets during osToken redemption
* @param osTokenConfig The address of the osToken config contract
* @param osTokenVaultController The address of the osToken vault controller contract
* @param data The redemption data
* @return receivedAssets The amount of received assets
*/
function calculateReceivedAssets(
IOsTokenConfig osTokenConfig,
IOsTokenVaultController osTokenVaultController,
RedemptionData memory data
) external view returns (uint256 receivedAssets) {
// SLOAD to memory
IOsTokenConfig.Config memory config = osTokenConfig.getConfig(address(this));
if (data.isLiquidation && config.liqThresholdPercent == _disabledLiqThreshold) {
revert Errors.LiquidationDisabled();
}

// calculate received assets
if (data.isLiquidation) {
receivedAssets = Math.mulDiv(
osTokenVaultController.convertToAssets(data.redeemedOsTokenShares),
config.liqBonusPercent,
_maxPercent
);
} else {
receivedAssets = osTokenVaultController.convertToAssets(data.redeemedOsTokenShares);
}

{
// check whether received assets are valid
if (receivedAssets > data.depositedAssets || receivedAssets > data.availableAssets) {
revert Errors.InvalidReceivedAssets();
}

if (data.isLiquidation) {
// check health factor violation in case of liquidation
if (
Math.mulDiv(
data.depositedAssets * _wad,
config.liqThresholdPercent,
data.mintedAssets * _maxPercent
) >= _hfLiqThreshold
) {
revert Errors.InvalidHealthFactor();
}
}
}
}
}
Loading