From d29be5d05abdae0a17c11025d90fc07b86a25b31 Mon Sep 17 00:00:00 2001 From: Franco NG Date: Thu, 22 Aug 2024 10:37:11 +0200 Subject: [PATCH 1/2] Replace L2VestingWalletPaused by L2VestingWalletEmergencyWithdraw --- .../L1VestingWalletEmergencyWithdraw.s.sol | 62 +++++++++++++++++++ .../L1/paused/L1VestingWalletPaused.s.sol | 56 ----------------- .../L2/paused/L2VestingWalletPaused.s.sol | 38 +++++++----- script/contracts/Utils.sol | 25 +++++--- ...> deployVestingWalletEmergencyWithdraw.sh} | 16 ++--- .../L1VestingWalletEmergencyWithdraw.sol | 11 ++++ src/L1/paused/L1VestingWalletPaused.sol | 11 ---- .../L2VestingWalletEmergencyWithdraw.sol | 20 ++++++ src/L2/paused/L2VestingWalletPaused.sol | 42 ------------- ...=> L2VestingWalletEmergencyWithdraw.t.sol} | 56 +++++++---------- test/utils/Utils.t.sol | 6 +- 11 files changed, 164 insertions(+), 179 deletions(-) create mode 100644 script/contracts/L1/paused/L1VestingWalletEmergencyWithdraw.s.sol delete mode 100644 script/contracts/L1/paused/L1VestingWalletPaused.s.sol rename script/paused/{deployPausedVestingWallet.sh => deployVestingWalletEmergencyWithdraw.sh} (69%) create mode 100644 src/L1/paused/L1VestingWalletEmergencyWithdraw.sol delete mode 100644 src/L1/paused/L1VestingWalletPaused.sol create mode 100644 src/L2/paused/L2VestingWalletEmergencyWithdraw.sol delete mode 100644 src/L2/paused/L2VestingWalletPaused.sol rename test/L2/paused/{L2VestingWalletPaused.t.sol => L2VestingWalletEmergencyWithdraw.t.sol} (67%) diff --git a/script/contracts/L1/paused/L1VestingWalletEmergencyWithdraw.s.sol b/script/contracts/L1/paused/L1VestingWalletEmergencyWithdraw.s.sol new file mode 100644 index 00000000..be741e28 --- /dev/null +++ b/script/contracts/L1/paused/L1VestingWalletEmergencyWithdraw.s.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.23; + +import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import { Upgrades } from "openzeppelin-foundry-upgrades/Upgrades.sol"; +import { Options } from "openzeppelin-foundry-upgrades/Options.sol"; +import { Script, console2 } from "forge-std/Script.sol"; +import { L1VestingWalletEmergencyWithdraw } from "src/L1/paused/L1VestingWalletEmergencyWithdraw.sol"; +import "script/contracts/Utils.sol"; + +/// @title L1VestingWalletEmergencyWithdrawScript - L1VestingWalletEmergencyWithdraw contract deployment script +/// @notice This contract is used to deploy L1VestingWalletEmergencyWithdraw contract and write its address to JSON +/// file. +contract L1VestingWalletEmergencyWithdrawScript is Script { + /// @notice Utils contract which provides functions to read and write JSON files containing L1 and L2 addresses. + Utils utils; + + function setUp() public { + utils = new Utils(); + } + + /// @notice This function deploys L1VestingWalletEmergencyWithdraw contract and writes its address to JSON file. + function run() public { + // Deployer's private key. This key is used to deploy the contract. + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + // Validate L1VestingWalletEmergencyWithdraw contract if it is implemented correctly so that it may be used as + // new + // implementation for the proxy contract. + Options memory opts; + opts.referenceContract = "L1VestingWallet.sol"; + opts.unsafeAllow = "constructor"; + Upgrades.validateUpgrade("L1VestingWalletEmergencyWithdraw.sol", opts); + + console2.log("Deploying L1VestingWalletEmergencyWithdraw contract..."); + + // deploy L1VestingWalletEmergencyWithdraw contract + vm.startBroadcast(deployerPrivateKey); + L1VestingWalletEmergencyWithdraw l1VestingWalletEmergencyWithdrawImplementation = + new L1VestingWalletEmergencyWithdraw(); + vm.stopBroadcast(); + + assert(address(l1VestingWalletEmergencyWithdrawImplementation) != address(0)); + + // ERC1967Utils: keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. + assert( + l1VestingWalletEmergencyWithdrawImplementation.proxiableUUID() + == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1) + ); + + console2.log("L1VestingWalletEmergencyWithdraw contract successfully deployed!"); + console2.log( + "L1VestingWalletEmergencyWithdraw (Implementation) address: %s", + address(l1VestingWalletEmergencyWithdrawImplementation) + ); + + // write L1VestingWalletEmergencyWithdraw address to l1addresses.json + Utils.L1AddressesConfig memory l1AddressesConfig = utils.readL1AddressesFile(utils.getL1AddressesFilePath()); + l1AddressesConfig.L1VestingWalletEmergencyWithdraw = address(l1VestingWalletEmergencyWithdrawImplementation); + utils.writeL1AddressesFile(l1AddressesConfig, utils.getL1AddressesFilePath()); + } +} diff --git a/script/contracts/L1/paused/L1VestingWalletPaused.s.sol b/script/contracts/L1/paused/L1VestingWalletPaused.s.sol deleted file mode 100644 index 6cbcb8a2..00000000 --- a/script/contracts/L1/paused/L1VestingWalletPaused.s.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.23; - -import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -import { Upgrades } from "openzeppelin-foundry-upgrades/Upgrades.sol"; -import { Options } from "openzeppelin-foundry-upgrades/Options.sol"; -import { Script, console2 } from "forge-std/Script.sol"; -import { L1VestingWalletPaused } from "src/L1/paused/L1VestingWalletPaused.sol"; -import "script/contracts/Utils.sol"; - -/// @title L1VestingWalletPausedScript - L1VestingWalletPaused contract deployment script -/// @notice This contract is used to deploy L1VestingWalletPaused contract and write its address to JSON file. -contract L1VestingWalletPausedScript is Script { - /// @notice Utils contract which provides functions to read and write JSON files containing L1 and L2 addresses. - Utils utils; - - function setUp() public { - utils = new Utils(); - } - - /// @notice This function deploys L1VestingWalletPaused contract and writes its address to JSON file. - function run() public { - // Deployer's private key. This key is used to deploy the contract. - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - - // Validate L1VestingWalletPaused contract if it is implemented correctly so that it may be used as new - // implementation for the proxy contract. - Options memory opts; - opts.referenceContract = "L1VestingWallet.sol"; - opts.unsafeAllow = "constructor"; - Upgrades.validateUpgrade("L1VestingWalletPaused.sol", opts); - - console2.log("Deploying L1VestingWalletPaused contract..."); - - // deploy L1VestingWalletPaused contract - vm.startBroadcast(deployerPrivateKey); - L1VestingWalletPaused l1VestingWalletPausedImplementation = new L1VestingWalletPaused(); - vm.stopBroadcast(); - - assert(address(l1VestingWalletPausedImplementation) != address(0)); - - // ERC1967Utils: keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. - assert( - l1VestingWalletPausedImplementation.proxiableUUID() - == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1) - ); - - console2.log("L1VestingWalletPaused contract successfully deployed!"); - console2.log("L1VestingWalletPaused (Implementation) address: %s", address(l1VestingWalletPausedImplementation)); - - // write L1VestingWalletPaused address to l1addresses.json - Utils.L1AddressesConfig memory l1AddressesConfig = utils.readL1AddressesFile(utils.getL1AddressesFilePath()); - l1AddressesConfig.L1VestingWalletPaused = address(l1VestingWalletPausedImplementation); - utils.writeL1AddressesFile(l1AddressesConfig, utils.getL1AddressesFilePath()); - } -} diff --git a/script/contracts/L2/paused/L2VestingWalletPaused.s.sol b/script/contracts/L2/paused/L2VestingWalletPaused.s.sol index 3473654a..c9e41984 100644 --- a/script/contracts/L2/paused/L2VestingWalletPaused.s.sol +++ b/script/contracts/L2/paused/L2VestingWalletPaused.s.sol @@ -5,12 +5,13 @@ import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy import { Upgrades } from "openzeppelin-foundry-upgrades/Upgrades.sol"; import { Options } from "openzeppelin-foundry-upgrades/Options.sol"; import { Script, console2 } from "forge-std/Script.sol"; -import { L2VestingWalletPaused } from "src/L2/paused/L2VestingWalletPaused.sol"; +import { L2VestingWalletEmergencyWithdraw } from "src/L2/paused/L2VestingWalletEmergencyWithdraw.sol"; import "script/contracts/Utils.sol"; -/// @title L2VestingWalletPausedScript - L2VestingWalletPaused contract deployment script -/// @notice This contract is used to deploy L2VestingWalletPaused contract and write its address to JSON file. -contract L2VestingWalletPausedScript is Script { +/// @title L2VestingWalletEmergencyWithdrawScript - L2VestingWalletEmergencyWithdraw contract deployment script +/// @notice This contract is used to deploy L2VestingWalletEmergencyWithdraw contract and write its address to JSON +/// file. +contract L2VestingWalletEmergencyWithdrawScript is Script { /// @notice Utils contract which provides functions to read and write JSON files containing L1 and L2 addresses. Utils utils; @@ -18,39 +19,44 @@ contract L2VestingWalletPausedScript is Script { utils = new Utils(); } - /// @notice This function deploys L2VestingWalletPaused contract and writes its address to JSON file. + /// @notice This function deploys L2VestingWalletEmergencyWithdraw contract and writes its address to JSON file. function run() public { // Deployer's private key. This key is used to deploy the contract. uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - // Validate L2VestingWalletPaused contract if it is implemented correctly so that it may be used as new + // Validate L2VestingWalletEmergencyWithdraw contract if it is implemented correctly so that it may be used as + // new // implementation for the proxy contract. Options memory opts; opts.referenceContract = "L2VestingWallet.sol"; opts.unsafeAllow = "constructor"; - Upgrades.validateUpgrade("L2VestingWalletPaused.sol", opts); + Upgrades.validateUpgrade("L2VestingWalletEmergencyWithdraw.sol", opts); - console2.log("Deploying L2VestingWalletPaused contract..."); + console2.log("Deploying L2VestingWalletEmergencyWithdraw contract..."); - // deploy L2VestingWalletPaused contract + // deploy L2VestingWalletEmergencyWithdraw contract vm.startBroadcast(deployerPrivateKey); - L2VestingWalletPaused l2VestingWalletPausedImplementation = new L2VestingWalletPaused(); + L2VestingWalletEmergencyWithdraw l2VestingWalletEmergencyWithdrawImplementation = + new L2VestingWalletEmergencyWithdraw(); vm.stopBroadcast(); - assert(address(l2VestingWalletPausedImplementation) != address(0)); + assert(address(l2VestingWalletEmergencyWithdrawImplementation) != address(0)); // ERC1967Utils: keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. assert( - l2VestingWalletPausedImplementation.proxiableUUID() + l2VestingWalletEmergencyWithdrawImplementation.proxiableUUID() == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1) ); - console2.log("L2VestingWalletPaused contract successfully deployed!"); - console2.log("L2VestingWalletPaused (Implementation) address: %s", address(l2VestingWalletPausedImplementation)); + console2.log("L2VestingWalletEmergencyWithdraw contract successfully deployed!"); + console2.log( + "L2VestingWalletEmergencyWithdraw (Implementation) address: %s", + address(l2VestingWalletEmergencyWithdrawImplementation) + ); - // write L2VestingWalletPaused address to l2addresses.json + // write L2VestingWalletEmergencyWithdraw address to l2addresses.json Utils.L2AddressesConfig memory l2AddressesConfig = utils.readL2AddressesFile(utils.getL2AddressesFilePath()); - l2AddressesConfig.L2VestingWalletPaused = address(l2VestingWalletPausedImplementation); + l2AddressesConfig.L2VestingWalletEmergencyWithdraw = address(l2VestingWalletEmergencyWithdrawImplementation); utils.writeL2AddressesFile(l2AddressesConfig, utils.getL2AddressesFilePath()); } } diff --git a/script/contracts/Utils.sol b/script/contracts/Utils.sol index c7436502..28cc6d6d 100644 --- a/script/contracts/Utils.sol +++ b/script/contracts/Utils.sol @@ -15,8 +15,8 @@ contract Utils is Script { address L1LiskToken; /// @notice The Current implementation of L1 Vesting Wallet. address L1VestingWalletImplementation; - /// @notice L1 VestingWalletPaused address. - address L1VestingWalletPaused; + /// @notice L1 VestingWalletEmergencyWithdraw address. + address L1VestingWalletEmergencyWithdraw; } /// @notice This struct is used to read and write L2 addresses to JSON file. @@ -57,8 +57,8 @@ contract Utils is Script { address L2TimelockController; /// @notice The Current implementation of L2 Vesting Wallet. address L2VestingWalletImplementation; - /// @notice L2 VestingWalletPaused address. - address L2VestingWalletPaused; + /// @notice L2 VestingWalletEmergencyWithdraw address. + address L2VestingWalletEmergencyWithdraw; /// @notice L2 Voting Power contract (in Proxy), which users interact with. address L2VotingPower; /// @notice The Current implementation of L2 Voting Power Contract. @@ -156,8 +156,10 @@ contract Utils is Script { l1AddressesConfig.L1VestingWalletImplementation = l1VestingWalletImplementation; } catch { } - try vm.parseJsonAddress(addressJson, ".L1VestingWalletPaused") returns (address l1VestingWalletPaused) { - l1AddressesConfig.L1VestingWalletPaused = l1VestingWalletPaused; + try vm.parseJsonAddress(addressJson, ".L1VestingWalletEmergencyWithdraw") returns ( + address l1VestingWalletEmergencyWithdraw + ) { + l1AddressesConfig.L1VestingWalletEmergencyWithdraw = l1VestingWalletEmergencyWithdraw; } catch { } return l1AddressesConfig; @@ -170,7 +172,8 @@ contract Utils is Script { string memory json = ""; vm.serializeAddress(json, "L1LiskToken", cfg.L1LiskToken); vm.serializeAddress(json, "L1VestingWalletImplementation", cfg.L1VestingWalletImplementation); - string memory finalJson = vm.serializeAddress(json, "L1VestingWalletPaused", cfg.L1VestingWalletPaused); + string memory finalJson = + vm.serializeAddress(json, "L1VestingWalletEmergencyWithdraw", cfg.L1VestingWalletEmergencyWithdraw); finalJson.write(filePath); } @@ -258,8 +261,10 @@ contract Utils is Script { l2AddressesConfig.L2VestingWalletImplementation = l2VestingWalletImplementation; } catch { } - try vm.parseJsonAddress(addressJson, ".L2VestingWalletPaused") returns (address l2VestingWalletPaused) { - l2AddressesConfig.L2VestingWalletPaused = l2VestingWalletPaused; + try vm.parseJsonAddress(addressJson, ".L2VestingWalletEmergencyWithdraw") returns ( + address l2VestingWalletEmergencyWithdraw + ) { + l2AddressesConfig.L2VestingWalletEmergencyWithdraw = l2VestingWalletEmergencyWithdraw; } catch { } try vm.parseJsonAddress(addressJson, ".L2VotingPower") returns (address l2VotingPower) { @@ -301,7 +306,7 @@ contract Utils is Script { vm.serializeAddress(json, "L2StakingImplementation", cfg.L2StakingImplementation); vm.serializeAddress(json, "L2TimelockController", cfg.L2TimelockController); vm.serializeAddress(json, "L2VestingWalletImplementation", cfg.L2VestingWalletImplementation); - vm.serializeAddress(json, "L2VestingWalletPaused", cfg.L2VestingWalletPaused); + vm.serializeAddress(json, "L2VestingWalletEmergencyWithdraw", cfg.L2VestingWalletEmergencyWithdraw); vm.serializeAddress(json, "L2VotingPower", cfg.L2VotingPower); vm.serializeAddress(json, "L2VotingPowerImplementation", cfg.L2VotingPowerImplementation); string memory finalJson = vm.serializeAddress(json, "L2VotingPowerPaused", cfg.L2VotingPowerPaused); diff --git a/script/paused/deployPausedVestingWallet.sh b/script/paused/deployVestingWalletEmergencyWithdraw.sh similarity index 69% rename from script/paused/deployPausedVestingWallet.sh rename to script/paused/deployVestingWalletEmergencyWithdraw.sh index 0e12613c..a7838d0f 100755 --- a/script/paused/deployPausedVestingWallet.sh +++ b/script/paused/deployVestingWalletEmergencyWithdraw.sh @@ -31,18 +31,18 @@ echo "Cleaning up the build artifacts to be able to deploy the contract..." forge clean echo "Done." -echo "Deploying and if enabled verifying L2VestingWalletPaused smart contract..." +echo "Deploying and if enabled verifying L2VestingWalletEmergencyWithdraw smart contract..." if [ -z "$CONTRACT_VERIFIER" ] then - forge script --rpc-url="$L2_RPC_URL" --broadcast -vvvv script/contracts/L2/paused/L2VestingWalletPaused.s.sol:L2VestingWalletPausedScript + forge script --rpc-url="$L2_RPC_URL" --broadcast -vvvv script/contracts/L2/paused/L2VestingWalletEmergencyWithdraw.s.sol:L2VestingWalletEmergencyWithdrawScript else if [ $CONTRACT_VERIFIER = "blockscout" ] then - forge script --rpc-url="$L2_RPC_URL" --broadcast --verify --verifier blockscout --verifier-url $L2_VERIFIER_URL -vvvv script/contracts/L2/paused/L2VestingWalletPaused.s.sol:L2VestingWalletPausedScript + forge script --rpc-url="$L2_RPC_URL" --broadcast --verify --verifier blockscout --verifier-url $L2_VERIFIER_URL -vvvv script/contracts/L2/paused/L2VestingWalletEmergencyWithdraw.s.sol:L2VestingWalletEmergencyWithdrawScript fi if [ $CONTRACT_VERIFIER = "etherscan" ] then - forge script --rpc-url="$L2_RPC_URL" --broadcast --verify --verifier etherscan --etherscan-api-key="$L2_ETHERSCAN_API_KEY" -vvvv script/contracts/L2/paused/L2VestingWalletPaused.s.sol:L2VestingWalletPausedScript + forge script --rpc-url="$L2_RPC_URL" --broadcast --verify --verifier etherscan --etherscan-api-key="$L2_ETHERSCAN_API_KEY" -vvvv script/contracts/L2/paused/L2VestingWalletEmergencyWithdraw.s.sol:L2VestingWalletEmergencyWithdrawScript fi fi echo "Done." @@ -51,18 +51,18 @@ echo "Cleaning up the build artifacts to be able to deploy the next contract..." forge clean echo "Done." -echo "Deploying and if enabled verifying L1VestingWalletPaused smart contract..." +echo "Deploying and if enabled verifying L1VestingWalletEmergencyWithdraw smart contract..." if [ -z "$CONTRACT_VERIFIER" ] then - forge script --rpc-url="$L1_RPC_URL" --broadcast -vvvv script/contracts/L1/paused/L1VestingWalletPaused.s.sol:L1VestingWalletPausedScript + forge script --rpc-url="$L1_RPC_URL" --broadcast -vvvv script/contracts/L1/paused/L1VestingWalletEmergencyWithdraw.s.sol:L1VestingWalletEmergencyWithdrawScript else if [ $CONTRACT_VERIFIER = "blockscout" ] then - forge script --rpc-url="$L1_RPC_URL" --broadcast --verify --verifier blockscout --verifier-url $L1_VERIFIER_URL -vvvv script/contracts/L1/paused/L1VestingWalletPaused.s.sol:L1VestingWalletPausedScript + forge script --rpc-url="$L1_RPC_URL" --broadcast --verify --verifier blockscout --verifier-url $L1_VERIFIER_URL -vvvv script/contracts/L1/paused/L1VestingWalletEmergencyWithdraw.s.sol:L1VestingWalletEmergencyWithdrawScript fi if [ $CONTRACT_VERIFIER = "etherscan" ] then - forge script --rpc-url="$L1_RPC_URL" --broadcast --verify --verifier etherscan --etherscan-api-key="$L1_ETHERSCAN_API_KEY" -vvvv script/contracts/L1/paused/L1VestingWalletPaused.s.sol:L1VestingWalletPausedScript + forge script --rpc-url="$L1_RPC_URL" --broadcast --verify --verifier etherscan --etherscan-api-key="$L1_ETHERSCAN_API_KEY" -vvvv script/contracts/L1/paused/L1VestingWalletEmergencyWithdraw.s.sol:L1VestingWalletEmergencyWithdrawScript fi fi echo "Done." \ No newline at end of file diff --git a/src/L1/paused/L1VestingWalletEmergencyWithdraw.sol b/src/L1/paused/L1VestingWalletEmergencyWithdraw.sol new file mode 100644 index 00000000..b48253ee --- /dev/null +++ b/src/L1/paused/L1VestingWalletEmergencyWithdraw.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.23; + +import { L2VestingWalletEmergencyWithdraw } from "src/L2/paused/L2VestingWalletEmergencyWithdraw.sol"; + +/// @title L1VestingWalletEmergencyWithdraw - Paused version of L1VestingWallet contract +/// @notice This contract is used to pause the L1VestingWallet contract. In case of any emergency, the owner can upgrade +/// and +/// pause the contract to prevent any further vesting operations. +/// L1VestingWalletEmergencyWithdraw shares the same functionality of L2VestingWalletEmergencyWithdraw. +contract L1VestingWalletEmergencyWithdraw is L2VestingWalletEmergencyWithdraw { } diff --git a/src/L1/paused/L1VestingWalletPaused.sol b/src/L1/paused/L1VestingWalletPaused.sol deleted file mode 100644 index 4039b005..00000000 --- a/src/L1/paused/L1VestingWalletPaused.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.23; - -import { L2VestingWalletPaused } from "src/L2/paused/L2VestingWalletPaused.sol"; - -/// @title L1VestingWalletPaused - Paused version of L1VestingWallet contract -/// @notice This contract is used to pause the L1VestingWallet contract. In case of any emergency, the owner can upgrade -/// and -/// pause the contract to prevent any further vesting operations. -/// L1VestingWalletPaused shares the same functionality of L1VestingWalletPaused. -contract L1VestingWalletPaused is L2VestingWalletPaused { } diff --git a/src/L2/paused/L2VestingWalletEmergencyWithdraw.sol b/src/L2/paused/L2VestingWalletEmergencyWithdraw.sol new file mode 100644 index 00000000..e86b1b2a --- /dev/null +++ b/src/L2/paused/L2VestingWalletEmergencyWithdraw.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.23; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { L2VestingWallet } from "src/L2/L2VestingWallet.sol"; + +/// @title L2VestingWalletEmergencyWithdraw - L2VestingWallet contract with Emergency Withdraw +/// @notice This is a contingency contract of L2VestingWallet. In case of any emergency, the owner can upgrade +/// and withdraw all tokens from the contract. +contract L2VestingWalletEmergencyWithdraw is L2VestingWallet { + /// @notice Setting global params. + function initializeWithEmergencyWithdraw(IERC20[] memory _token) public reinitializer(2) { + version = "1.0.0-emergency-withdraw"; + + for (uint256 i; i < _token.length; i++) { + IERC20 token = _token[i]; + token.transfer(getRoleMember(CONTRACT_ADMIN_ROLE, 0), token.balanceOf(address(this))); + } + } +} diff --git a/src/L2/paused/L2VestingWalletPaused.sol b/src/L2/paused/L2VestingWalletPaused.sol deleted file mode 100644 index e2ed47ea..00000000 --- a/src/L2/paused/L2VestingWalletPaused.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.23; - -import { L2VestingWallet } from "src/L2/L2VestingWallet.sol"; - -/// @title L2VestingWalletPaused - Paused version of L2VestingWallet contract -/// @notice This contract is used to pause the L2VestingWallet contract. In case of any emergency, the owner can upgrade -/// and -/// pause the contract to prevent any further vesting operations. -contract L2VestingWalletPaused is L2VestingWallet { - error VestingWalletIsPaused(); - - /// @notice Setting global params. - function initializePaused() public reinitializer(2) { - version = "1.0.0-paused"; - } - - /// @notice Override the release function to prevent release of token from being processed. - function release(address) public virtual override { - revert VestingWalletIsPaused(); - } - - /// @notice Override the release function to prevent release of token from being processed. - function release() public virtual override { - revert VestingWalletIsPaused(); - } - - /// @notice Override the acceptOwnership function to prevent change of ownership from being processed. - function acceptOwnership() public virtual override { - revert VestingWalletIsPaused(); - } - - /// @notice Override the acceptOwnership function to prevent change of ownership from being processed. - function transferOwnership(address) public virtual override { - revert VestingWalletIsPaused(); - } - - /// @notice Override the acceptOwnership function to prevent change of ownership from being processed. - function renounceOwnership() public virtual override { - revert VestingWalletIsPaused(); - } -} diff --git a/test/L2/paused/L2VestingWalletPaused.t.sol b/test/L2/paused/L2VestingWalletEmergencyWithdraw.t.sol similarity index 67% rename from test/L2/paused/L2VestingWalletPaused.t.sol rename to test/L2/paused/L2VestingWalletEmergencyWithdraw.t.sol index f2bab1fb..d4d99f67 100644 --- a/test/L2/paused/L2VestingWalletPaused.t.sol +++ b/test/L2/paused/L2VestingWalletEmergencyWithdraw.t.sol @@ -2,9 +2,10 @@ pragma solidity 0.8.23; import { Test, console, stdJson } from "forge-std/Test.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { L2VestingWallet } from "src/L2/L2VestingWallet.sol"; -import { L2VestingWalletPaused } from "src/L2/paused/L2VestingWalletPaused.sol"; +import { L2VestingWalletEmergencyWithdraw } from "src/L2/paused/L2VestingWalletEmergencyWithdraw.sol"; import { MockERC20 } from "test/mock/MockERC20.sol"; contract L2VestingWalletV2UnpausedMock is L2VestingWallet { @@ -17,12 +18,12 @@ contract L2VestingWalletV2UnpausedMock is L2VestingWallet { } } -contract L2VestingWalletPausedTest is Test { +contract L2VestingWalletEmergencyWithdrawTest is Test { using stdJson for string; L2VestingWallet public l2VestingWallet; L2VestingWallet public l2VestingWalletImplementation; - L2VestingWalletPaused public l2VestingWalletPausedImplementation; + L2VestingWalletEmergencyWithdraw public l2VestingWalletEmergencyWithdrawImplementation; MockERC20 public mockToken; @@ -62,44 +63,33 @@ contract L2VestingWalletPausedTest is Test { mockToken = new MockERC20(vestAmount); mockToken.transfer(address(l2VestingWallet), vestAmount); - // deploy L2VestingWalletPaused implementation contract - l2VestingWalletPausedImplementation = new L2VestingWalletPaused(); - - // upgrade L2VestingWallet contract to L2VestingWalletPaused contract - vm.startPrank(contractAdmin); - l2VestingWallet.upgradeToAndCall( - address(l2VestingWalletPausedImplementation), - abi.encodeWithSelector(l2VestingWalletPausedImplementation.initializePaused.selector) - ); - vm.stopPrank(); + // deploy L2VestingWalletEmergencyWithdraw implementation contract + l2VestingWalletEmergencyWithdrawImplementation = new L2VestingWalletEmergencyWithdraw(); } - function test_ReleaseWithAddress_Paused() public { - vm.expectRevert(L2VestingWalletPaused.VestingWalletIsPaused.selector); - l2VestingWallet.release(address(0)); - } + function test_TokenWithdrewAfterInitialize() public { + // upgrade L2VestingWallet contract to L2VestingWalletEmergencyWithdraw contract - function test_Release_Paused() public { - vm.expectRevert(L2VestingWalletPaused.VestingWalletIsPaused.selector); - l2VestingWallet.release(); - } + IERC20[] memory tokens = new IERC20[](1); + tokens[0] = IERC20(address(mockToken)); - function test_AcceptOwnership_Paused() public { - vm.expectRevert(L2VestingWalletPaused.VestingWalletIsPaused.selector); - l2VestingWallet.acceptOwnership(); - } + uint256 contractAdminBalanceBefore = mockToken.balanceOf(contractAdmin); + uint256 vestingWalletBalanceBefore = mockToken.balanceOf(address(l2VestingWallet)); - function test_TransferOwnership_Paused() public { - vm.expectRevert(L2VestingWalletPaused.VestingWalletIsPaused.selector); - l2VestingWallet.transferOwnership(address(0)); - } + vm.startPrank(contractAdmin); + l2VestingWallet.upgradeToAndCall( + address(l2VestingWalletEmergencyWithdrawImplementation), + abi.encodeWithSelector( + l2VestingWalletEmergencyWithdrawImplementation.initializeWithEmergencyWithdraw.selector, tokens + ) + ); + vm.stopPrank(); - function test_RenounceOwnership_Paused() public { - vm.expectRevert(L2VestingWalletPaused.VestingWalletIsPaused.selector); - l2VestingWallet.renounceOwnership(); + assertEq(mockToken.balanceOf(address(l2VestingWallet)), 0); + assertEq(mockToken.balanceOf(contractAdmin), contractAdminBalanceBefore + vestingWalletBalanceBefore); } - function test_UpgradeToAndCall_CanUpgradeFromPausedContractToNewContract() public { + function test_UpgradeToAndCall_CanUpgradeFromEmergencyWithdrawContractToNewContract() public { L2VestingWalletV2UnpausedMock l2VestingWalletV2MockImplementation = new L2VestingWalletV2UnpausedMock(); // upgrade L2VestingWallet contract to L2VestingWalletV2 contract diff --git a/test/utils/Utils.t.sol b/test/utils/Utils.t.sol index a0c2111f..46659dc3 100644 --- a/test/utils/Utils.t.sol +++ b/test/utils/Utils.t.sol @@ -21,7 +21,7 @@ contract UtilsTest is Test { Utils.L1AddressesConfig memory config = Utils.L1AddressesConfig({ L1LiskToken: address(0x1), L1VestingWalletImplementation: address(0x2), - L1VestingWalletPaused: address(0x3) + L1VestingWalletEmergencyWithdraw: address(0x3) }); utils.writeL1AddressesFile(config, "./l1Addresses.json"); @@ -55,7 +55,7 @@ contract UtilsTest is Test { L2StakingImplementation: address(index++), L2TimelockController: address(index++), L2VestingWalletImplementation: address(index++), - L2VestingWalletPaused: address(index++), + L2VestingWalletEmergencyWithdraw: address(index++), L2VotingPower: address(index++), L2VotingPowerImplementation: address(index++), L2VotingPowerPaused: address(index++) @@ -77,7 +77,7 @@ contract UtilsTest is Test { assertEq(configReadFromFile.L2StakingImplementation, config.L2StakingImplementation); assertEq(configReadFromFile.L2TimelockController, config.L2TimelockController); assertEq(configReadFromFile.L2VestingWalletImplementation, config.L2VestingWalletImplementation); - assertEq(configReadFromFile.L2VestingWalletPaused, config.L2VestingWalletPaused); + assertEq(configReadFromFile.L2VestingWalletEmergencyWithdraw, config.L2VestingWalletEmergencyWithdraw); assertEq(configReadFromFile.L2VotingPower, config.L2VotingPower); assertEq(configReadFromFile.L2VotingPowerImplementation, config.L2VotingPowerImplementation); From 4f4deee36a9a84c2aab4ba4db2c343fe67c97f41 Mon Sep 17 00:00:00 2001 From: Franco NG Date: Thu, 22 Aug 2024 10:53:31 +0200 Subject: [PATCH 2/2] Fix Slither --- ...etPaused.s.sol => L2VestingWalletEmergencyWithdraw.s.sol} | 0 src/L2/paused/L2VestingWalletEmergencyWithdraw.sol | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) rename script/contracts/L2/paused/{L2VestingWalletPaused.s.sol => L2VestingWalletEmergencyWithdraw.s.sol} (100%) diff --git a/script/contracts/L2/paused/L2VestingWalletPaused.s.sol b/script/contracts/L2/paused/L2VestingWalletEmergencyWithdraw.s.sol similarity index 100% rename from script/contracts/L2/paused/L2VestingWalletPaused.s.sol rename to script/contracts/L2/paused/L2VestingWalletEmergencyWithdraw.s.sol diff --git a/src/L2/paused/L2VestingWalletEmergencyWithdraw.sol b/src/L2/paused/L2VestingWalletEmergencyWithdraw.sol index e86b1b2a..75faaf43 100644 --- a/src/L2/paused/L2VestingWalletEmergencyWithdraw.sol +++ b/src/L2/paused/L2VestingWalletEmergencyWithdraw.sol @@ -2,19 +2,22 @@ pragma solidity 0.8.23; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { L2VestingWallet } from "src/L2/L2VestingWallet.sol"; /// @title L2VestingWalletEmergencyWithdraw - L2VestingWallet contract with Emergency Withdraw /// @notice This is a contingency contract of L2VestingWallet. In case of any emergency, the owner can upgrade /// and withdraw all tokens from the contract. contract L2VestingWalletEmergencyWithdraw is L2VestingWallet { + using SafeERC20 for IERC20; + /// @notice Setting global params. function initializeWithEmergencyWithdraw(IERC20[] memory _token) public reinitializer(2) { version = "1.0.0-emergency-withdraw"; for (uint256 i; i < _token.length; i++) { IERC20 token = _token[i]; - token.transfer(getRoleMember(CONTRACT_ADMIN_ROLE, 0), token.balanceOf(address(this))); + token.safeTransfer(getRoleMember(CONTRACT_ADMIN_ROLE, 0), token.balanceOf(address(this))); } } }