diff --git a/src/core/BaseRestakingController.sol b/src/core/BaseRestakingController.sol index 95a1cac2..feb1bce8 100644 --- a/src/core/BaseRestakingController.sol +++ b/src/core/BaseRestakingController.sol @@ -8,9 +8,11 @@ import {ClientChainGatewayStorage} from "../storage/ClientChainGatewayStorage.so import {OptionsBuilder} from "@layerzero-v2/oapp/contracts/oapp/libs/OptionsBuilder.sol"; import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol"; abstract contract BaseRestakingController is PausableUpgradeable, + ReentrancyGuardUpgradeable, OAppSenderUpgradeable, IBaseRestakingController, ClientChainGatewayStorage @@ -25,6 +27,7 @@ abstract contract BaseRestakingController is isTokenWhitelisted(token) isValidAmount(amount) whenNotPaused + nonReentrant { if (token == VIRTUAL_STAKED_ETH_ADDRESS) { IExoCapsule capsule = _getCapsule(msg.sender); @@ -44,6 +47,7 @@ abstract contract BaseRestakingController is isValidAmount(amount) isValidBech32Address(operator) whenNotPaused + nonReentrant { bytes memory actionArgs = abi.encodePacked(bytes32(bytes20(token)), bytes32(bytes20(msg.sender)), bytes(operator), amount); @@ -58,6 +62,7 @@ abstract contract BaseRestakingController is isValidAmount(amount) isValidBech32Address(operator) whenNotPaused + nonReentrant { bytes memory actionArgs = abi.encodePacked(bytes32(bytes20(token)), bytes32(bytes20(msg.sender)), bytes(operator), amount); diff --git a/src/core/Bootstrap.sol b/src/core/Bootstrap.sol index 77b1da8d..5abba722 100644 --- a/src/core/Bootstrap.sol +++ b/src/core/Bootstrap.sol @@ -81,6 +81,7 @@ contract Bootstrap is // contract controlled by one. __Ownable_init_unchained(owner); __Pausable_init_unchained(); + __ReentrancyGuard_init_unchained(); } /** diff --git a/src/core/ClientChainGateway.sol b/src/core/ClientChainGateway.sol index edd05f8a..bf39d044 100644 --- a/src/core/ClientChainGateway.sol +++ b/src/core/ClientChainGateway.sol @@ -84,6 +84,7 @@ contract ClientChainGateway is __Ownable_init_unchained(exocoreValidatorSetAddress); __OAppCore_init_unchained(exocoreValidatorSetAddress); __Pausable_init_unchained(); + __ReentrancyGuard_init_unchained(); } function _clearBootstrapData() internal { @@ -119,7 +120,7 @@ contract ClientChainGateway is } // implementation of ITokenWhitelister - function addWhitelistTokens(address[] calldata tokens) external payable onlyOwner whenNotPaused { + function addWhitelistTokens(address[] calldata tokens) external payable onlyOwner whenNotPaused nonReentrant { _addWhitelistTokens(tokens); } diff --git a/src/core/ExocoreGateway.sol b/src/core/ExocoreGateway.sol index ac6a6036..10234e03 100644 --- a/src/core/ExocoreGateway.sol +++ b/src/core/ExocoreGateway.sol @@ -22,11 +22,13 @@ import {ILayerZeroReceiver} from "@layerzero-v2/protocol/contracts/interfaces/IL import {OwnableUpgradeable} from "@openzeppelin-upgradeable/contracts/access/OwnableUpgradeable.sol"; import {Initializable} from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol"; contract ExocoreGateway is Initializable, PausableUpgradeable, OwnableUpgradeable, + ReentrancyGuardUpgradeable, IExocoreGateway, ExocoreGatewayStorage, OAppUpgradeable @@ -60,6 +62,7 @@ contract ExocoreGateway is __Ownable_init_unchained(exocoreValidatorSetAddress); __OAppCore_init_unchained(exocoreValidatorSetAddress); __Pausable_init_unchained(); + __ReentrancyGuard_init_unchained(); } function _initializeWhitelistFunctionSelectors() private { @@ -94,7 +97,7 @@ contract ExocoreGateway is // setPeer) or be triggered by Golang after the contract is deployed. // For manual calls, this function should be called immediately after deployment and // then never needs to be called again. - function markBootstrapOnAllChains() public whenNotPaused { + function markBootstrapOnAllChains() public whenNotPaused nonReentrant { (bool success, bytes memory result) = ASSETS_PRECOMPILE_ADDRESS.staticcall(abi.encodeWithSelector(ASSETS_CONTRACT.getClientChains.selector)); require(success, "ExocoreGateway: failed to get client chain ids"); @@ -145,7 +148,13 @@ contract ExocoreGateway is } } - function _lzReceive(Origin calldata _origin, bytes calldata payload) internal virtual override whenNotPaused { + function _lzReceive(Origin calldata _origin, bytes calldata payload) + internal + virtual + override + whenNotPaused + nonReentrant + { _verifyAndUpdateNonce(_origin.srcEid, _origin.sender, _origin.nonce); Action act = Action(uint8(payload[0])); diff --git a/src/core/LSTRestakingController.sol b/src/core/LSTRestakingController.sol index 8c2ee688..2e2be4a6 100644 --- a/src/core/LSTRestakingController.sol +++ b/src/core/LSTRestakingController.sol @@ -6,8 +6,14 @@ import {IVault} from "../interfaces/IVault.sol"; import {BaseRestakingController} from "./BaseRestakingController.sol"; import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol"; -abstract contract LSTRestakingController is PausableUpgradeable, ILSTRestakingController, BaseRestakingController { +abstract contract LSTRestakingController is + PausableUpgradeable, + ReentrancyGuardUpgradeable, + ILSTRestakingController, + BaseRestakingController +{ function deposit(address token, uint256 amount) external @@ -15,6 +21,7 @@ abstract contract LSTRestakingController is PausableUpgradeable, ILSTRestakingCo isTokenWhitelisted(token) isValidAmount(amount) whenNotPaused + nonReentrant { IVault vault = _getVault(token); vault.deposit(msg.sender, amount); @@ -31,6 +38,7 @@ abstract contract LSTRestakingController is PausableUpgradeable, ILSTRestakingCo isTokenWhitelisted(token) isValidAmount(principalAmount) whenNotPaused + nonReentrant { bytes memory actionArgs = abi.encodePacked(bytes32(bytes20(token)), bytes32(bytes20(msg.sender)), principalAmount); @@ -45,6 +53,7 @@ abstract contract LSTRestakingController is PausableUpgradeable, ILSTRestakingCo isTokenWhitelisted(token) isValidAmount(rewardAmount) whenNotPaused + nonReentrant { bytes memory actionArgs = abi.encodePacked(bytes32(bytes20(token)), bytes32(bytes20(msg.sender)), rewardAmount); bytes memory encodedRequest = abi.encode(token, msg.sender, rewardAmount); @@ -60,6 +69,7 @@ abstract contract LSTRestakingController is PausableUpgradeable, ILSTRestakingCo isValidAmount(amount) isValidBech32Address(operator) whenNotPaused + nonReentrant { IVault vault = _getVault(token); vault.deposit(msg.sender, amount); diff --git a/src/core/NativeRestakingController.sol b/src/core/NativeRestakingController.sol index 5789fa30..b0097fb7 100644 --- a/src/core/NativeRestakingController.sol +++ b/src/core/NativeRestakingController.sol @@ -8,10 +8,12 @@ import {BaseRestakingController} from "./BaseRestakingController.sol"; import {ExoCapsule} from "./ExoCapsule.sol"; import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol"; import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; abstract contract NativeRestakingController is PausableUpgradeable, + ReentrancyGuardUpgradeable, INativeRestakingController, BaseRestakingController { @@ -22,6 +24,7 @@ abstract contract NativeRestakingController is external payable whenNotPaused + nonReentrant { require(msg.value == 32 ether, "NativeRestakingController: stake value must be exactly 32 ether"); @@ -58,7 +61,7 @@ abstract contract NativeRestakingController is function depositBeaconChainValidator( bytes32[] calldata validatorContainer, IExoCapsule.ValidatorContainerProof calldata proof - ) external payable whenNotPaused { + ) external payable whenNotPaused nonReentrant { IExoCapsule capsule = _getCapsule(msg.sender); capsule.verifyDepositProof(validatorContainer, proof); @@ -75,13 +78,13 @@ abstract contract NativeRestakingController is IExoCapsule.ValidatorContainerProof calldata validatorProof, bytes32[] calldata withdrawalContainer, IExoCapsule.WithdrawalContainerProof calldata withdrawalProof - ) external payable whenNotPaused {} + ) external payable whenNotPaused nonReentrant {} function processBeaconChainFullWithdrawal( bytes32[] calldata validatorContainer, IExoCapsule.ValidatorContainerProof calldata validatorProof, bytes32[] calldata withdrawalContainer, IExoCapsule.WithdrawalContainerProof calldata withdrawalProof - ) external payable whenNotPaused {} + ) external payable whenNotPaused nonReentrant {} }