Skip to content

Conversation

@0xCooki
Copy link

@0xCooki 0xCooki commented Nov 1, 2024

LGE

  • LGE Staking contract
  • Deploy scripts
  • Tests

LGE Migration

  • Interface and first pass at V1 contract

OzUSD

  • Fixed event emission issue

@0xCooki 0xCooki requested a review from jacko125 November 1, 2024 03:45
Comment on lines 72 to 93
constructor(
address _owner,
address _stETH,
address _wstETH,
address[] memory _tokens,
uint256[] memory _depositCaps
) {
_transferOwnership(_owner);
stETH = _stETH;
wstETH = _wstETH;
IstETH(stETH).approve(wstETH, ~uint256(0));
uint256 length = _tokens.length;
require(
length == _depositCaps.length, "LGE Staking: Tokens array length must equal the Deposit Caps array length."
);
for (uint256 i; i < length; ++i) {
allowlisted[_tokens[i]] = true;
emit AllowlistSet(_tokens[i], true);
depositCap[_tokens[i]] = _depositCaps[i];
emit DepositCapSet(_tokens[i], _depositCaps[i]);
}
}

Check warning

Code scanning / Slither

Unused return Medium

Comment on lines +151 to +168
function migrate(address _l2Destination, address[] calldata _tokens) external nonReentrant whenNotPaused {
require(migrationActivated(), "LGE Staking: Migration not active.");
require(_l2Destination != address(0), "LGE Staking: May not send tokens to the zero address.");
uint256 length = _tokens.length;
require(length > 0, "LGE Staking: Must migrate some tokens.");
uint256[] memory amounts = new uint256[](length);
uint256 amount;
for (uint256 i; i < length; i++) {
amount = balance[_tokens[i]][msg.sender];
require(amount > 0, "LGE Staking: No tokens to migrate.");
balance[_tokens[i]][msg.sender] -= amount;
totalDeposited[_tokens[i]] -= amount;
amounts[i] = amount;
IERC20(_tokens[i]).safeTransfer(address(lgeMigration), amount);
}
lgeMigration.migrate(_l2Destination, _tokens, amounts);
emit TokensMigrated(msg.sender, _l2Destination, _tokens, amounts);
}

Check warning

Code scanning / Slither

Reentrancy vulnerabilities Medium

Reentrancy in LGEStaking.migrate(address,address[]):
External calls:
- IERC20(_tokens[i]).safeTransfer(address(lgeMigration),amount)
State variables written after the call(s):
- balance[_tokens[i]][msg.sender] -= amount
LGEStaking.balance can be used in cross function reentrancies:
- LGEStaking.balance
- totalDeposited[_tokens[i]] -= amount
LGEStaking.totalDeposited can be used in cross function reentrancies:
- LGEStaking.totalDeposited
Comment on lines 116 to 129
function depositETH() external payable nonReentrant whenNotPaused {
require(!migrationActivated(), "LGE Staking: May not deposit once migration has been activated.");
require(msg.value > 0, "LGE Staking: May not deposit nothing.");
require(allowlisted[wstETH], "LGE Staking: Token must be allowlisted.");
IstETH(stETH).submit{value: msg.value}(address(0));
uint256 wstETHAmount = IwstETH(wstETH).wrap(IstETH(stETH).balanceOf(address(this)));
require(
totalDeposited[wstETH] + wstETHAmount < depositCap[wstETH],
"LGE Staking: deposit amount exceeds deposit cap."
);
balance[wstETH][msg.sender] += wstETHAmount;
totalDeposited[wstETH] += wstETHAmount;
emit Deposit(wstETH, wstETHAmount, msg.sender);
}

Check warning

Code scanning / Slither

Unused return Medium

Comment on lines 101 to 117
function depositERC20(address _token, uint256 _amount) external nonReentrant whenNotPaused {
require(!migrationActivated(), "LGE Staking: May not deposit once migration has been activated.");
require(_amount > 0, "LGE Staking: May not deposit nothing.");
require(allowlisted[_token], "LGE Staking: Token must be allowlisted.");
require(
totalDeposited[_token] + _amount < depositCap[_token], "LGE Staking: deposit amount exceeds deposit cap."
);
uint256 balanceBefore = IERC20(_token).balanceOf(address(this));
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
require(
IERC20(_token).balanceOf(address(this)) - balanceBefore == _amount,
"LGE Staking: Fee-on-transfer tokens not supported."
);
balance[_token][msg.sender] += _amount;
totalDeposited[_token] += _amount;
emit Deposit(_token, _amount, msg.sender);
}

Check warning

Code scanning / Slither

Reentrancy vulnerabilities Medium

Reentrancy in LGEStaking.depositERC20(address,uint256):
External calls:
- IERC20(_token).safeTransferFrom(msg.sender,address(this),_amount)
State variables written after the call(s):
- totalDeposited[_token] += _amount
LGEStaking.totalDeposited can be used in cross function reentrancies:
- LGEStaking.totalDeposited
/// @notice This function allows the owner to modify the deposit cap for deposited tokens.
/// @param _token The token address to modify the deposit cap.
/// @param _newDepositCap The new deposit cap.
function setDepositCap(address _token, uint256 _newDepositCap) external onlyOwner {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xCooki

Do we want to ensure _newDepositCap is validated to ensure it has realistic values?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's necessary. Suppose an unrealistic value is set, a second transaction can be made to correct it.

/// @dev The new migration contract must conform to the ILGEMigration interface.
/// @dev If this contract is set to address(0) migration is deactivated
function setMigrationContract(address _contract) external onlyOwner {
lgeMigration = ILGEMigration(_contract);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if lgeMigration is set to malicious contract then users calling "migrate" will be transferred to it.

Need to ensure Owner control is set to multisig

} else if (_tokens[i] == wstETH) {
/// Handle wstETH
IERC20(_tokens[i]).safeApprove(address(l1LidoTokensBridge), _amounts[i]);
l1LidoTokensBridge.depositERC20To(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xCooki

Given we are planning to support Hyperlane Warp routes for wstETH, do we want to keep the lido token bridge here for migrating wstETH?

Hyperlane could support wstETH as ERC20.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, this needs to change given the bridging solution per asset we decide for Ozean.

} else {
/// Handle other tokens
IERC20(_tokens[i]).safeApprove(address(l1StandardBridge), _amounts[i]);
l1StandardBridge.depositERC20To(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Hyperlane bridge have the same interface 'bridge.depositERC20To()or we are going to usel1standardBridge` for the LGE migration ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hyperlane have their own contract interface, the migration contract will need to be updated given the bridging solution per asset we decide for Ozean.

Copy link

@jacko125 jacko125 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xCooki Reviewed some comments about the Migration contract and LGE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants