From f2b82c0bbe5f3a6dc586d84926f3486dd817527f Mon Sep 17 00:00:00 2001 From: vicnaum Date: Tue, 6 Feb 2024 21:30:07 +0100 Subject: [PATCH] misc: new and updated Deployment scripts --- script/DeployLensHub.s.sol | 254 +++++++++++++++++++++++ script/DeployPermissionlessCreator.s.sol | 175 ++++++++++++++++ script/forkUpgradeLensHub.sh | 27 +++ script/run.sh | 6 +- script/verifyStorageSlots.sh | 10 +- 5 files changed, 465 insertions(+), 7 deletions(-) create mode 100644 script/DeployLensHub.s.sol create mode 100644 script/DeployPermissionlessCreator.s.sol create mode 100644 script/forkUpgradeLensHub.sh diff --git a/script/DeployLensHub.s.sol b/script/DeployLensHub.s.sol new file mode 100644 index 0000000..ae702d7 --- /dev/null +++ b/script/DeployLensHub.s.sol @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {ForkManagement} from 'script/helpers/ForkManagement.sol'; +import 'forge-std/Script.sol'; +import {LibString} from 'solady/utils/LibString.sol'; +import {FollowNFT} from 'contracts/FollowNFT.sol'; +import {LensHubInitializable} from 'contracts/misc/LensHubInitializable.sol'; +import {Types} from 'contracts/libraries/constants/Types.sol'; +import {Governance} from 'contracts/misc/access/Governance.sol'; +import {LensHandles} from 'contracts/namespaces/LensHandles.sol'; + +contract DeployLensHub is Script, ForkManagement { + using stdJson for string; + + struct LensAccount { + uint256 ownerPk; + address owner; + uint256 profileId; + } + + LensAccount _deployer; + + string mnemonic; + + uint256 internal PROFILE_GUARDIAN_COOLDOWN; + uint256 internal HANDLE_GUARDIAN_COOLDOWN; + + address lensHub; + address legacyCollectNFTImpl; + address followNFTImpl; + address moduleRegistry; + + address lensHandlesAddress; + address tokenHandleRegistryAddress; + address legacyFeeFollowModule; + address legacyProfileFollowModule; + address newFeeFollowModule; + address lensHandlesOwner; + address lensHandlesImpl; + + address governanceContract; + address governanceAdmin; + address lensHubV2Impl; + + string addressesFile = 'addressesV2.txt'; + + // TODO: Use from test/ContractAddresses + struct Module { + address addy; + string name; + } + + // TODO: Move this somewhere common (also in UpgradeForkTest) + function findModuleHelper( + Module[] memory modules, + string memory moduleNameToFind + ) internal pure returns (Module memory) { + for (uint256 i = 0; i < modules.length; i++) { + if (LibString.eq(modules[i].name, moduleNameToFind)) { + return modules[i]; + } + } + revert('Module not found'); + } + + function saveContractAddress(string memory contractName, address deployedAddress) internal { + // console.log('Saving %s (%s) into addresses under %s environment', contractName, deployedAddress, targetEnv); + string[] memory inputs = new string[](5); + inputs[0] = 'node'; + inputs[1] = 'script/helpers/saveAddress.js'; + inputs[2] = targetEnv; + inputs[3] = contractName; + inputs[4] = vm.toString(deployedAddress); + // bytes memory res = + vm.ffi(inputs); + // string memory output = abi.decode(res, (string)); + // console.log(output); + } + + function loadPrivateKeys() internal { + if (isEnvSet('MNEMONIC')) { + mnemonic = vm.envString('MNEMONIC'); + } + + if (bytes(mnemonic).length == 0) { + revert('Missing mnemonic'); + } + + console.log('\n'); + + (_deployer.owner, _deployer.ownerPk) = deriveRememberKey(mnemonic, 0); + console.logBytes32(bytes32(_deployer.ownerPk)); + console.log('Deployer address: %s', address(_deployer.owner)); + + console.log('\n'); + + console.log('Current block:', block.number); + } + + function loadBaseAddresses() internal override { + lensHub = json.readAddress(string(abi.encodePacked('.', targetEnv, '.LensHubProxy'))); + vm.label(lensHub, 'LensHub'); + console.log('Lens Hub Proxy: %s', lensHub); + + legacyCollectNFTImpl = json.readAddress(string(abi.encodePacked('.', targetEnv, '.LegacyCollectNFTImpl'))); + vm.label(legacyCollectNFTImpl, 'LegacyCollectNFTImpl'); + console.log('LegacyCollectNFTImpl: %s', legacyCollectNFTImpl); + + moduleRegistry = json.readAddress(string(abi.encodePacked('.', targetEnv, '.ModuleRegistry'))); + vm.label(moduleRegistry, 'ModuleRegistry'); + console.log('ModuleRegistry: %s', moduleRegistry); + + PROFILE_GUARDIAN_COOLDOWN = json.readUint( + string(abi.encodePacked('.', targetEnv, '.LensProfilesGuardianTimelock')) + ); + console.log('PROFILE_GUARDIAN_COOLDOWN: %s', PROFILE_GUARDIAN_COOLDOWN); + + HANDLE_GUARDIAN_COOLDOWN = json.readUint( + string(abi.encodePacked('.', targetEnv, '.LensHandlesGuardianTimelock')) + ); + console.log('HANDLE_GUARDIAN_COOLDOWN: %s', HANDLE_GUARDIAN_COOLDOWN); + + lensHandlesAddress = json.readAddress(string(abi.encodePacked('.', targetEnv, '.LensHandles'))); + + tokenHandleRegistryAddress = json.readAddress(string(abi.encodePacked('.', targetEnv, '.TokenHandleRegistry'))); + + Module[] memory followModules = abi.decode( + vm.parseJson(json, string(abi.encodePacked('.', targetEnv, '.Modules.v1.follow'))), + (Module[]) + ); + + legacyFeeFollowModule = findModuleHelper(followModules, 'FeeFollowModule').addy; + vm.label(legacyFeeFollowModule, 'LegacyFeeFollowModule'); + console.log('Legacy Fee Follow Module: %s', legacyFeeFollowModule); + + legacyProfileFollowModule = findModuleHelper(followModules, 'ProfileFollowModule').addy; + vm.label(legacyProfileFollowModule, 'LegacyProfileFollowModule'); + console.log('Legacy Profile Follow Module: %s', legacyProfileFollowModule); + + followModules = abi.decode( + vm.parseJson(json, string(abi.encodePacked('.', targetEnv, '.Modules.v2.follow'))), + (Module[]) + ); + + newFeeFollowModule = findModuleHelper(followModules, 'FeeFollowModule').addy; + vm.label(newFeeFollowModule, 'NewFeeFollowModule'); + console.log('New Fee Follow Module: %s', newFeeFollowModule); + + governanceContract = LensHubInitializable(lensHub).getGovernance(); + governanceAdmin = Governance(governanceContract).owner(); + + lensHandlesOwner = governanceAdmin; + vm.label(lensHandlesOwner, 'LensHandlesOwner'); + console.log('LensHandlesOwner: %s', lensHandlesOwner); + + followNFTImpl = json.readAddress(string(abi.encodePacked('.', targetEnv, '.FollowNFTImpl'))); + vm.label(followNFTImpl, 'FollowNFTImpl'); + console.log('FollowNFTImpl: %s', followNFTImpl); + + lensHandlesImpl = json.readAddress(string(abi.encodePacked('.', targetEnv, '.LensHandlesImpl'))); + vm.label(lensHandlesImpl, 'LensHandlesImpl'); + console.log('LensHandlesImpl: %s', lensHandlesImpl); + } + + function deploy() internal { + if (lensHub == address(0)) { + console.log('LensHub not set'); + revert('LensHub not set'); + } + + if (lensHandlesOwner == address(0)) { + console.log('lensHandlesOwner not set'); + revert('lensHandlesOwner not set'); + } + + if (HANDLE_GUARDIAN_COOLDOWN == 0) { + console.log('HANDLE_GUARDIAN_COOLDOWN not set'); + revert('HANDLE_GUARDIAN_COOLDOWN not set'); + } + + if (legacyCollectNFTImpl == address(0)) { + console.log('LegacyCollectNFTImpl not set'); + revert('LegacyCollectNFTImpl not set'); + } + + if (moduleRegistry == address(0)) { + console.log('ModuleRegistry not set'); + revert('ModuleRegistry not set'); + } + + if (PROFILE_GUARDIAN_COOLDOWN == 0) { + console.log('PROFILE_GUARDIAN_COOLDOWN not set'); + revert('PROFILE_GUARDIAN_COOLDOWN not set'); + } + + console.log('PROFILE_GUARDIAN_COOLDOWN: %s', PROFILE_GUARDIAN_COOLDOWN); + + // Pass all the fucking shit and deploy LensHub V2 Impl with: + vm.startBroadcast(_deployer.ownerPk); + lensHubV2Impl = address( + new LensHubInitializable( + followNFTImpl, + legacyCollectNFTImpl, + moduleRegistry, + PROFILE_GUARDIAN_COOLDOWN, + Types.MigrationParams({ + lensHandlesAddress: lensHandlesAddress, + tokenHandleRegistryAddress: tokenHandleRegistryAddress, + legacyFeeFollowModule: legacyFeeFollowModule, + legacyProfileFollowModule: legacyProfileFollowModule, + newFeeFollowModule: newFeeFollowModule + }) + ) + ); + vm.stopBroadcast(); + + console.log('"arguments": ['); + console.log('\t"%s"', followNFTImpl); + console.log('\t"%s"', legacyCollectNFTImpl); + console.log('\t"%s"', moduleRegistry); + console.log('\t"%s"', PROFILE_GUARDIAN_COOLDOWN); + console.log( + '\t"%s"', + string.concat( + '(', + vm.toString(lensHandlesAddress), + ', ', + vm.toString(tokenHandleRegistryAddress), + ', ', + vm.toString(legacyFeeFollowModule), + ', ', + vm.toString(legacyProfileFollowModule), + ', ', + vm.toString(newFeeFollowModule), + ')' + ) + ); + console.log(']'); + + vm.writeLine(addressesFile, string.concat('LensHubV2Impl: ', vm.toString(lensHubV2Impl))); + saveContractAddress('LensHubV2Impl', lensHubV2Impl); + console.log('LensHubV2Impl: %s', lensHubV2Impl); + } + + function run(string memory targetEnv_) external { + targetEnv = targetEnv_; + loadJson(); + checkNetworkParams(); + loadBaseAddresses(); + loadPrivateKeys(); + deploy(); + } +} diff --git a/script/DeployPermissionlessCreator.s.sol b/script/DeployPermissionlessCreator.s.sol new file mode 100644 index 0000000..c72fc2b --- /dev/null +++ b/script/DeployPermissionlessCreator.s.sol @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + +import {ForkManagement} from 'script/helpers/ForkManagement.sol'; +import 'forge-std/Script.sol'; +import {LibString} from 'solady/utils/LibString.sol'; +import {Types} from 'contracts/libraries/constants/Types.sol'; +import {Governance} from 'contracts/misc/access/Governance.sol'; +import {PermissionlessCreator} from 'contracts/misc/PermissionlessCreator.sol'; +import {TransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; +import {LensHubInitializable} from 'contracts/misc/LensHubInitializable.sol'; + +contract DeployPermissionlessCreator is Script, ForkManagement { + using stdJson for string; + + struct LensAccount { + uint256 ownerPk; + address owner; + uint256 profileId; + } + + LensAccount _deployer; + + string mnemonic; + + uint256 internal PROFILE_GUARDIAN_COOLDOWN; + uint256 internal HANDLE_GUARDIAN_COOLDOWN; + + address lensHub; + + address lensHandlesAddress; + address tokenHandleRegistryAddress; + + address governanceContract; + address governanceAdmin; + + address proxyAdminContractAdmin; + + address permissionlessCreatorImpl; + address permissionlessCreator; + + string addressesFile = 'addressesV2.txt'; + + // TODO: Use from test/ContractAddresses + struct Module { + address addy; + string name; + } + + // TODO: Move this somewhere common (also in UpgradeForkTest) + function findModuleHelper( + Module[] memory modules, + string memory moduleNameToFind + ) internal pure returns (Module memory) { + for (uint256 i = 0; i < modules.length; i++) { + if (LibString.eq(modules[i].name, moduleNameToFind)) { + return modules[i]; + } + } + revert('Module not found'); + } + + function saveContractAddress(string memory contractName, address deployedAddress) internal { + // console.log('Saving %s (%s) into addresses under %s environment', contractName, deployedAddress, targetEnv); + string[] memory inputs = new string[](5); + inputs[0] = 'node'; + inputs[1] = 'script/helpers/saveAddress.js'; + inputs[2] = targetEnv; + inputs[3] = contractName; + inputs[4] = vm.toString(deployedAddress); + // bytes memory res = + vm.ffi(inputs); + // string memory output = abi.decode(res, (string)); + // console.log(output); + } + + function loadPrivateKeys() internal { + if (isEnvSet('MNEMONIC')) { + mnemonic = vm.envString('MNEMONIC'); + } + + if (bytes(mnemonic).length == 0) { + revert('Missing mnemonic'); + } + + console.log('\n'); + + (_deployer.owner, _deployer.ownerPk) = deriveRememberKey(mnemonic, 0); + console.logBytes32(bytes32(_deployer.ownerPk)); + console.log('Deployer address: %s', address(_deployer.owner)); + + console.log('\n'); + + console.log('Current block:', block.number); + } + + function loadBaseAddresses() internal override { + lensHub = json.readAddress(string(abi.encodePacked('.', targetEnv, '.LensHubProxy'))); + vm.label(lensHub, 'LensHub'); + console.log('Lens Hub Proxy: %s', lensHub); + + lensHandlesAddress = json.readAddress(string(abi.encodePacked('.', targetEnv, '.LensHandles'))); + + tokenHandleRegistryAddress = json.readAddress(string(abi.encodePacked('.', targetEnv, '.TokenHandleRegistry'))); + + governanceContract = LensHubInitializable(lensHub).getGovernance(); + vm.label(governanceContract, 'Governance'); + console.log('Governance Contract: %s', governanceContract); + + governanceAdmin = Governance(governanceContract).owner(); + vm.label(governanceAdmin, 'GovernanceAdmin'); + console.log('Governance Contract Admin: %s', governanceAdmin); + + proxyAdminContractAdmin = json.readAddress( + string(abi.encodePacked('.', targetEnv, '.ProxyAdminContractAdmin')) + ); + vm.label(proxyAdminContractAdmin, 'ProxyAdminContractAdmin'); + console.log('ProxyAdmin Contract Admin: %s', proxyAdminContractAdmin); + } + + function deploy() internal { + if (lensHub == address(0)) { + console.log('LensHub not set'); + revert('LensHub not set'); + } + + if (proxyAdminContractAdmin == address(0)) { + console.log('ProxyAdminContractAdmin not set'); + revert('ProxyAdminContractAdmin not set'); + } + + if (lensHandlesAddress == address(0)) { + console.log('lensHandlesAddress not set'); + revert('lensHandlesAddress not set'); + } + + if (tokenHandleRegistryAddress == address(0)) { + console.log('tokenHandleRegistryAddress not set'); + revert('tokenHandleRegistryAddress not set'); + } + + // Pass all the fucking shit and deploy LensHub V2 Impl with: + vm.startBroadcast(_deployer.ownerPk); + + permissionlessCreatorImpl = address( + new PermissionlessCreator(governanceAdmin, lensHub, lensHandlesAddress, tokenHandleRegistryAddress) + ); + + // Make LensHandles a transparentUpgradeableProxy + permissionlessCreator = address( + new TransparentUpgradeableProxy(permissionlessCreatorImpl, proxyAdminContractAdmin, '') + ); + vm.stopBroadcast(); + + vm.writeLine( + addressesFile, + string.concat('PermissionlessCreatorImpl: ', vm.toString(permissionlessCreatorImpl)) + ); + saveContractAddress('PermissionlessCreatorImpl', permissionlessCreatorImpl); + console.log('PermissionlessCreatorImpl: %s', permissionlessCreatorImpl); + + vm.writeLine(addressesFile, string.concat('PermissionlessCreator: ', vm.toString(permissionlessCreator))); + saveContractAddress('PermissionlessCreator', permissionlessCreator); + console.log('PermissionlessCreator: %s', permissionlessCreator); + } + + function run(string memory targetEnv_) external { + targetEnv = targetEnv_; + loadJson(); + checkNetworkParams(); + loadBaseAddresses(); + loadPrivateKeys(); + deploy(); + } +} diff --git a/script/forkUpgradeLensHub.sh b/script/forkUpgradeLensHub.sh new file mode 100644 index 0000000..aa26f52 --- /dev/null +++ b/script/forkUpgradeLensHub.sh @@ -0,0 +1,27 @@ +source .env + +set -e + +TARGET=$1 + +if [[ "$TARGET" == "" ]] + then + echo "No TARGET specified. Terminating" + exit 1 +fi +echo "Using target: $TARGET" + + +IMPLEMENTATION_SLOT="0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" +LENSHUB=$(node script/helpers/readAddress.js $TARGET LensHubProxy) +PROXY_CONTRACT=$(node script/helpers/readAddress.js $TARGET ProxyAdminContract) +PROXY_CONTRACT_OWNER=$(cast call $PROXY_CONTRACT "owner()(address)") + +cast rpc anvil_impersonateAccount $PROXY_CONTRACT_OWNER +cast send $PROXY_CONTRACT "proxy_upgrade(address)" "0xb4A26f55Cc2d1473b8A7649d90d34ba52A480391" --unlocked --from $PROXY_CONTRACT_OWNER + +NEW_IMPLEMENTATION=$(cast parse-bytes32-address $(cast storage $LENSHUB $IMPLEMENTATION_SLOT)) + +echo "Successfully upgraded LensHub to $NEW_IMPLEMENTATION" + +cast rpc anvil_stopImpersonatingAccount $PROXY_CONTRACT_OWNER diff --git a/script/run.sh b/script/run.sh index 3d36185..dee75bf 100644 --- a/script/run.sh +++ b/script/run.sh @@ -39,7 +39,7 @@ CALLDATA=$(cast calldata "run(string)" $TARGET) echo "Interactions calldata:" echo "$CALLDATA" -forge script script/$SCRIPT_NAME.s.sol:$SCRIPT_NAME -s $CALLDATA --rpc-url $NETWORK -vv --legacy --skip test --ffi +forge script script/$SCRIPT_NAME.s.sol:$SCRIPT_NAME --sig $CALLDATA --rpc-url $NETWORK -vv --legacy --skip test --ffi # If the confirmation override is set to s or S - then we skip the rest of the script and exit with success if [[ "$CONFIRMATION_OVERRIDE" == "s" || "$CONFIRMATION_OVERRIDE" == "S" ]] @@ -83,10 +83,10 @@ if [[ "$CONFIRMATION" == "y" || "$CONFIRMATION" == "Y" ]] NETWORK="matic" fi - catapulta script script/$SCRIPT_NAME.s.sol --chain $NETWORK -s $CALLDATA --legacy --skip test --ffi --slow --skip-git + catapulta script script/$SCRIPT_NAME.s.sol --chain $NETWORK --sig $CALLDATA --legacy --skip test --ffi --slow --skip-git exit 0 else - forge script script/$SCRIPT_NAME.s.sol:$SCRIPT_NAME -s $CALLDATA --rpc-url $NETWORK -vv --legacy --skip test --ffi --slow --broadcast + forge script script/$SCRIPT_NAME.s.sol:$SCRIPT_NAME --sig $CALLDATA --rpc-url $NETWORK -vv --legacy --skip test --ffi --slow --broadcast fi else diff --git a/script/verifyStorageSlots.sh b/script/verifyStorageSlots.sh index 7e74f66..407cde5 100644 --- a/script/verifyStorageSlots.sh +++ b/script/verifyStorageSlots.sh @@ -7,6 +7,8 @@ # (It is normal for the numbers in end of type names to be different) source .env +set -e + if [[ $(colordiff --help 2>/dev/null) ]] then shopt -s expand_aliases @@ -65,10 +67,10 @@ if [[ $NETWORK == "" ]] exit 1 fi -if [[ $NETWORK == "mumbai" ]] - then - NETWORK="polygon-mumbai" -fi +# if [[ $NETWORK == "mumbai" ]] +# then +# NETWORK="polygon-mumbai" +# fi PROXY_ADDRESS=$(node script/helpers/readAddress.js $TARGET ${PROXY_NAME}) NEW_IMPLEMENTATION_ADDRESS=$(node script/helpers/readAddress.js $TARGET ${NEW_IMPL_NAME})