From ce79a8d38e872e8da37f45c5e47db6faf644fe4a Mon Sep 17 00:00:00 2001 From: 1marcghannam <1marc.ghannam@gmail.com> Date: Tue, 6 Feb 2024 11:23:19 -0500 Subject: [PATCH 1/6] feat: Deployment scripts and contract changes --- contracts/core/StakingPool.sol | 14 ++-- contracts/core/priorityPool/PriorityPool.sol | 12 +-- scripts/prod/deploy-imp-contracts-2.ts | 84 ++++++++++++++++++++ scripts/prod/upgrade-contracts-2.ts | 73 +++++++++++++++++ 4 files changed, 172 insertions(+), 11 deletions(-) create mode 100644 scripts/prod/deploy-imp-contracts-2.ts create mode 100644 scripts/prod/upgrade-contracts-2.ts diff --git a/contracts/core/StakingPool.sol b/contracts/core/StakingPool.sol index acfd47f9..4e0a7b1b 100644 --- a/contracts/core/StakingPool.sol +++ b/contracts/core/StakingPool.sol @@ -77,12 +77,14 @@ contract StakingPool is StakingRewardsPool { **/ function deposit(address _account, uint256 _amount) external onlyPriorityPool { require(strategies.length > 0, "Must be > 0 strategies to stake"); - - token.safeTransferFrom(msg.sender, address(this), _amount); - depositLiquidity(); - - _mint(_account, _amount); - totalStaked += _amount; + if (_amount > 0) { + token.safeTransferFrom(msg.sender, address(this), _amount); + depositLiquidity(); + _mint(_account, _amount); + totalStaked += _amount; + } else { + depositLiquidity(); + } } /** diff --git a/contracts/core/priorityPool/PriorityPool.sol b/contracts/core/priorityPool/PriorityPool.sol index c9f70ca8..e92559b0 100644 --- a/contracts/core/priorityPool/PriorityPool.sol +++ b/contracts/core/priorityPool/PriorityPool.sol @@ -61,7 +61,7 @@ contract PriorityPool is UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeabl ); event SetPoolStatus(PoolStatus status); event SetQueueDepositParams(uint128 queueDepositMin, uint128 queueDepositMax); - event DepositQueuedTokens(uint256 amount); + event DepositTokens(uint256 unusedTokensAmount, uint256 queuedTokensAmount); error InvalidValue(); error UnauthorizedToken(); @@ -558,12 +558,14 @@ contract PriorityPool is UUPSUpgradeable, OwnableUpgradeable, PausableUpgradeabl _depositMax - toDepositFromStakingPool ); - totalQueued = _totalQueued - toDepositFromQueue; - depositsSinceLastUpdate += toDepositFromQueue; - sharesSinceLastUpdate += stakingPool.getSharesByStake(toDepositFromQueue); stakingPool.deposit(address(this), toDepositFromQueue); - emit DepositQueuedTokens(toDepositFromQueue); + if (toDepositFromQueue != 0) { + totalQueued = _totalQueued - toDepositFromQueue; + depositsSinceLastUpdate += toDepositFromQueue; + sharesSinceLastUpdate += stakingPool.getSharesByStake(toDepositFromQueue); + } + emit DepositTokens(toDepositFromStakingPool, toDepositFromQueue); } /** diff --git a/scripts/prod/deploy-imp-contracts-2.ts b/scripts/prod/deploy-imp-contracts-2.ts new file mode 100644 index 00000000..743ff70a --- /dev/null +++ b/scripts/prod/deploy-imp-contracts-2.ts @@ -0,0 +1,84 @@ +import { ethers, upgrades, run } from 'hardhat' +import { getContract } from '../utils/deployment' +import { StakingPool, PriorityPool, CommunityVCS } from '../../typechain-types' + +async function main() { + const stakingPool = (await getContract('LINK_StakingPool')) as StakingPool + const priorityPool = (await getContract('LINK_PriorityPool')) as PriorityPool + const communityVCS = (await getContract('LINK_CommunityVCS')) as CommunityVCS + const communityVaultAutomationFactory = await ethers.getContractFactory( + 'CommunityVaultAutomation' + ) + + const communityVCSAddress = '0xAc12290b097f6893322F5430627e472131fBC1B5' + const minRewardsTotal = ethers.utils.parseUnits('650', 18) + const minRewardsPerVault = ethers.utils.parseUnits('65', 18) + + const communityVaultAutomation = await communityVaultAutomationFactory.deploy( + communityVCSAddress, + minRewardsTotal, + minRewardsPerVault + ) + await communityVaultAutomation.deployed() + await communityVaultAutomation.deployTransaction.wait(5) + console.log('CommunityVaultAutomation deployed at:', communityVaultAutomation.address) + await verifyContract(communityVaultAutomation.address, [ + communityVCSAddress, + minRewardsTotal, + minRewardsPerVault, + ]) + + const stakingPoolImp = (await upgrades.prepareUpgrade( + stakingPool.address, + await ethers.getContractFactory('StakingPool'), + { + kind: 'uups', + unsafeAllowRenames: false, + } + )) as string + console.log('StakingPool implementation deployed at: ', stakingPoolImp) + + await verifyContract(stakingPoolImp, []) + + const priorityPoolImp = (await upgrades.prepareUpgrade( + priorityPool.address, + await ethers.getContractFactory('PriorityPool'), + { + kind: 'uups', + unsafeAllowRenames: false, + } + )) as string + console.log('PriorityPool implementation deployed at: ', priorityPoolImp) + + await verifyContract(priorityPoolImp, []) + + const communityVCSImp = (await upgrades.prepareUpgrade( + communityVCS.address, + await ethers.getContractFactory('CommunityVCS'), + { + kind: 'uups', + unsafeAllowRenames: false, + } + )) as string + console.log('CommunityVCS implementation deployed at: ', communityVCSImp) + await verifyContract(communityVCSImp, []) +} + +async function verifyContract(contractAddress: string, constructorArguments: any[]) { + try { + await run('verify:verify', { + address: contractAddress, + constructorArguments: constructorArguments, + }) + console.log(`Contract verified: ${contractAddress}`) + } catch (error: any) { + console.error(`Verification failed for ${contractAddress}: ${error.message}`) + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/scripts/prod/upgrade-contracts-2.ts b/scripts/prod/upgrade-contracts-2.ts new file mode 100644 index 00000000..4922c741 --- /dev/null +++ b/scripts/prod/upgrade-contracts-2.ts @@ -0,0 +1,73 @@ +import { ethers } from 'hardhat' +import Safe, { EthersAdapter } from '@safe-global/protocol-kit' +import SafeApiKit from '@safe-global/api-kit' +import { MetaTransactionData } from '@safe-global/safe-core-sdk-types' +import { PriorityPool, StakingPool, CommunityVCS } from '../../typechain-types' +import { getContract } from '../utils/deployment' +import { getAccounts } from '../utils/helpers' + +const multisigAddress = '0xB351EC0FEaF4B99FdFD36b484d9EC90D0422493D' + +// New implementation addresses for the contracts +const priorityPoolNewImplementation = '0xYourNewPriorityPoolAddress' +const stakingPoolNewImplementation = '0xYourNewStakingPoolAddress' +const communityVCSNewImplementation = '0xYourNewCommunityVCSAddress' + +async function main() { + const { signers } = await getAccounts() + const ethAdapter = new EthersAdapter({ + ethers, + signerOrProvider: signers[0], + }) + const safeSdk = await Safe.create({ ethAdapter, safeAddress: multisigAddress }) + const safeService = new SafeApiKit({ + txServiceUrl: 'https://safe-transaction-mainnet.safe.global', + ethAdapter, + }) + + const priorityPool = (await getContract('PriorityPool')) as PriorityPool + const stakingPool = (await getContract('StakingPool')) as StakingPool + const communityVCS = (await getContract('CommunityVCS')) as CommunityVCS + + const safeTransactionData: MetaTransactionData[] = [ + { + to: priorityPool.address, + data: + (await priorityPool.populateTransaction.upgradeTo(priorityPoolNewImplementation)).data || + '', + value: '0', + }, + { + to: stakingPool.address, + data: + (await stakingPool.populateTransaction.upgradeTo(stakingPoolNewImplementation)).data || '', + value: '0', + }, + { + to: communityVCS.address, + data: + (await communityVCS.populateTransaction.upgradeTo(communityVCSNewImplementation)).data || + '', + value: '0', + }, + ] + + const safeTransaction = await safeSdk.createTransaction({ safeTransactionData }) + const safeTxHash = await safeSdk.getTransactionHash(safeTransaction) + const senderSignature = await safeSdk.signTransactionHash(safeTxHash) + + await safeService.proposeTransaction({ + safeAddress: multisigAddress, + safeTransactionData: safeTransaction.data, + safeTxHash, + senderAddress: signers[0].address, + senderSignature: senderSignature.data, + }) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) From 5ea16ef0b701e022df3b8448bb7c9e6d179b4df8 Mon Sep 17 00:00:00 2001 From: AnonJon Date: Wed, 14 Feb 2024 08:59:00 -0600 Subject: [PATCH 2/6] add script test --- scripts/input/1/config.json | 5 +- .../fork/scripts/Deployment.2.24.t.sol | 60 +++++++++++++++++++ test/foundry/utils/proxy/UUPSProxy.sol | 8 +++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 test/foundry/fork/scripts/Deployment.2.24.t.sol create mode 100644 test/foundry/utils/proxy/UUPSProxy.sol diff --git a/scripts/input/1/config.json b/scripts/input/1/config.json index f9142c01..3e42eb0a 100644 --- a/scripts/input/1/config.json +++ b/scripts/input/1/config.json @@ -1,4 +1,7 @@ { "CommunityVCS": "0xAc12290b097f6893322F5430627e472131fBC1B5", - "MerkleDistributor": "0xe7Dd77d408920c000C40C35c4c111318Ba8B4767" + "MerkleDistributor": "0xe7Dd77d408920c000C40C35c4c111318Ba8B4767", + "PriorityPool": "0xDdC796a66E8b83d0BcCD97dF33A6CcFBA8fd60eA", + "StakingPool": "0xb8b295df2cd735b15BE5Eb419517Aa626fc43cD5", + "Multisig": "0xB351EC0FEaF4B99FdFD36b484d9EC90D0422493D" } diff --git a/test/foundry/fork/scripts/Deployment.2.24.t.sol b/test/foundry/fork/scripts/Deployment.2.24.t.sol new file mode 100644 index 00000000..c7ce6f4a --- /dev/null +++ b/test/foundry/fork/scripts/Deployment.2.24.t.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.15; +import {StakingPool} from "../../../../contracts/core/StakingPool.sol"; +import {PriorityPool} from "../../../../contracts/core/priorityPool/PriorityPool.sol"; +import {CommunityVCS} from "../../../../contracts/linkStaking/CommunityVCS.sol"; +import {CommunityVaultAutomation} from "../../../../contracts/linkStaking/CommunityVaultAutomation.sol"; +import {BaseTest} from "../../Base.t.sol"; + +contract Deployment is BaseTest { + bool internal _fork = true; + StakingPool internal stakingPool; + PriorityPool internal priorityPool; + CommunityVCS internal communityVCS; + CommunityVaultAutomation internal communityVaultAutomation; + uint256 internal minRewardsTotal = 650 ether; + uint256 internal minRewardsPerVault = 65 ether; + address internal multisig; + + function setUp() public { + BaseTest.init(_fork); + communityVCS = CommunityVCS(getValue("CommunityVCS")); + stakingPool = StakingPool(getValue("StakingPool")); + priorityPool = PriorityPool(getValue("PriorityPool")); + multisig = getValue("Multisig"); + vm.startPrank(multisig); + communityVaultAutomation = new CommunityVaultAutomation(address(communityVCS), minRewardsTotal, minRewardsPerVault); + + // upgrade CommunityVCS + CommunityVCS impl = new CommunityVCS(); + communityVCS.upgradeTo(address(impl)); + + // upgrade StakingPool + StakingPool stakingPoolImpl = new StakingPool(); + stakingPool.upgradeTo(address(stakingPoolImpl)); + + // upgrade PriorityPool + PriorityPool priorityPoolImpl = new PriorityPool(); + priorityPool.upgradeTo(address(priorityPoolImpl)); + vm.stopPrank(); + } + + function testDeployment_upgrade_successful() public { + assertEq(address(communityVCS), address(getValue("CommunityVCS"))); + assertEq(address(stakingPool), getValue("StakingPool")); + assertEq(address(priorityPool), getValue("PriorityPool")); + } + + function testDeployment_CommunityVaultAutomation_success() public { + assertEq(communityVaultAutomation.minRewardsTotal(), minRewardsTotal); + assertEq(communityVaultAutomation.minRewardsPerVault(), minRewardsPerVault); + } + + function testDeployment_StakingPool_owner() public { + assertEq(stakingPool.priorityPool(), address(priorityPool)); + } + + function testDeployment_PriorityPool_owner() public { + assertEq(address(priorityPool.stakingPool()), address(stakingPool)); + } +} diff --git a/test/foundry/utils/proxy/UUPSProxy.sol b/test/foundry/utils/proxy/UUPSProxy.sol new file mode 100644 index 00000000..087d654e --- /dev/null +++ b/test/foundry/utils/proxy/UUPSProxy.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.15; + +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +contract UUPSProxy is ERC1967Proxy { + constructor(address _implementation, bytes memory _data) ERC1967Proxy(_implementation, _data) {} +} From d1a6dc5ab34150a7d34bea4d11b2e92a278bd5df Mon Sep 17 00:00:00 2001 From: AnonJon Date: Wed, 14 Feb 2024 09:11:23 -0600 Subject: [PATCH 3/6] update test names --- test/foundry/fork/scripts/Deployment.2.24.t.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/foundry/fork/scripts/Deployment.2.24.t.sol b/test/foundry/fork/scripts/Deployment.2.24.t.sol index c7ce6f4a..a5dae8b4 100644 --- a/test/foundry/fork/scripts/Deployment.2.24.t.sol +++ b/test/foundry/fork/scripts/Deployment.2.24.t.sol @@ -39,22 +39,22 @@ contract Deployment is BaseTest { vm.stopPrank(); } - function testDeployment_upgrade_successful() public { + function testFork_upgrade_successful() public { assertEq(address(communityVCS), address(getValue("CommunityVCS"))); assertEq(address(stakingPool), getValue("StakingPool")); assertEq(address(priorityPool), getValue("PriorityPool")); } - function testDeployment_CommunityVaultAutomation_success() public { + function testFork_CommunityVaultAutomation_success() public { assertEq(communityVaultAutomation.minRewardsTotal(), minRewardsTotal); assertEq(communityVaultAutomation.minRewardsPerVault(), minRewardsPerVault); } - function testDeployment_StakingPool_owner() public { + function testFork_StakingPool_owner() public { assertEq(stakingPool.priorityPool(), address(priorityPool)); } - function testDeployment_PriorityPool_owner() public { + function testFork_PriorityPool_owner() public { assertEq(address(priorityPool.stakingPool()), address(stakingPool)); } } From 2c7f17ca86216756cdb193c2eeeda758b9939e07 Mon Sep 17 00:00:00 2001 From: AnonJon Date: Wed, 14 Feb 2024 09:27:19 -0600 Subject: [PATCH 4/6] update workflow --- .github/workflows/continuous-integration.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index adc4a1d7..704cbc18 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -41,6 +41,8 @@ jobs: run: yarn compile - name: Run tests + env: + ETHEREUM_RPC_URL: ${{ secrets.ETHEREUM_RPC_URL }} run: | yarn test forge test --no-match-test testFork -vvv From e198be04332fefd47e1c61a2057ef9616994d968 Mon Sep 17 00:00:00 2001 From: AnonJon Date: Wed, 14 Feb 2024 09:33:55 -0600 Subject: [PATCH 5/6] update workflow --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 704cbc18..07f5654c 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -45,4 +45,4 @@ jobs: ETHEREUM_RPC_URL: ${{ secrets.ETHEREUM_RPC_URL }} run: | yarn test - forge test --no-match-test testFork -vvv + forge test --no-match-test testFork -vvv --ffi From 28ac6b0c2102815d845d41d027e36f1b211bbb35 Mon Sep 17 00:00:00 2001 From: 1marcghannam <1marc.ghannam@gmail.com> Date: Wed, 21 Feb 2024 11:02:45 -0500 Subject: [PATCH 6/6] feat: Remove community vault automation --- scripts/prod/deploy-imp-contracts-2.ts | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/scripts/prod/deploy-imp-contracts-2.ts b/scripts/prod/deploy-imp-contracts-2.ts index 743ff70a..a3d58f8a 100644 --- a/scripts/prod/deploy-imp-contracts-2.ts +++ b/scripts/prod/deploy-imp-contracts-2.ts @@ -6,27 +6,6 @@ async function main() { const stakingPool = (await getContract('LINK_StakingPool')) as StakingPool const priorityPool = (await getContract('LINK_PriorityPool')) as PriorityPool const communityVCS = (await getContract('LINK_CommunityVCS')) as CommunityVCS - const communityVaultAutomationFactory = await ethers.getContractFactory( - 'CommunityVaultAutomation' - ) - - const communityVCSAddress = '0xAc12290b097f6893322F5430627e472131fBC1B5' - const minRewardsTotal = ethers.utils.parseUnits('650', 18) - const minRewardsPerVault = ethers.utils.parseUnits('65', 18) - - const communityVaultAutomation = await communityVaultAutomationFactory.deploy( - communityVCSAddress, - minRewardsTotal, - minRewardsPerVault - ) - await communityVaultAutomation.deployed() - await communityVaultAutomation.deployTransaction.wait(5) - console.log('CommunityVaultAutomation deployed at:', communityVaultAutomation.address) - await verifyContract(communityVaultAutomation.address, [ - communityVCSAddress, - minRewardsTotal, - minRewardsPerVault, - ]) const stakingPoolImp = (await upgrades.prepareUpgrade( stakingPool.address,