Skip to content

Commit

Permalink
audit fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
gus-stdr committed Feb 9, 2024
1 parent ab370e5 commit 9ca0bb5
Show file tree
Hide file tree
Showing 16 changed files with 144 additions and 165 deletions.
2 changes: 1 addition & 1 deletion contracts/LRTConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ contract LRTConfig is ILRTConfig, AccessControlUpgradeable {
/// @dev Adds a new supported asset
/// @param asset Asset address
/// @param depositLimit Deposit limit for the asset
function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(LRTConstants.MANAGER) {
function addNewSupportedAsset(address asset, uint256 depositLimit) external onlyRole(DEFAULT_ADMIN_ROLE) {
_addNewSupportedAsset(asset, depositLimit);
}

Expand Down
85 changes: 60 additions & 25 deletions contracts/LRTDepositPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,43 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad
/// @dev only callable by LRT admin
/// @param nodeDelegatorAddress NodeDelegator contract address
function removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) public onlyLRTAdmin {
// revert if node delegator contract has assets lying in it or it has asset in eigenlayer asset strategies
// 1. remove assets from node delegator contract to LRTDepositPool
address[] memory supportedAssets = lrtConfig.getSupportedAssetList();

uint256 supportedAssetsLength = supportedAssets.length;

for (uint256 i; i < supportedAssetsLength;) {
// check the case for ETH
if (supportedAssets[i] == LRTConstants.ETH_TOKEN) {
uint256 ethBalance = nodeDelegatorAddress.balance;
if (ethBalance > 0) {
INodeDelegator(nodeDelegatorAddress).sendETHFromDepositPoolToNDC{ value: ethBalance }();
}
} else {
// LST case
uint256 assetBalance = IERC20(supportedAssets[i]).balanceOf(nodeDelegatorAddress);

if (assetBalance > 0) {
INodeDelegator(nodeDelegatorAddress).transferBackToLRTDepositPool(supportedAssets[i], assetBalance);
}
}

unchecked {
++i;
}
}

// 2. revert if node delegator contract has asset in eigenlayer asset strategies

// check if NDC has native ETH balance in eigen layer
if (
INodeDelegator(nodeDelegatorAddress).stakedButUnverifiedNativeETH() > 0
|| INodeDelegator(nodeDelegatorAddress).getETHEigenPodBalance() > 0
) {
revert NodeDelegatorHasETHInEigenlayer();
}

// check if NDC has LST balance in eigen layer
(address[] memory assets, uint256[] memory assetBalances) =
INodeDelegator(nodeDelegatorAddress).getAssetBalances();

Expand All @@ -269,6 +305,7 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad
}
}

// 3. remove node delegator contract from queue
uint256 length = nodeDelegatorQueue.length;
uint256 ndcIndex;

Expand All @@ -287,7 +324,9 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad
}
}

// remove node delegator contract from queue
// remove from isNodeDelegator mapping
isNodeDelegator[nodeDelegatorAddress] = 0;
// remove from nodeDelegatorQueue
nodeDelegatorQueue[ndcIndex] = nodeDelegatorQueue[length - 1];
nodeDelegatorQueue.pop();

Expand Down Expand Up @@ -338,48 +377,42 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad
INodeDelegator(nodeDelegator).sendETHFromDepositPoolToNDC{ value: amount }();
}

/// @notice swap assets that are accepted by LRTDepositPool
/// @dev use LRTOracle to get price for fromToken to toToken. Only callable by LRT manager
/// @param fromAsset Asset address to swap from
/// @notice swap ETH for LST asset which is accepted by LRTDepositPool
/// @dev use LRTOracle to get price for toToken. Only callable by LRT manager
/// @param toAsset Asset address to swap to
/// @param fromAssetAmount Asset amount to swap from
/// @param minToAssetAmount Minimum asset amount to swap to

function swapAssetWithinDepositPool(
address fromAsset,
function swapETHForAssetWithinDepositPool(
address toAsset,
uint256 fromAssetAmount,
uint256 minToAssetAmount
)
external
payable
onlyLRTManager
onlySupportedAsset(fromAsset)
onlySupportedAsset(toAsset)
{
// checks
uint256 toAssetAmount = getSwapAssetReturnAmount(fromAsset, toAsset, fromAssetAmount);
if (toAssetAmount < minToAssetAmount || IERC20(toAsset).balanceOf(address(this)) < toAssetAmount) {
uint256 ethAmountSent = msg.value;

uint256 returnAmount = getSwapETHToAssetReturnAmount(toAsset, ethAmountSent);

if (returnAmount < minToAssetAmount || IERC20(toAsset).balanceOf(address(this)) < returnAmount) {
revert NotEnoughAssetToTransfer();
}

// interactions
IERC20(fromAsset).transferFrom(msg.sender, address(this), fromAssetAmount);
IERC20(toAsset).transfer(msg.sender, returnAmount);

IERC20(toAsset).transfer(msg.sender, toAssetAmount);

emit AssetSwapped(fromAsset, toAsset, fromAssetAmount, toAssetAmount);
emit ETHSwappedForLST(ethAmountSent, toAsset, returnAmount);
}

/// @notice get return amount for swapping assets that are accepted by LRTDepositPool
/// @dev use LRTOracle to get price for fromToken to toToken
/// @param fromAsset Asset address to swap from
/// @notice get return amount for swapping ETH to asset that is accepted by LRTDepositPool
/// @dev use LRTOracle to get price for toToken
/// @param toAsset Asset address to swap to
/// @param fromAssetAmount Asset amount to swap from
/// @param ethAmountToSend Eth amount to swap from
/// @return returnAmount Return amount of toAsset
function getSwapAssetReturnAmount(
address fromAsset,
function getSwapETHToAssetReturnAmount(
address toAsset,
uint256 fromAssetAmount
uint256 ethAmountToSend
)
public
view
Expand All @@ -388,7 +421,9 @@ contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgrad
address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE);
ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress);

return lrtOracle.getAssetPrice(fromAsset) * fromAssetAmount / lrtOracle.getAssetPrice(toAsset);
uint256 ethPricePerUint = 1e18;

return ethPricePerUint * ethAmountToSend / lrtOracle.getAssetPrice(toAsset);
}

/// @notice update max node delegator count
Expand Down
11 changes: 2 additions & 9 deletions contracts/LRTOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,9 @@ contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, Initializable {
//////////////////////////////////////////////////////////////*/

/// @dev add/update the price oracle of any supported asset
/// @dev only LRTManager is allowed
/// @dev only onlyLRTAdmin is allowed
/// @param asset asset address for which oracle price needs to be added/updated
function updatePriceOracleFor(
address asset,
address priceOracle
)
external
onlyLRTManager
onlySupportedAsset(asset)
{
function updatePriceOracleFor(address asset, address priceOracle) external onlyLRTAdmin onlySupportedAsset(asset) {
UtilLib.checkNonZeroAddress(priceOracle);
assetPriceOracle[asset] = priceOracle;
emit AssetPriceOracleUpdate(asset, priceOracle);
Expand Down
4 changes: 2 additions & 2 deletions contracts/NodeDelegator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ contract NodeDelegator is INodeDelegator, LRTConfigRoleChecker, PausableUpgradea

uint256 balance = token.balanceOf(address(this));

emit AssetDepositIntoStrategy(asset, strategy, balance);

IEigenStrategyManager(eigenlayerStrategyManagerAddress).depositIntoStrategy(IStrategy(strategy), token, balance);

emit AssetDepositIntoStrategy(asset, strategy, balance);
}

/// @notice Transfers an asset back to the LRT deposit pool
Expand Down
9 changes: 0 additions & 9 deletions contracts/RSETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,4 @@ contract RSETH is Initializable, LRTConfigRoleChecker, ERC20Upgradeable, Pausabl
function unpause() external onlyLRTAdmin {
_unpause();
}

/// @notice Updates the LRT config contract
/// @dev only callable by the rsETH admin
/// @param _lrtConfig the new LRT config contract
function updateLRTConfig(address _lrtConfig) external override onlyLRTAdmin {
UtilLib.checkNonZeroAddress(_lrtConfig);
lrtConfig = ILRTConfig(_lrtConfig);
emit UpdatedLRTConfig(_lrtConfig);
}
}
5 changes: 2 additions & 3 deletions contracts/interfaces/ILRTDepositPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface ILRTDepositPool {
error MinimumAmountToReceiveNotMet();
error NodeDelegatorNotFound();
error NodeDelegatorHasAssetBalance(address assetAddress, uint256 assetBalance);
error NodeDelegatorHasETHInEigenlayer();

//events
event MaxNodeDelegatorLimitUpdated(uint256 maxNodeDelegatorLimit);
Expand All @@ -26,9 +27,7 @@ interface ILRTDepositPool {
);
event ETHDeposit(address indexed depositor, uint256 depositAmount, uint256 rsethMintAmount, string referralId);
event MinAmountToDepositUpdated(uint256 minAmountToDeposit);
event AssetSwapped(
address indexed fromAsset, address indexed toAsset, uint256 fromAssetAmount, uint256 toAssetAmount
);
event ETHSwappedForLST(uint256 ethAmount, address indexed toAsset, uint256 returnAmount);

function depositAsset(
address asset,
Expand Down
4 changes: 4 additions & 0 deletions contracts/interfaces/INodeDelegator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ interface INodeDelegator {
error StrategyIsNotSetForAsset();
error InvalidETHSender();

// getter
function stakedButUnverifiedNativeETH() external view returns (uint256);

// methods
function depositAssetIntoStrategy(address asset) external;

Expand All @@ -25,5 +28,6 @@ interface INodeDelegator {

function getAssetBalance(address asset) external view returns (uint256);
function getETHEigenPodBalance() external view returns (uint256);
function transferBackToLRTDepositPool(address asset, uint256 amount) external;
function sendETHFromDepositPoolToNDC() external payable;
}
2 changes: 0 additions & 2 deletions contracts/interfaces/IRSETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,4 @@ interface IRSETH is IERC20 {
function pause() external;

function unpause() external;

function updateLRTConfig(address _lrtConfig) external;
}
2 changes: 2 additions & 0 deletions contracts/utils/LRTConfigRoleChecker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ abstract contract LRTConfigRoleChecker {
/// @dev only callable by LRT admin
/// @param lrtConfigAddr the new LRT config contract Address
function updateLRTConfig(address lrtConfigAddr) external virtual onlyLRTAdmin {
if (address(lrtConfig) != address(0)) revert ILRTConfig.ValueAlreadyInUse();

UtilLib.checkNonZeroAddress(lrtConfigAddr);
lrtConfig = ILRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
Expand Down
10 changes: 5 additions & 5 deletions test/LRTConfigTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,23 @@ contract LRTConfigAddNewSupportedAssetTest is LRTConfigTest {
}

function test_RevertWhenAssetIsZero() external {
vm.startPrank(manager);
vm.startPrank(admin);
vm.expectRevert(UtilLib.ZeroAddressNotAllowed.selector);
lrtConfig.addNewSupportedAsset(address(0), 1000);
vm.stopPrank();
}

function test_RevertAddNewSupportedAssetIfNotManager() external {
function test_RevertAddNewSupportedAssetIfNotAdmin() external {
vm.startPrank(alice);
vm.expectRevert(
"AccessControl: account 0x328809bc894f92807417d2dad6b7c998c1afdac6 is missing role 0xaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c"
"AccessControl: account 0x328809bc894f92807417d2dad6b7c998c1afdac6 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000"
);
lrtConfig.addNewSupportedAsset(address(stETH), 1000);
vm.stopPrank();
}

function test_RevertAddNewSupportedAssetIfAssetAlreadySupported() external {
vm.startPrank(manager);
vm.startPrank(admin);
vm.expectRevert(ILRTConfig.AssetAlreadySupported.selector);
lrtConfig.addNewSupportedAsset(address(stETH), 1000);
vm.stopPrank();
Expand All @@ -162,7 +162,7 @@ contract LRTConfigAddNewSupportedAssetTest is LRTConfigTest {
uint256 depositLimit = 1000;
MockToken newToken = new MockToken("New Token", "NT");

vm.startPrank(manager);
vm.startPrank(admin);
lrtConfig.addNewSupportedAsset(address(newToken), depositLimit);
vm.stopPrank();

Expand Down
Loading

0 comments on commit 9ca0bb5

Please sign in to comment.