From f9979cefee6ded8f5b923f26b733eeee531a6bc6 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Mon, 19 Aug 2024 19:43:49 -0400 Subject: [PATCH 01/69] unit test with mocks --- .../contracts-0.8/common/EpochManager.sol | 15 ++++ .../test/MockCeloUnreleasedTreasure.sol | 15 ++++ .../unit/common/CeloUnreleasedTreasure.t.sol | 25 ++++++ .../test-sol/unit/common/EpochManager.t.sol | 81 +++++++++++++++++-- 4 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index e4ddeb11a3c..b995e706924 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -235,6 +235,21 @@ contract EpochManager is return currentEpochNumber; } +/// returns epoch processing state + function getEpochProcessingState() + external + view + returns (uint256, uint256, uint256, uint256, uint256) + { + return ( + uint256(epochProcessing.status), + epochProcessing.perValidatorReward, + epochProcessing.totalRewardsVoter, + epochProcessing.totalRewardsCommunity, + epochProcessing.totalRewardsCarbonFund + ); + } + function getElected() external view returns (address[] memory) { return elected; } diff --git a/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol b/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol new file mode 100644 index 00000000000..01918041585 --- /dev/null +++ b/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol @@ -0,0 +1,15 @@ +pragma solidity >=0.8.0 <0.9.0; +// solhint-disable no-unused-vars + +import "../../../contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; + +import "forge-std-8/console2.sol"; + +/** + * @title A mock CeloDistributionSchedule for testing. + */ +contract MockCeloUnreleasedTreasure is ICeloUnreleasedTreasure { + function release(address to, uint256 amount) external { + console2.log("Released"); + } +} diff --git a/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol b/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol index 35e69e93c6f..a471de4f894 100644 --- a/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol +++ b/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol @@ -25,6 +25,7 @@ contract CeloUnreleasedTreasureTest is Test, TestConstants, IsL2Check { address owner = address(this); address celoTokenAddress = actor("celoTokenAddress"); + address epochManagerAddress = actor("epochManagerAddress"); address celoDistributionOwner = actor("celoDistributionOwner"); address communityRewardFund = actor("communityRewardFund"); @@ -82,6 +83,7 @@ contract CeloUnreleasedTreasureTest is Test, TestConstants, IsL2Check { registry.setAddressFor("CeloToken", address(celoToken)); registry.setAddressFor("Governance", address(governance)); + registry.setAddressFor("EpochManager", address(epochManagerAddress)); vm.deal(address(0), CELO_SUPPLY_CAP); assertEq(celoToken.totalSupply(), 0, "starting total supply not zero."); @@ -144,3 +146,26 @@ contract CeloUnreleasedTreasureTest_initialize is CeloUnreleasedTreasureTest { payableAddress.transfer(1 ether); } } + +contract CeloUnreleasedTreasureTest_release is CeloUnreleasedTreasureTest { + function setUp() public override { + super.setUp(); + newCeloUnreleasedTreasure(); + } + + function test_ShouldTrasferToRecepientAddress() public { + uint256 _balanceBefore = randomAddress.balance; + vm.prank(epochManagerAddress); + + celoUnreleasedTreasure.release(randomAddress, 4); + uint256 _balanceAfter = randomAddress.balance; + assertGt(_balanceAfter, _balanceBefore); + } + + function test_Reverts_WhenCalledByOtherThanEpochManager() public { + vm.prank(randomAddress); + + vm.expectRevert("Only the EpochManager contract can call this function."); + celoUnreleasedTreasure.release(randomAddress, 4); + } +} diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index d7078dd1000..a829d46a8cf 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -18,6 +18,7 @@ import "@celo-contracts/common/interfaces/IRegistry.sol"; import { EpochRewardsMock08 } from "@celo-contracts-8/governance/test/EpochRewardsMock.sol"; import { ValidatorsMock08 } from "@celo-contracts-8/governance/test/ValidatorsMock.sol"; +import { MockCeloUnreleasedTreasure } from "@celo-contracts-8/common/test/MockCeloUnreleasedTreasure.sol"; contract EpochManagerTest is Test, TestConstants, Utils08 { EpochManager epochManager; @@ -33,11 +34,12 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { uint256 firstEpochNumber = 100; uint256 firstEpochBlock = 100; + uint256 epochDuration = DAY; address[] firstElected; IRegistry registry; ICeloToken celoToken; - CeloUnreleasedTreasure celoUnreleasedTreasure; + MockCeloUnreleasedTreasure celoUnreleasedTreasure; ScoreManager scoreManager; uint256 celoAmountForRate = 1e24; @@ -62,13 +64,14 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { epochRewards = new EpochRewardsMock08(); validators = new ValidatorsMock08(); stableToken = new MockStableToken08(); - celoUnreleasedTreasure = new CeloUnreleasedTreasure(false); + celoUnreleasedTreasure = new MockCeloUnreleasedTreasure(); firstElected.push(actor("validator1")); firstElected.push(actor("validator2")); address celoTokenAddress = actor("celoTokenAddress"); address scoreManagerAddress = actor("scoreManagerAddress"); + address celoUnreleasedTreasureAddress = actor("celoUnreleasedTreasureAddress"); address reserveAddress = actor("reserve"); epochManagerInitializer = actor("initializer"); @@ -100,10 +103,13 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { (uint256 res0, uint256 res00) = sortedOracles.medianRate(address(stableToken)); scoreManager.setValidatorScore(actor("validator1"), 1); - uint256 res = scoreManager.getValidatorScore(actor("validator1")); - uint256 res2 = epochRewards.getCommunityRewardFraction(); - epochManager.initialize(REGISTRY_ADDRESS, 10, carbonOffsettingPartner, epochManagerInitializer); + epochManager.initialize( + REGISTRY_ADDRESS, + epochDuration, + carbonOffsettingPartner, + epochManagerInitializer + ); blockTravel(vm, firstEpochBlock); } @@ -112,8 +118,9 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { contract EpochManagerTest_initialize is EpochManagerTest { function test_initialize() public virtual { assertEq(address(epochManager.registry()), REGISTRY_ADDRESS); - assertEq(epochManager.epochDuration(), 10); + assertEq(epochManager.epochDuration(), epochDuration); assertEq(epochManager.carbonOffsettingPartner(), carbonOffsettingPartner); + assertEq(epochManager.epochManagerInitializer(), epochManagerInitializer); } function test_Reverts_WhenAlreadyInitialized() public virtual { @@ -126,6 +133,21 @@ contract EpochManagerTest_initializeSystem is EpochManagerTest { function test_processCanBeStarted() public virtual { vm.prank(epochManagerInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + ( + uint256 _firstEpochBlock, + uint256 _lastEpochBlock, + uint256 _startTimestamp, + uint256 _currentEpochEndTimestamp, + uint256 _currentRewardsBlock + ) = epochManager.getCurrentEpoch(); + assertEq(epochManager.epochManagerInitializer(), address(0)); + assertEq(epochManager.firstKnownEpoch(), firstEpochNumber); + assertEq(_firstEpochBlock, firstEpochBlock); + assertEq(_lastEpochBlock, 0); + assertEq(_startTimestamp, block.timestamp); + assertEq(_currentEpochEndTimestamp, 0); + assertEq(_currentRewardsBlock, 0); + assertEq(epochManager.getElected(), firstElected); } function test_Reverts_processCannotBeStartedAgain() public virtual { @@ -161,4 +183,51 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { vm.expectRevert("Epoch is not ready to start"); epochManager.startNextEpochProcess(); } + + function test_Reverts_WhenEpochProcessingAlreadyStarted() public { + vm.prank(epochManagerInitializer); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + + blockTravel(vm, 43200); + timeTravel(vm, DAY); + + epochManager.startNextEpochProcess(); + vm.expectRevert("Epoch process is already started"); + epochManager.startNextEpochProcess(); + } + + function test_SetsTheEpochRewardBlockAndRewardAmounts() public { + vm.prank(epochManagerInitializer); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + + blockTravel(vm, 43200); + timeTravel(vm, DAY); + + epochManager.startNextEpochProcess(); + (, , , uint256 _currentEpochEndTimestamp, uint256 _currentRewardsBlock) = epochManager + .getCurrentEpoch(); + assertEq(_currentRewardsBlock, block.number); + } + + function test_SetsTheEpochRewardBlock() public { + vm.prank(epochManagerInitializer); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + + blockTravel(vm, 43200); + timeTravel(vm, DAY); + + epochManager.startNextEpochProcess(); + ( + uint256 status, + uint256 perValidatorReward, + uint256 totalRewardsVoter, + uint256 totalRewardsCommunity, + uint256 totalRewardsCarbonFund + ) = epochManager.getEpochProcessingState(); + assertEq(status, 1); + assertEq(perValidatorReward, 5); + assertEq(totalRewardsVoter, 5); + assertEq(totalRewardsCommunity, 5); + assertEq(totalRewardsCarbonFund, 5); + } } From 75bf9388c0eb6f1c7d27bdab0b2dde689991bc53 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Mon, 19 Aug 2024 20:01:44 -0400 Subject: [PATCH 02/69] ++ integration tests --- .../common/CeloUnreleasedTreasure.sol | 1 - .../governance/test/EpochRewardsMock.sol | 9 +- .../governance/test/MockElection.sol | 89 +++++++ .../stability/test/MockReserve.sol | 49 ++++ .../integration/EpochManagerIntegration.sol | 247 ++++++++++++++++++ .../test-sol/unit/common/EpochManager.t.sol | 5 +- 6 files changed, 390 insertions(+), 10 deletions(-) create mode 100644 packages/protocol/contracts-0.8/governance/test/MockElection.sol create mode 100644 packages/protocol/contracts-0.8/stability/test/MockReserve.sol create mode 100644 packages/protocol/test-sol/integration/EpochManagerIntegration.sol diff --git a/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol b/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol index 1e17e37d517..2acde5c26c1 100644 --- a/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol +++ b/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol @@ -8,7 +8,6 @@ import "./UsingRegistry.sol"; import "../common/IsL2Check.sol"; import "../../contracts/common/Initializable.sol"; -import "../../contracts/common/interfaces/ICeloToken.sol"; import "./interfaces/ICeloUnreleasedTreasureInitializer.sol"; import "@openzeppelin/contracts8/token/ERC20/IERC20.sol"; diff --git a/packages/protocol/contracts-0.8/governance/test/EpochRewardsMock.sol b/packages/protocol/contracts-0.8/governance/test/EpochRewardsMock.sol index 528d36d3f88..3b718164112 100644 --- a/packages/protocol/contracts-0.8/governance/test/EpochRewardsMock.sol +++ b/packages/protocol/contracts-0.8/governance/test/EpochRewardsMock.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.7 <0.8.20; import "../../../contracts/governance/interfaces/IEpochRewards.sol"; -// import "forge-std-8/console2.sol"; + /** * @title A wrapper around EpochRewards that exposes internal functions for testing. */ @@ -21,9 +21,7 @@ contract EpochRewardsMock08 is IEpochRewards { } // TODO: (soloseng) implement mock - function updateTargetVotingYield() external { - // console2.log("### Updating Target Voting Yield"); - } + function updateTargetVotingYield() external {} // mocks the precompile function numberValidatorsInCurrentSet() public view returns (uint256) { @@ -38,8 +36,7 @@ contract EpochRewardsMock08 is IEpochRewards { view returns (uint256, uint256, uint256, uint256) { - // console2.log("### calculating Target Epoch Rewards"); - return (1, 1, 1, 1); + return (5, 5, 5, 5); } function getTargetVotingYieldParameters() external view returns (uint256, uint256, uint256) { return (0, 0, 0); diff --git a/packages/protocol/contracts-0.8/governance/test/MockElection.sol b/packages/protocol/contracts-0.8/governance/test/MockElection.sol new file mode 100644 index 00000000000..4e0379a4b68 --- /dev/null +++ b/packages/protocol/contracts-0.8/governance/test/MockElection.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.7 <0.8.20; + +import "../../../contracts-0.8/common/IsL2Check.sol"; + + + +/** + * @title Holds a list of addresses of validators + */ +contract MockElection08 is IsL2Check { + mapping(address => bool) public isIneligible; + mapping(address => bool) public isEligible; + mapping(address => bool) public allowedToVoteOverMaxNumberOfGroups; + address[] public electedValidators; + uint256 active; + uint256 total; + + function markGroupIneligible(address account) external { + isIneligible[account] = true; + } + + function markGroupEligible(address account, address, address) external onlyL1 { + isEligible[account] = true; + } + + function setActiveVotes(uint256 value) external { + active = value; + } + + function setTotalVotes(uint256 value) external { + total = value; + } + + function setElectedValidators(address[] calldata _electedValidators) external { + electedValidators = _electedValidators; + } + + function vote(address, uint256, address, address) external onlyL1 returns (bool) { + return true; + } + + function activate(address) external onlyL1 returns (bool) { + return true; + } + + function revokeAllActive(address, address, address, uint256) external returns (bool) { + return true; + } + + function revokeActive(address, uint256, address, address, uint256) external returns (bool) { + return true; + } + + function revokePending(address, uint256, address, address, uint256) external returns (bool) { + return true; + } + + function forceDecrementVotes( + address, + uint256 value, + address[] calldata, + address[] calldata, + uint256[] calldata + ) external returns (uint256) { + this.setActiveVotes(this.getActiveVotes() - value); + return value; + } + + function getTotalVotes() external view returns (uint256) { + return total; + } + + function getActiveVotes() external view returns (uint256) { + return active; + } + + function getTotalVotesByAccount(address) external view returns (uint256) { + return 0; + } + + function electValidatorSigners() external view returns (address[] memory) { + return electedValidators; + } + + function setAllowedToVoteOverMaxNumberOfGroups(address account, bool flag) public onlyL1 { + allowedToVoteOverMaxNumberOfGroups[account] = flag; + } +} diff --git a/packages/protocol/contracts-0.8/stability/test/MockReserve.sol b/packages/protocol/contracts-0.8/stability/test/MockReserve.sol new file mode 100644 index 00000000000..09b64ab4385 --- /dev/null +++ b/packages/protocol/contracts-0.8/stability/test/MockReserve.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.7 <0.8.20; + +// solhint-disable no-unused-vars + +import "@openzeppelin/contracts8/token/ERC20/IERC20.sol"; + +/** + * @title A mock Reserve for testing. + */ +contract MockReserve08 { + mapping(address => bool) public tokens; + + IERC20 public goldToken; + + // solhint-disable-next-line no-empty-blocks + receive() external payable {} + + function setGoldToken(address goldTokenAddress) external { + goldToken = IERC20(goldTokenAddress); + } + + function transferGold(address to, uint256 value) external returns (bool) { + require(goldToken.transfer(to, value), "gold token transfer failed"); + return true; + } + + function transferExchangeGold(address to, uint256 value) external returns (bool) { + require(goldToken.transfer(to, value), "gold token transfer failed"); + return true; + } + + function addToken(address token) external returns (bool) { + tokens[token] = true; + return true; + } + + function getUnfrozenReserveGoldBalance() external view returns (uint256) { + return address(this).balance; + } + + function burnToken(address) external pure returns (bool) { + return true; + } + + function getReserveGoldBalance() public view returns (uint256) { + return address(this).balance; + } +} diff --git a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol new file mode 100644 index 00000000000..cf6180fac38 --- /dev/null +++ b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.7 <0.8.20; + +import "celo-foundry-8/Test.sol"; +import "@celo-contracts-8/common/EpochManager.sol"; + +// import "@celo-contracts-8/common/interfaces/ICeloToken.sol"; +import "@celo-contracts-8/common/ScoreManager.sol"; +import "@celo-contracts-8/common/CeloUnreleasedTreasure.sol"; +import "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; + +import { TestConstants } from "@test-sol/constants.sol"; +import { Utils08 } from "@test-sol/utils08.sol"; + +import "@celo-contracts/stability/test/MockSortedOracles.sol"; + +import "@celo-contracts/common/interfaces/IRegistry.sol"; +import "@celo-contracts/common/interfaces/IFreezer.sol"; +import "@celo-contracts/governance/interfaces/IEpochRewards.sol"; +import "@celo-contracts/governance/interfaces/IEpochRewardsInitializer.sol"; + +import { ValidatorsMock08 } from "@celo-contracts-8/governance/test/ValidatorsMock.sol"; +import { MockElection08 } from "@celo-contracts-8/governance/test/MockElection.sol"; +import { MockReserve08 } from "@celo-contracts-8/stability/test/MockReserve.sol"; +import { MockStableToken08 } from "@celo-contracts-8/stability/test/MockStableToken.sol"; + +contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { + EpochManager epochManager; + MockSortedOracles sortedOracles; + + MockStableToken08 stableToken; + MockReserve08 reserve; + + ValidatorsMock08 validators; + MockElection08 election; + + address epochManagerInitializer; + address carbonOffsettingPartner; + address communityRewardFund; + + uint256 firstEpochNumber = 100; + uint256 firstEpochBlock = 100; + address[] firstElected; + + IRegistry registry; + IERC20 celoToken; + IEpochRewards epochRewards; + IEpochRewardsInitializer epochRewardsInitializer; + IFreezer freezer; + CeloUnreleasedTreasure celoUnreleasedTreasure; + ScoreManager scoreManager; + + uint256 celoAmountForRate = 1e24; + uint256 stableAmountForRate = 2 * celoAmountForRate; + + uint256 constant L1_MINTED_CELO_SUPPLY = 692702432463315819704447326; // as of May 15 2024 + + uint256 constant CELO_SUPPLY_CAP = 1000000000 ether; // 1 billion Celo + uint256 constant GENESIS_CELO_SUPPLY = 600000000 ether; // 600 million Celo + + uint256 constant FIFTEEN_YEAR_LINEAR_REWARD = (CELO_SUPPLY_CAP - GENESIS_CELO_SUPPLY) / 2; // 200 million Celo + + uint256 constant FIFTEEN_YEAR_CELO_SUPPLY = GENESIS_CELO_SUPPLY + FIFTEEN_YEAR_LINEAR_REWARD; // 800 million Celo (includes GENESIS_CELO_SUPPLY) + + uint256 constant MAX_L2_DISTRIBUTION = FIFTEEN_YEAR_CELO_SUPPLY - L1_MINTED_CELO_SUPPLY; // 107.2 million Celo + + uint256 constant L2_INITIAL_STASH_BALANCE = FIFTEEN_YEAR_LINEAR_REWARD + MAX_L2_DISTRIBUTION; // leftover from L1 target supply plus the 2nd 15 year term. + + uint256 constant targetVotingYieldParamsInitial = 0.00016e24; // 0.00016 + uint256 constant targetVotingYieldParamsMax = 0.0005e24; // 0.0005 + uint256 constant targetVotingYieldParamsAdjustmentFactor = 1127990000000000000; // 0.00000112799 + + uint256 constant rewardsMultiplierMax = 2 * FIXED1; // 2 + uint256 constant rewardsMultiplierAdjustmentsUnderspend = 0.5e24; // 0.5 + uint256 constant rewardsMultiplierAdjustmentsOverspend = 5e24; // 5 + + uint256 constant targetVotingGoldFraction = (2 * FIXED1) / uint256(3); + uint256 constant targetValidatorEpochPayment = 1e13; + uint256 constant communityRewardFraction = FIXED1 / 4; + uint256 constant carbonOffsettingFraction = FIXED1 / 200; + + function setUp() public virtual { + epochManager = new EpochManager(true); + sortedOracles = new MockSortedOracles(); + // epochRewards = new EpochRewardsMock08(); + election = new MockElection08(); + validators = new ValidatorsMock08(); + reserve = new MockReserve08(); + stableToken = new MockStableToken08(); + // stableToken = new MockCeloToken(); + + celoUnreleasedTreasure = new CeloUnreleasedTreasure(false); + + firstElected.push(actor("validator1")); + firstElected.push(actor("validator2")); + + address celoTokenAddress = actor("celoTokenAddress"); + address scoreManagerAddress = actor("scoreManagerAddress"); + address epochRewardsAddress = actor("epochRewardsAddress"); + address freezerAddress = actor("freezerAddress"); + // address reserveAddress = actor("reserve"); + + epochManagerInitializer = actor("initializer"); + carbonOffsettingPartner = actor("carbonOffsettingPartner"); + communityRewardFund = actor("communityRewardFund"); + + deployCodeTo("Registry.sol", abi.encode(false), REGISTRY_ADDRESS); + deployCodeTo("GoldToken.sol", abi.encode(false), celoTokenAddress); + deployCodeTo("ScoreManager.sol", abi.encode(false), scoreManagerAddress); + deployCodeTo("Freezer.sol", abi.encode(false), freezerAddress); + deployCodeTo("EpochRewards.sol", abi.encode(true), epochRewardsAddress); + + registry = IRegistry(REGISTRY_ADDRESS); + celoToken = IERC20(celoTokenAddress); + epochRewardsInitializer = IEpochRewardsInitializer(epochRewardsAddress); + epochRewards = IEpochRewards(epochRewardsAddress); + freezer = IFreezer(freezerAddress); + scoreManager = ScoreManager(scoreManagerAddress); + + registry.setAddressFor(EpochManagerContract, address(epochManager)); + registry.setAddressFor(SortedOraclesContract, address(sortedOracles)); + registry.setAddressFor(GovernanceContract, communityRewardFund); + registry.setAddressFor(EpochRewardsContract, address(epochRewards)); + registry.setAddressFor(ValidatorsContract, address(validators)); + registry.setAddressFor(ScoreManagerContract, address(scoreManager)); + registry.setAddressFor(StableTokenContract, address(stableToken)); + registry.setAddressFor(CeloUnreleasedTreasureContract, address(celoUnreleasedTreasure)); + registry.setAddressFor(CeloTokenContract, address(celoToken)); + registry.setAddressFor(ReserveContract, address(reserve)); + + registry.setAddressFor(ElectionContract, address(election)); + // registry.setAddressFor(SortedOraclesContract, address(mockSortedOracles)); + // registry.setAddressFor(StableTokenContract, address(mockStableToken)); + // registry.setAddressFor(CeloTokenContract, address(mockGoldToken)); + registry.setAddressFor(FreezerContract, address(freezer)); + + vm.deal(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); + vm.deal(address(reserve), L1_MINTED_CELO_SUPPLY); + vm.deal(address(reserve), L1_MINTED_CELO_SUPPLY); + + bool res1 = sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); + (uint256 res0, uint256 res00) = sortedOracles.medianRate(address(stableToken)); + + scoreManager.setValidatorScore(actor("validator1"), 1); + uint256 res = scoreManager.getValidatorScore(actor("validator1")); + uint256 res2 = epochRewards.getCommunityRewardFraction(); + + console2.log("### res2", res2); + + epochRewardsInitializer.initialize( + address(registry), + targetVotingYieldParamsInitial, + targetVotingYieldParamsMax, + targetVotingYieldParamsAdjustmentFactor, + rewardsMultiplierMax, + rewardsMultiplierAdjustmentsUnderspend, + rewardsMultiplierAdjustmentsOverspend, + targetVotingGoldFraction, + targetValidatorEpochPayment, + communityRewardFraction, + address(0), + carbonOffsettingFraction + ); + + epochManager.initialize( + REGISTRY_ADDRESS, + DAY, + carbonOffsettingPartner, + epochManagerInitializer + ); + + blockTravel(vm, firstEpochBlock); + + // epochManager. + } +} + +contract EpochManagerIntegrationTest_initialize is EpochManagerIntegrationTest { + function test_initialize() public virtual { + assertEq(address(epochManager.registry()), REGISTRY_ADDRESS); + assertEq(epochManager.epochDuration(), DAY); + assertEq(epochManager.carbonOffsettingPartner(), carbonOffsettingPartner); + } + + function test_Reverts_WhenAlreadyInitialized() public virtual { + vm.expectRevert("contract already initialized"); + epochManager.initialize( + REGISTRY_ADDRESS, + DAY, + carbonOffsettingPartner, + epochManagerInitializer + ); + } +} + +contract EpochManagerIntegrationTest_initializeSystem is EpochManagerIntegrationTest { + function test_processCanBeStarted() public virtual { + vm.prank(epochManagerInitializer); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + } + + function test_Reverts_processCannotBeStartedAgain() public virtual { + vm.prank(epochManagerInitializer); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + vm.prank(address(0)); + vm.expectRevert("Epoch system already initialized"); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + } + + function test_Reverts_WhenSystemInitializedByOtherContract() public virtual { + vm.expectRevert("msg.sender is not Initializer"); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + } +} + +contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegrationTest { + function test_Reverts_whenSystemNotInitialized() public { + vm.expectRevert("Epoch system not initialized"); + epochManager.startNextEpochProcess(); + } + + function test_Reverts_WhenEndOfEpochHasNotBeenReached() public { + vm.prank(epochManagerInitializer); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + + vm.expectRevert("Epoch is not ready to start"); + epochManager.startNextEpochProcess(); + } + + function test_Succeeds() public { + vm.prank(epochManagerInitializer); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + + blockTravel(vm, 43200); + timeTravel(vm, DAY); + console2.log("current epoch timestamp", block.timestamp); + + uint256 _currentEpoch = epochManager.currentEpochNumber(); + console2.log("### Current epoch duration:", epochManager.epochDuration()); + (, , , uint256 _currentEpochEndTimestamp, uint256 _currentRewardsBlock) = epochManager + .getCurrentEpoch(); + + epochManager.startNextEpochProcess(); + console2.log("### Done"); + assertEq(_currentRewardsBlock, block.number - 1); + } +} diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index a829d46a8cf..7b25175e4a5 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -71,7 +71,6 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { address celoTokenAddress = actor("celoTokenAddress"); address scoreManagerAddress = actor("scoreManagerAddress"); - address celoUnreleasedTreasureAddress = actor("celoUnreleasedTreasureAddress"); address reserveAddress = actor("reserve"); epochManagerInitializer = actor("initializer"); @@ -196,7 +195,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { epochManager.startNextEpochProcess(); } - function test_SetsTheEpochRewardBlockAndRewardAmounts() public { + function test_SetsTheEpochRewardBlock() public { vm.prank(epochManagerInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); @@ -209,7 +208,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { assertEq(_currentRewardsBlock, block.number); } - function test_SetsTheEpochRewardBlock() public { + function test_SetsTheEpochRewardAmounts() public { vm.prank(epochManagerInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); From cb47ec938ee8f7012f30dbdee59cb1fd69ca63c4 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Mon, 19 Aug 2024 20:08:41 -0400 Subject: [PATCH 03/69] clean up --- .../test-sol/integration/EpochManagerIntegration.sol | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol index cf6180fac38..fa7c09d8aa3 100644 --- a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol +++ b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol @@ -82,12 +82,11 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { function setUp() public virtual { epochManager = new EpochManager(true); sortedOracles = new MockSortedOracles(); - // epochRewards = new EpochRewardsMock08(); + election = new MockElection08(); validators = new ValidatorsMock08(); reserve = new MockReserve08(); stableToken = new MockStableToken08(); - // stableToken = new MockCeloToken(); celoUnreleasedTreasure = new CeloUnreleasedTreasure(false); @@ -98,7 +97,6 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { address scoreManagerAddress = actor("scoreManagerAddress"); address epochRewardsAddress = actor("epochRewardsAddress"); address freezerAddress = actor("freezerAddress"); - // address reserveAddress = actor("reserve"); epochManagerInitializer = actor("initializer"); carbonOffsettingPartner = actor("carbonOffsettingPartner"); @@ -129,9 +127,6 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { registry.setAddressFor(ReserveContract, address(reserve)); registry.setAddressFor(ElectionContract, address(election)); - // registry.setAddressFor(SortedOraclesContract, address(mockSortedOracles)); - // registry.setAddressFor(StableTokenContract, address(mockStableToken)); - // registry.setAddressFor(CeloTokenContract, address(mockGoldToken)); registry.setAddressFor(FreezerContract, address(freezer)); vm.deal(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); @@ -171,7 +166,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { blockTravel(vm, firstEpochBlock); - // epochManager. + } } From b8f55844c689cb7b5e2ac2e6ac01cc233bf33894 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 20 Aug 2024 10:34:06 -0400 Subject: [PATCH 04/69] -- logging --- .../common/test/MockCeloUnreleasedTreasure.sol | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol b/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol index 01918041585..3fb25ac173b 100644 --- a/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol +++ b/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol @@ -3,13 +3,9 @@ pragma solidity >=0.8.0 <0.9.0; import "../../../contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; -import "forge-std-8/console2.sol"; - /** * @title A mock CeloDistributionSchedule for testing. */ contract MockCeloUnreleasedTreasure is ICeloUnreleasedTreasure { - function release(address to, uint256 amount) external { - console2.log("Released"); - } + function release(address to, uint256 amount) external {} } From 282ef91636750b5d9339a67d84e1fb15c77a1d57 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:24:30 -0400 Subject: [PATCH 05/69] removed duplicate interface --- .../common/interfaces/ICeloToken.sol | 34 ------------------- .../common/interfaces/ICeloToken.sol | 1 + 2 files changed, 1 insertion(+), 34 deletions(-) delete mode 100644 packages/protocol/contracts-0.8/common/interfaces/ICeloToken.sol diff --git a/packages/protocol/contracts-0.8/common/interfaces/ICeloToken.sol b/packages/protocol/contracts-0.8/common/interfaces/ICeloToken.sol deleted file mode 100644 index e774da6f884..00000000000 --- a/packages/protocol/contracts-0.8/common/interfaces/ICeloToken.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.5.13 <0.9.0; - -import "@openzeppelin/contracts8/token/ERC20/IERC20.sol"; - -/** - * @dev Interface of the ERC20 standard as defined in the EIP. Does not include - * the optional functions; to access them see {ERC20Detailed}. - */ -interface ICeloToken is IERC20 { - /** - * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. - * @param registryAddress Address of the Registry contract. - */ - function initialize(address registryAddress) external; - - /** - * @notice Updates the address pointing to a Registry contract. - * @param registryAddress The address of a registry contract for routing to other contracts. - */ - function setRegistry(address registryAddress) external; - - /** - * @dev Mints a new token. - * @param to The address that will own the minted token. - * @param value The amount of token to be minted. - */ - function mint(address to, uint256 value) external returns (bool); - - /** - * @notice Returns amount of CELO that has been allocated. - */ - function allocatedSupply() external view returns (uint256); -} diff --git a/packages/protocol/contracts/common/interfaces/ICeloToken.sol b/packages/protocol/contracts/common/interfaces/ICeloToken.sol index 8e2986adc53..6ebfcc6a615 100644 --- a/packages/protocol/contracts/common/interfaces/ICeloToken.sol +++ b/packages/protocol/contracts/common/interfaces/ICeloToken.sol @@ -12,4 +12,5 @@ interface ICeloToken { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); + function allocatedSupply() external view returns (uint256); } From 40711cb503898d89520de1393ec99095e0bd70a2 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:26:50 -0400 Subject: [PATCH 06/69] using `MockCeloToken` to get test to pass. Fails when it hits a precompile in `EpochRewards.sol` --- .../common/test/MockCeloToken.sol | 45 +++++++++++++++++++ .../integration/EpochManagerIntegration.sol | 30 +++++++------ 2 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 packages/protocol/contracts-0.8/common/test/MockCeloToken.sol diff --git a/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol b/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol new file mode 100644 index 00000000000..56e50e88213 --- /dev/null +++ b/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol @@ -0,0 +1,45 @@ +pragma solidity >=0.8.0 <0.9.0; +// solhint-disable no-unused-vars + + +/** + * @title A mock StableToken for testing. + */ +contract MockCeloToken08 { + uint256 public totalSupply_; + uint8 public constant decimals = 18; + mapping(address => uint256) balances; + + function setTotalSupply(uint256 value) external { + totalSupply_ = value; + } + + function transfer(address to, uint256 amount) external returns (bool) { + return _transfer(msg.sender, to, amount); + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + return _transfer(from, to, amount); + } + + function _transfer(address from, address to, uint256 amount) internal returns (bool) { + if (balances[from] < amount) { + return false; + } + balances[from] -= amount; + balances[to] += amount; + return true; + } + + function setBalanceOf(address a, uint256 value) external { + balances[a] = value; + } + + function balanceOf(address a) public view returns (uint256) { + return balances[a]; + } + + function totalSupply() public view returns (uint256) { + return totalSupply_; + } +} diff --git a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol index fa7c09d8aa3..8f6e3caf48e 100644 --- a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol +++ b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol @@ -23,12 +23,14 @@ import { ValidatorsMock08 } from "@celo-contracts-8/governance/test/ValidatorsMo import { MockElection08 } from "@celo-contracts-8/governance/test/MockElection.sol"; import { MockReserve08 } from "@celo-contracts-8/stability/test/MockReserve.sol"; import { MockStableToken08 } from "@celo-contracts-8/stability/test/MockStableToken.sol"; +import { MockCeloToken08 } from "@celo-contracts-8/common/test/MockCeloToken.sol"; contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { EpochManager epochManager; MockSortedOracles sortedOracles; MockStableToken08 stableToken; + MockCeloToken08 celoToken; MockReserve08 reserve; ValidatorsMock08 validators; @@ -43,7 +45,6 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { address[] firstElected; IRegistry registry; - IERC20 celoToken; IEpochRewards epochRewards; IEpochRewardsInitializer epochRewardsInitializer; IFreezer freezer; @@ -87,13 +88,14 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { validators = new ValidatorsMock08(); reserve = new MockReserve08(); stableToken = new MockStableToken08(); + celoToken = new MockCeloToken08(); celoUnreleasedTreasure = new CeloUnreleasedTreasure(false); firstElected.push(actor("validator1")); firstElected.push(actor("validator2")); - address celoTokenAddress = actor("celoTokenAddress"); + // address celoTokenAddress = actor("celoTokenAddress"); address scoreManagerAddress = actor("scoreManagerAddress"); address epochRewardsAddress = actor("epochRewardsAddress"); address freezerAddress = actor("freezerAddress"); @@ -103,13 +105,13 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { communityRewardFund = actor("communityRewardFund"); deployCodeTo("Registry.sol", abi.encode(false), REGISTRY_ADDRESS); - deployCodeTo("GoldToken.sol", abi.encode(false), celoTokenAddress); + // deployCodeTo("GoldToken.sol", abi.encode(false), celoTokenAddress); deployCodeTo("ScoreManager.sol", abi.encode(false), scoreManagerAddress); deployCodeTo("Freezer.sol", abi.encode(false), freezerAddress); deployCodeTo("EpochRewards.sol", abi.encode(true), epochRewardsAddress); registry = IRegistry(REGISTRY_ADDRESS); - celoToken = IERC20(celoTokenAddress); + // celoToken = IERC20(celoTokenAddress); epochRewardsInitializer = IEpochRewardsInitializer(epochRewardsAddress); epochRewards = IEpochRewards(epochRewardsAddress); freezer = IFreezer(freezerAddress); @@ -122,25 +124,21 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { registry.setAddressFor(ValidatorsContract, address(validators)); registry.setAddressFor(ScoreManagerContract, address(scoreManager)); registry.setAddressFor(StableTokenContract, address(stableToken)); - registry.setAddressFor(CeloUnreleasedTreasureContract, address(celoUnreleasedTreasure)); registry.setAddressFor(CeloTokenContract, address(celoToken)); + registry.setAddressFor(CeloUnreleasedTreasureContract, address(celoUnreleasedTreasure)); registry.setAddressFor(ReserveContract, address(reserve)); - registry.setAddressFor(ElectionContract, address(election)); registry.setAddressFor(FreezerContract, address(freezer)); + celoToken.setTotalSupply(CELO_SUPPLY_CAP); vm.deal(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); vm.deal(address(reserve), L1_MINTED_CELO_SUPPLY); - vm.deal(address(reserve), L1_MINTED_CELO_SUPPLY); bool res1 = sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); (uint256 res0, uint256 res00) = sortedOracles.medianRate(address(stableToken)); scoreManager.setValidatorScore(actor("validator1"), 1); uint256 res = scoreManager.getValidatorScore(actor("validator1")); - uint256 res2 = epochRewards.getCommunityRewardFraction(); - - console2.log("### res2", res2); epochRewardsInitializer.initialize( address(registry), @@ -157,6 +155,10 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { carbonOffsettingFraction ); + uint256 res2 = epochRewards.getCommunityRewardFraction(); + + console2.log("### res2", res2); + epochManager.initialize( REGISTRY_ADDRESS, DAY, @@ -165,8 +167,8 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { ); blockTravel(vm, firstEpochBlock); - - + // makes sure test know this is L2. + deployCodeTo("Registry.sol", abi.encode(false), PROXY_ADMIN_ADDRESS); } } @@ -232,10 +234,12 @@ contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegr uint256 _currentEpoch = epochManager.currentEpochNumber(); console2.log("### Current epoch duration:", epochManager.epochDuration()); + + epochManager.startNextEpochProcess(); + (, , , uint256 _currentEpochEndTimestamp, uint256 _currentRewardsBlock) = epochManager .getCurrentEpoch(); - epochManager.startNextEpochProcess(); console2.log("### Done"); assertEq(_currentRewardsBlock, block.number - 1); } From 654b2798ff7733e0f1b7ab900a9f8e5529a0bb75 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 20 Aug 2024 15:34:55 -0400 Subject: [PATCH 07/69] removed endEpochTimestamp --- .../protocol/contracts-0.8/common/EpochManager.sol | 14 +++----------- .../common/interfaces/IEpochManager.sol | 2 +- .../integration/EpochManagerIntegration.sol | 2 +- .../test-sol/unit/common/EpochManager.t.sol | 9 ++------- 4 files changed, 7 insertions(+), 20 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 257f9f5701d..04f93d59d2f 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -23,7 +23,6 @@ contract EpochManager is uint256 firstBlock; uint256 lastBlock; uint256 startTimestamp; - uint256 endTimestamp; uint256 rewardsBlock; } @@ -172,7 +171,6 @@ contract EpochManager is require(isOnEpochProcess(), "Epoch process is not started"); // finalize epoch // TODO last block should be the block before and timestamp from previous block - epochs[currentEpochNumber].endTimestamp = block.timestamp; epochs[currentEpochNumber].lastBlock = block.number - 1; // start new epoch currentEpochNumber++; @@ -218,16 +216,10 @@ contract EpochManager is } /// returns the current epoch Info - function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256, uint256) { + function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256) { Epoch storage _epoch = epochs[currentEpochNumber]; - return ( - _epoch.firstBlock, - _epoch.lastBlock, - _epoch.startTimestamp, - _epoch.endTimestamp, - _epoch.rewardsBlock - ); + return (_epoch.firstBlock, _epoch.lastBlock, _epoch.startTimestamp, _epoch.rewardsBlock); } /// returns the current epoch number. @@ -235,7 +227,7 @@ contract EpochManager is return currentEpochNumber; } -/// returns epoch processing state + /// returns epoch processing state function getEpochProcessingState() external view diff --git a/packages/protocol/contracts-0.8/common/interfaces/IEpochManager.sol b/packages/protocol/contracts-0.8/common/interfaces/IEpochManager.sol index 04158ea9dee..e69151739a2 100644 --- a/packages/protocol/contracts-0.8/common/interfaces/IEpochManager.sol +++ b/packages/protocol/contracts-0.8/common/interfaces/IEpochManager.sol @@ -18,7 +18,7 @@ interface IEpochManager is IBlocker { // uint16[] calldata lessers, // uint16 greaters // ) external; - function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256, uint256); + function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256); function getCurrentEpochNumber() external view returns (uint256); // function getElected() external view returns (address[] memory); // // function getElectedAtEpoch(uint256 epoch) external view returns (address[] memory); diff --git a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol index 8f6e3caf48e..b665bd49158 100644 --- a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol +++ b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol @@ -237,7 +237,7 @@ contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegr epochManager.startNextEpochProcess(); - (, , , uint256 _currentEpochEndTimestamp, uint256 _currentRewardsBlock) = epochManager + (, , , uint256 _currentRewardsBlock) = epochManager .getCurrentEpoch(); console2.log("### Done"); diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 7b25175e4a5..954e050c48b 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.7 <0.8.20; import "celo-foundry-8/Test.sol"; import "@celo-contracts-8/common/EpochManager.sol"; import "@celo-contracts-8/stability/test/MockStableToken.sol"; -import "@celo-contracts-8/common/interfaces/ICeloToken.sol"; +import "@celo-contracts/common/interfaces/ICeloToken.sol"; import "@celo-contracts-8/common/ScoreManager.sol"; import { CeloUnreleasedTreasure } from "@celo-contracts-8/common/CeloUnreleasedTreasure.sol"; import { ICeloUnreleasedTreasure } from "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; @@ -136,7 +136,6 @@ contract EpochManagerTest_initializeSystem is EpochManagerTest { uint256 _firstEpochBlock, uint256 _lastEpochBlock, uint256 _startTimestamp, - uint256 _currentEpochEndTimestamp, uint256 _currentRewardsBlock ) = epochManager.getCurrentEpoch(); assertEq(epochManager.epochManagerInitializer(), address(0)); @@ -144,7 +143,6 @@ contract EpochManagerTest_initializeSystem is EpochManagerTest { assertEq(_firstEpochBlock, firstEpochBlock); assertEq(_lastEpochBlock, 0); assertEq(_startTimestamp, block.timestamp); - assertEq(_currentEpochEndTimestamp, 0); assertEq(_currentRewardsBlock, 0); assertEq(epochManager.getElected(), firstElected); } @@ -166,7 +164,6 @@ contract EpochManagerTest_initializeSystem is EpochManagerTest { contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { function test_Reverts_whenSystemNotInitialized() public { uint256 _currentEpoch = epochManager.currentEpochNumber(); - (, , , uint256 _currentEpochEndTimestamp, ) = epochManager.getCurrentEpoch(); vm.expectRevert("Epoch system not initialized"); epochManager.startNextEpochProcess(); @@ -177,7 +174,6 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); uint256 _currentEpoch = epochManager.currentEpochNumber(); - (, , , uint256 _currentEpochEndTimestamp, ) = epochManager.getCurrentEpoch(); vm.expectRevert("Epoch is not ready to start"); epochManager.startNextEpochProcess(); @@ -203,8 +199,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { timeTravel(vm, DAY); epochManager.startNextEpochProcess(); - (, , , uint256 _currentEpochEndTimestamp, uint256 _currentRewardsBlock) = epochManager - .getCurrentEpoch(); + (, , , uint256 _currentRewardsBlock) = epochManager.getCurrentEpoch(); assertEq(_currentRewardsBlock, block.number); } From 207210731e308403062cba1be341d6ad399ffe58 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:08:05 -0400 Subject: [PATCH 08/69] moved IEpochManager to 0.5 folder --- .../protocol/contracts-0.8/common/EpochManager.sol | 3 +-- .../protocol/contracts-0.8/common/UsingRegistry.sol | 11 ++++------- packages/protocol/contracts/common/UsingRegistry.sol | 5 +++++ .../protocol/contracts/common/UsingRegistryV2.sol | 5 +++++ .../common/interfaces/IEpochManager.sol | 9 +++------ 5 files changed, 18 insertions(+), 15 deletions(-) rename packages/protocol/{contracts-0.8 => contracts}/common/interfaces/IEpochManager.sol (81%) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 04f93d59d2f..2a12178d41c 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -4,13 +4,13 @@ pragma solidity >=0.8.7 <0.8.20; import "@openzeppelin/contracts8/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts8/access/Ownable.sol"; -import "./interfaces/IEpochManager.sol"; import "./interfaces/IOracle.sol"; import "./interfaces/IStableToken.sol"; import "../common/UsingRegistry.sol"; import "../../contracts/common/Initializable.sol"; import "../../contracts/common/interfaces/ICeloVersionedContract.sol"; +import "../../contracts/common/interfaces/IEpochManager.sol"; contract EpochManager is Initializable, @@ -218,7 +218,6 @@ contract EpochManager is /// returns the current epoch Info function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256) { Epoch storage _epoch = epochs[currentEpochNumber]; - return (_epoch.firstBlock, _epoch.lastBlock, _epoch.startTimestamp, _epoch.rewardsBlock); } diff --git a/packages/protocol/contracts-0.8/common/UsingRegistry.sol b/packages/protocol/contracts-0.8/common/UsingRegistry.sol index 2c14330c2a3..fc678408e0f 100644 --- a/packages/protocol/contracts-0.8/common/UsingRegistry.sol +++ b/packages/protocol/contracts-0.8/common/UsingRegistry.sol @@ -7,12 +7,13 @@ pragma solidity >=0.8.0 <0.8.20; import "@openzeppelin/contracts8/access/Ownable.sol"; import "@openzeppelin/contracts8/token/ERC20/IERC20.sol"; -import "./interfaces/IEpochManager.sol"; - import "../../contracts/common/interfaces/IRegistry.sol"; import "../../contracts/common/interfaces/IAccounts.sol"; import "../../contracts/common/interfaces/IFreezer.sol"; import "../../contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; +import "../../contracts/common/interfaces/IFeeCurrencyWhitelist.sol"; +import "../../contracts/common/interfaces/IFeeHandlerSeller.sol"; +import "../../contracts/common/interfaces/IEpochManager.sol"; import "../../contracts/governance/interfaces/IGovernance.sol"; import "../../contracts/governance/interfaces/ILockedGold.sol"; import "../../contracts/governance/interfaces/ILockedCelo.sol"; @@ -20,12 +21,8 @@ import "../../contracts/governance/interfaces/IValidators.sol"; import "../../contracts/governance/interfaces/IElection.sol"; import "../../contracts/governance/interfaces/IEpochRewards.sol"; import "../../contracts/stability/interfaces/ISortedOracles.sol"; -import "../../contracts/common/interfaces/IFeeCurrencyWhitelist.sol"; -import "./interfaces/IScoreReader.sol"; -import "../../contracts/governance/interfaces/IElection.sol"; -import "../../contracts/common/interfaces/IFeeHandlerSeller.sol"; -import "../../contracts/governance/interfaces/IEpochRewards.sol"; +import "./interfaces/IScoreReader.sol"; contract UsingRegistry is Ownable { // solhint-disable state-visibility diff --git a/packages/protocol/contracts/common/UsingRegistry.sol b/packages/protocol/contracts/common/UsingRegistry.sol index 304698bdc5f..563ba18b6e8 100644 --- a/packages/protocol/contracts/common/UsingRegistry.sol +++ b/packages/protocol/contracts/common/UsingRegistry.sol @@ -9,6 +9,7 @@ import "./interfaces/IFeeCurrencyWhitelist.sol"; import "./interfaces/IFreezer.sol"; import "./interfaces/IRegistry.sol"; import "./interfaces/ICeloUnreleasedTreasure.sol"; +import "./interfaces/IEpochManager.sol"; import "../governance/interfaces/IElection.sol"; import "../governance/interfaces/IEpochRewards.sol"; @@ -152,4 +153,8 @@ contract UsingRegistry is Ownable { function getEpochRewards() internal view returns (IEpochRewards) { return IEpochRewards(registry.getAddressForOrDie(EPOCH_REWARDS_REGISTRY_ID)); } + + function getEpochManager() internal view returns (IEpochManager) { + return IEpochManager(registry.getAddressForOrDie(EPOCH_MANAGER_REGISTRY_ID)); + } } diff --git a/packages/protocol/contracts/common/UsingRegistryV2.sol b/packages/protocol/contracts/common/UsingRegistryV2.sol index 27ba69b12cc..18dbeb39667 100644 --- a/packages/protocol/contracts/common/UsingRegistryV2.sol +++ b/packages/protocol/contracts/common/UsingRegistryV2.sol @@ -8,6 +8,7 @@ import "./interfaces/IFeeCurrencyWhitelist.sol"; import "./interfaces/IFreezer.sol"; import "./interfaces/IRegistry.sol"; import "./interfaces/ICeloUnreleasedTreasure.sol"; +import "./interfaces/IEpochManager.sol"; import "../governance/interfaces/IElection.sol"; import "../governance/interfaces/IEpochRewards.sol"; @@ -191,4 +192,8 @@ contract UsingRegistryV2 { function getEpochRewards() internal view returns (IEpochRewards) { return IEpochRewards(registryContract.getAddressForOrDie(EPOCH_REWARDS_REGISTRY_ID)); } + + function getEpochManager() internal view returns (IEpochManager) { + return IEpochManager(registryContract.getAddressForOrDie(EPOCH_MANAGER_REGISTRY_ID)); + } } diff --git a/packages/protocol/contracts-0.8/common/interfaces/IEpochManager.sol b/packages/protocol/contracts/common/interfaces/IEpochManager.sol similarity index 81% rename from packages/protocol/contracts-0.8/common/interfaces/IEpochManager.sol rename to packages/protocol/contracts/common/interfaces/IEpochManager.sol index e69151739a2..948a5dc3a52 100644 --- a/packages/protocol/contracts-0.8/common/interfaces/IEpochManager.sol +++ b/packages/protocol/contracts/common/interfaces/IEpochManager.sol @@ -1,11 +1,8 @@ // SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.0 <0.9.0; +pragma solidity >=0.5.13 <0.9.0; -interface IBlocker { - function isBlocked() external view returns (bool); -} -interface IEpochManager is IBlocker { +interface IEpochManager{ function initializeSystem( uint256 firstEpochNumber, uint256 firstEpochBlock, @@ -20,7 +17,7 @@ interface IEpochManager is IBlocker { // ) external; function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256); function getCurrentEpochNumber() external view returns (uint256); - // function getElected() external view returns (address[] memory); + function getElected() external view returns (address[] memory); // // function getElectedAtEpoch(uint256 epoch) external view returns (address[] memory); // function getFirstBlockAtEpoch(uint256 epoch) external view returns (uint256); // function getLastBlockAtEpoch(uint256 epoch) external view returns (uint256); From 9a6c01f893bcc556c80aeafaf705ffce78ab9ca7 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:17:24 -0400 Subject: [PATCH 09/69] added L2 conditions for EpochRewards functions using precompiles Still missing tests --- .../contracts/governance/EpochRewards.sol | 18 +++++++++++++++++- .../unit/governance/network/EpochRewards.t.sol | 5 ++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/protocol/contracts/governance/EpochRewards.sol b/packages/protocol/contracts/governance/EpochRewards.sol index d8ad463265f..0513e62f306 100644 --- a/packages/protocol/contracts/governance/EpochRewards.sol +++ b/packages/protocol/contracts/governance/EpochRewards.sol @@ -9,6 +9,7 @@ import "../common/Freezable.sol"; import "../common/Initializable.sol"; import "../common/UsingRegistry.sol"; import "../common/UsingPrecompiles.sol"; +import "../common/interfaces/ICeloToken.sol"; import "../common/interfaces/ICeloVersionedContract.sol"; /** @@ -450,6 +451,12 @@ contract EpochRewards is function getTargetTotalEpochPaymentsInGold() public view returns (uint256) { address stableTokenAddress = registry.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID); (uint256 numerator, uint256 denominator) = getSortedOracles().medianRate(stableTokenAddress); + if (isL2()) { + return + getEpochManager().getElected().length.mul(targetValidatorEpochPayment).mul(denominator).div( + numerator + ); + } return numberValidatorsInCurrentSet().mul(targetValidatorEpochPayment).mul(denominator).div( numerator @@ -461,7 +468,16 @@ contract EpochRewards is * @return The fraction of floating Gold being used for voting in validator elections. */ function getVotingGoldFraction() public view returns (uint256) { - uint256 liquidGold = getCeloToken().totalSupply().sub(getReserve().getReserveGoldBalance()); + uint256 liquidGold; + if (isL2()) { + liquidGold = ICeloToken(address(getCeloToken())).allocatedSupply().sub( + getReserve().getReserveGoldBalance() + ); + } else { + liquidGold = ICeloToken(address(getCeloToken())).totalSupply().sub( + getReserve().getReserveGoldBalance() + ); + } uint256 votingGold = getElection().getTotalVotes(); return FixidityLib.newFixed(votingGold).divide(FixidityLib.newFixed(liquidGold)).unwrap(); } diff --git a/packages/protocol/test-sol/unit/governance/network/EpochRewards.t.sol b/packages/protocol/test-sol/unit/governance/network/EpochRewards.t.sol index 64de3207dfb..7c8a848f26d 100644 --- a/packages/protocol/test-sol/unit/governance/network/EpochRewards.t.sol +++ b/packages/protocol/test-sol/unit/governance/network/EpochRewards.t.sol @@ -446,6 +446,7 @@ contract EpochRewardsTest_getTargetVoterRewards is EpochRewardsTest { } contract EpochRewardsTest_getTargetTotalEpochPaymentsInGold is EpochRewardsTest { + // TODO(soloseng): add L2 test case that uses EpochManager function test_ShouldgetTargetTotalEpochPaymentsInGold_WhenExchangeRateIsSet() public { uint256 numberValidators = 100; epochRewards.setNumberValidatorsInCurrentSet(numberValidators); @@ -456,6 +457,7 @@ contract EpochRewardsTest_getTargetTotalEpochPaymentsInGold is EpochRewardsTest } contract EpochRewardsTest_getRewardsMultiplier is EpochRewardsTest { + // TODO(soloseng): add L2 test case using EpochManager uint256 constant timeDelta = YEAR * 10; uint256 expectedTargetTotalSupply; uint256 expectedTargetRemainingSupply; @@ -502,6 +504,7 @@ contract EpochRewardsTest_getRewardsMultiplier is EpochRewardsTest { } contract EpochRewardsTest_updateTargetVotingYield is EpochRewardsTest { + //TODO(soloseng): add L2 test case that uses epochManager uint256 constant totalSupply = 6000000 ether; uint256 constant reserveBalance = 1000000 ether; uint256 constant floatingSupply = totalSupply - reserveBalance; @@ -758,7 +761,7 @@ contract EpochRewardsTest_updateTargetVotingYield is EpochRewardsTest { epochRewards.updateTargetVotingYield(); } } - +// TODO(soloseng): add L2 test case that uses the result from epochManager contract EpochRewardsTest_WhenThereAreActiveVotesAStableTokenExchangeRateIsSetAndTheActualRemainingSupplyIs10pMoreThanTheTargetRemainingSupplyAfterRewards_calculateTargetEpochRewards is EpochRewardsTest { From c48b8e547bb02646807ef1f3c364a44dfae560ec Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:09:37 -0400 Subject: [PATCH 10/69] renamed EpochManagerInitializer due to name conflict --- .../contracts-0.8/common/EpochManager.sol | 18 +++++++------- ....sol => EpochManagerSystemInitializer.sol} | 2 +- packages/protocol/test-sol/constants.sol | 1 - .../integration/EpochManagerIntegration.sol | 19 ++++++++------- .../test-sol/unit/common/EpochManager.t.sol | 24 +++++++++---------- 5 files changed, 32 insertions(+), 32 deletions(-) rename packages/protocol/contracts-0.8/common/{EpochManagerInitializer.sol => EpochManagerSystemInitializer.sol} (95%) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 2a12178d41c..07c3d13dab0 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -58,7 +58,7 @@ contract EpochManager is mapping(address => uint256) public validatorPendingPayments; address public carbonOffsettingPartner; - address public epochManagerInitializer; + address public EpochManagerSystemInitializer; /** * @notice Event emited when epochProcessing has begun. @@ -72,8 +72,8 @@ contract EpochManager is */ event EpochProcessingEnded(uint256 indexed epochNumber); - modifier onlyEpochManagerInitializer() { - require(msg.sender == epochManagerInitializer, "msg.sender is not Initializer"); + modifier onlyEpochManagerSystemInitializer() { + require(msg.sender == epochManagerSystemInitializer, "msg.sender is not Initializer"); _; } @@ -92,14 +92,14 @@ contract EpochManager is address registryAddress, uint256 newEpochDuration, address _carbonOffsettingPartner, - address _epochManagerInitializer + address _epochManagerSystemInitializer ) external initializer { - require(_epochManagerInitializer != address(0), "EpochManagerInitializer address is required"); + require(_epochManagerSystemInitializer != address(0), "EpochManagerSystemInitializer address is required"); _transferOwnership(msg.sender); setRegistry(registryAddress); setEpochDuration(newEpochDuration); carbonOffsettingPartner = _carbonOffsettingPartner; - epochManagerInitializer = _epochManagerInitializer; + epochManagerSystemInitializer = _epochManagerSystemInitializer; } // DESIGNDESICION(XXX): we assume that the first epoch on the L2 starts as soon as the system is initialized @@ -109,7 +109,7 @@ contract EpochManager is uint256 firstEpochNumber, uint256 firstEpochBlock, address[] memory firstElected - ) external onlyEpochManagerInitializer { + ) external onlyEpochManagerSystemInitializer { require(!systemAlreadyInitialized(), "Epoch system already initialized"); require(firstEpochNumber > 0, "First epoch number must be greater than 0"); require(firstEpochBlock > 0, "First epoch block must be greater than 0"); @@ -126,7 +126,7 @@ contract EpochManager is _currentEpoch.startTimestamp = block.timestamp; elected = firstElected; - epochManagerInitializer = address(0); + epochManagerSystemInitializer = address(0); } // TODO maybe "freezeEpochRewards" "prepareForNextEpoch" @@ -290,7 +290,7 @@ contract EpochManager is } function systemAlreadyInitialized() public view returns (bool) { - return initialized && epochManagerInitializer == address(0); + return initialized && epochManagerSystemInitializer == address(0); } function allocateValidatorsRewards() internal { diff --git a/packages/protocol/contracts-0.8/common/EpochManagerInitializer.sol b/packages/protocol/contracts-0.8/common/EpochManagerSystemInitializer.sol similarity index 95% rename from packages/protocol/contracts-0.8/common/EpochManagerInitializer.sol rename to packages/protocol/contracts-0.8/common/EpochManagerSystemInitializer.sol index 42226a3e67c..1e150446e00 100644 --- a/packages/protocol/contracts-0.8/common/EpochManagerInitializer.sol +++ b/packages/protocol/contracts-0.8/common/EpochManagerSystemInitializer.sol @@ -8,7 +8,7 @@ import "../../contracts/common/Initializable.sol"; import "../../contracts/common/interfaces/ICeloVersionedContract.sol"; import "../../contracts/governance/interfaces/IEpochRewards.sol"; -contract EpochManagerInitializer is Initializable, UsingPrecompiles, UsingRegistry { +contract EpochManagerSystemInitializer is Initializable, UsingPrecompiles, UsingRegistry { /** * @notice Sets initialized == true on implementation contracts * @param test Set to true to skip implementation initialization diff --git a/packages/protocol/test-sol/constants.sol b/packages/protocol/test-sol/constants.sol index 7225ca89ed2..93857df5e52 100644 --- a/packages/protocol/test-sol/constants.sol +++ b/packages/protocol/test-sol/constants.sol @@ -25,7 +25,6 @@ contract TestConstants { string constant GovernanceContract = "Governance"; string constant EpochRewardsContract = "EpochRewards"; string constant EpochManagerContract = "EpochManager"; - string constant EpochManagerInitializerContract = "EpochManagerInitializer"; string constant ScoreManagerContract = "ScoreManager"; string constant ReserveContract = "Reserve"; string constant CeloUnreleasedTreasureContract = "CeloUnreleasedTreasure"; diff --git a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol index b665bd49158..c2e2b51b604 100644 --- a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol +++ b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol @@ -36,7 +36,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { ValidatorsMock08 validators; MockElection08 election; - address epochManagerInitializer; + address epochManagerSystemInitializer; address carbonOffsettingPartner; address communityRewardFund; @@ -100,7 +100,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { address epochRewardsAddress = actor("epochRewardsAddress"); address freezerAddress = actor("freezerAddress"); - epochManagerInitializer = actor("initializer"); + epochManagerSystemInitializer = actor("epochManagerSystemInitializer"); carbonOffsettingPartner = actor("carbonOffsettingPartner"); communityRewardFund = actor("communityRewardFund"); @@ -131,8 +131,9 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { registry.setAddressFor(FreezerContract, address(freezer)); celoToken.setTotalSupply(CELO_SUPPLY_CAP); + // election.setTotalVotes(5); vm.deal(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); - vm.deal(address(reserve), L1_MINTED_CELO_SUPPLY); + // vm.deal(address(reserve), 69411663406170917420347916); // current as of 08/20/24 bool res1 = sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); (uint256 res0, uint256 res00) = sortedOracles.medianRate(address(stableToken)); @@ -163,7 +164,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { REGISTRY_ADDRESS, DAY, carbonOffsettingPartner, - epochManagerInitializer + epochManagerSystemInitializer ); blockTravel(vm, firstEpochBlock); @@ -185,19 +186,19 @@ contract EpochManagerIntegrationTest_initialize is EpochManagerIntegrationTest { REGISTRY_ADDRESS, DAY, carbonOffsettingPartner, - epochManagerInitializer + epochManagerSystemInitializer ); } } contract EpochManagerIntegrationTest_initializeSystem is EpochManagerIntegrationTest { function test_processCanBeStarted() public virtual { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); } function test_Reverts_processCannotBeStartedAgain() public virtual { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); vm.prank(address(0)); vm.expectRevert("Epoch system already initialized"); @@ -217,7 +218,7 @@ contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegr } function test_Reverts_WhenEndOfEpochHasNotBeenReached() public { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); vm.expectRevert("Epoch is not ready to start"); @@ -225,7 +226,7 @@ contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegr } function test_Succeeds() public { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); blockTravel(vm, 43200); diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 954e050c48b..79f24401e98 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -28,7 +28,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { EpochRewardsMock08 epochRewards; ValidatorsMock08 validators; - address epochManagerInitializer; + address epochManagerSystemInitializer; address carbonOffsettingPartner; address communityRewardFund; @@ -73,7 +73,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { address scoreManagerAddress = actor("scoreManagerAddress"); address reserveAddress = actor("reserve"); - epochManagerInitializer = actor("initializer"); + epochManagerSystemInitializer = actor("epochManagerSystemInitializer"); carbonOffsettingPartner = actor("carbonOffsettingPartner"); communityRewardFund = actor("communityRewardFund"); @@ -107,7 +107,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { REGISTRY_ADDRESS, epochDuration, carbonOffsettingPartner, - epochManagerInitializer + epochManagerSystemInitializer ); blockTravel(vm, firstEpochBlock); @@ -119,18 +119,18 @@ contract EpochManagerTest_initialize is EpochManagerTest { assertEq(address(epochManager.registry()), REGISTRY_ADDRESS); assertEq(epochManager.epochDuration(), epochDuration); assertEq(epochManager.carbonOffsettingPartner(), carbonOffsettingPartner); - assertEq(epochManager.epochManagerInitializer(), epochManagerInitializer); + assertEq(epochManager.epochManagerSystemInitializer(), epochManagerSystemInitializer); } function test_Reverts_WhenAlreadyInitialized() public virtual { vm.expectRevert("contract already initialized"); - epochManager.initialize(REGISTRY_ADDRESS, 10, carbonOffsettingPartner, epochManagerInitializer); + epochManager.initialize(REGISTRY_ADDRESS, 10, carbonOffsettingPartner, epochManagerSystemInitializer); } } contract EpochManagerTest_initializeSystem is EpochManagerTest { function test_processCanBeStarted() public virtual { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); ( uint256 _firstEpochBlock, @@ -138,7 +138,7 @@ contract EpochManagerTest_initializeSystem is EpochManagerTest { uint256 _startTimestamp, uint256 _currentRewardsBlock ) = epochManager.getCurrentEpoch(); - assertEq(epochManager.epochManagerInitializer(), address(0)); + assertEq(epochManager.epochManagerSystemInitializer(), address(0)); assertEq(epochManager.firstKnownEpoch(), firstEpochNumber); assertEq(_firstEpochBlock, firstEpochBlock); assertEq(_lastEpochBlock, 0); @@ -148,7 +148,7 @@ contract EpochManagerTest_initializeSystem is EpochManagerTest { } function test_Reverts_processCannotBeStartedAgain() public virtual { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); vm.prank(address(0)); vm.expectRevert("Epoch system already initialized"); @@ -170,7 +170,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } function test_Reverts_WhenEndOfEpochHasNotBeenReached() public { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); uint256 _currentEpoch = epochManager.currentEpochNumber(); @@ -180,7 +180,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } function test_Reverts_WhenEpochProcessingAlreadyStarted() public { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); blockTravel(vm, 43200); @@ -192,7 +192,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } function test_SetsTheEpochRewardBlock() public { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); blockTravel(vm, 43200); @@ -204,7 +204,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } function test_SetsTheEpochRewardAmounts() public { - vm.prank(epochManagerInitializer); + vm.prank(epochManagerSystemInitializer); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); blockTravel(vm, 43200); From 47f93af9f22668d95e6542368a4551520467c1b7 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:42:35 -0400 Subject: [PATCH 11/69] ++ more unit test --- .../common/CeloUnreleasedTreasure.sol | 4 +- .../common/test/MockCeloToken.sol | 17 +++- .../common/interfaces/ICeloToken.sol | 2 + .../unit/common/CeloUnreleasedTreasure.t.sol | 5 +- .../test-sol/unit/common/EpochManager.t.sol | 89 ++++++++++++++----- 5 files changed, 88 insertions(+), 29 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol b/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol index 2acde5c26c1..71328251405 100644 --- a/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol +++ b/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol @@ -48,8 +48,8 @@ contract CeloUnreleasedTreasure is UsingRegistry, ReentrancyGuard, Initializable */ function release(address to, uint256 amount) external onlyEpochManager { require(address(this).balance >= amount, "Insufficient balance."); - IERC20 celoToken = IERC20(address(getCeloToken())); - celoToken.transfer(to, amount); + IERC20 celoToken = getCeloToken(); + require(celoToken.transfer(to, amount), "CELO transfer failed."); emit Released(to, amount); } diff --git a/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol b/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol index 56e50e88213..792193c0b54 100644 --- a/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol +++ b/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol @@ -1,7 +1,6 @@ pragma solidity >=0.8.0 <0.9.0; // solhint-disable no-unused-vars - /** * @title A mock StableToken for testing. */ @@ -10,6 +9,19 @@ contract MockCeloToken08 { uint8 public constant decimals = 18; mapping(address => uint256) balances; + uint256 constant L1_MINTED_CELO_SUPPLY = 692702432463315819704447326; // as of May 15 2024 + + uint256 constant CELO_SUPPLY_CAP = 1000000000 ether; // 1 billion Celo + uint256 constant GENESIS_CELO_SUPPLY = 600000000 ether; // 600 million Celo + + uint256 constant FIFTEEN_YEAR_LINEAR_REWARD = (CELO_SUPPLY_CAP - GENESIS_CELO_SUPPLY) / 2; // 200 million Celo + + uint256 constant FIFTEEN_YEAR_CELO_SUPPLY = GENESIS_CELO_SUPPLY + FIFTEEN_YEAR_LINEAR_REWARD; // 800 million Celo (includes GENESIS_CELO_SUPPLY) + + uint256 constant MAX_L2_DISTRIBUTION = FIFTEEN_YEAR_CELO_SUPPLY - L1_MINTED_CELO_SUPPLY; // 107.2 million Celo + + uint256 constant L2_INITIAL_STASH_BALANCE = FIFTEEN_YEAR_LINEAR_REWARD + MAX_L2_DISTRIBUTION; // leftover from L1 target supply plus the 2nd 15 year term. + function setTotalSupply(uint256 value) external { totalSupply_ = value; } @@ -42,4 +54,7 @@ contract MockCeloToken08 { function totalSupply() public view returns (uint256) { return totalSupply_; } + function allocatedSupply() public view returns (uint256) { + return CELO_SUPPLY_CAP - L2_INITIAL_STASH_BALANCE; + } } diff --git a/packages/protocol/contracts/common/interfaces/ICeloToken.sol b/packages/protocol/contracts/common/interfaces/ICeloToken.sol index 6ebfcc6a615..b702ed994ca 100644 --- a/packages/protocol/contracts/common/interfaces/ICeloToken.sol +++ b/packages/protocol/contracts/common/interfaces/ICeloToken.sol @@ -9,8 +9,10 @@ interface ICeloToken { function initialize(address) external; function transferWithComment(address, uint256, string calldata) external returns (bool); function burn(uint256 value) external returns (bool); + function mint(address to, uint256 value) external returns (bool); function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function allocatedSupply() external view returns (uint256); + function totalSupply() external view returns (uint256); } diff --git a/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol b/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol index a471de4f894..c35c625d462 100644 --- a/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol +++ b/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol @@ -5,7 +5,7 @@ pragma experimental ABIEncoderV2; import "celo-foundry-8/Test.sol"; import "@celo-contracts/common/FixidityLib.sol"; import "@celo-contracts/common/interfaces/IRegistry.sol"; -import "@celo-contracts-8/common/interfaces/ICeloToken.sol"; +import "@celo-contracts/common/interfaces/ICeloToken.sol"; import "@celo-contracts/governance/interfaces/IGovernance.sol"; import { CeloUnreleasedTreasure } from "@celo-contracts-8/common/CeloUnreleasedTreasure.sol"; import "@celo-contracts-8/common/IsL2Check.sol"; @@ -76,7 +76,6 @@ contract CeloUnreleasedTreasureTest is Test, TestConstants, IsL2Check { deployCodeTo("GoldToken.sol", abi.encode(false), celoTokenAddress); celoToken = ICeloToken(celoTokenAddress); - celoToken.setRegistry(REGISTRY_ADDRESS); // Using a mock contract, as foundry does not allow for library linking when using deployCodeTo governance = new MockGovernance(); @@ -153,7 +152,7 @@ contract CeloUnreleasedTreasureTest_release is CeloUnreleasedTreasureTest { newCeloUnreleasedTreasure(); } - function test_ShouldTrasferToRecepientAddress() public { + function test_ShouldTransferToRecepientAddress() public { uint256 _balanceBefore = randomAddress.balance; vm.prank(epochManagerAddress); diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 79f24401e98..a7e2357632f 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.7 <0.8.20; import "celo-foundry-8/Test.sol"; import "@celo-contracts-8/common/EpochManager.sol"; import "@celo-contracts-8/stability/test/MockStableToken.sol"; +import "@celo-contracts-8/common/test/MockCeloToken.sol"; import "@celo-contracts/common/interfaces/ICeloToken.sol"; import "@celo-contracts-8/common/ScoreManager.sol"; import { CeloUnreleasedTreasure } from "@celo-contracts-8/common/CeloUnreleasedTreasure.sol"; @@ -31,6 +32,8 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { address epochManagerSystemInitializer; address carbonOffsettingPartner; address communityRewardFund; + address reserveAddress; + address scoreManagerAddress; uint256 firstEpochNumber = 100; uint256 firstEpochBlock = 100; @@ -38,7 +41,8 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { address[] firstElected; IRegistry registry; - ICeloToken celoToken; + MockCeloToken08 celoToken; + // CeloUnreleasedTreasure celoUnreleasedTreasure; MockCeloUnreleasedTreasure celoUnreleasedTreasure; ScoreManager scoreManager; @@ -58,31 +62,34 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { uint256 constant L2_INITIAL_STASH_BALANCE = FIFTEEN_YEAR_LINEAR_REWARD + MAX_L2_DISTRIBUTION; // leftover from L1 target supply plus the 2nd 15 year term. + event EpochProcessingStarted(uint256 indexed epochNumber); + function setUp() public virtual { epochManager = new EpochManager(true); sortedOracles = new MockSortedOracles(); epochRewards = new EpochRewardsMock08(); validators = new ValidatorsMock08(); stableToken = new MockStableToken08(); + celoToken = new MockCeloToken08(); + // celoUnreleasedTreasure = new CeloUnreleasedTreasure(true); celoUnreleasedTreasure = new MockCeloUnreleasedTreasure(); firstElected.push(actor("validator1")); firstElected.push(actor("validator2")); - address celoTokenAddress = actor("celoTokenAddress"); - address scoreManagerAddress = actor("scoreManagerAddress"); - address reserveAddress = actor("reserve"); + scoreManagerAddress = actor("scoreManagerAddress"); + + reserveAddress = actor("reserve"); epochManagerSystemInitializer = actor("epochManagerSystemInitializer"); carbonOffsettingPartner = actor("carbonOffsettingPartner"); communityRewardFund = actor("communityRewardFund"); deployCodeTo("Registry.sol", abi.encode(false), REGISTRY_ADDRESS); - deployCodeTo("GoldToken.sol", abi.encode(false), celoTokenAddress); + deployCodeTo("ScoreManager.sol", abi.encode(false), scoreManagerAddress); registry = IRegistry(REGISTRY_ADDRESS); - celoToken = ICeloToken(celoTokenAddress); scoreManager = ScoreManager(scoreManagerAddress); registry.setAddressFor(EpochManagerContract, address(epochManager)); @@ -96,10 +103,11 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { registry.setAddressFor(CeloTokenContract, address(celoToken)); registry.setAddressFor(ReserveContract, reserveAddress); + celoToken.setTotalSupply(CELO_SUPPLY_CAP); vm.deal(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); + celoToken.setBalanceOf(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); - bool res1 = sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); - (uint256 res0, uint256 res00) = sortedOracles.medianRate(address(stableToken)); + sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); scoreManager.setValidatorScore(actor("validator1"), 1); @@ -112,6 +120,14 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { blockTravel(vm, firstEpochBlock); } + + function initializeEpochManagerSystem() public { + vm.prank(epochManagerSystemInitializer); + epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + + blockTravel(vm, 43200); + timeTravel(vm, DAY); + } } contract EpochManagerTest_initialize is EpochManagerTest { @@ -124,7 +140,12 @@ contract EpochManagerTest_initialize is EpochManagerTest { function test_Reverts_WhenAlreadyInitialized() public virtual { vm.expectRevert("contract already initialized"); - epochManager.initialize(REGISTRY_ADDRESS, 10, carbonOffsettingPartner, epochManagerSystemInitializer); + epochManager.initialize( + REGISTRY_ADDRESS, + 10, + carbonOffsettingPartner, + epochManagerSystemInitializer + ); } } @@ -180,23 +201,28 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } function test_Reverts_WhenEpochProcessingAlreadyStarted() public { - vm.prank(epochManagerSystemInitializer); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + // vm.prank(epochManagerSystemInitializer); + // epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - blockTravel(vm, 43200); - timeTravel(vm, DAY); + // blockTravel(vm, 43200); + // timeTravel(vm, DAY); + initializeEpochManagerSystem(); epochManager.startNextEpochProcess(); vm.expectRevert("Epoch process is already started"); epochManager.startNextEpochProcess(); } - function test_SetsTheEpochRewardBlock() public { - vm.prank(epochManagerSystemInitializer); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + function test_Emits_EpochProcessingStartedEvent() public { + initializeEpochManagerSystem(); - blockTravel(vm, 43200); - timeTravel(vm, DAY); + vm.expectEmit(true, true, true, true); + emit EpochProcessingStarted(firstEpochNumber); + epochManager.startNextEpochProcess(); + } + + function test_SetsTheEpochRewardBlock() public { + initializeEpochManagerSystem(); epochManager.startNextEpochProcess(); (, , , uint256 _currentRewardsBlock) = epochManager.getCurrentEpoch(); @@ -204,11 +230,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } function test_SetsTheEpochRewardAmounts() public { - vm.prank(epochManagerSystemInitializer); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - - blockTravel(vm, 43200); - timeTravel(vm, DAY); + initializeEpochManagerSystem(); epochManager.startNextEpochProcess(); ( @@ -224,4 +246,25 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { assertEq(totalRewardsCommunity, 5); assertEq(totalRewardsCarbonFund, 5); } + + function test_ShouldMintTotalValidatorStableRewardsToEpochManager() public { + initializeEpochManagerSystem(); + uint256 beforeBalance = stableToken.balanceOf(address(epochManager)); + epochManager.startNextEpochProcess(); + + uint256 afterBalance = stableToken.balanceOf(address(epochManager)); + assertEq(afterBalance, 2); + } + + //XXX(soloseng):This test fails because the mock doesnt actually mint. + // if the actual contract is deployed for testing, the function reverts when calling `getCeloUnreleasedTreasure().release()` + // after getting the celoToken interface from registry + + function skip_test_ShouldReleaseCorrectAmountToReserve() public { + initializeEpochManagerSystem(); + uint256 reserveBalanceBefore = celoToken.balanceOf(reserveAddress); + epochManager.startNextEpochProcess(); + uint256 reserveBalanceAfter = celoToken.balanceOf(reserveAddress); + assertEq(reserveBalanceAfter, reserveBalanceBefore + 4); + } } From d3b1db4dc24b494687ad7e7560368293a8103844 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:52:25 -0400 Subject: [PATCH 12/69] setup anvil migration fix name conflict --- .../contracts-0.8/common/EpochManager.sol | 19 ++++----- ...nitializer.sol => EpochManagerEnabler.sol} | 3 +- .../contracts-0.8/common/ScoreManager.sol | 4 +- .../IEpochManagerEnablerInitializer.sol | 6 +++ .../interfaces/IEpochManagerInitializer.sol | 11 +++++ .../interfaces/IScoreManagerInitializer.sol | 6 +++ .../interfaces/IEpochManagerEnabler.sol | 7 ++++ .../protocol/migrations_sol/Migration.s.sol | 41 +++++++++++++++++++ .../protocol/migrations_sol/constants.sol | 7 +++- .../migrations_sol/migrationsConfig.json | 4 ++ .../integration/EpochManagerIntegration.sol | 27 ++++++------ .../test-sol/unit/common/EpochManager.t.sol | 30 +++++--------- 12 files changed, 117 insertions(+), 48 deletions(-) rename packages/protocol/contracts-0.8/common/{EpochManagerSystemInitializer.sol => EpochManagerEnabler.sol} (92%) create mode 100644 packages/protocol/contracts-0.8/common/interfaces/IEpochManagerEnablerInitializer.sol create mode 100644 packages/protocol/contracts-0.8/common/interfaces/IEpochManagerInitializer.sol create mode 100644 packages/protocol/contracts-0.8/common/interfaces/IScoreManagerInitializer.sol create mode 100644 packages/protocol/contracts/common/interfaces/IEpochManagerEnabler.sol diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 07c3d13dab0..db240d8f373 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -58,7 +58,7 @@ contract EpochManager is mapping(address => uint256) public validatorPendingPayments; address public carbonOffsettingPartner; - address public EpochManagerSystemInitializer; + address public epochManagerEnabler; /** * @notice Event emited when epochProcessing has begun. @@ -72,8 +72,8 @@ contract EpochManager is */ event EpochProcessingEnded(uint256 indexed epochNumber); - modifier onlyEpochManagerSystemInitializer() { - require(msg.sender == epochManagerSystemInitializer, "msg.sender is not Initializer"); + modifier onlyEpochManagerEnabler() { + require(msg.sender == epochManagerEnabler, "msg.sender is not Initializer"); _; } @@ -92,14 +92,14 @@ contract EpochManager is address registryAddress, uint256 newEpochDuration, address _carbonOffsettingPartner, - address _epochManagerSystemInitializer + address _epochManagerEnabler ) external initializer { - require(_epochManagerSystemInitializer != address(0), "EpochManagerSystemInitializer address is required"); + require(_epochManagerEnabler != address(0), "EpochManagerEnabler address is required"); _transferOwnership(msg.sender); setRegistry(registryAddress); setEpochDuration(newEpochDuration); carbonOffsettingPartner = _carbonOffsettingPartner; - epochManagerSystemInitializer = _epochManagerSystemInitializer; + epochManagerEnabler = _epochManagerEnabler; } // DESIGNDESICION(XXX): we assume that the first epoch on the L2 starts as soon as the system is initialized @@ -109,7 +109,7 @@ contract EpochManager is uint256 firstEpochNumber, uint256 firstEpochBlock, address[] memory firstElected - ) external onlyEpochManagerSystemInitializer { + ) external onlyEpochManagerEnabler { require(!systemAlreadyInitialized(), "Epoch system already initialized"); require(firstEpochNumber > 0, "First epoch number must be greater than 0"); require(firstEpochBlock > 0, "First epoch block must be greater than 0"); @@ -126,7 +126,7 @@ contract EpochManager is _currentEpoch.startTimestamp = block.timestamp; elected = firstElected; - epochManagerSystemInitializer = address(0); + epochManagerEnabler = address(0); } // TODO maybe "freezeEpochRewards" "prepareForNextEpoch" @@ -290,7 +290,7 @@ contract EpochManager is } function systemAlreadyInitialized() public view returns (bool) { - return initialized && epochManagerSystemInitializer == address(0); + return initialized && epochManagerEnabler == address(0); } function allocateValidatorsRewards() internal { @@ -318,7 +318,6 @@ contract EpochManager is ); uint256 CELOequivalent = (numerator * totalRewards) / denominator; - // this is not a mint anymore getCeloUnreleasedTreasure().release( registry.getAddressForOrDie(RESERVE_REGISTRY_ID), CELOequivalent diff --git a/packages/protocol/contracts-0.8/common/EpochManagerSystemInitializer.sol b/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol similarity index 92% rename from packages/protocol/contracts-0.8/common/EpochManagerSystemInitializer.sol rename to packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol index 1e150446e00..f94c5370704 100644 --- a/packages/protocol/contracts-0.8/common/EpochManagerSystemInitializer.sol +++ b/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol @@ -6,9 +6,10 @@ import "../common/UsingPrecompiles.sol"; import "../../contracts/common/Initializable.sol"; import "../../contracts/common/interfaces/ICeloVersionedContract.sol"; +import "../../contracts/common/interfaces/IEpochManagerEnabler.sol"; import "../../contracts/governance/interfaces/IEpochRewards.sol"; -contract EpochManagerSystemInitializer is Initializable, UsingPrecompiles, UsingRegistry { +contract EpochManagerEnabler is Initializable, UsingPrecompiles, UsingRegistry { /** * @notice Sets initialized == true on implementation contracts * @param test Set to true to skip implementation initialization diff --git a/packages/protocol/contracts-0.8/common/ScoreManager.sol b/packages/protocol/contracts-0.8/common/ScoreManager.sol index d91705cdf65..c8075d52733 100644 --- a/packages/protocol/contracts-0.8/common/ScoreManager.sol +++ b/packages/protocol/contracts-0.8/common/ScoreManager.sol @@ -16,10 +16,8 @@ contract ScoreManager is Initializable, Ownable { /** * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. - * @param registryAddress The address of the registry core smart contract. - * @param newEpochDuration The duration of an epoch in seconds. */ - function initialize(address registryAddress, uint256 newEpochDuration) external initializer { + function initialize() external initializer { _transferOwnership(msg.sender); } diff --git a/packages/protocol/contracts-0.8/common/interfaces/IEpochManagerEnablerInitializer.sol b/packages/protocol/contracts-0.8/common/interfaces/IEpochManagerEnablerInitializer.sol new file mode 100644 index 00000000000..3643d5ec711 --- /dev/null +++ b/packages/protocol/contracts-0.8/common/interfaces/IEpochManagerEnablerInitializer.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.5.13 <0.9.0; + +interface IEpochManagerEnablerInitializer { + function initialize(address registryAddress) external; +} diff --git a/packages/protocol/contracts-0.8/common/interfaces/IEpochManagerInitializer.sol b/packages/protocol/contracts-0.8/common/interfaces/IEpochManagerInitializer.sol new file mode 100644 index 00000000000..119e2f8616e --- /dev/null +++ b/packages/protocol/contracts-0.8/common/interfaces/IEpochManagerInitializer.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.5.13 <0.9.0; + +interface IEpochManagerInitializer { + function initialize( + address registryAddress, + uint256 newEpochDuration, + address _carbonOffsettingPartner, + address _epochManagerEnabler + ) external; +} diff --git a/packages/protocol/contracts-0.8/common/interfaces/IScoreManagerInitializer.sol b/packages/protocol/contracts-0.8/common/interfaces/IScoreManagerInitializer.sol new file mode 100644 index 00000000000..f6229cf72b5 --- /dev/null +++ b/packages/protocol/contracts-0.8/common/interfaces/IScoreManagerInitializer.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.5.13 <0.9.0; + +interface IScoreManagerInitializer { + function initialize() external; +} diff --git a/packages/protocol/contracts/common/interfaces/IEpochManagerEnabler.sol b/packages/protocol/contracts/common/interfaces/IEpochManagerEnabler.sol new file mode 100644 index 00000000000..bfd969402f9 --- /dev/null +++ b/packages/protocol/contracts/common/interfaces/IEpochManagerEnabler.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.5.13 <0.9.0; + +interface IEpochManagerEnabler { + function initEpochManager() external; + function getEpochNumber() external returns (uint256); +} diff --git a/packages/protocol/migrations_sol/Migration.s.sol b/packages/protocol/migrations_sol/Migration.s.sol index 049adef1507..af04e4d4fe6 100644 --- a/packages/protocol/migrations_sol/Migration.s.sol +++ b/packages/protocol/migrations_sol/Migration.s.sol @@ -50,6 +50,9 @@ import "@celo-contracts/stability/interfaces/ISortedOracles.sol"; import "@celo-contracts-8/common/interfaces/IFeeCurrencyDirectoryInitializer.sol"; import "@celo-contracts-8/common/interfaces/IGasPriceMinimumInitializer.sol"; import "@celo-contracts-8/common/interfaces/ICeloUnreleasedTreasureInitializer.sol"; +import "@celo-contracts-8/common/interfaces/IEpochManagerEnablerInitializer.sol"; +import "@celo-contracts-8/common/interfaces/IEpochManagerInitializer.sol"; +import "@celo-contracts-8/common/interfaces/IScoreManagerInitializer.sol"; import "@celo-contracts-8/common/interfaces/IFeeCurrencyDirectory.sol"; import "@celo-contracts-8/common/UsingRegistry.sol"; @@ -228,6 +231,9 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { migrateFeeHandler(json); migrateOdisPayments(); migrateCeloUnreleasedTreasure(); + migrateEpochManagerEnabler(); + migrateEpochManager(json); + migrateScoreManager(); migrateGovernance(json); vm.stopBroadcast(); @@ -920,6 +926,41 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { ); } + function migrateEpochManagerEnabler() public { + deployProxiedContract( + "EpochManagerEnabler", + abi.encodeWithSelector(IEpochManagerEnablerInitializer.initialize.selector, REGISTRY_ADDRESS) + ); + } + function migrateScoreManager() public { + deployProxiedContract( + "ScoreManager", + abi.encodeWithSelector(IScoreManagerInitializer.initialize.selector) + ); + } + + function migrateEpochManager(string memory json) public { + address carbonOffsettingPartner = abi.decode( + json.parseRaw(".epochManager.carbonOffsettingPartner"), + (address) + ); + address newEpochDuration = abi.decode( + json.parseRaw(".epochManager.newEpochDuration"), + (address) + ); + + deployProxiedContract( + "EpochManager", + abi.encodeWithSelector( + IEpochManagerInitializer.initialize.selector, + REGISTRY_ADDRESS, + newEpochDuration, + carbonOffsettingPartner, + registry.getAddressForString("EpochManagerEnabler") + ) + ); + } + function migrateGovernance(string memory json) public { bool useApprover = abi.decode(json.parseRaw(".governanceApproverMultiSig.required"), (bool)); diff --git a/packages/protocol/migrations_sol/constants.sol b/packages/protocol/migrations_sol/constants.sol index cf4ff6c0526..0c9cf6c7f20 100644 --- a/packages/protocol/migrations_sol/constants.sol +++ b/packages/protocol/migrations_sol/constants.sol @@ -7,7 +7,7 @@ contract MigrationsConstants is TestConstants { address constant DEPLOYER_ACCOUNT = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; // List of contracts that are expected to be in Registry.sol - string[24] contractsInRegistry = [ + string[27] contractsInRegistry = [ "Accounts", "BlockchainParameters", "CeloUnreleasedTreasure", @@ -16,6 +16,8 @@ contract MigrationsConstants is TestConstants { "DowntimeSlasher", "Election", "EpochRewards", + "EpochManagerEnabler", + "EpochManager", "Escrow", "FederatedAttestations", "FeeCurrencyWhitelist", @@ -31,6 +33,7 @@ contract MigrationsConstants is TestConstants { "SortedOracles", "UniswapFeeHandlerSeller", "MentoFeeHandlerSeller", - "Validators" + "Validators", + "ScoreManager" ]; } diff --git a/packages/protocol/migrations_sol/migrationsConfig.json b/packages/protocol/migrations_sol/migrationsConfig.json index 54c5e208267..f5bceca3910 100644 --- a/packages/protocol/migrations_sol/migrationsConfig.json +++ b/packages/protocol/migrations_sol/migrationsConfig.json @@ -110,6 +110,10 @@ "carbonOffsettingFraction": 1000000000000000000000, "frozen": false }, + "epochManager": { + "newEpochDuration":86400, + "carbonOffsettingPartner": "0x0000000000000000000000000000000000000000" + }, "random": { "randomnessBlockRetentionWindow": "720", "randomnessBlockRetentionWindow_helper": "HOUR / 5" diff --git a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol index c2e2b51b604..3261158c415 100644 --- a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol +++ b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol @@ -6,6 +6,7 @@ import "@celo-contracts-8/common/EpochManager.sol"; // import "@celo-contracts-8/common/interfaces/ICeloToken.sol"; import "@celo-contracts-8/common/ScoreManager.sol"; +import "@celo-contracts-8/common/EpochManagerEnabler.sol"; import "@celo-contracts-8/common/CeloUnreleasedTreasure.sol"; import "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; @@ -36,7 +37,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { ValidatorsMock08 validators; MockElection08 election; - address epochManagerSystemInitializer; + // address epochManagerEnabler; address carbonOffsettingPartner; address communityRewardFund; @@ -50,6 +51,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { IFreezer freezer; CeloUnreleasedTreasure celoUnreleasedTreasure; ScoreManager scoreManager; + EpochManagerEnabler epochManagerEnabler; uint256 celoAmountForRate = 1e24; uint256 stableAmountForRate = 2 * celoAmountForRate; @@ -82,6 +84,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { function setUp() public virtual { epochManager = new EpochManager(true); + epochManagerEnabler = new EpochManagerEnabler(true); sortedOracles = new MockSortedOracles(); election = new MockElection08(); @@ -100,7 +103,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { address epochRewardsAddress = actor("epochRewardsAddress"); address freezerAddress = actor("freezerAddress"); - epochManagerSystemInitializer = actor("epochManagerSystemInitializer"); + // epochManagerEnabler = actor("epochManagerEnabler"); carbonOffsettingPartner = actor("carbonOffsettingPartner"); communityRewardFund = actor("communityRewardFund"); @@ -131,9 +134,9 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { registry.setAddressFor(FreezerContract, address(freezer)); celoToken.setTotalSupply(CELO_SUPPLY_CAP); - // election.setTotalVotes(5); + election.setTotalVotes(5); vm.deal(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); - // vm.deal(address(reserve), 69411663406170917420347916); // current as of 08/20/24 + vm.deal(address(reserve), 69411663406170917420347916); // current as of 08/20/24 bool res1 = sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); (uint256 res0, uint256 res00) = sortedOracles.medianRate(address(stableToken)); @@ -164,7 +167,7 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { REGISTRY_ADDRESS, DAY, carbonOffsettingPartner, - epochManagerSystemInitializer + address(epochManagerEnabler) ); blockTravel(vm, firstEpochBlock); @@ -186,20 +189,21 @@ contract EpochManagerIntegrationTest_initialize is EpochManagerIntegrationTest { REGISTRY_ADDRESS, DAY, carbonOffsettingPartner, - epochManagerSystemInitializer + address(epochManagerEnabler) ); } } contract EpochManagerIntegrationTest_initializeSystem is EpochManagerIntegrationTest { function test_processCanBeStarted() public virtual { - vm.prank(epochManagerSystemInitializer); + vm.prank(address(epochManagerEnabler)); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); } function test_Reverts_processCannotBeStartedAgain() public virtual { - vm.prank(epochManagerSystemInitializer); + vm.prank(address(epochManagerEnabler)); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); + vm.prank(address(0)); vm.expectRevert("Epoch system already initialized"); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); @@ -218,7 +222,7 @@ contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegr } function test_Reverts_WhenEndOfEpochHasNotBeenReached() public { - vm.prank(epochManagerSystemInitializer); + vm.prank(address(epochManagerEnabler)); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); vm.expectRevert("Epoch is not ready to start"); @@ -226,7 +230,7 @@ contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegr } function test_Succeeds() public { - vm.prank(epochManagerSystemInitializer); + vm.prank(address(epochManagerEnabler)); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); blockTravel(vm, 43200); @@ -238,8 +242,7 @@ contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegr epochManager.startNextEpochProcess(); - (, , , uint256 _currentRewardsBlock) = epochManager - .getCurrentEpoch(); + (, , , uint256 _currentRewardsBlock) = epochManager.getCurrentEpoch(); console2.log("### Done"); assertEq(_currentRewardsBlock, block.number - 1); diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index a7e2357632f..769adac5d0d 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -29,7 +29,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { EpochRewardsMock08 epochRewards; ValidatorsMock08 validators; - address epochManagerSystemInitializer; + address epochManagerEnabler; address carbonOffsettingPartner; address communityRewardFund; address reserveAddress; @@ -81,7 +81,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { reserveAddress = actor("reserve"); - epochManagerSystemInitializer = actor("epochManagerSystemInitializer"); + epochManagerEnabler = actor("epochManagerEnabler"); carbonOffsettingPartner = actor("carbonOffsettingPartner"); communityRewardFund = actor("communityRewardFund"); @@ -115,14 +115,14 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { REGISTRY_ADDRESS, epochDuration, carbonOffsettingPartner, - epochManagerSystemInitializer + epochManagerEnabler ); blockTravel(vm, firstEpochBlock); } function initializeEpochManagerSystem() public { - vm.prank(epochManagerSystemInitializer); + vm.prank(epochManagerEnabler); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); blockTravel(vm, 43200); @@ -135,23 +135,18 @@ contract EpochManagerTest_initialize is EpochManagerTest { assertEq(address(epochManager.registry()), REGISTRY_ADDRESS); assertEq(epochManager.epochDuration(), epochDuration); assertEq(epochManager.carbonOffsettingPartner(), carbonOffsettingPartner); - assertEq(epochManager.epochManagerSystemInitializer(), epochManagerSystemInitializer); + assertEq(epochManager.epochManagerEnabler(), epochManagerEnabler); } function test_Reverts_WhenAlreadyInitialized() public virtual { vm.expectRevert("contract already initialized"); - epochManager.initialize( - REGISTRY_ADDRESS, - 10, - carbonOffsettingPartner, - epochManagerSystemInitializer - ); + epochManager.initialize(REGISTRY_ADDRESS, 10, carbonOffsettingPartner, epochManagerEnabler); } } contract EpochManagerTest_initializeSystem is EpochManagerTest { function test_processCanBeStarted() public virtual { - vm.prank(epochManagerSystemInitializer); + vm.prank(epochManagerEnabler); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); ( uint256 _firstEpochBlock, @@ -159,7 +154,7 @@ contract EpochManagerTest_initializeSystem is EpochManagerTest { uint256 _startTimestamp, uint256 _currentRewardsBlock ) = epochManager.getCurrentEpoch(); - assertEq(epochManager.epochManagerSystemInitializer(), address(0)); + assertEq(epochManager.epochManagerEnabler(), address(0)); assertEq(epochManager.firstKnownEpoch(), firstEpochNumber); assertEq(_firstEpochBlock, firstEpochBlock); assertEq(_lastEpochBlock, 0); @@ -169,7 +164,7 @@ contract EpochManagerTest_initializeSystem is EpochManagerTest { } function test_Reverts_processCannotBeStartedAgain() public virtual { - vm.prank(epochManagerSystemInitializer); + vm.prank(epochManagerEnabler); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); vm.prank(address(0)); vm.expectRevert("Epoch system already initialized"); @@ -191,7 +186,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } function test_Reverts_WhenEndOfEpochHasNotBeenReached() public { - vm.prank(epochManagerSystemInitializer); + vm.prank(epochManagerEnabler); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); uint256 _currentEpoch = epochManager.currentEpochNumber(); @@ -201,11 +196,6 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } function test_Reverts_WhenEpochProcessingAlreadyStarted() public { - // vm.prank(epochManagerSystemInitializer); - // epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - - // blockTravel(vm, 43200); - // timeTravel(vm, DAY); initializeEpochManagerSystem(); epochManager.startNextEpochProcess(); From 2ba9360fbefcc5d6185e678b0bc7a4dd1878449b Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:16:32 -0400 Subject: [PATCH 13/69] compiles --- .../common/test/MockEpochManager.sol | 14 ++++---------- .../common/interfaces/IEpochManager.sol | 4 ++-- .../integration/EpochManagerIntegration.sol | 17 ++--------------- .../unit/common/CeloUnreleasedTreasure.t.sol | 4 ++-- 4 files changed, 10 insertions(+), 29 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol b/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol index 8efb865a15b..4125c9c5843 100644 --- a/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol +++ b/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol @@ -22,7 +22,7 @@ contract MockEpochManager is IEpochManager { uint256 public firstKnownEpoch; uint256 private currentEpochNumber; address[] public elected; - address public epochManagerInitializer; + address public epochManagerEnabler; bool initialized; mapping(uint256 => Epoch) private epochs; @@ -45,7 +45,7 @@ contract MockEpochManager is IEpochManager { elected = firstElected; initialized = true; - epochManagerInitializer = address(0); + epochManagerEnabler = address(0); } function startNextEpochProcess() external {} @@ -55,16 +55,10 @@ contract MockEpochManager is IEpochManager { address[] calldata greaters ) external {} - function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256, uint256) { + function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256) { Epoch storage _epoch = epochs[currentEpochNumber]; - return ( - _epoch.firstBlock, - _epoch.lastBlock, - _epoch.startTimestamp, - _epoch.endTimestamp, - _epoch.rewardsBlock - ); + return (_epoch.firstBlock, _epoch.lastBlock, _epoch.startTimestamp, _epoch.rewardsBlock); } function getCurrentEpochNumber() external view returns (uint256) { diff --git a/packages/protocol/contracts/common/interfaces/IEpochManager.sol b/packages/protocol/contracts/common/interfaces/IEpochManager.sol index 964187f9f53..b140a5e17ed 100644 --- a/packages/protocol/contracts/common/interfaces/IEpochManager.sol +++ b/packages/protocol/contracts/common/interfaces/IEpochManager.sol @@ -14,9 +14,9 @@ interface IEpochManager { address[] calldata lessers, address[] calldata greaters ) external; - function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256, uint256); + function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256); function getCurrentEpochNumber() external view returns (uint256); function getElected() external view returns (address[] memory); - function epochManagerInitializer() external view returns (address); + function epochManagerEnabler() external view returns (address); function epochDuration() external view returns (uint256); } diff --git a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol index 3261158c415..6ae70a9496b 100644 --- a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol +++ b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol @@ -20,7 +20,7 @@ import "@celo-contracts/common/interfaces/IFreezer.sol"; import "@celo-contracts/governance/interfaces/IEpochRewards.sol"; import "@celo-contracts/governance/interfaces/IEpochRewardsInitializer.sol"; -import { ValidatorsMock08 } from "@celo-contracts-8/governance/test/ValidatorsMock.sol"; +import { ValidatorsMock08 } from "@celo-contracts-8/governance/test/ValidatorsMock08.sol"; import { MockElection08 } from "@celo-contracts-8/governance/test/MockElection.sol"; import { MockReserve08 } from "@celo-contracts-8/stability/test/MockReserve.sol"; import { MockStableToken08 } from "@celo-contracts-8/stability/test/MockStableToken.sol"; @@ -56,19 +56,6 @@ contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { uint256 celoAmountForRate = 1e24; uint256 stableAmountForRate = 2 * celoAmountForRate; - uint256 constant L1_MINTED_CELO_SUPPLY = 692702432463315819704447326; // as of May 15 2024 - - uint256 constant CELO_SUPPLY_CAP = 1000000000 ether; // 1 billion Celo - uint256 constant GENESIS_CELO_SUPPLY = 600000000 ether; // 600 million Celo - - uint256 constant FIFTEEN_YEAR_LINEAR_REWARD = (CELO_SUPPLY_CAP - GENESIS_CELO_SUPPLY) / 2; // 200 million Celo - - uint256 constant FIFTEEN_YEAR_CELO_SUPPLY = GENESIS_CELO_SUPPLY + FIFTEEN_YEAR_LINEAR_REWARD; // 800 million Celo (includes GENESIS_CELO_SUPPLY) - - uint256 constant MAX_L2_DISTRIBUTION = FIFTEEN_YEAR_CELO_SUPPLY - L1_MINTED_CELO_SUPPLY; // 107.2 million Celo - - uint256 constant L2_INITIAL_STASH_BALANCE = FIFTEEN_YEAR_LINEAR_REWARD + MAX_L2_DISTRIBUTION; // leftover from L1 target supply plus the 2nd 15 year term. - uint256 constant targetVotingYieldParamsInitial = 0.00016e24; // 0.00016 uint256 constant targetVotingYieldParamsMax = 0.0005e24; // 0.0005 uint256 constant targetVotingYieldParamsAdjustmentFactor = 1127990000000000000; // 0.00000112799 @@ -237,7 +224,7 @@ contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegr timeTravel(vm, DAY); console2.log("current epoch timestamp", block.timestamp); - uint256 _currentEpoch = epochManager.currentEpochNumber(); + uint256 _currentEpoch = epochManager.getCurrentEpochNumber(); console2.log("### Current epoch duration:", epochManager.epochDuration()); epochManager.startNextEpochProcess(); diff --git a/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol b/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol index 71dc7f727db..953b7d7a113 100644 --- a/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol +++ b/packages/protocol/test-sol/unit/common/CeloUnreleasedTreasure.t.sol @@ -73,11 +73,11 @@ contract CeloUnreleasedTreasureTest is Test, TestConstants, IsL2Check { registry.setAddressFor("EpochManager", address(epochManagerAddress)); vm.deal(address(0), CELO_SUPPLY_CAP); - assertEq(celoToken.totalSupply(), 0, "starting total supply not zero."); + assertEq(celoToken.allocatedSupply(), 0, "starting total supply not zero."); // Mint L1 supply vm.prank(address(0)); celoToken.mint(randomAddress, L1_MINTED_CELO_SUPPLY); - assertEq(celoToken.totalSupply(), L1_MINTED_CELO_SUPPLY, "total supply incorrect."); + assertEq(celoToken.allocatedSupply(), L1_MINTED_CELO_SUPPLY, "total supply incorrect."); } function newCeloUnreleasedTreasure() internal returns (CeloUnreleasedTreasure) { From 35b637ad7462ee9d0bc3bcea2dfd0588d2f34d62 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:17:20 -0400 Subject: [PATCH 14/69] ++ require fund in unreleased treasury --- packages/protocol/contracts-0.8/common/EpochManager.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index e9720ac630f..41884623050 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -111,6 +111,11 @@ contract EpochManager is uint256 firstEpochBlock, address[] memory firstElected ) external onlyEpochManagerEnabler { + require( + getCeloToken().balanceOf(registry.getAddressForOrDie(CELO_UNRELEASED_TREASURE_REGISTRY_ID)) > + 0, + "CeloUnreleasedTreasury not yet funded." + ); require(!systemAlreadyInitialized(), "Epoch system already initialized"); require(firstEpochNumber > 0, "First epoch number must be greater than 0"); require(firstEpochBlock > 0, "First epoch block must be greater than 0"); From c02c0a45ecf51f4a946ffa483185abeba11b498f Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:47:33 -0400 Subject: [PATCH 15/69] Updated regex --- packages/protocol/test-sol/utils/ECDSAHelper.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/test-sol/utils/ECDSAHelper.sol b/packages/protocol/test-sol/utils/ECDSAHelper.sol index cd85d52cccd..aaa7c1119ae 100644 --- a/packages/protocol/test-sol/utils/ECDSAHelper.sol +++ b/packages/protocol/test-sol/utils/ECDSAHelper.sol @@ -13,7 +13,7 @@ contract ECDSAHelper is Test { bytes32 _s ) public returns (bytes memory) { address SECP256K1Address = actor("SECP256K1Address"); - deployCodeTo("out/SECP256K1.sol/SECP256K1.0.5.17.json", SECP256K1Address); + deployCodeTo("SECP256K1.sol:SECP256K1", SECP256K1Address); sECP256K1 = ISECP256K1(SECP256K1Address); string memory header = "\x19Ethereum Signed Message:\n32"; From 92ac7cf8ddc88cacca7c5741cdf8afb6c09d55ea Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:53:02 -0400 Subject: [PATCH 16/69] ++ registry 0.8 for testing only --- .../contracts-0.8/common/Registry.sol | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 packages/protocol/contracts-0.8/common/Registry.sol diff --git a/packages/protocol/contracts-0.8/common/Registry.sol b/packages/protocol/contracts-0.8/common/Registry.sol new file mode 100644 index 00000000000..62804534aec --- /dev/null +++ b/packages/protocol/contracts-0.8/common/Registry.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.7 <0.8.20; + +import "@openzeppelin/contracts8/utils/math/SafeMath.sol"; +import "@openzeppelin/contracts8/access/Ownable.sol"; + +import "../../contracts/common/interfaces/IRegistry.sol"; +import "../../contracts/common/interfaces/IRegistryInitializer.sol"; +import "../../contracts/common/Initializable.sol"; + +/** + * @title Routes identifiers to addresses. + */ +contract Registry is IRegistry, IRegistryInitializer, Ownable, Initializable { + using SafeMath for uint256; + + mapping(bytes32 => address) public registry; + + event RegistryUpdated(string identifier, bytes32 indexed identifierHash, address indexed addr); + + /** + * @notice Sets initialized == true on implementation contracts + * @param test Set to true to skip implementation initialization + */ + constructor(bool test) public Initializable(test) {} + + /** + * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. + */ + function initialize() external initializer { + _transferOwnership(msg.sender); + } + + /** + * @notice Associates the given address with the given identifier. + * @param identifier Identifier of contract whose address we want to set. + * @param addr Address of contract. + */ + function setAddressFor(string calldata identifier, address addr) external onlyOwner { + bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); + registry[identifierHash] = addr; + emit RegistryUpdated(identifier, identifierHash, addr); + } + + /** + * @notice Gets address associated with the given identifierHash. + * @param identifierHash Identifier hash of contract whose address we want to look up. + * @dev Throws if address not set. + */ + function getAddressForOrDie(bytes32 identifierHash) external view returns (address) { + require(registry[identifierHash] != address(0), "identifier has no registry entry"); + return registry[identifierHash]; + } + + /** + * @notice Gets address associated with the given identifierHash. + * @param identifierHash Identifier hash of contract whose address we want to look up. + */ + function getAddressFor(bytes32 identifierHash) external view returns (address) { + return registry[identifierHash]; + } + + /** + * @notice Gets address associated with the given identifier. + * @param identifier Identifier of contract whose address we want to look up. + * @dev Throws if address not set. + */ + function getAddressForStringOrDie(string calldata identifier) external view returns (address) { + bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); + require(registry[identifierHash] != address(0), "identifier has no registry entry"); + return registry[identifierHash]; + } + + /** + * @notice Gets address associated with the given identifier. + * @param identifier Identifier of contract whose address we want to look up. + */ + function getAddressForString(string calldata identifier) external view returns (address) { + bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); + return registry[identifierHash]; + } + + /** + * @notice Iterates over provided array of identifiers, getting the address for each. + * Returns true if `sender` matches the address of one of the provided identifiers. + * @param identifierHashes Array of hashes of approved identifiers. + * @param sender Address in question to verify membership. + * @return True if `sender` corresponds to the address of any of `identifiers` + * registry entries. + */ + function isOneOf( + bytes32[] calldata identifierHashes, + address sender + ) external view returns (bool) { + for (uint256 i = 0; i < identifierHashes.length; i = i.add(1)) { + if (registry[identifierHashes[i]] == sender) { + return true; + } + } + return false; + } +} From f50ac8b42f882ba57badb4db2715dcb4d54dcdad Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:54:18 -0400 Subject: [PATCH 17/69] clean up --- packages/protocol/test-sol/unit/common/EpochManager.t.sol | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index a3e174d26da..d513e02a509 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -42,7 +42,6 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { IRegistry registry; MockCeloToken08 celoToken; - // CeloUnreleasedTreasure celoUnreleasedTreasure; MockCeloUnreleasedTreasure celoUnreleasedTreasure; ScoreManager scoreManager; @@ -58,7 +57,6 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { validators = new ValidatorsMock08(); stableToken = new MockStableToken08(); celoToken = new MockCeloToken08(); - // celoUnreleasedTreasure = new CeloUnreleasedTreasure(true); celoUnreleasedTreasure = new MockCeloUnreleasedTreasure(); firstElected.push(actor("validator1")); @@ -174,9 +172,6 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { vm.prank(epochManagerEnabler); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - // uint256 _currentEpoch = epochManager.getCurrentEpochNumber(); - // (, , , uint256 _currentEpochEndTimestamp, ) = epochManager.getCurrentEpoch(); - vm.expectRevert("Epoch is not ready to start"); epochManager.startNextEpochProcess(); } From 3aa816c87b11bdfa9e1ce9c741b69b2f77d9675c Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:33:18 -0400 Subject: [PATCH 18/69] ++ unit test --- .../contracts-0.8/common/CeloUnreleasedTreasure.sol | 4 +--- .../common/test/MockCeloUnreleasedTreasure.sol | 8 ++++++-- packages/protocol/lib/registry-utils.ts | 3 +++ packages/protocol/test-sol/unit/common/EpochManager.t.sol | 8 +++----- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol b/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol index 71328251405..d2b263536d3 100644 --- a/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol +++ b/packages/protocol/contracts-0.8/common/CeloUnreleasedTreasure.sol @@ -9,7 +9,6 @@ import "../common/IsL2Check.sol"; import "../../contracts/common/Initializable.sol"; import "./interfaces/ICeloUnreleasedTreasureInitializer.sol"; -import "@openzeppelin/contracts8/token/ERC20/IERC20.sol"; /** * @title Contract for unreleased Celo tokens. @@ -48,8 +47,7 @@ contract CeloUnreleasedTreasure is UsingRegistry, ReentrancyGuard, Initializable */ function release(address to, uint256 amount) external onlyEpochManager { require(address(this).balance >= amount, "Insufficient balance."); - IERC20 celoToken = getCeloToken(); - require(celoToken.transfer(to, amount), "CELO transfer failed."); + require(getCeloToken().transfer(to, amount), "CELO transfer failed."); emit Released(to, amount); } diff --git a/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol b/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol index 3fb25ac173b..ef7c127eb24 100644 --- a/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol +++ b/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol @@ -2,10 +2,14 @@ pragma solidity >=0.8.0 <0.9.0; // solhint-disable no-unused-vars import "../../../contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; +import "../UsingRegistry.sol"; /** * @title A mock CeloDistributionSchedule for testing. */ -contract MockCeloUnreleasedTreasure is ICeloUnreleasedTreasure { - function release(address to, uint256 amount) external {} +contract MockCeloUnreleasedTreasure is ICeloUnreleasedTreasure, UsingRegistry { + function release(address to, uint256 amount) external { + require(address(this).balance >= amount, "Insufficient balance."); + require(getCeloToken().transfer(to, amount), "CELO transfer failed."); + } } diff --git a/packages/protocol/lib/registry-utils.ts b/packages/protocol/lib/registry-utils.ts index 5b565848913..df9e5f79a6d 100644 --- a/packages/protocol/lib/registry-utils.ts +++ b/packages/protocol/lib/registry-utils.ts @@ -19,6 +19,9 @@ export enum CeloContractName { DowntimeSlasher = 'DowntimeSlasher', Election = 'Election', EpochRewards = 'EpochRewards', + EpochManagerEnabler = 'EpochManagerEnabler', + EpochManager = 'EpochManager', + ScoreManager = 'ScoreManager', Escrow = 'Escrow', Exchange = 'Exchange', ExchangeEUR = 'ExchangeEUR', diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index d513e02a509..6930d5a1283 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -92,6 +92,8 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { vm.deal(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); celoToken.setBalanceOf(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); + celoUnreleasedTreasure.setRegistry(REGISTRY_ADDRESS); + sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); scoreManager.setValidatorScore(actor("validator1"), 1); @@ -227,11 +229,7 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { assertEq(afterBalance, 2); } - //XXX(soloseng):This test fails because the mock doesnt actually mint. - // if the actual contract is deployed for testing, the function reverts when calling `getCeloUnreleasedTreasure().release()` - // after getting the celoToken interface from registry - - function skip_test_ShouldReleaseCorrectAmountToReserve() public { + function test_ShouldReleaseCorrectAmountToReserve() public { initializeEpochManagerSystem(); uint256 reserveBalanceBefore = celoToken.balanceOf(reserveAddress); epochManager.startNextEpochProcess(); From 180162bb97a5c59a395910232d24a13b7ba9cd63 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:40:42 -0400 Subject: [PATCH 19/69] initial integration test using L1 devchain --- .../devchain/migration/Migration.t.sol | 139 +++++++++++++++++- 1 file changed, 133 insertions(+), 6 deletions(-) diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index c5c141a1114..f4754a5dd15 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -1,19 +1,29 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.7 <0.8.20; +pragma solidity >=0.5.13 <0.8.20; -import { Test } from "forge-std-8/Test.sol"; -import "forge-std-8/console2.sol"; +import "celo-foundry-8/Test.sol"; +import { Utils08 } from "@test-sol/utils08.sol"; import { TestConstants } from "@test-sol/constants.sol"; import { MigrationsConstants } from "@migrations-sol/constants.sol"; import "@celo-contracts/common/interfaces/IRegistry.sol"; import "@celo-contracts/common/interfaces/IProxy.sol"; +import "@celo-contracts/common/interfaces/ICeloToken.sol"; +import "@celo-contracts/common/interfaces/IAccounts.sol"; +import "@celo-contracts/common/interfaces/IEpochManager.sol"; +import "@celo-contracts/common/interfaces/IEpochManagerEnabler.sol"; -contract IntegrationTest is Test, TestConstants { +import "@celo-contracts/governance/interfaces/IValidators.sol"; + +import "@celo-contracts-8/common/interfaces/IPrecompiles.sol"; + +contract IntegrationTest is Test, TestConstants, Utils08 { IRegistry registry = IRegistry(REGISTRY_ADDRESS); - function setUp() public {} + uint256 constant RESERVE_BALANCE = 69411663406170917420347916; // current as of 08/20/24 + + function setUp() public virtual {} /** * @notice Removes CBOR encoded metadata from the tail of the deployedBytecode. @@ -70,6 +80,7 @@ contract RegistryIntegrationTest is IntegrationTest, MigrationsConstants { bytes32 hashValidators = keccak256(abi.encodePacked("Validators")); bytes32 hashCeloToken = keccak256(abi.encodePacked("CeloToken")); bytes32 hashLockedCelo = keccak256(abi.encodePacked("LockedCelo")); + bytes32 hashEpochManager = keccak256(abi.encodePacked("EpochManager")); for (uint256 i = 0; i < contractsInRegistry.length; i++) { // Read name from list of core contracts @@ -89,7 +100,8 @@ contract RegistryIntegrationTest is IntegrationTest, MigrationsConstants { hashContractName != hashSortedOracles && hashContractName != hashValidators && hashContractName != hashCeloToken && // TODO: remove once GoldToken contract has been renamed to CeloToken - hashContractName != hashLockedCelo // TODO: remove once LockedGold contract has been renamed to LockedCelo + hashContractName != hashLockedCelo && // TODO: remove once LockedGold contract has been renamed to LockedCelo + hashContractName != hashEpochManager ) { // Get proxy address registered in the Registry address proxyAddress = registry.getAddressForStringOrDie(contractName); @@ -123,3 +135,118 @@ contract RegistryIntegrationTest is IntegrationTest, MigrationsConstants { } } } + +contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { + ICeloToken celoToken; + IAccounts accountsContract; + IValidators validatorsContract; + IEpochManager epochManager; + IEpochManagerEnabler epochManagerEnabler; + + address reserveAddress; + address unreleasedTreasury; + address randomAddress; + + uint256 firstEpochNumber = 100; + uint256 firstEpochBlock = 100; + address[] firstElected; + address[] validatorsList; + + function setUp() public override { + super.setUp(); + randomAddress = actor("randomAddress"); + + validatorsContract = IValidators(registry.getAddressForStringOrDie("Validators")); + + validatorsList = validatorsContract.getRegisteredValidators(); + + unreleasedTreasury = registry.getAddressForStringOrDie("CeloUnreleasedTreasure"); + reserveAddress = registry.getAddressForStringOrDie("Reserve"); + + // mint to the reserve + celoToken = ICeloToken(registry.getAddressForStringOrDie("GoldToken")); + + vm.deal(address(0), CELO_SUPPLY_CAP); + vm.prank(address(0)); + celoToken.mint(reserveAddress, RESERVE_BALANCE); + + vm.prank(address(0)); + celoToken.mint(randomAddress, L1_MINTED_CELO_SUPPLY - RESERVE_BALANCE); // mint outstanding l1 supply before L2. + + epochManager = IEpochManager(registry.getAddressForStringOrDie("EpochManager")); + epochManagerEnabler = IEpochManagerEnabler( + registry.getAddressForStringOrDie("EpochManagerEnabler") + ); + } + + function test_IsSetupCorrect() public { + assertEq( + registry.getAddressForStringOrDie("EpochManagerEnabler"), + epochManager.epochManagerEnabler() + ); + assertEq( + registry.getAddressForStringOrDie("EpochManagerEnabler"), + address(epochManagerEnabler) + ); + assertEq(address(epochManagerEnabler), epochManager.epochManagerEnabler()); + } + + function test_Reverts_whenSystemNotInitialized() public { + vm.expectRevert("Epoch system not initialized"); + epochManager.startNextEpochProcess(); + } + + function test_Reverts_WhenEndOfEpochHasNotBeenReached() public { + // fund treasury + vm.prank(address(0)); + celoToken.mint(unreleasedTreasury, L2_INITIAL_STASH_BALANCE); + + uint256 l1EpochNumber = IPrecompiles(address(validatorsContract)).getEpochNumber(); + + vm.prank(address(epochManagerEnabler)); + epochManager.initializeSystem(l1EpochNumber, block.number, validatorsList); + + vm.expectRevert("Epoch is not ready to start"); + epochManager.startNextEpochProcess(); + } + + function test_Reverts_whenAlreadyInitialized() public { + _MockL2Migration(validatorsList); + + vm.prank(address(0)); + vm.expectRevert("Epoch system already initialized"); + epochManager.initializeSystem(100, block.number, firstElected); + } + + function test_SetsCurrentRewardBlock() public { + _MockL2Migration(validatorsList); + + blockTravel(vm, 43200); + timeTravel(vm, DAY); + + uint256 _currentEpoch = epochManager.getCurrentEpochNumber(); + + epochManager.startNextEpochProcess(); + + (, , , uint256 _currentRewardsBlock) = epochManager.getCurrentEpoch(); + + assertEq(_currentRewardsBlock, block.number - 1); + } + + function _MockL2Migration(address[] memory _validatorsList) internal { + for (uint256 i = 0; i < _validatorsList.length; i++) { + firstElected.push(_validatorsList[i]); + } + + uint256 l1EpochNumber = IPrecompiles(address(validatorsContract)).getEpochNumber(); + + vm.prank(address(0)); + celoToken.mint(unreleasedTreasury, L2_INITIAL_STASH_BALANCE); + + deployCodeTo("Registry.sol", abi.encode(false), PROXY_ADMIN_ADDRESS); + + vm.prank(address(epochManagerEnabler)); + + epochManager.initializeSystem(l1EpochNumber, block.number, firstElected); + } +} From 22946ff2f0757fa5f99f1742f6308e6da6b1392a Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:42:46 -0400 Subject: [PATCH 20/69] ++ comment --- packages/protocol/test-sol/devchain/migration/Migration.t.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index f4754a5dd15..a2098d4e81f 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -218,6 +218,7 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { epochManager.initializeSystem(100, block.number, firstElected); } + // XXX(soloseng): fails because EpochManager is not yet permissioned by stableToken to mint function test_SetsCurrentRewardBlock() public { _MockL2Migration(validatorsList); From 0ed7e930c1d4b1e3e0c45553042a3dd02f6edebb Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:44:50 -0400 Subject: [PATCH 21/69] -- forge based integration test --- .../integration/EpochManagerIntegration.sol | 237 ------------------ 1 file changed, 237 deletions(-) delete mode 100644 packages/protocol/test-sol/integration/EpochManagerIntegration.sol diff --git a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol b/packages/protocol/test-sol/integration/EpochManagerIntegration.sol deleted file mode 100644 index 6ae70a9496b..00000000000 --- a/packages/protocol/test-sol/integration/EpochManagerIntegration.sol +++ /dev/null @@ -1,237 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.7 <0.8.20; - -import "celo-foundry-8/Test.sol"; -import "@celo-contracts-8/common/EpochManager.sol"; - -// import "@celo-contracts-8/common/interfaces/ICeloToken.sol"; -import "@celo-contracts-8/common/ScoreManager.sol"; -import "@celo-contracts-8/common/EpochManagerEnabler.sol"; -import "@celo-contracts-8/common/CeloUnreleasedTreasure.sol"; -import "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; - -import { TestConstants } from "@test-sol/constants.sol"; -import { Utils08 } from "@test-sol/utils08.sol"; - -import "@celo-contracts/stability/test/MockSortedOracles.sol"; - -import "@celo-contracts/common/interfaces/IRegistry.sol"; -import "@celo-contracts/common/interfaces/IFreezer.sol"; -import "@celo-contracts/governance/interfaces/IEpochRewards.sol"; -import "@celo-contracts/governance/interfaces/IEpochRewardsInitializer.sol"; - -import { ValidatorsMock08 } from "@celo-contracts-8/governance/test/ValidatorsMock08.sol"; -import { MockElection08 } from "@celo-contracts-8/governance/test/MockElection.sol"; -import { MockReserve08 } from "@celo-contracts-8/stability/test/MockReserve.sol"; -import { MockStableToken08 } from "@celo-contracts-8/stability/test/MockStableToken.sol"; -import { MockCeloToken08 } from "@celo-contracts-8/common/test/MockCeloToken.sol"; - -contract EpochManagerIntegrationTest is Test, TestConstants, Utils08 { - EpochManager epochManager; - MockSortedOracles sortedOracles; - - MockStableToken08 stableToken; - MockCeloToken08 celoToken; - MockReserve08 reserve; - - ValidatorsMock08 validators; - MockElection08 election; - - // address epochManagerEnabler; - address carbonOffsettingPartner; - address communityRewardFund; - - uint256 firstEpochNumber = 100; - uint256 firstEpochBlock = 100; - address[] firstElected; - - IRegistry registry; - IEpochRewards epochRewards; - IEpochRewardsInitializer epochRewardsInitializer; - IFreezer freezer; - CeloUnreleasedTreasure celoUnreleasedTreasure; - ScoreManager scoreManager; - EpochManagerEnabler epochManagerEnabler; - - uint256 celoAmountForRate = 1e24; - uint256 stableAmountForRate = 2 * celoAmountForRate; - - uint256 constant targetVotingYieldParamsInitial = 0.00016e24; // 0.00016 - uint256 constant targetVotingYieldParamsMax = 0.0005e24; // 0.0005 - uint256 constant targetVotingYieldParamsAdjustmentFactor = 1127990000000000000; // 0.00000112799 - - uint256 constant rewardsMultiplierMax = 2 * FIXED1; // 2 - uint256 constant rewardsMultiplierAdjustmentsUnderspend = 0.5e24; // 0.5 - uint256 constant rewardsMultiplierAdjustmentsOverspend = 5e24; // 5 - - uint256 constant targetVotingGoldFraction = (2 * FIXED1) / uint256(3); - uint256 constant targetValidatorEpochPayment = 1e13; - uint256 constant communityRewardFraction = FIXED1 / 4; - uint256 constant carbonOffsettingFraction = FIXED1 / 200; - - function setUp() public virtual { - epochManager = new EpochManager(true); - epochManagerEnabler = new EpochManagerEnabler(true); - sortedOracles = new MockSortedOracles(); - - election = new MockElection08(); - validators = new ValidatorsMock08(); - reserve = new MockReserve08(); - stableToken = new MockStableToken08(); - celoToken = new MockCeloToken08(); - - celoUnreleasedTreasure = new CeloUnreleasedTreasure(false); - - firstElected.push(actor("validator1")); - firstElected.push(actor("validator2")); - - // address celoTokenAddress = actor("celoTokenAddress"); - address scoreManagerAddress = actor("scoreManagerAddress"); - address epochRewardsAddress = actor("epochRewardsAddress"); - address freezerAddress = actor("freezerAddress"); - - // epochManagerEnabler = actor("epochManagerEnabler"); - carbonOffsettingPartner = actor("carbonOffsettingPartner"); - communityRewardFund = actor("communityRewardFund"); - - deployCodeTo("Registry.sol", abi.encode(false), REGISTRY_ADDRESS); - // deployCodeTo("GoldToken.sol", abi.encode(false), celoTokenAddress); - deployCodeTo("ScoreManager.sol", abi.encode(false), scoreManagerAddress); - deployCodeTo("Freezer.sol", abi.encode(false), freezerAddress); - deployCodeTo("EpochRewards.sol", abi.encode(true), epochRewardsAddress); - - registry = IRegistry(REGISTRY_ADDRESS); - // celoToken = IERC20(celoTokenAddress); - epochRewardsInitializer = IEpochRewardsInitializer(epochRewardsAddress); - epochRewards = IEpochRewards(epochRewardsAddress); - freezer = IFreezer(freezerAddress); - scoreManager = ScoreManager(scoreManagerAddress); - - registry.setAddressFor(EpochManagerContract, address(epochManager)); - registry.setAddressFor(SortedOraclesContract, address(sortedOracles)); - registry.setAddressFor(GovernanceContract, communityRewardFund); - registry.setAddressFor(EpochRewardsContract, address(epochRewards)); - registry.setAddressFor(ValidatorsContract, address(validators)); - registry.setAddressFor(ScoreManagerContract, address(scoreManager)); - registry.setAddressFor(StableTokenContract, address(stableToken)); - registry.setAddressFor(CeloTokenContract, address(celoToken)); - registry.setAddressFor(CeloUnreleasedTreasureContract, address(celoUnreleasedTreasure)); - registry.setAddressFor(ReserveContract, address(reserve)); - registry.setAddressFor(ElectionContract, address(election)); - registry.setAddressFor(FreezerContract, address(freezer)); - - celoToken.setTotalSupply(CELO_SUPPLY_CAP); - election.setTotalVotes(5); - vm.deal(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); - vm.deal(address(reserve), 69411663406170917420347916); // current as of 08/20/24 - - bool res1 = sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); - (uint256 res0, uint256 res00) = sortedOracles.medianRate(address(stableToken)); - - scoreManager.setValidatorScore(actor("validator1"), 1); - uint256 res = scoreManager.getValidatorScore(actor("validator1")); - - epochRewardsInitializer.initialize( - address(registry), - targetVotingYieldParamsInitial, - targetVotingYieldParamsMax, - targetVotingYieldParamsAdjustmentFactor, - rewardsMultiplierMax, - rewardsMultiplierAdjustmentsUnderspend, - rewardsMultiplierAdjustmentsOverspend, - targetVotingGoldFraction, - targetValidatorEpochPayment, - communityRewardFraction, - address(0), - carbonOffsettingFraction - ); - - uint256 res2 = epochRewards.getCommunityRewardFraction(); - - console2.log("### res2", res2); - - epochManager.initialize( - REGISTRY_ADDRESS, - DAY, - carbonOffsettingPartner, - address(epochManagerEnabler) - ); - - blockTravel(vm, firstEpochBlock); - // makes sure test know this is L2. - deployCodeTo("Registry.sol", abi.encode(false), PROXY_ADMIN_ADDRESS); - } -} - -contract EpochManagerIntegrationTest_initialize is EpochManagerIntegrationTest { - function test_initialize() public virtual { - assertEq(address(epochManager.registry()), REGISTRY_ADDRESS); - assertEq(epochManager.epochDuration(), DAY); - assertEq(epochManager.carbonOffsettingPartner(), carbonOffsettingPartner); - } - - function test_Reverts_WhenAlreadyInitialized() public virtual { - vm.expectRevert("contract already initialized"); - epochManager.initialize( - REGISTRY_ADDRESS, - DAY, - carbonOffsettingPartner, - address(epochManagerEnabler) - ); - } -} - -contract EpochManagerIntegrationTest_initializeSystem is EpochManagerIntegrationTest { - function test_processCanBeStarted() public virtual { - vm.prank(address(epochManagerEnabler)); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - } - - function test_Reverts_processCannotBeStartedAgain() public virtual { - vm.prank(address(epochManagerEnabler)); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - - vm.prank(address(0)); - vm.expectRevert("Epoch system already initialized"); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - } - - function test_Reverts_WhenSystemInitializedByOtherContract() public virtual { - vm.expectRevert("msg.sender is not Initializer"); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - } -} - -contract EpochManagerIntegrationTest_startNextEpochProcess is EpochManagerIntegrationTest { - function test_Reverts_whenSystemNotInitialized() public { - vm.expectRevert("Epoch system not initialized"); - epochManager.startNextEpochProcess(); - } - - function test_Reverts_WhenEndOfEpochHasNotBeenReached() public { - vm.prank(address(epochManagerEnabler)); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - - vm.expectRevert("Epoch is not ready to start"); - epochManager.startNextEpochProcess(); - } - - function test_Succeeds() public { - vm.prank(address(epochManagerEnabler)); - epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); - - blockTravel(vm, 43200); - timeTravel(vm, DAY); - console2.log("current epoch timestamp", block.timestamp); - - uint256 _currentEpoch = epochManager.getCurrentEpochNumber(); - console2.log("### Current epoch duration:", epochManager.epochDuration()); - - epochManager.startNextEpochProcess(); - - (, , , uint256 _currentRewardsBlock) = epochManager.getCurrentEpoch(); - - console2.log("### Done"); - assertEq(_currentRewardsBlock, block.number - 1); - } -} From 8f0ea64e80791e17fc66269adeef66e24f472e5c Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 27 Aug 2024 19:34:51 -0400 Subject: [PATCH 22/69] ++ to const --- packages/protocol/scripts/consts.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/protocol/scripts/consts.ts b/packages/protocol/scripts/consts.ts index 729b0dfb276..d0edb652342 100644 --- a/packages/protocol/scripts/consts.ts +++ b/packages/protocol/scripts/consts.ts @@ -58,6 +58,7 @@ export const CoreContracts = [ 'Election', 'EpochRewards', 'EpochManager', + 'EpochManagerEnabler', 'Governance', 'GovernanceApproverMultiSig', 'BlockchainParameters', From cfa7cdb99744926ff85597839ca1e5cafbf3d759 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 28 Aug 2024 09:01:31 -0400 Subject: [PATCH 23/69] happy linter --- .../protocol/contracts-0.8/governance/test/MockElection.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/protocol/contracts-0.8/governance/test/MockElection.sol b/packages/protocol/contracts-0.8/governance/test/MockElection.sol index 4e0379a4b68..043a2af095e 100644 --- a/packages/protocol/contracts-0.8/governance/test/MockElection.sol +++ b/packages/protocol/contracts-0.8/governance/test/MockElection.sol @@ -3,8 +3,6 @@ pragma solidity >=0.8.7 <0.8.20; import "../../../contracts-0.8/common/IsL2Check.sol"; - - /** * @title Holds a list of addresses of validators */ From cdf7aea590a88493af3a1523490af3cd82d4c2fa Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:47:52 -0400 Subject: [PATCH 24/69] update contract name --- .../contracts-0.8/common/{Registry.sol => Registry08.sol} | 2 +- .../contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol | 2 +- packages/protocol/test-sol/devchain/migration/Migration.t.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename packages/protocol/contracts-0.8/common/{Registry.sol => Registry08.sol} (97%) diff --git a/packages/protocol/contracts-0.8/common/Registry.sol b/packages/protocol/contracts-0.8/common/Registry08.sol similarity index 97% rename from packages/protocol/contracts-0.8/common/Registry.sol rename to packages/protocol/contracts-0.8/common/Registry08.sol index 62804534aec..63a8d769486 100644 --- a/packages/protocol/contracts-0.8/common/Registry.sol +++ b/packages/protocol/contracts-0.8/common/Registry08.sol @@ -11,7 +11,7 @@ import "../../contracts/common/Initializable.sol"; /** * @title Routes identifiers to addresses. */ -contract Registry is IRegistry, IRegistryInitializer, Ownable, Initializable { +contract Registry08 is IRegistry, IRegistryInitializer, Ownable, Initializable { using SafeMath for uint256; mapping(bytes32 => address) public registry; diff --git a/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol b/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol index ef7c127eb24..8aecc77331d 100644 --- a/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol +++ b/packages/protocol/contracts-0.8/common/test/MockCeloUnreleasedTreasure.sol @@ -5,7 +5,7 @@ import "../../../contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; import "../UsingRegistry.sol"; /** - * @title A mock CeloDistributionSchedule for testing. + * @title A mock CeloUnreleasedTreasure for testing. */ contract MockCeloUnreleasedTreasure is ICeloUnreleasedTreasure, UsingRegistry { function release(address to, uint256 amount) external { diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index a2098d4e81f..f4a297b0934 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -244,7 +244,7 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { vm.prank(address(0)); celoToken.mint(unreleasedTreasury, L2_INITIAL_STASH_BALANCE); - deployCodeTo("Registry.sol", abi.encode(false), PROXY_ADMIN_ADDRESS); + deployCodeTo("Registry08.sol", abi.encode(false), PROXY_ADMIN_ADDRESS); vm.prank(address(epochManagerEnabler)); From 4b709d313e67ca4c10b00ec7ac62b4f2eebf5d48 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 29 Aug 2024 12:42:43 +0200 Subject: [PATCH 25/69] Adding truffle migrations --- packages/protocol/contractPackages.ts | 5 +- .../proxies/EpochManagerEnablerProxy.sol | 6 +++ .../common/proxies/EpochManagerProxy.sol | 6 +++ .../common/proxies/ScoreManagerProxy.sol | 6 +++ packages/protocol/lib/proxy-utils.ts | 46 +++++++++++-------- packages/protocol/lib/web3-utils.ts | 6 +++ .../protocol/migrations_ts/29_governance.ts | 2 +- .../migrations_ts/3_1_score_manager.ts | 18 ++++++++ .../3_2_epoch_manager_enabler.ts | 20 ++++++++ .../migrations_ts/3_3_epoch_manager.ts | 28 +++++++++++ 10 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 packages/protocol/contracts/common/proxies/EpochManagerEnablerProxy.sol create mode 100644 packages/protocol/contracts/common/proxies/EpochManagerProxy.sol create mode 100644 packages/protocol/contracts/common/proxies/ScoreManagerProxy.sol create mode 100644 packages/protocol/migrations_ts/3_1_score_manager.ts create mode 100644 packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts create mode 100644 packages/protocol/migrations_ts/3_3_epoch_manager.ts diff --git a/packages/protocol/contractPackages.ts b/packages/protocol/contractPackages.ts index 177ec1b6baa..7e0ee0776d8 100644 --- a/packages/protocol/contractPackages.ts +++ b/packages/protocol/contractPackages.ts @@ -48,13 +48,16 @@ export const SOLIDITY_08_PACKAGE = { proxiesPath: '/', // Proxies are still with 0.5 contracts // Proxies shouldn't have to be added to a list manually // https://github.com/celo-org/celo-monorepo/issues/10555 - contracts: ['GasPriceMinimum', 'FeeCurrencyDirectory', 'CeloUnreleasedTreasure', 'Validators'], + contracts: ['GasPriceMinimum', 'FeeCurrencyDirectory', 'CeloUnreleasedTreasure', 'Validators', 'EpochManager', 'EpochManagerEnabler', 'ScoreManager'], proxyContracts: [ 'GasPriceMinimumProxy', 'FeeCurrencyDirectoryProxy', 'MentoFeeCurrencyAdapterV1', 'CeloUnreleasedTreasureProxy', 'ValidatorsProxy', + 'EpochManagerProxy', + 'EpochManagerEnablerProxy', + 'ScoreManagerProxy', ], truffleConfig: 'truffle-config0.8.js', } satisfies ContractPackage diff --git a/packages/protocol/contracts/common/proxies/EpochManagerEnablerProxy.sol b/packages/protocol/contracts/common/proxies/EpochManagerEnablerProxy.sol new file mode 100644 index 00000000000..ddd10f3cd43 --- /dev/null +++ b/packages/protocol/contracts/common/proxies/EpochManagerEnablerProxy.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.5.13; + +import "../Proxy.sol"; + +/* solhint-disable-next-line no-empty-blocks */ +contract EpochManagerEnablerProxy is Proxy {} diff --git a/packages/protocol/contracts/common/proxies/EpochManagerProxy.sol b/packages/protocol/contracts/common/proxies/EpochManagerProxy.sol new file mode 100644 index 00000000000..7f5fc943e37 --- /dev/null +++ b/packages/protocol/contracts/common/proxies/EpochManagerProxy.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.5.13; + +import "../Proxy.sol"; + +/* solhint-disable-next-line no-empty-blocks */ +contract EpochManagerProxy is Proxy {} diff --git a/packages/protocol/contracts/common/proxies/ScoreManagerProxy.sol b/packages/protocol/contracts/common/proxies/ScoreManagerProxy.sol new file mode 100644 index 00000000000..d46446ee16b --- /dev/null +++ b/packages/protocol/contracts/common/proxies/ScoreManagerProxy.sol @@ -0,0 +1,6 @@ +pragma solidity ^0.5.13; + +import "../Proxy.sol"; + +/* solhint-disable-next-line no-empty-blocks */ +contract ScoreManagerProxy is Proxy {} diff --git a/packages/protocol/lib/proxy-utils.ts b/packages/protocol/lib/proxy-utils.ts index a2bd042271e..a24bd1fe688 100644 --- a/packages/protocol/lib/proxy-utils.ts +++ b/packages/protocol/lib/proxy-utils.ts @@ -42,27 +42,33 @@ export async function setAndInitializeImplementation( }, ...args: any[] ) { - const callData = web3.eth.abi.encodeFunctionCall(initializerAbi, args) - if (txOptions.from != null) { - // The proxied contract needs to be funded prior to initialization - if (txOptions.value != null) { - // Proxy's fallback fn expects the contract's implementation to be set already - // So we set the implementation first, send the funding, and then set and initialize again. - await retryTx(proxy._setImplementation, [implementationAddress, { from: txOptions.from }]) - await retryTx(web3.eth.sendTransaction, [ - { - from: txOptions.from, - to: proxy.address, - value: txOptions.value, - }, + try { + + + const callData = web3.eth.abi.encodeFunctionCall(initializerAbi, args) + if (txOptions.from != null) { + // The proxied contract needs to be funded prior to initialization + if (txOptions.value != null) { + // Proxy's fallback fn expects the contract's implementation to be set already + // So we set the implementation first, send the funding, and then set and initialize again. + await retryTx(proxy._setImplementation, [implementationAddress, { from: txOptions.from }]) + await retryTx(web3.eth.sendTransaction, [ + { + from: txOptions.from, + to: proxy.address, + value: txOptions.value, + }, + ]) + } + return retryTx(proxy._setAndInitializeImplementation, [ + implementationAddress, + callData as any, + { from: txOptions.from }, ]) + } else { + return retryTx(proxy._setAndInitializeImplementation, [implementationAddress, callData as any]) } - return retryTx(proxy._setAndInitializeImplementation, [ - implementationAddress, - callData as any, - { from: txOptions.from }, - ]) - } else { - return retryTx(proxy._setAndInitializeImplementation, [implementationAddress, callData as any]) + } catch (error) { + console.log("errror", error); } } diff --git a/packages/protocol/lib/web3-utils.ts b/packages/protocol/lib/web3-utils.ts index 0f1f3869704..ebaae5d256a 100644 --- a/packages/protocol/lib/web3-utils.ts +++ b/packages/protocol/lib/web3-utils.ts @@ -207,6 +207,12 @@ export async function _setInitialProxyImplementation< return receipt.tx } +export const getProxiedContract = async (contractName: string, contractPackage: ContractPackage) => { + const artifactsObject = ArtifactsSingleton.getInstance(contractPackage, artifacts) + /* eslint-disable-next-line */ + return await getDeployedProxiedContract(contractName, artifactsObject) +} + export async function getDeployedProxiedContract( contractName: string, customArtifacts: any diff --git a/packages/protocol/migrations_ts/29_governance.ts b/packages/protocol/migrations_ts/29_governance.ts index 3cbf66bc7b3..db6b106d4d0 100644 --- a/packages/protocol/migrations_ts/29_governance.ts +++ b/packages/protocol/migrations_ts/29_governance.ts @@ -129,7 +129,7 @@ module.exports = deploymentForCoreContract( __contractPackage: MENTO_PACKAGE, }, { - contracts: ['GasPriceMinimum', 'Validators'], + contracts: ['GasPriceMinimum', 'Validators', 'EpochManager', 'ScoreManager', 'EpochManagerEnabler'], __contractPackage: SOLIDITY_08_PACKAGE, }, ] diff --git a/packages/protocol/migrations_ts/3_1_score_manager.ts b/packages/protocol/migrations_ts/3_1_score_manager.ts new file mode 100644 index 00000000000..88fca40159a --- /dev/null +++ b/packages/protocol/migrations_ts/3_1_score_manager.ts @@ -0,0 +1,18 @@ +import { SOLIDITY_08_PACKAGE } from '@celo/protocol/contractPackages' +import { CeloContractName } from '@celo/protocol/lib/registry-utils' +import { deploymentForCoreContract } from '@celo/protocol/lib/web3-utils' +import { ScoreManagerInstance } from 'types/08' + +const initializeArgs = async (): Promise => { + return [ + ] +} + +module.exports = deploymentForCoreContract( + web3, + artifacts, + CeloContractName.ScoreManager, + initializeArgs, + undefined, + SOLIDITY_08_PACKAGE +) diff --git a/packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts b/packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts new file mode 100644 index 00000000000..4a8f02bc531 --- /dev/null +++ b/packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts @@ -0,0 +1,20 @@ +import { SOLIDITY_08_PACKAGE } from '@celo/protocol/contractPackages' +import { CeloContractName } from '@celo/protocol/lib/registry-utils' +import { deploymentForCoreContract } from '@celo/protocol/lib/web3-utils' +import { config } from '@celo/protocol/migrationsConfig' +import { EpochManagerEnablerInstance } from 'types/08' + +const initializeArgs = async (): Promise => { + return [ + config.registry.predeployedProxyAddress, + ] +} + +module.exports = deploymentForCoreContract( + web3, + artifacts, + CeloContractName.EpochManagerEnabler, + initializeArgs, + undefined, + SOLIDITY_08_PACKAGE +) diff --git a/packages/protocol/migrations_ts/3_3_epoch_manager.ts b/packages/protocol/migrations_ts/3_3_epoch_manager.ts new file mode 100644 index 00000000000..0b03925a62e --- /dev/null +++ b/packages/protocol/migrations_ts/3_3_epoch_manager.ts @@ -0,0 +1,28 @@ +import { SOLIDITY_08_PACKAGE } from '@celo/protocol/contractPackages' +import { CeloContractName } from '@celo/protocol/lib/registry-utils' +import { deploymentForCoreContract, getProxiedContract } from '@celo/protocol/lib/web3-utils' +import { config } from '@celo/protocol/migrationsConfig' +import { EpochManagerInstance } from 'types/08' + +const initializeArgs = async (): Promise => { + const epochManagerInitializer = await getProxiedContract( + CeloContractName.EpochManagerEnabler, + SOLIDITY_08_PACKAGE + ) + + return [ + config.registry.predeployedProxyAddress, + config.epochManager.newEpochDuration, + config.epochManager.carbonOffsettingPartner, + epochManagerInitializer.address + ] +} + +module.exports = deploymentForCoreContract( + web3, + artifacts, + CeloContractName.EpochManager, + initializeArgs, + undefined, + SOLIDITY_08_PACKAGE +) From 969f9d3c3319fd967d38632aff4708e0c09c6d2a Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 29 Aug 2024 12:48:56 +0200 Subject: [PATCH 26/69] Fix of L2 Anvil migrations --- .../protocol/migrations_sol/MigrationL2.s.sol | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/protocol/migrations_sol/MigrationL2.s.sol b/packages/protocol/migrations_sol/MigrationL2.s.sol index dde3001ae9f..45878f1bc9e 100644 --- a/packages/protocol/migrations_sol/MigrationL2.s.sol +++ b/packages/protocol/migrations_sol/MigrationL2.s.sol @@ -16,7 +16,7 @@ contract MigrationL2 is Script, MigrationsConstants, UsingRegistry { vm.startBroadcast(DEPLOYER_ACCOUNT); setupUsingRegistry(); - activateCeloUnreleasedTreasure(); + dealToCeloUnreleasedTreasure(); vm.stopBroadcast(); } @@ -26,17 +26,7 @@ contract MigrationL2 is Script, MigrationsConstants, UsingRegistry { setRegistry(REGISTRY_ADDRESS); } - function activateCeloUnreleasedTreasure() public { - uint256 l2StartTime = 1721909903 - 5; // Arbitrarily 5 seconds before last black - uint256 communityRewardFraction = getEpochRewards().getCommunityRewardFraction(); - address carbonOffsettingPartner = 0x22579CA45eE22E2E16dDF72D955D6cf4c767B0eF; - uint256 carbonOffsettingFraction = getEpochRewards().getCarbonOffsettingFraction(); - - getCeloUnreleasedTreasure().activate( - l2StartTime, - communityRewardFraction, - carbonOffsettingPartner, - carbonOffsettingFraction - ); + function dealToCeloUnreleasedTreasure() public { + vm.deal(address(getCeloUnreleasedTreasure()), 1_000_000 ether); } } From 8838c5c57307889f6270a981cf93d85f5c73929b Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 29 Aug 2024 14:34:46 +0200 Subject: [PATCH 27/69] Improved anvil devchain compilation --- packages/protocol/contractPackages.ts | 10 ++++++++- .../common/test/MockCeloToken.sol | 20 ++++++++--------- packages/protocol/foundry.toml | 1 + packages/protocol/migrationsConfig.js | 7 ++++++ .../protocol/migrations_ts/29_governance.ts | 8 ++++++- .../migrations_ts/3_1_score_manager.ts | 3 +-- .../3_2_epoch_manager_enabler.ts | 4 +--- .../migrations_ts/3_3_epoch_manager.ts | 2 +- .../create_and_migrate_anvil_devchain.sh | 4 ++-- .../devchain/Import05Dependencies.sol | 22 +++++++++++++++++++ .../test-sol/devchain/ImportPrecompiles.t.sol | 7 ++++++ 11 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 packages/protocol/test-sol/devchain/Import05Dependencies.sol create mode 100644 packages/protocol/test-sol/devchain/ImportPrecompiles.t.sol diff --git a/packages/protocol/contractPackages.ts b/packages/protocol/contractPackages.ts index 7e0ee0776d8..45e3452ad5e 100644 --- a/packages/protocol/contractPackages.ts +++ b/packages/protocol/contractPackages.ts @@ -48,7 +48,15 @@ export const SOLIDITY_08_PACKAGE = { proxiesPath: '/', // Proxies are still with 0.5 contracts // Proxies shouldn't have to be added to a list manually // https://github.com/celo-org/celo-monorepo/issues/10555 - contracts: ['GasPriceMinimum', 'FeeCurrencyDirectory', 'CeloUnreleasedTreasure', 'Validators', 'EpochManager', 'EpochManagerEnabler', 'ScoreManager'], + contracts: [ + 'GasPriceMinimum', + 'FeeCurrencyDirectory', + 'CeloUnreleasedTreasure', + 'Validators', + 'EpochManager', + 'EpochManagerEnabler', + 'ScoreManager', + ], proxyContracts: [ 'GasPriceMinimumProxy', 'FeeCurrencyDirectoryProxy', diff --git a/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol b/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol index 792193c0b54..8e6892f5d4d 100644 --- a/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol +++ b/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol @@ -34,15 +34,6 @@ contract MockCeloToken08 { return _transfer(from, to, amount); } - function _transfer(address from, address to, uint256 amount) internal returns (bool) { - if (balances[from] < amount) { - return false; - } - balances[from] -= amount; - balances[to] += amount; - return true; - } - function setBalanceOf(address a, uint256 value) external { balances[a] = value; } @@ -54,7 +45,16 @@ contract MockCeloToken08 { function totalSupply() public view returns (uint256) { return totalSupply_; } - function allocatedSupply() public view returns (uint256) { + function allocatedSupply() public pure returns (uint256) { return CELO_SUPPLY_CAP - L2_INITIAL_STASH_BALANCE; } + + function _transfer(address from, address to, uint256 amount) internal returns (bool) { + if (balances[from] < amount) { + return false; + } + balances[from] -= amount; + balances[to] += amount; + return true; + } } diff --git a/packages/protocol/foundry.toml b/packages/protocol/foundry.toml index ed1c21166cc..c934ff7bbbe 100644 --- a/packages/protocol/foundry.toml +++ b/packages/protocol/foundry.toml @@ -37,6 +37,7 @@ fs_permissions = [ ] [profile.devchain] # Special profile for the tests that require an anvil devchain +test = 'test-sol/devchain' match_path = "**/test-sol/devchain/**" no_match_path = "{**/test/BLS12Passthrough.sol,**/test/RandomTest.sol}" diff --git a/packages/protocol/migrationsConfig.js b/packages/protocol/migrationsConfig.js index b8fd53e1e44..6baf43424a7 100644 --- a/packages/protocol/migrationsConfig.js +++ b/packages/protocol/migrationsConfig.js @@ -77,6 +77,10 @@ const DefaultConfig = { carbonOffsettingFraction: 1 / 1000, frozen: false, }, + epochManager: { + newEpochDuration: 100, + carbonOffsettingPartner: '0x0000000000000000000000000000000000000000', + }, exchange: { spread: 5 / 1000, reserveFraction: 1 / 100, @@ -165,6 +169,9 @@ const DefaultConfig = { numRequiredConfirmations: 1, numInternalRequiredConfirmations: 1, }, + scoreManager: { + newEpochDuration: 100, + }, stableToken: { decimals: 18, goldPrice: 1, diff --git a/packages/protocol/migrations_ts/29_governance.ts b/packages/protocol/migrations_ts/29_governance.ts index db6b106d4d0..634f711a5ac 100644 --- a/packages/protocol/migrations_ts/29_governance.ts +++ b/packages/protocol/migrations_ts/29_governance.ts @@ -129,7 +129,13 @@ module.exports = deploymentForCoreContract( __contractPackage: MENTO_PACKAGE, }, { - contracts: ['GasPriceMinimum', 'Validators', 'EpochManager', 'ScoreManager', 'EpochManagerEnabler'], + contracts: [ + 'GasPriceMinimum', + 'Validators', + 'EpochManager', + 'ScoreManager', + 'EpochManagerEnabler', + ], __contractPackage: SOLIDITY_08_PACKAGE, }, ] diff --git a/packages/protocol/migrations_ts/3_1_score_manager.ts b/packages/protocol/migrations_ts/3_1_score_manager.ts index 88fca40159a..93a74670975 100644 --- a/packages/protocol/migrations_ts/3_1_score_manager.ts +++ b/packages/protocol/migrations_ts/3_1_score_manager.ts @@ -4,8 +4,7 @@ import { deploymentForCoreContract } from '@celo/protocol/lib/web3-utils' import { ScoreManagerInstance } from 'types/08' const initializeArgs = async (): Promise => { - return [ - ] + return [] } module.exports = deploymentForCoreContract( diff --git a/packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts b/packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts index 4a8f02bc531..6a9a3d9220f 100644 --- a/packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts +++ b/packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts @@ -5,9 +5,7 @@ import { config } from '@celo/protocol/migrationsConfig' import { EpochManagerEnablerInstance } from 'types/08' const initializeArgs = async (): Promise => { - return [ - config.registry.predeployedProxyAddress, - ] + return [config.registry.predeployedProxyAddress] } module.exports = deploymentForCoreContract( diff --git a/packages/protocol/migrations_ts/3_3_epoch_manager.ts b/packages/protocol/migrations_ts/3_3_epoch_manager.ts index 0b03925a62e..6769b4ac5ed 100644 --- a/packages/protocol/migrations_ts/3_3_epoch_manager.ts +++ b/packages/protocol/migrations_ts/3_3_epoch_manager.ts @@ -14,7 +14,7 @@ const initializeArgs = async (): Promise => { config.registry.predeployedProxyAddress, config.epochManager.newEpochDuration, config.epochManager.carbonOffsettingPartner, - epochManagerInitializer.address + epochManagerInitializer.address, ] } diff --git a/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh b/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh index 0fbbe697958..4e02bef49f2 100755 --- a/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh +++ b/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh @@ -29,8 +29,8 @@ echo "Library flags are: $LIBRARY_FLAGS" # Build all contracts with deployed libraries # Including contracts that depend on libraries. This step replaces the library placeholder # in the bytecode with the address of the actually deployed library. -echo "Compiling with libraries... " -time forge build $LIBRARY_FLAGS +echo "Compiling with libraries..." +time FOUNDRY_PROFILE=devchain forge build $LIBRARY_FLAGS # Deploy precompile contracts source $PWD/scripts/foundry/deploy_precompiles.sh diff --git a/packages/protocol/test-sol/devchain/Import05Dependencies.sol b/packages/protocol/test-sol/devchain/Import05Dependencies.sol new file mode 100644 index 00000000000..a5f83076ca1 --- /dev/null +++ b/packages/protocol/test-sol/devchain/Import05Dependencies.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.5.13; + +// this file only exists so that foundry compiles this contracts +import { Proxy } from "@celo-contracts/common/Proxy.sol"; +import { ProxyFactory } from "@celo-contracts/common/ProxyFactory.sol"; +import { GoldToken } from "@celo-contracts/common/GoldToken.sol"; +import { Accounts } from "@celo-contracts/common/Accounts.sol"; +import { Election } from "@celo-contracts/governance/Election.sol"; +import { Governance } from "@celo-contracts/governance/Governance.sol"; +import { LockedGold } from "@celo-contracts/governance/LockedGold.sol"; +import { GovernanceApproverMultiSig } from "@celo-contracts/governance/GovernanceApproverMultiSig.sol"; +import { Escrow } from "@celo-contracts/identity/Escrow.sol"; +import { FederatedAttestations } from "@celo-contracts/identity/FederatedAttestations.sol"; +import { SortedOracles } from "@celo-contracts/stability/SortedOracles.sol"; +import { ReserveSpenderMultiSig } from "@mento-core/contracts/ReserveSpenderMultiSig.sol"; +import { Reserve } from "@mento-core/contracts/Reserve.sol"; +import { StableToken } from "@mento-core/contracts/StableToken.sol"; +import { StableTokenEUR } from "@mento-core/contracts/StableTokenEUR.sol"; +import { StableTokenBRL } from "@mento-core/contracts/StableTokenBRL.sol"; +import { Exchange } from "@mento-core/contracts/Exchange.sol"; + +contract Import05 {} diff --git a/packages/protocol/test-sol/devchain/ImportPrecompiles.t.sol b/packages/protocol/test-sol/devchain/ImportPrecompiles.t.sol new file mode 100644 index 00000000000..3c0040b0ab2 --- /dev/null +++ b/packages/protocol/test-sol/devchain/ImportPrecompiles.t.sol @@ -0,0 +1,7 @@ +pragma solidity >=0.8.7 <0.8.20; + +// this file only exists so that foundry compiles this contracts +import "@test-sol/precompiles/ProofOfPossesionPrecompile.sol"; +import "@test-sol/precompiles/EpochSizePrecompile.sol"; + +contract ImportPrecompiles {} From 93274c8a2fe400fb9c3ae937aac8ff575b984648 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 29 Aug 2024 15:11:38 +0200 Subject: [PATCH 28/69] Release init params --- .../contracts-0.8/common/EpochManager.sol | 9 +++++++++ .../initializationData/release12.json | 3 ++- .../test-sol/unit/common/EpochManager.t.sol | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 41884623050..3a48e3248cd 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -103,6 +103,15 @@ contract EpochManager is epochManagerEnabler = _epochManagerEnabler; } + /** + * @notice Sets the address of the Epoch Manager Enabler. + * @param _epochManagerEnabler The address of the Epoch Manager Enabler. + */ + function setEpochMangerEnabler(address _epochManagerEnabler) external onlyOwner { + require(_epochManagerEnabler != address(0), "EpochManagerEnabler address is required"); + epochManagerEnabler = _epochManagerEnabler; + } + // DESIGNDESICION(XXX): we assume that the first epoch on the L2 starts as soon as the system is initialized // to minimize amount of "limbo blocks" the network should stop relatively close to an epoch number (but wigh enough time) // to have time to call the function EpochInitializer.migrateEpochAndValidators() diff --git a/packages/protocol/releaseData/initializationData/release12.json b/packages/protocol/releaseData/initializationData/release12.json index 9968a3a2c70..4805f4b66ed 100644 --- a/packages/protocol/releaseData/initializationData/release12.json +++ b/packages/protocol/releaseData/initializationData/release12.json @@ -1,4 +1,5 @@ { "FeeCurrencyDirectory": [], - "CeloUnreleasedTreasure": ["0x000000000000000000000000000000000000ce10"] + "CeloUnreleasedTreasure": ["0x000000000000000000000000000000000000ce10"], + "EpochManager": ["0x000000000000000000000000000000000000ce10", 86400, "0xD533Ca259b330c7A88f74E000a3FaEa2d63B7972", "0x0000000000000000000000000000000000000000"] } diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 6930d5a1283..0e61a98119d 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -34,6 +34,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { address communityRewardFund; address reserveAddress; address scoreManagerAddress; + address nonOwner; uint256 firstEpochNumber = 100; uint256 firstEpochBlock = 100; @@ -69,6 +70,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { epochManagerEnabler = actor("epochManagerEnabler"); carbonOffsettingPartner = actor("carbonOffsettingPartner"); communityRewardFund = actor("communityRewardFund"); + nonOwner = actor("nonOwner"); deployCodeTo("Registry.sol", abi.encode(false), REGISTRY_ADDRESS); @@ -237,3 +239,19 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { assertEq(reserveBalanceAfter, reserveBalanceBefore + 4); } } + + +contract EpochManagerTest_setEpochMangerEnabler is EpochManagerTest { + function test_setEpochMangerEnabler() public { + vm.prank(epochManager.owner()); + address newEpochManagerEnabler = actor("newEpochManagerEnabler"); + epochManager.setEpochMangerEnabler(newEpochManagerEnabler); + assertEq(epochManager.epochManagerEnabler(), newEpochManagerEnabler); + } + + function test_Reverts_WhenNotCalledByEpochManagerEnabler() public { + vm.expectRevert("Ownable: caller is not the owner"); + vm.prank(nonOwner); + epochManager.setEpochMangerEnabler(actor("newEpochManagerEnabler")); + } +} From b49f92953bf6219e89644677898ba0d179334a57 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Thu, 29 Aug 2024 11:26:17 -0400 Subject: [PATCH 29/69] ++ PR feedback --- .../protocol/contracts/governance/Election.sol | 10 +++++++++- .../contracts/governance/EpochRewards.sol | 17 ++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/protocol/contracts/governance/Election.sol b/packages/protocol/contracts/governance/Election.sol index d6b928e6e25..86836975774 100644 --- a/packages/protocol/contracts/governance/Election.sol +++ b/packages/protocol/contracts/governance/Election.sol @@ -153,6 +153,14 @@ contract Election is ); event EpochRewardsDistributedToVoters(address indexed group, uint256 value); + modifier onlyVmOrPermitted(address permittedAddress) { + if (isL2()) require(msg.sender == permittedAddress, "Only permitted address can call"); + else { + require(msg.sender == address(0), "Only VM can call"); + } + _; + } + /** * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. * @param registryAddress The address of the registry core smart contract. @@ -340,7 +348,7 @@ contract Election is uint256 value, address lesser, address greater - ) external onlyVm onlyL1 { + ) external onlyVmOrPermitted(registry.getAddressFor(EPOCH_MANAGER_REGISTRY_ID)) { _distributeEpochRewards(group, value, lesser, greater); } diff --git a/packages/protocol/contracts/governance/EpochRewards.sol b/packages/protocol/contracts/governance/EpochRewards.sol index e04ac3c68c7..774da4f90d9 100644 --- a/packages/protocol/contracts/governance/EpochRewards.sol +++ b/packages/protocol/contracts/governance/EpochRewards.sol @@ -85,12 +85,11 @@ contract EpochRewards is event TargetVotingYieldUpdated(uint256 fraction); - modifier onlyVmOrEpochManager() { - require( - msg.sender == address(0) || - msg.sender == registry.getAddressForOrDie(EPOCH_MANAGER_REGISTRY_ID), - "Only VM or Epoch Manager can call" - ); + modifier onlyVmOrPermitted(address permittedAddress) { + if (isL2()) require(msg.sender == permittedAddress, "Only permitted address can call"); + else { + require(msg.sender == address(0), "Only VM can call"); + } _; } @@ -153,7 +152,11 @@ contract EpochRewards is * voting Gold fraction. * @dev Only called directly by the protocol. */ - function updateTargetVotingYield() external onlyVmOrEpochManager onlyWhenNotFrozen { + function updateTargetVotingYield() + external + onlyVmOrPermitted(registry.getAddressFor(EPOCH_MANAGER_REGISTRY_ID)) + onlyWhenNotFrozen + { _updateTargetVotingYield(); } From 1b616ca1d4a28c56123be8a5e3a3fe96c32129ba Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 10 Sep 2024 13:39:30 -0400 Subject: [PATCH 30/69] ++ checks --- packages/protocol/contracts-0.8/common/EpochManager.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 41884623050..9309beb515f 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -95,6 +95,7 @@ contract EpochManager is address _carbonOffsettingPartner, address _epochManagerEnabler ) external initializer { + require(_carbonOffsettingPartner != address(0), "carbonOffsettingPartner address is required"); require(_epochManagerEnabler != address(0), "EpochManagerEnabler address is required"); _transferOwnership(msg.sender); setRegistry(registryAddress); @@ -111,6 +112,10 @@ contract EpochManager is uint256 firstEpochBlock, address[] memory firstElected ) external onlyEpochManagerEnabler { + require( + address(registry.getAddressForOrDie(CELO_UNRELEASED_TREASURE_REGISTRY_ID)).balance > 0, + "CeloUnreleasedTreasury not yet funded." + ); require( getCeloToken().balanceOf(registry.getAddressForOrDie(CELO_UNRELEASED_TREASURE_REGISTRY_ID)) > 0, @@ -301,7 +306,6 @@ contract EpochManager is } function allocateValidatorsRewards() internal { - // TODO complete this function uint256 totalRewards = 0; IScoreReader scoreReader = getScoreReader(); IValidators validators = getValidators(); From b47dba3a5ce80dc02048bd4ce3fed88960081e31 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Tue, 10 Sep 2024 13:54:36 -0400 Subject: [PATCH 31/69] updated carbon address --- packages/protocol/migrations_sol/migrationsConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/migrations_sol/migrationsConfig.json b/packages/protocol/migrations_sol/migrationsConfig.json index f5bceca3910..8c1c97fb21a 100644 --- a/packages/protocol/migrations_sol/migrationsConfig.json +++ b/packages/protocol/migrations_sol/migrationsConfig.json @@ -112,7 +112,7 @@ }, "epochManager": { "newEpochDuration":86400, - "carbonOffsettingPartner": "0x0000000000000000000000000000000000000000" + "carbonOffsettingPartner": "0xD533Ca259b330c7A88f74E000a3FaEa2d63B7972" }, "random": { "randomnessBlockRetentionWindow": "720", From f34e7e0f4e55af5ecafb3567bf85e4665ad7136f Mon Sep 17 00:00:00 2001 From: pahor167 Date: Wed, 11 Sep 2024 16:48:12 +0200 Subject: [PATCH 32/69] E2E test --- .../contracts-0.8/common/EpochManager.sol | 4 +- .../common/interfaces/IScoreManager.sol | 10 + .../common/test/MockEpochManager.sol | 7 + .../contracts-0.8/governance/Validators.sol | 16 ++ .../governance/test/ValidatorsMock08.sol | 2 + .../common/interfaces/IEpochManager.sol | 6 + .../contracts/governance/Election.sol | 13 +- .../governance/interfaces/IValidators.sol | 3 + .../migrations_sol/migrationsConfig.json | 10 +- .../create_and_migrate_anvil_devchain.sh | 5 +- .../scripts/foundry/run_e2e_tests_in_anvil.sh | 7 +- .../devchain/Import05Dependencies.sol | 5 + .../devchain/e2e/common/EpochManager.t.sol | 192 ++++++++++++++++++ .../protocol/test-sol/devchain/e2e/utils.sol | 19 ++ .../protocol/test-sol/utils/ECDSAHelper08.sol | 34 ++++ packages/protocol/test-sol/utils08.sol | 14 ++ 16 files changed, 334 insertions(+), 13 deletions(-) create mode 100644 packages/protocol/contracts-0.8/common/interfaces/IScoreManager.sol create mode 100644 packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol create mode 100644 packages/protocol/test-sol/utils/ECDSAHelper08.sol diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 3a48e3248cd..d32b157457e 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -225,7 +225,7 @@ contract EpochManager is epochProcessing.totalRewardsCarbonFund ); // run elections - elected = getElection().electNValidatorSigners(10, 20); + elected = getElection().electValidatorSigners(); // TODO check how to nullify stuct epochProcessing.status = EpochProcessStatus.NotStarted; } @@ -326,7 +326,7 @@ contract EpochManager is totalRewards += validatorReward; } // Mint all cUSD required for payment and the corresponding CELO - IStableToken(getStableToken()).mint(address(this), totalRewards); + getValidators().mintStableToken(address(this), totalRewards); // this should have a setter for the oracle. (uint256 numerator, uint256 denominator) = IOracle(address(getSortedOracles())).getExchangeRate( diff --git a/packages/protocol/contracts-0.8/common/interfaces/IScoreManager.sol b/packages/protocol/contracts-0.8/common/interfaces/IScoreManager.sol new file mode 100644 index 00000000000..b06f8c452a4 --- /dev/null +++ b/packages/protocol/contracts-0.8/common/interfaces/IScoreManager.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.5.13 <0.9.0; + +interface IScoreManager { + function setGroupScore(address group, uint256 score) external; + function setValidatorScore(address validator, uint256 score) external; + function getValidatorScore(address validator) external view returns (uint256); + function getGroupScore(address validator) external view returns (uint256); + function owner() external view returns (address); +} diff --git a/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol b/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol index 4125c9c5843..4335e0c8b84 100644 --- a/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol +++ b/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol @@ -67,4 +67,11 @@ contract MockEpochManager is IEpochManager { function getElected() external view returns (address[] memory) { return elected; } + + function getEpochProcessingState() + external + view + returns (uint256, uint256, uint256, uint256, uint256) { + return (0, 0, 0, 0, 0); + } } diff --git a/packages/protocol/contracts-0.8/governance/Validators.sol b/packages/protocol/contracts-0.8/governance/Validators.sol index 68a816edfcb..70e891eecb0 100644 --- a/packages/protocol/contracts-0.8/governance/Validators.sol +++ b/packages/protocol/contracts-0.8/governance/Validators.sol @@ -166,6 +166,11 @@ contract Validators is _; } + modifier onlyEpochManager() { + require(msg.sender == address(getEpochManager()), "Only epoch manager can call"); + _; + } + /** * @notice Sets initialized == true on implementation contracts * @param test Set to true to skip implementation initialization @@ -211,6 +216,17 @@ contract Validators is setDowntimeGracePeriod(initParams.downtimeGracePeriod); } + /** + * @notice Mints stable token to the beneficiary. + * @dev Callable only by epoch manager. + * @param beneficiary The address to mint the stable token to. + * @param amount The amount of stable token to mint. + */ + function mintStableToken(address beneficiary, uint256 amount) external onlyEpochManager { + IStableToken stableToken = IStableToken(getStableToken()); + stableToken.mint(beneficiary, amount); + } + /** * @notice Updates a validator's score based on its uptime for the epoch. * @param signer The validator signer of the validator account whose score needs updating. diff --git a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol index 28857cb69b0..b20e8e6e597 100644 --- a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol +++ b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol @@ -106,6 +106,8 @@ contract ValidatorsMock08 is IValidators { function setSlashingMultiplierResetPeriod(uint256 value) external {} function setDowntimeGracePeriod(uint256 value) external {} + function mintStableToken(address beneficiary, uint256 amount) external {} + // only registered contract function updateEcdsaPublicKey( address account, diff --git a/packages/protocol/contracts/common/interfaces/IEpochManager.sol b/packages/protocol/contracts/common/interfaces/IEpochManager.sol index b140a5e17ed..6d94a842fc3 100644 --- a/packages/protocol/contracts/common/interfaces/IEpochManager.sol +++ b/packages/protocol/contracts/common/interfaces/IEpochManager.sol @@ -19,4 +19,10 @@ interface IEpochManager { function getElected() external view returns (address[] memory); function epochManagerEnabler() external view returns (address); function epochDuration() external view returns (uint256); + function firstKnownEpoch() external view returns (uint256); + function getEpochProcessingState() + external + view + returns (uint256, uint256, uint256, uint256, uint256); + } diff --git a/packages/protocol/contracts/governance/Election.sol b/packages/protocol/contracts/governance/Election.sol index d6b928e6e25..e5277b5b156 100644 --- a/packages/protocol/contracts/governance/Election.sol +++ b/packages/protocol/contracts/governance/Election.sol @@ -153,6 +153,15 @@ contract Election is ); event EpochRewardsDistributedToVoters(address indexed group, uint256 value); + modifier onlyVmOrEpochManager() { + if (isL2()) { + require(msg.sender == address(getEpochManager()), "Only EpochManager can call"); + } else { + require(msg.sender == address(0), "Only VM can call"); + } + _; + } + /** * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. * @param registryAddress The address of the registry core smart contract. @@ -340,7 +349,7 @@ contract Election is uint256 value, address lesser, address greater - ) external onlyVm onlyL1 { + ) external onlyVmOrEpochManager { _distributeEpochRewards(group, value, lesser, greater); } @@ -949,7 +958,7 @@ contract Election is uint256 value, address lesser, address greater - ) internal onlyL1 { + ) internal { if (votes.total.eligible.contains(group)) { uint256 newVoteTotal = votes.total.eligible.getValue(group).add(value); votes.total.eligible.update(group, newVoteTotal, lesser, greater); diff --git a/packages/protocol/contracts/governance/interfaces/IValidators.sol b/packages/protocol/contracts/governance/interfaces/IValidators.sol index 01e16821776..dc1df4edf1d 100644 --- a/packages/protocol/contracts/governance/interfaces/IValidators.sol +++ b/packages/protocol/contracts/governance/interfaces/IValidators.sol @@ -50,6 +50,9 @@ interface IValidators { function forceDeaffiliateIfValidator(address) external; function halveSlashingMultiplier(address) external; + // only EpochManager + function mintStableToken(address beneficiary, uint256 amount) external; + // view functions function maxGroupSize() external view returns (uint256); function downtimeGracePeriod() external view returns (uint256); diff --git a/packages/protocol/migrations_sol/migrationsConfig.json b/packages/protocol/migrations_sol/migrationsConfig.json index f5bceca3910..a505cfef89e 100644 --- a/packages/protocol/migrations_sol/migrationsConfig.json +++ b/packages/protocol/migrations_sol/migrationsConfig.json @@ -89,14 +89,14 @@ }, "epochRewards": { "targetVotingYieldParameters": { - "initial": 0, + "initial": 160000000000000000000, "max": 500000000000000000000, "max_helper": "(x + 1) ^ 365 = 1.20", "adjustmentFactor": 0, "adjustmentFactor_helper": "Change to 1 / 3650 once Mainnet activated." }, "rewardsMultiplierParameters": { - "max": 2, + "max": 2000000000000000000000000, "adjustmentFactors": { "underspend": 500000000000000000000000, "overspend": 5000000000000000000000000 @@ -106,13 +106,13 @@ "maxValidatorEpochPayment": 205479452054794520547, "maxValidatorEpochPayment_helper": "(75,000 / 365) * 10 ^ 18", "communityRewardFraction": 250000000000000000000000, - "carbonOffsettingPartner": "0x0000000000000000000000000000000000000000", + "carbonOffsettingPartner": "0x0000000000000000000000000000000000000001", "carbonOffsettingFraction": 1000000000000000000000, "frozen": false }, "epochManager": { "newEpochDuration":86400, - "carbonOffsettingPartner": "0x0000000000000000000000000000000000000000" + "carbonOffsettingPartner": "0x0000000000000000000000000000000000000001" }, "random": { "randomnessBlockRetentionWindow": "720", @@ -166,4 +166,4 @@ "skipSetConstitution": false, "skipTransferOwnership": false } -} \ No newline at end of file +} diff --git a/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh b/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh index 4e02bef49f2..eda428e1405 100755 --- a/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh +++ b/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh @@ -62,7 +62,10 @@ forge script \ # Keeping track of the finish time to measure how long it takes to run the script entirely ELAPSED_TIME=$(($SECONDS - $START_TIME)) -echo "Total elapsed time: $ELAPSED_TIME seconds" +echo "Migration script total elapsed time: $ELAPSED_TIME seconds" + +# this helps to make sure that devchain state is actually being saved +sleep 1 # Rename devchain artifact and remove unused directory mv $ANVIL_FOLDER/state.json $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME diff --git a/packages/protocol/scripts/foundry/run_e2e_tests_in_anvil.sh b/packages/protocol/scripts/foundry/run_e2e_tests_in_anvil.sh index d515b84e5bc..3ecf3824427 100755 --- a/packages/protocol/scripts/foundry/run_e2e_tests_in_anvil.sh +++ b/packages/protocol/scripts/foundry/run_e2e_tests_in_anvil.sh @@ -8,13 +8,14 @@ source $PWD/scripts/foundry/constants.sh echo "Generating and running devchain before running e2e tests..." source $PWD/scripts/foundry/create_and_migrate_anvil_devchain.sh + # Run e2e tests echo "Running e2e tests..." -forge test \ +time FOUNDRY_PROFILE=devchain forge test \ -vvv \ ---match-path "*test-sol/e2e/*" \ +--match-path "*test-sol/devchain/e2e/*" \ --fork-url $ANVIL_RPC_URL # Stop devchain echo "Stopping devchain..." -source $PWD/scripts/foundry/stop_anvil.sh \ No newline at end of file +source $PWD/scripts/foundry/stop_anvil.sh diff --git a/packages/protocol/test-sol/devchain/Import05Dependencies.sol b/packages/protocol/test-sol/devchain/Import05Dependencies.sol index a5f83076ca1..abda9ed6c3d 100644 --- a/packages/protocol/test-sol/devchain/Import05Dependencies.sol +++ b/packages/protocol/test-sol/devchain/Import05Dependencies.sol @@ -19,4 +19,9 @@ import { StableTokenEUR } from "@mento-core/contracts/StableTokenEUR.sol"; import { StableTokenBRL } from "@mento-core/contracts/StableTokenBRL.sol"; import { Exchange } from "@mento-core/contracts/Exchange.sol"; + +import { IEpochManager } from "@celo-contracts/common/interfaces/IEpochManager.sol"; +import { IValidators } from "@celo-contracts/governance/interfaces/IValidators.sol"; +import "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; + contract Import05 {} diff --git a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol new file mode 100644 index 00000000000..16d24d6b774 --- /dev/null +++ b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.7 <0.8.20; + +import "celo-foundry-8/Test.sol"; +import { Devchain } from "@test-sol/devchain/e2e/utils.sol"; +import { Utils08 } from "@test-sol/utils08.sol"; + +import { IEpochManager } from "@celo-contracts/common/interfaces/IEpochManager.sol"; + +import "@celo-contracts-8/common/FeeCurrencyDirectory.sol"; +import "@test-sol/utils/ECDSAHelper08.sol"; + +contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { + + address epochManagerOwner; + address epochManagerEnabler; + address[] firstElected; + + uint256 epochDuration; + + struct VoterWithPK { + address voter; + uint256 privateKey; + } + + mapping(address => uint256) addressToPrivateKeys; + mapping(address => VoterWithPK) validatorToVoter; + + function setUp() public virtual { + uint256 totalVotes = election.getTotalVotes(); + + epochManagerOwner = Ownable(address(epochManager)).owner(); + epochManagerEnabler = epochManager.epochManagerEnabler(); + firstElected = getValidators().getRegisteredValidators(); + + epochDuration = epochManager.epochDuration(); + + vm.deal(address(celoUnreleasedTreasure), 800_000_000 ether); // 80% of the total supply to the treasure - whis will be yet distributed + } + + function activateValidators() public { + + uint256[] memory valKeys = new uint256[](2); + valKeys[0] = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; + valKeys[1] = 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a; + + for (uint256 i = 0; i < valKeys.length; i++) { + address account = vm.addr(valKeys[i]); + addressToPrivateKeys[account] = valKeys[i]; + } + + + address[] memory registeredValidators = getValidators().getRegisteredValidators(); + for (uint256 i = 0; i < registeredValidators.length; i++) { + (,,address validatorGroup,,) = getValidators().getValidator(registeredValidators[i]); + travelEpochL1(vm); + travelEpochL1(vm); + travelEpochL1(vm); + vm.startPrank(validatorGroup); + election.activate(validatorGroup); + vm.stopPrank(); + } + } + + function authorizeVoteSigner(uint256 signerPk, address account) internal { + bytes32 messageHash = keccak256(abi.encodePacked(account)); + bytes32 prefixedHash = ECDSAHelper08.toEthSignedMessageHash(messageHash); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(signerPk, prefixedHash); + vm.prank(account); + accounts.authorizeVoteSigner(vm.addr(signerPk), v, r, s); + } +} + +contract E2E_EpochManager_InitializeSystem is E2E_EpochManager{ + function setUp() public override { + super.setUp(); + whenL2(vm); + } + + function test_shouldRevert_WhenCalledByNonEnabler() public { + vm.expectRevert("msg.sender is not Initializer"); + epochManager.initializeSystem(1,1, firstElected); + } + + function test_ShouldInitializeSystem() public { + vm.prank(epochManagerEnabler); + epochManager.initializeSystem(42,43, firstElected); + + assertEq(epochManager.firstKnownEpoch(), 42); + assertEq(epochManager.getCurrentEpochNumber(), 42); + + (uint256 firstBlock, uint256 lastBlock, uint256 startTimestamp, uint256 rewardsBlock) = epochManager.getCurrentEpoch(); + assertEq(firstBlock, 43); + assertEq(lastBlock, 0); + assertEq(startTimestamp, block.timestamp); + assertEq(rewardsBlock, 0); + } +} + +contract E2E_EpochManager_StartNextEpochProcess is E2E_EpochManager{ + function setUp() public override { + super.setUp(); + activateValidators(); + whenL2(vm); + + + vm.prank(epochManagerEnabler); + epochManager.initializeSystem(1,1, firstElected); + } + + function test_shouldHaveInitialValues() public { + assertEq(epochManager.firstKnownEpoch(), 1); + assertEq(epochManager.getCurrentEpochNumber(), 1); + + // get getEpochProcessingState + (uint256 status, uint256 perValidatorReward, uint256 totalRewardsVote, uint256 totalRewardsCommunity, uint256 totalRewardsCarbonFund) = epochManager.getEpochProcessingState(); + assertEq(status, 0); // Not started + assertEq(perValidatorReward, 0); + assertEq(totalRewardsVote, 0); + assertEq(totalRewardsCommunity, 0); + assertEq(totalRewardsCarbonFund, 0); + } + + function test_shouldStartNextEpochProcessing() public { + timeTravel(vm, epochDuration + 1); + + epochManager.startNextEpochProcess(); + + (uint256 status, uint256 perValidatorReward, uint256 totalRewardsVote, uint256 totalRewardsCommunity, uint256 totalRewardsCarbonFund) = epochManager.getEpochProcessingState(); + assertEq(status, 1); // Started + assertGt(perValidatorReward, 0, "perValidatorReward"); + assertGt(totalRewardsVote, 0, "totalRewardsVote"); + assertGt(totalRewardsCommunity, 0, "totalRewardsCommunity"); + assertGt(totalRewardsCarbonFund, 0, "totalRewardsCarbonFund"); + } +} + + +contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { + + address[] groups; + + + function setUp() public override { + super.setUp(); + activateValidators(); + whenL2(vm); + + vm.prank(epochManagerEnabler); + epochManager.initializeSystem(1,1, firstElected); + + timeTravel(vm, epochDuration + 1); + epochManager.startNextEpochProcess(); + + groups = getValidators().getRegisteredValidatorGroups(); + + vm.prank(scoreManager.owner()); + scoreManager.setGroupScore(groups[0], 1e24); + } + + function test_shouldFinishNextEpochProcessing() public { + + + uint256[] memory groupActiveBalances = new uint256[](groups.length); + for (uint256 i = 0; i < groups.length; i++) { + groupActiveBalances[i] = election.getActiveVotesForGroup(groups[i]); + } + + address[] memory lessers = new address[](1); + lessers[0] = address(0); + + address[] memory greaters = new address[](1); + greaters[0] = address(0); + + uint256 currentEpoch = epochManager.getCurrentEpochNumber(); + address[] memory currentlyElected = epochManager.getElected(); + + epochManager.finishNextEpochProcess(groups, lessers, greaters); + + assertEq(currentEpoch + 1, epochManager.getCurrentEpochNumber()); + + address[] memory newlyElected = epochManager.getElected(); + + for (uint256 i = 0; i < currentlyElected.length; i++) { + assertEq(currentlyElected[i], newlyElected[i]); + } + + for (uint256 i = 0; i < groups.length; i++) { + assertGt(election.getActiveVotesForGroup(groups[i]), groupActiveBalances[i]); + } + } +} diff --git a/packages/protocol/test-sol/devchain/e2e/utils.sol b/packages/protocol/test-sol/devchain/e2e/utils.sol index cd1c57b8200..48275cb8d0e 100644 --- a/packages/protocol/test-sol/devchain/e2e/utils.sol +++ b/packages/protocol/test-sol/devchain/e2e/utils.sol @@ -3,10 +3,16 @@ pragma solidity >=0.8.7 <0.8.20; import "@celo-contracts-8/common/UsingRegistry.sol"; import "@celo-contracts/common/interfaces/IRegistry.sol"; +import { IEpochManager } from "@celo-contracts/common/interfaces/IEpochManager.sol"; +import { IAccounts } from "@celo-contracts/common/interfaces/IAccounts.sol"; +import { IScoreManager } from "@celo-contracts-8/common/interfaces/IScoreManager.sol"; +import { IValidators } from "@celo-contracts/governance/interfaces/IValidators.sol"; +import { IElection } from "@celo-contracts/governance/interfaces/IElection.sol"; // All core contracts that are expected to be in the Registry on the devchain import "@celo-contracts-8/common/FeeCurrencyDirectory.sol"; import "@celo-contracts/stability/interfaces/ISortedOracles.sol"; +import "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; import { TestConstants } from "@test-sol/constants.sol"; @@ -17,6 +23,12 @@ contract Devchain is UsingRegistry, TestConstants { // All core contracts that are expected to be in the Registry on the devchain ISortedOracles sortedOracles; FeeCurrencyDirectory feeCurrencyDirectory; + IEpochManager epochManager; + ICeloUnreleasedTreasure celoUnreleasedTreasure; + IValidators validators; + IAccounts accounts; + IScoreManager scoreManager; + IElection election; constructor() { // The following line is required by UsingRegistry.sol @@ -28,6 +40,13 @@ contract Devchain is UsingRegistry, TestConstants { devchainRegistry.getAddressForStringOrDie("FeeCurrencyDirectory") ); // FeeCurrencyDirectory is not in UsingRegistry.sol + epochManager = getEpochManager(); + celoUnreleasedTreasure = getCeloUnreleasedTreasure(); + validators = getValidators(); + accounts = getAccounts(); + scoreManager = IScoreManager(address(getScoreReader())); + election = getElection(); + // TODO: Add missing core contracts below (see list in migrations_sol/constants.sol) // TODO: Consider asserting that all contracts we expect are available in the Devchain class // (see list in migrations_sol/constants.sol) diff --git a/packages/protocol/test-sol/utils/ECDSAHelper08.sol b/packages/protocol/test-sol/utils/ECDSAHelper08.sol new file mode 100644 index 00000000000..4daf6063696 --- /dev/null +++ b/packages/protocol/test-sol/utils/ECDSAHelper08.sol @@ -0,0 +1,34 @@ +pragma solidity >=0.5.13 <0.8.20; +import "celo-foundry-8/Test.sol"; +import "@test-sol/utils/SECP256K1.sol"; + +contract ECDSAHelper08 is Test{ + ISECP256K1 sECP256K1; + + function addressToPublicKey( + bytes32 message, + uint8 _v, + bytes32 _r, + bytes32 _s + ) public returns (bytes memory) { + address SECP256K1Address = actor("SECP256K1Address"); + deployCodeTo("SECP256K1.sol:SECP256K1", SECP256K1Address); + sECP256K1 = ISECP256K1(SECP256K1Address); + + string memory header = "\x19Ethereum Signed Message:\n32"; + bytes32 _message = keccak256(abi.encodePacked(header, message)); + (uint256 x, uint256 y) = sECP256K1.recover( + uint256(_message), + _v - 27, + uint256(_r), + uint256(_s) + ); + return abi.encodePacked(x, y); + } + + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { + // 32 is the length in bytes of hash, + // enforced by the type signature above + return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); + } +} diff --git a/packages/protocol/test-sol/utils08.sol b/packages/protocol/test-sol/utils08.sol index 681380e6e87..dd747d99f55 100644 --- a/packages/protocol/test-sol/utils08.sol +++ b/packages/protocol/test-sol/utils08.sol @@ -3,6 +3,9 @@ pragma solidity >=0.5.13 <0.9.0; import "celo-foundry-8/Test.sol"; contract Utils08 { + + uint256 constant public secondsInOneBlock = 5; + function timeTravel(Vm vm, uint256 timeDelta) public { vm.warp(block.timestamp + timeDelta); } @@ -11,8 +14,19 @@ contract Utils08 { vm.roll(block.number + blockDelta); } + function travelEpochL1(Vm vm) public { + uint256 blocksInEpoch = 17280; + uint256 timeDelta = blocksInEpoch * secondsInOneBlock; + blockTravel(vm, blocksInEpoch); + timeTravel(vm, timeDelta); + } + // This function can be also found in OpenZeppelin's library, but in a newer version than the one function compareStrings(string memory a, string memory b) public pure returns (bool) { return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); } + + function whenL2(Vm vm) public { + vm.etch(0x4200000000000000000000000000000000000018, abi.encodePacked(bytes1(0x01))); + } } From a050d27e32f6f36570de9b371892187f49f92936 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Wed, 11 Sep 2024 16:53:13 +0200 Subject: [PATCH 33/69] lint --- .../common/interfaces/IScoreManager.sol | 2 +- .../common/test/MockEpochManager.sol | 5 +- .../contracts-0.8/governance/Validators.sol | 2 +- .../common/interfaces/IEpochManager.sol | 1 - .../devchain/Import05Dependencies.sol | 1 - .../devchain/e2e/common/EpochManager.t.sol | 90 ++++++++++--------- .../test-sol/unit/common/EpochManager.t.sol | 3 +- .../protocol/test-sol/utils/ECDSAHelper08.sol | 12 +-- packages/protocol/test-sol/utils08.sol | 5 +- 9 files changed, 63 insertions(+), 58 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/interfaces/IScoreManager.sol b/packages/protocol/contracts-0.8/common/interfaces/IScoreManager.sol index b06f8c452a4..0020fd65df0 100644 --- a/packages/protocol/contracts-0.8/common/interfaces/IScoreManager.sol +++ b/packages/protocol/contracts-0.8/common/interfaces/IScoreManager.sol @@ -6,5 +6,5 @@ interface IScoreManager { function setValidatorScore(address validator, uint256 score) external; function getValidatorScore(address validator) external view returns (uint256); function getGroupScore(address validator) external view returns (uint256); - function owner() external view returns (address); + function owner() external view returns (address); } diff --git a/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol b/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol index 4335e0c8b84..c4cb4d2e8ce 100644 --- a/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol +++ b/packages/protocol/contracts-0.8/common/test/MockEpochManager.sol @@ -71,7 +71,8 @@ contract MockEpochManager is IEpochManager { function getEpochProcessingState() external view - returns (uint256, uint256, uint256, uint256, uint256) { + returns (uint256, uint256, uint256, uint256, uint256) + { return (0, 0, 0, 0, 0); - } + } } diff --git a/packages/protocol/contracts-0.8/governance/Validators.sol b/packages/protocol/contracts-0.8/governance/Validators.sol index 70e891eecb0..35d559db5e5 100644 --- a/packages/protocol/contracts-0.8/governance/Validators.sol +++ b/packages/protocol/contracts-0.8/governance/Validators.sol @@ -216,7 +216,7 @@ contract Validators is setDowntimeGracePeriod(initParams.downtimeGracePeriod); } - /** + /** * @notice Mints stable token to the beneficiary. * @dev Callable only by epoch manager. * @param beneficiary The address to mint the stable token to. diff --git a/packages/protocol/contracts/common/interfaces/IEpochManager.sol b/packages/protocol/contracts/common/interfaces/IEpochManager.sol index 6d94a842fc3..806e5d5ae0b 100644 --- a/packages/protocol/contracts/common/interfaces/IEpochManager.sol +++ b/packages/protocol/contracts/common/interfaces/IEpochManager.sol @@ -24,5 +24,4 @@ interface IEpochManager { external view returns (uint256, uint256, uint256, uint256, uint256); - } diff --git a/packages/protocol/test-sol/devchain/Import05Dependencies.sol b/packages/protocol/test-sol/devchain/Import05Dependencies.sol index abda9ed6c3d..43fc02435fc 100644 --- a/packages/protocol/test-sol/devchain/Import05Dependencies.sol +++ b/packages/protocol/test-sol/devchain/Import05Dependencies.sol @@ -19,7 +19,6 @@ import { StableTokenEUR } from "@mento-core/contracts/StableTokenEUR.sol"; import { StableTokenBRL } from "@mento-core/contracts/StableTokenBRL.sol"; import { Exchange } from "@mento-core/contracts/Exchange.sol"; - import { IEpochManager } from "@celo-contracts/common/interfaces/IEpochManager.sol"; import { IValidators } from "@celo-contracts/governance/interfaces/IValidators.sol"; import "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; diff --git a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol index 16d24d6b774..6a234607dab 100644 --- a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol @@ -11,7 +11,6 @@ import "@celo-contracts-8/common/FeeCurrencyDirectory.sol"; import "@test-sol/utils/ECDSAHelper08.sol"; contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { - address epochManagerOwner; address epochManagerEnabler; address[] firstElected; @@ -27,19 +26,18 @@ contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { mapping(address => VoterWithPK) validatorToVoter; function setUp() public virtual { - uint256 totalVotes = election.getTotalVotes(); - - epochManagerOwner = Ownable(address(epochManager)).owner(); - epochManagerEnabler = epochManager.epochManagerEnabler(); - firstElected = getValidators().getRegisteredValidators(); + uint256 totalVotes = election.getTotalVotes(); + + epochManagerOwner = Ownable(address(epochManager)).owner(); + epochManagerEnabler = epochManager.epochManagerEnabler(); + firstElected = getValidators().getRegisteredValidators(); - epochDuration = epochManager.epochDuration(); + epochDuration = epochManager.epochDuration(); - vm.deal(address(celoUnreleasedTreasure), 800_000_000 ether); // 80% of the total supply to the treasure - whis will be yet distributed + vm.deal(address(celoUnreleasedTreasure), 800_000_000 ether); // 80% of the total supply to the treasure - whis will be yet distributed } function activateValidators() public { - uint256[] memory valKeys = new uint256[](2); valKeys[0] = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; valKeys[1] = 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a; @@ -49,10 +47,9 @@ contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { addressToPrivateKeys[account] = valKeys[i]; } - address[] memory registeredValidators = getValidators().getRegisteredValidators(); for (uint256 i = 0; i < registeredValidators.length; i++) { - (,,address validatorGroup,,) = getValidators().getValidator(registeredValidators[i]); + (, , address validatorGroup, , ) = getValidators().getValidator(registeredValidators[i]); travelEpochL1(vm); travelEpochL1(vm); travelEpochL1(vm); @@ -71,25 +68,30 @@ contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { } } -contract E2E_EpochManager_InitializeSystem is E2E_EpochManager{ +contract E2E_EpochManager_InitializeSystem is E2E_EpochManager { function setUp() public override { - super.setUp(); - whenL2(vm); + super.setUp(); + whenL2(vm); } function test_shouldRevert_WhenCalledByNonEnabler() public { vm.expectRevert("msg.sender is not Initializer"); - epochManager.initializeSystem(1,1, firstElected); + epochManager.initializeSystem(1, 1, firstElected); } function test_ShouldInitializeSystem() public { vm.prank(epochManagerEnabler); - epochManager.initializeSystem(42,43, firstElected); + epochManager.initializeSystem(42, 43, firstElected); assertEq(epochManager.firstKnownEpoch(), 42); assertEq(epochManager.getCurrentEpochNumber(), 42); - (uint256 firstBlock, uint256 lastBlock, uint256 startTimestamp, uint256 rewardsBlock) = epochManager.getCurrentEpoch(); + ( + uint256 firstBlock, + uint256 lastBlock, + uint256 startTimestamp, + uint256 rewardsBlock + ) = epochManager.getCurrentEpoch(); assertEq(firstBlock, 43); assertEq(lastBlock, 0); assertEq(startTimestamp, block.timestamp); @@ -97,15 +99,14 @@ contract E2E_EpochManager_InitializeSystem is E2E_EpochManager{ } } -contract E2E_EpochManager_StartNextEpochProcess is E2E_EpochManager{ +contract E2E_EpochManager_StartNextEpochProcess is E2E_EpochManager { function setUp() public override { - super.setUp(); - activateValidators(); - whenL2(vm); + super.setUp(); + activateValidators(); + whenL2(vm); - - vm.prank(epochManagerEnabler); - epochManager.initializeSystem(1,1, firstElected); + vm.prank(epochManagerEnabler); + epochManager.initializeSystem(1, 1, firstElected); } function test_shouldHaveInitialValues() public { @@ -113,7 +114,13 @@ contract E2E_EpochManager_StartNextEpochProcess is E2E_EpochManager{ assertEq(epochManager.getCurrentEpochNumber(), 1); // get getEpochProcessingState - (uint256 status, uint256 perValidatorReward, uint256 totalRewardsVote, uint256 totalRewardsCommunity, uint256 totalRewardsCarbonFund) = epochManager.getEpochProcessingState(); + ( + uint256 status, + uint256 perValidatorReward, + uint256 totalRewardsVote, + uint256 totalRewardsCommunity, + uint256 totalRewardsCarbonFund + ) = epochManager.getEpochProcessingState(); assertEq(status, 0); // Not started assertEq(perValidatorReward, 0); assertEq(totalRewardsVote, 0); @@ -126,7 +133,13 @@ contract E2E_EpochManager_StartNextEpochProcess is E2E_EpochManager{ epochManager.startNextEpochProcess(); - (uint256 status, uint256 perValidatorReward, uint256 totalRewardsVote, uint256 totalRewardsCommunity, uint256 totalRewardsCarbonFund) = epochManager.getEpochProcessingState(); + ( + uint256 status, + uint256 perValidatorReward, + uint256 totalRewardsVote, + uint256 totalRewardsCommunity, + uint256 totalRewardsCarbonFund + ) = epochManager.getEpochProcessingState(); assertEq(status, 1); // Started assertGt(perValidatorReward, 0, "perValidatorReward"); assertGt(totalRewardsVote, 0, "totalRewardsVote"); @@ -135,32 +148,27 @@ contract E2E_EpochManager_StartNextEpochProcess is E2E_EpochManager{ } } - contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { - address[] groups; - function setUp() public override { - super.setUp(); - activateValidators(); - whenL2(vm); + super.setUp(); + activateValidators(); + whenL2(vm); - vm.prank(epochManagerEnabler); - epochManager.initializeSystem(1,1, firstElected); + vm.prank(epochManagerEnabler); + epochManager.initializeSystem(1, 1, firstElected); - timeTravel(vm, epochDuration + 1); - epochManager.startNextEpochProcess(); + timeTravel(vm, epochDuration + 1); + epochManager.startNextEpochProcess(); - groups = getValidators().getRegisteredValidatorGroups(); + groups = getValidators().getRegisteredValidatorGroups(); - vm.prank(scoreManager.owner()); - scoreManager.setGroupScore(groups[0], 1e24); + vm.prank(scoreManager.owner()); + scoreManager.setGroupScore(groups[0], 1e24); } function test_shouldFinishNextEpochProcessing() public { - - uint256[] memory groupActiveBalances = new uint256[](groups.length); for (uint256 i = 0; i < groups.length; i++) { groupActiveBalances[i] = election.getActiveVotesForGroup(groups[i]); diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 0e61a98119d..7956eb6deb9 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -240,11 +240,10 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { } } - contract EpochManagerTest_setEpochMangerEnabler is EpochManagerTest { function test_setEpochMangerEnabler() public { vm.prank(epochManager.owner()); - address newEpochManagerEnabler = actor("newEpochManagerEnabler"); + address newEpochManagerEnabler = actor("newEpochManagerEnabler"); epochManager.setEpochMangerEnabler(newEpochManagerEnabler); assertEq(epochManager.epochManagerEnabler(), newEpochManagerEnabler); } diff --git a/packages/protocol/test-sol/utils/ECDSAHelper08.sol b/packages/protocol/test-sol/utils/ECDSAHelper08.sol index 4daf6063696..3c761bb9e76 100644 --- a/packages/protocol/test-sol/utils/ECDSAHelper08.sol +++ b/packages/protocol/test-sol/utils/ECDSAHelper08.sol @@ -2,7 +2,7 @@ pragma solidity >=0.5.13 <0.8.20; import "celo-foundry-8/Test.sol"; import "@test-sol/utils/SECP256K1.sol"; -contract ECDSAHelper08 is Test{ +contract ECDSAHelper08 is Test { ISECP256K1 sECP256K1; function addressToPublicKey( @@ -26,9 +26,9 @@ contract ECDSAHelper08 is Test{ return abi.encodePacked(x, y); } - function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { - // 32 is the length in bytes of hash, - // enforced by the type signature above - return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); - } + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { + // 32 is the length in bytes of hash, + // enforced by the type signature above + return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); + } } diff --git a/packages/protocol/test-sol/utils08.sol b/packages/protocol/test-sol/utils08.sol index dd747d99f55..93c9ccd0ff0 100644 --- a/packages/protocol/test-sol/utils08.sol +++ b/packages/protocol/test-sol/utils08.sol @@ -3,8 +3,7 @@ pragma solidity >=0.5.13 <0.9.0; import "celo-foundry-8/Test.sol"; contract Utils08 { - - uint256 constant public secondsInOneBlock = 5; + uint256 public constant secondsInOneBlock = 5; function timeTravel(Vm vm, uint256 timeDelta) public { vm.warp(block.timestamp + timeDelta); @@ -27,6 +26,6 @@ contract Utils08 { } function whenL2(Vm vm) public { - vm.etch(0x4200000000000000000000000000000000000018, abi.encodePacked(bytes1(0x01))); + vm.etch(0x4200000000000000000000000000000000000018, abi.encodePacked(bytes1(0x01))); } } From 48db87181e5759d4d16ced34bcde3ee9cb30f7d0 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 11 Sep 2024 11:05:33 -0400 Subject: [PATCH 34/69] proxy stableToken mint call via Validators contract --- .../protocol/contracts-0.8/common/EpochManager.sol | 4 +++- .../contracts-0.8/governance/Validators.sol | 14 ++++++++++++++ .../governance/test/ValidatorsMock08.sol | 2 ++ .../governance/interfaces/IValidators.sol | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 9309beb515f..8ba043546e1 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -311,6 +311,7 @@ contract EpochManager is IValidators validators = getValidators(); for (uint i = 0; i < elected.length; i++) { + console2.log("### index:", i); uint256 validatorScore = scoreReader.getValidatorScore(elected[i]); uint256 validatorReward = validators.computeEpochReward( elected[i], @@ -321,7 +322,8 @@ contract EpochManager is totalRewards += validatorReward; } // Mint all cUSD required for payment and the corresponding CELO - IStableToken(getStableToken()).mint(address(this), totalRewards); + // TODO(soloseng): add test to check that epoch manager received funds. + validators.mintStableToEpochManager(totalRewards); // this should have a setter for the oracle. (uint256 numerator, uint256 denominator) = IOracle(address(getSortedOracles())).getExchangeRate( diff --git a/packages/protocol/contracts-0.8/governance/Validators.sol b/packages/protocol/contracts-0.8/governance/Validators.sol index 68a816edfcb..1b3cbac97a3 100644 --- a/packages/protocol/contracts-0.8/governance/Validators.sol +++ b/packages/protocol/contracts-0.8/governance/Validators.sol @@ -647,6 +647,20 @@ contract Validators is group.slashInfo.lastSlashed = block.timestamp; } + // TODO(soloseng): add test to check that this function can only mint to epoch manager. + function mintStableToEpochManager( + uint256 amount + ) external onlyL2 nonReentrant onlyRegisteredContract(EPOCH_MANAGER_REGISTRY_ID) { + require(amount > 0, "mint amount is zero."); + require( + IStableToken(getStableToken()).mint( + registry.getAddressForOrDie(EPOCH_MANAGER_REGISTRY_ID), + amount + ), + "mint failed to epoch manager" + ); + } + /** * @notice Returns the validator BLS key. * @param signer The account that registered the validator or its authorized signing address. diff --git a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol index 28857cb69b0..0589e4df5ff 100644 --- a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol +++ b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol @@ -23,6 +23,8 @@ contract ValidatorsMock08 is IValidators { // return _distributeEpochPaymentsFromSigner(signer, maxPayment); } + function mintStableToEpochManager(uint256 amount) external {} + function registerValidator( bytes calldata ecdsaPublicKey, bytes calldata blsPublicKey, diff --git a/packages/protocol/contracts/governance/interfaces/IValidators.sol b/packages/protocol/contracts/governance/interfaces/IValidators.sol index 01e16821776..e7b2db4953a 100644 --- a/packages/protocol/contracts/governance/interfaces/IValidators.sol +++ b/packages/protocol/contracts/governance/interfaces/IValidators.sol @@ -41,6 +41,7 @@ interface IValidators { bytes calldata, bytes calldata ) external returns (bool); + function mintStableToEpochManager(uint256 amount) external; // only VM function updateValidatorScoreFromSigner(address, uint256) external; From bbb239fedb86e38edac69c957b112d59afad4240 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:58:40 -0400 Subject: [PATCH 35/69] -- duplicate imports --- packages/protocol/contracts/common/UsingRegistry.sol | 1 - packages/protocol/contracts/common/UsingRegistryV2.sol | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/protocol/contracts/common/UsingRegistry.sol b/packages/protocol/contracts/common/UsingRegistry.sol index 82e307e8c4c..08eb3f36507 100644 --- a/packages/protocol/contracts/common/UsingRegistry.sol +++ b/packages/protocol/contracts/common/UsingRegistry.sol @@ -10,7 +10,6 @@ import "./interfaces/IFeeCurrencyWhitelist.sol"; import "./interfaces/IFreezer.sol"; import "./interfaces/IRegistry.sol"; import "./interfaces/ICeloUnreleasedTreasure.sol"; -import "./interfaces/IEpochManager.sol"; import "../governance/interfaces/IElection.sol"; import "../governance/interfaces/IEpochRewards.sol"; diff --git a/packages/protocol/contracts/common/UsingRegistryV2.sol b/packages/protocol/contracts/common/UsingRegistryV2.sol index f4505a1f559..3f812931c47 100644 --- a/packages/protocol/contracts/common/UsingRegistryV2.sol +++ b/packages/protocol/contracts/common/UsingRegistryV2.sol @@ -9,7 +9,6 @@ import "./interfaces/IFeeCurrencyWhitelist.sol"; import "./interfaces/IFreezer.sol"; import "./interfaces/IRegistry.sol"; import "./interfaces/ICeloUnreleasedTreasure.sol"; -import "./interfaces/IEpochManager.sol"; import "../governance/interfaces/IElection.sol"; import "../governance/interfaces/IEpochRewards.sol"; From 2ffeed2c82dd82b178883a29d8c28d64c02edf59 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:28:57 -0400 Subject: [PATCH 36/69] removed registry08. replaced with vm call --- .../contracts-0.8/common/Registry08.sol | 102 ------------------ packages/protocol/test-sol/utils08.sol | 4 + 2 files changed, 4 insertions(+), 102 deletions(-) delete mode 100644 packages/protocol/contracts-0.8/common/Registry08.sol diff --git a/packages/protocol/contracts-0.8/common/Registry08.sol b/packages/protocol/contracts-0.8/common/Registry08.sol deleted file mode 100644 index 63a8d769486..00000000000 --- a/packages/protocol/contracts-0.8/common/Registry08.sol +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity >=0.8.7 <0.8.20; - -import "@openzeppelin/contracts8/utils/math/SafeMath.sol"; -import "@openzeppelin/contracts8/access/Ownable.sol"; - -import "../../contracts/common/interfaces/IRegistry.sol"; -import "../../contracts/common/interfaces/IRegistryInitializer.sol"; -import "../../contracts/common/Initializable.sol"; - -/** - * @title Routes identifiers to addresses. - */ -contract Registry08 is IRegistry, IRegistryInitializer, Ownable, Initializable { - using SafeMath for uint256; - - mapping(bytes32 => address) public registry; - - event RegistryUpdated(string identifier, bytes32 indexed identifierHash, address indexed addr); - - /** - * @notice Sets initialized == true on implementation contracts - * @param test Set to true to skip implementation initialization - */ - constructor(bool test) public Initializable(test) {} - - /** - * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. - */ - function initialize() external initializer { - _transferOwnership(msg.sender); - } - - /** - * @notice Associates the given address with the given identifier. - * @param identifier Identifier of contract whose address we want to set. - * @param addr Address of contract. - */ - function setAddressFor(string calldata identifier, address addr) external onlyOwner { - bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); - registry[identifierHash] = addr; - emit RegistryUpdated(identifier, identifierHash, addr); - } - - /** - * @notice Gets address associated with the given identifierHash. - * @param identifierHash Identifier hash of contract whose address we want to look up. - * @dev Throws if address not set. - */ - function getAddressForOrDie(bytes32 identifierHash) external view returns (address) { - require(registry[identifierHash] != address(0), "identifier has no registry entry"); - return registry[identifierHash]; - } - - /** - * @notice Gets address associated with the given identifierHash. - * @param identifierHash Identifier hash of contract whose address we want to look up. - */ - function getAddressFor(bytes32 identifierHash) external view returns (address) { - return registry[identifierHash]; - } - - /** - * @notice Gets address associated with the given identifier. - * @param identifier Identifier of contract whose address we want to look up. - * @dev Throws if address not set. - */ - function getAddressForStringOrDie(string calldata identifier) external view returns (address) { - bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); - require(registry[identifierHash] != address(0), "identifier has no registry entry"); - return registry[identifierHash]; - } - - /** - * @notice Gets address associated with the given identifier. - * @param identifier Identifier of contract whose address we want to look up. - */ - function getAddressForString(string calldata identifier) external view returns (address) { - bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); - return registry[identifierHash]; - } - - /** - * @notice Iterates over provided array of identifiers, getting the address for each. - * Returns true if `sender` matches the address of one of the provided identifiers. - * @param identifierHashes Array of hashes of approved identifiers. - * @param sender Address in question to verify membership. - * @return True if `sender` corresponds to the address of any of `identifiers` - * registry entries. - */ - function isOneOf( - bytes32[] calldata identifierHashes, - address sender - ) external view returns (bool) { - for (uint256 i = 0; i < identifierHashes.length; i = i.add(1)) { - if (registry[identifierHashes[i]] == sender) { - return true; - } - } - return false; - } -} diff --git a/packages/protocol/test-sol/utils08.sol b/packages/protocol/test-sol/utils08.sol index 681380e6e87..668eb71ccb3 100644 --- a/packages/protocol/test-sol/utils08.sol +++ b/packages/protocol/test-sol/utils08.sol @@ -15,4 +15,8 @@ contract Utils08 { function compareStrings(string memory a, string memory b) public pure returns (bool) { return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b)))); } + + function whenL2(Vm vm) public { + vm.etch(0x4200000000000000000000000000000000000018, abi.encodePacked(bytes1(0x01))); + } } From b195ebb23c1b83f7adbced252e372175a823e6a9 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Wed, 11 Sep 2024 14:48:42 -0400 Subject: [PATCH 37/69] PR feedback --- packages/protocol/test-sol/devchain/migration/Migration.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index f4a297b0934..491ad7a77c0 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.5.13 <0.8.20; +pragma solidity >=0.8.0 <0.8.20; import "celo-foundry-8/Test.sol"; @@ -244,7 +244,7 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { vm.prank(address(0)); celoToken.mint(unreleasedTreasury, L2_INITIAL_STASH_BALANCE); - deployCodeTo("Registry08.sol", abi.encode(false), PROXY_ADMIN_ADDRESS); + whenL2(vm); vm.prank(address(epochManagerEnabler)); From e84a5b5b2de544efae2aeed9936212481d0aa329 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Thu, 12 Sep 2024 15:22:10 +0200 Subject: [PATCH 38/69] generate Ecdsa Pub Key dynamically in migration.s.sol --- .../protocol/migrations_sol/Migration.s.sol | 62 ++++++++++++++++--- .../migrations_sol/migrationsConfig.json | 5 +- .../create_and_migrate_anvil_devchain.sh | 2 +- .../create_and_migrate_anvil_l2_devchain.sh | 4 +- 4 files changed, 59 insertions(+), 14 deletions(-) diff --git a/packages/protocol/migrations_sol/Migration.s.sol b/packages/protocol/migrations_sol/Migration.s.sol index 8b32172228a..473a3731ea0 100644 --- a/packages/protocol/migrations_sol/Migration.s.sol +++ b/packages/protocol/migrations_sol/Migration.s.sol @@ -56,6 +56,8 @@ import "@celo-contracts-8/common/interfaces/IScoreManagerInitializer.sol"; import "@celo-contracts-8/common/interfaces/IFeeCurrencyDirectory.sol"; import "@celo-contracts-8/common/UsingRegistry.sol"; +import "@test-sol/utils/SECP256K1.sol"; + contract ForceTx { // event to trigger so a tx can be processed event VanillaEvent(string); @@ -1101,14 +1103,12 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { function registerValidator( uint256 validatorIndex, - bytes memory ecdsaPubKey, uint256 validatorKey, uint256 amountToLock, address groupToAffiliate ) public returns (address) { vm.startBroadcast(validatorKey); lockGold(amountToLock); - bytes memory _ecdsaPubKey = ecdsaPubKey; address accountAddress = (new ForceTx()).identity(); // these blobs are not checked in the contract @@ -1123,6 +1123,8 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { bytes16(0x05050505050505050505050505050506), bytes16(0x06060606060606060606060606060607) ); + + (bytes memory ecdsaPubKey, , , ) = _generateEcdsaPubKeyWithSigner(accountAddress, validatorKey); getValidators().registerValidator(ecdsaPubKey, newBlsPublicKey, newBlsPop); getValidators().affiliate(groupToAffiliate); console.log("Done registering validatora"); @@ -1164,6 +1166,57 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { vm.stopBroadcast(); } + function _generateEcdsaPubKeyWithSigner( + address _validator, + uint256 _signerPk + ) internal returns (bytes memory ecdsaPubKey, uint8 v, bytes32 r, bytes32 s) { + (v, r, s) = getParsedSignatureOfAddress(_validator, _signerPk); + + bytes32 addressHash = keccak256(abi.encodePacked(_validator)); + + ecdsaPubKey = addressToPublicKey(addressHash, v, r, s); + } + + function addressToPublicKey( + bytes32 message, + uint8 _v, + bytes32 _r, + bytes32 _s + ) public returns (bytes memory) { + address SECP256K1Address = actor("SECP256K1Address"); + deployCodeTo("SECP256K1.sol:SECP256K1", SECP256K1Address); + ISECP256K1 sECP256K1 = ISECP256K1(SECP256K1Address); + + string memory header = "\x19Ethereum Signed Message:\n32"; + bytes32 _message = keccak256(abi.encodePacked(header, message)); + (uint256 x, uint256 y) = sECP256K1.recover( + uint256(_message), + _v - 27, + uint256(_r), + uint256(_s) + ); + return abi.encodePacked(x, y); + } + + function actor(string memory name) internal returns (address) { + return vm.addr(uint256(keccak256(abi.encodePacked(name)))); + } + + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { + // 32 is the length in bytes of hash, + // enforced by the type signature above + return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); + } + + function getParsedSignatureOfAddress( + address _address, + uint256 privateKey + ) public pure returns (uint8, bytes32, bytes32) { + bytes32 addressHash = keccak256(abi.encodePacked(_address)); + bytes32 prefixedHash = toEthSignedMessageHash(addressHash); + return vm.sign(privateKey, prefixedHash); + } + function electValidators(string memory json) public { console.log("Electing validators: "); @@ -1178,7 +1231,6 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { json.parseRaw(".validators.validatorLockedGoldRequirements.value"), (uint256) ); - bytes[] memory ecdsaPubKeys = abi.decode(json.parseRaw(".validators.ecdsaPubKeys"), (bytes[])); // attestationKeys not migrated if (valKeys.length == 0) { @@ -1208,12 +1260,8 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { for (uint256 validatorIndex = 0; validatorIndex < amountOfGroups; validatorIndex++) { console.log("Validator key index", getValidatorKeyIndex(0, validatorIndex, maxGroupSize)); console.log("Registering validator #: ", validatorIndex); - bytes memory ecdsaPubKey = ecdsaPubKeys[ - getValidatorKeyIndex(0, validatorIndex, maxGroupSize) - ]; address validator = registerValidator( validatorIndex, - ecdsaPubKey, getValidatorKeyFromGroupGroup(valKeys, 0, validatorIndex, maxGroupSize), validatorLockedGoldRequirements, groupAddress diff --git a/packages/protocol/migrations_sol/migrationsConfig.json b/packages/protocol/migrations_sol/migrationsConfig.json index db98b72fd5d..59d9f67f220 100644 --- a/packages/protocol/migrations_sol/migrationsConfig.json +++ b/packages/protocol/migrations_sol/migrationsConfig.json @@ -76,10 +76,7 @@ "groupName": "cLabs", "commission": 100000000000000000000000, "votesRatioOfLastVsFirstGroup": 2000000000000000000000000, - "valKeys": ["0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d","0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a"], - "ecdsaPubKeys": [ - "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0x9d9031e97dd78ff8c15aa86939de9b1e791066a0224e331bc962a2099a7b1f0464b8bbafe1535f2301c72c2cb3535b172da30b02686ab0393d348614f157fbdb"] + "valKeys": ["0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d","0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a"] }, "election": { "minElectableValidators": 1, diff --git a/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh b/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh index eda428e1405..149cc3d7bea 100755 --- a/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh +++ b/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh @@ -58,7 +58,7 @@ forge script \ $SKIP_SIMULATION \ $NON_INTERACTIVE \ $LIBRARY_FLAGS \ - --rpc-url $ANVIL_RPC_URL || echo "Migration script failed" + --rpc-url $ANVIL_RPC_URL || { echo "Migration script failed"; exit 1; } # Keeping track of the finish time to measure how long it takes to run the script entirely ELAPSED_TIME=$(($SECONDS - $START_TIME)) diff --git a/packages/protocol/scripts/foundry/create_and_migrate_anvil_l2_devchain.sh b/packages/protocol/scripts/foundry/create_and_migrate_anvil_l2_devchain.sh index b1c0b145676..3abbe0d2fbd 100755 --- a/packages/protocol/scripts/foundry/create_and_migrate_anvil_l2_devchain.sh +++ b/packages/protocol/scripts/foundry/create_and_migrate_anvil_l2_devchain.sh @@ -48,7 +48,7 @@ forge script \ $BROADCAST \ $SKIP_SIMULATION \ $NON_INTERACTIVE \ - --rpc-url $ANVIL_RPC_URL || echo "L2 Migration script failed" + --rpc-url $ANVIL_RPC_URL || { echo "Migration script failed"; exit 1; } # Save L2 state so it can published to NPM cp $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME $TMP_FOLDER/$L2_DEVCHAIN_FILE_NAME @@ -58,4 +58,4 @@ echo "Saved anvil L2 state to $TMP_FOLDER/$L2_DEVCHAIN_FILE_NAME" cp $TMP_FOLDER/backup_$L1_DEVCHAIN_FILE_NAME $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME # Delete backup -rm $TMP_FOLDER/backup_$L1_DEVCHAIN_FILE_NAME \ No newline at end of file +rm $TMP_FOLDER/backup_$L1_DEVCHAIN_FILE_NAME From 3c2ebfc4d5961584dc5cb998f4eeb4b94bba71db Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:50:27 -0400 Subject: [PATCH 39/69] -- coment --- packages/protocol/contracts-0.8/common/EpochManager.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 8ba043546e1..0316da8fce2 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -311,7 +311,6 @@ contract EpochManager is IValidators validators = getValidators(); for (uint i = 0; i < elected.length; i++) { - console2.log("### index:", i); uint256 validatorScore = scoreReader.getValidatorScore(elected[i]); uint256 validatorReward = validators.computeEpochReward( elected[i], From 83bd5aad5f0c83fe1e1b806b89bb1665847e0a78 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:59:23 -0400 Subject: [PATCH 40/69] passing unit tests --- .../common/test/MockRegistry.sol | 102 ++++++++ .../contracts-0.8/governance/Validators.sol | 2 +- .../governance/test/ValidatorsMock08.sol | 231 +----------------- .../test-sol/unit/common/EpochManager.t.sol | 4 +- 4 files changed, 112 insertions(+), 227 deletions(-) create mode 100644 packages/protocol/contracts-0.8/common/test/MockRegistry.sol diff --git a/packages/protocol/contracts-0.8/common/test/MockRegistry.sol b/packages/protocol/contracts-0.8/common/test/MockRegistry.sol new file mode 100644 index 00000000000..cda7d7d133b --- /dev/null +++ b/packages/protocol/contracts-0.8/common/test/MockRegistry.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.7 <0.8.20; + +import "@openzeppelin/contracts8/utils/math/SafeMath.sol"; +import "@openzeppelin/contracts8/access/Ownable.sol"; + +import "@celo-contracts/common/interfaces/IRegistry.sol"; +import "@celo-contracts/common/interfaces/IRegistryInitializer.sol"; +import "@celo-contracts/common/Initializable.sol"; + +/** + * @title Routes identifiers to addresses. + */ +contract MockRegistry is IRegistry, IRegistryInitializer, Ownable, Initializable { + using SafeMath for uint256; + + mapping(bytes32 => address) public registry; + + event RegistryUpdated(string identifier, bytes32 indexed identifierHash, address indexed addr); + + /** + * @notice Sets initialized == true on implementation contracts + * @param test Set to true to skip implementation initialization + */ + constructor(bool test) public Initializable(test) {} + + /** + * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. + */ + function initialize() external initializer { + _transferOwnership(msg.sender); + } + + /** + * @notice Associates the given address with the given identifier. + * @param identifier Identifier of contract whose address we want to set. + * @param addr Address of contract. + */ + function setAddressFor(string calldata identifier, address addr) external onlyOwner { + bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); + registry[identifierHash] = addr; + emit RegistryUpdated(identifier, identifierHash, addr); + } + + /** + * @notice Gets address associated with the given identifierHash. + * @param identifierHash Identifier hash of contract whose address we want to look up. + * @dev Throws if address not set. + */ + function getAddressForOrDie(bytes32 identifierHash) external view returns (address) { + require(registry[identifierHash] != address(0), "identifier has no registry entry"); + return registry[identifierHash]; + } + + /** + * @notice Gets address associated with the given identifierHash. + * @param identifierHash Identifier hash of contract whose address we want to look up. + */ + function getAddressFor(bytes32 identifierHash) external view returns (address) { + return registry[identifierHash]; + } + + /** + * @notice Gets address associated with the given identifier. + * @param identifier Identifier of contract whose address we want to look up. + * @dev Throws if address not set. + */ + function getAddressForStringOrDie(string calldata identifier) external view returns (address) { + bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); + require(registry[identifierHash] != address(0), "identifier has no registry entry"); + return registry[identifierHash]; + } + + /** + * @notice Gets address associated with the given identifier. + * @param identifier Identifier of contract whose address we want to look up. + */ + function getAddressForString(string calldata identifier) external view returns (address) { + bytes32 identifierHash = keccak256(abi.encodePacked(identifier)); + return registry[identifierHash]; + } + + /** + * @notice Iterates over provided array of identifiers, getting the address for each. + * Returns true if `sender` matches the address of one of the provided identifiers. + * @param identifierHashes Array of hashes of approved identifiers. + * @param sender Address in question to verify membership. + * @return True if `sender` corresponds to the address of any of `identifiers` + * registry entries. + */ + function isOneOf( + bytes32[] calldata identifierHashes, + address sender + ) external view returns (bool) { + for (uint256 i = 0; i < identifierHashes.length; i = i.add(1)) { + if (registry[identifierHashes[i]] == sender) { + return true; + } + } + return false; + } +} diff --git a/packages/protocol/contracts-0.8/governance/Validators.sol b/packages/protocol/contracts-0.8/governance/Validators.sol index 1b3cbac97a3..dcd31636717 100644 --- a/packages/protocol/contracts-0.8/governance/Validators.sol +++ b/packages/protocol/contracts-0.8/governance/Validators.sol @@ -900,7 +900,7 @@ contract Validators is address account, uint256 score, uint256 maxPayment - ) external view returns (uint256) { + ) external view virtual returns (uint256) { require(isValidator(account), "Not a validator"); FixidityLib.Fraction memory scoreFraction = FixidityLib.wrap(score); require(scoreFraction.lte(FixidityLib.fixed1()), "Score must be <= 1"); diff --git a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol index 0589e4df5ff..c2d7fdf3d2c 100644 --- a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol +++ b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol @@ -1,252 +1,33 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.7 <0.8.20; -import "../../../contracts/governance/interfaces/IValidators.sol"; +import "../Validators.sol"; import "../../../contracts/common/FixidityLib.sol"; -// import "forge-std-8/console2.sol"; +import "forge-std-8/console2.sol"; /** * @title A wrapper around Validators that exposes onlyVm functions for testing. */ -contract ValidatorsMock08 is IValidators { - function updateValidatorScoreFromSigner(address signer, uint256 uptime) external { +contract ValidatorsMock08 is Validators(true) { + function updateValidatorScoreFromSigner(address signer, uint256 uptime) external override { // console2.log("### update Validator Score From Signer"); } function distributeEpochPaymentsFromSigner( address signer, uint256 maxPayment - ) external returns (uint256) { + ) external override returns (uint256) { // console2.log("### distributeEpochPaymentsFromSigner"); return 0; // return _distributeEpochPaymentsFromSigner(signer, maxPayment); } - function mintStableToEpochManager(uint256 amount) external {} - - function registerValidator( - bytes calldata ecdsaPublicKey, - bytes calldata blsPublicKey, - bytes calldata blsPop - ) external returns (bool) { - return true; - } - - function registerValidator(bytes calldata ecdsaPublicKey) external returns (bool) { - return true; - } - - function deregisterValidator(uint256 index) external returns (bool) { - return true; - } - function affiliate(address group) external returns (bool) { - return true; - } - function deaffiliate() external returns (bool) { - return true; - } - function updateBlsPublicKey( - bytes calldata blsPublicKey, - bytes calldata blsPop - ) external returns (bool) { - return true; - } - function registerValidatorGroup(uint256 commission) external returns (bool) { - return true; - } - function deregisterValidatorGroup(uint256 index) external returns (bool) { - return true; - } - function addMember(address validator) external returns (bool) { - return true; - } - function addFirstMember( - address validator, - address lesser, - address greater - ) external returns (bool) { - return true; - } - function removeMember(address validator) external returns (bool) { - return true; - } - function reorderMember( - address validator, - address lesserMember, - address greaterMember - ) external returns (bool) { - return true; - } - function updateCommission() external {} - function setNextCommissionUpdate(uint256 commission) external {} - function resetSlashingMultiplier() external {} - - // only owner - function setCommissionUpdateDelay(uint256 delay) external {} - function setMaxGroupSize(uint256 size) external returns (bool) { - return true; - } - function setMembershipHistoryLength(uint256 length) external returns (bool) { - return true; - } - function setValidatorScoreParameters( - uint256 exponent, - uint256 adjustmentSpeed - ) external returns (bool) { - return true; - } - function setGroupLockedGoldRequirements(uint256 value, uint256 duration) external returns (bool) { - return true; - } - function setValidatorLockedGoldRequirements( - uint256 value, - uint256 duration - ) external returns (bool) { - return true; - } - function setSlashingMultiplierResetPeriod(uint256 value) external {} - function setDowntimeGracePeriod(uint256 value) external {} - - // only registered contract - function updateEcdsaPublicKey( - address account, - address signer, - bytes calldata ecdsaPublicKey - ) external returns (bool) { - return true; - } - function updatePublicKeys( - address account, - address signer, - bytes calldata ecdsaPublicKey, - bytes calldata blsPublicKey, - bytes calldata blsPop - ) external returns (bool) { - return true; - } - - // only slasher - function forceDeaffiliateIfValidator(address validatorAccount) external {} - function halveSlashingMultiplier(address account) external {} - - // view functions - function maxGroupSize() external view returns (uint256) { - return 0; - } - function downtimeGracePeriod() external view returns (uint256) { - return 0; - } - function getCommissionUpdateDelay() external view returns (uint256) { - return 0; - } - function getValidatorScoreParameters() external view returns (uint256, uint256) { - return (0, 0); - } - - function getMembershipHistory( - address account - ) external view returns (uint256[] memory, address[] memory, uint256, uint256) { - return (new uint256[](0), new address[](0), 0, 0); - } - function calculateEpochScore(uint256 uptime) external view returns (uint256) { - return 0; - } - - function calculateGroupEpochScore(uint256[] calldata uptimes) external view returns (uint256) { - return 0; - } - - function getAccountLockedGoldRequirement(address account) external view returns (uint256) { - return 0; - } - - function meetsAccountLockedGoldRequirements(address account) external view returns (bool) { - return true; - } - function getValidatorBlsPublicKeyFromSigner(address singer) external view returns (bytes memory) { - return "0x"; - } - function getValidator( - address account - ) external view returns (bytes memory, bytes memory, address, uint256, address) { - return ("0x", "0x", address(0), 0, address(0)); - } - function getValidatorsGroup(address account) external view returns (address affiliation) { - affiliation = address(0); - } - function getValidatorGroup( - address account - ) - external - view - returns (address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256) - { - return (new address[](0), 0, 0, 0, new uint256[](0), 0, 0); - } - function getGroupNumMembers(address account) external view returns (uint256) { - return 0; - } - - function getTopGroupValidators( - address account, - uint256 n - ) external view returns (address[] memory) { - return new address[](0); - } - function getGroupsNumMembers( - address[] calldata accounts - ) external view returns (uint256[] memory) { - return new uint256[](0); - } - function getNumRegisteredValidators() external view returns (uint256) { - return 0; - } - - function groupMembershipInEpoch( - address account, - uint256 epochNumber, - uint256 index - ) external view returns (address) { - return address(0); - } - - function getValidatorLockedGoldRequirements() external view returns (uint256, uint256) { - return (0, 0); - } - function getGroupLockedGoldRequirements() external view returns (uint256, uint256) { - return (0, 0); - } - function getRegisteredValidators() external view returns (address[] memory) { - return new address[](0); - } - function getRegisteredValidatorGroups() external view returns (address[] memory) { - return new address[](0); - } - function isValidatorGroup(address account) external view returns (bool) { - return true; - } - function isValidator(address account) external view returns (bool) { - return true; - } - function getValidatorGroupSlashingMultiplier(address account) external view returns (uint256) { - return 0; - } - - function getMembershipInLastEpoch(address account) external view returns (address) { - return address(0); - } - function getMembershipInLastEpochFromSigner(address signer) external view returns (address) { - return address(0); - } function computeEpochReward( address account, uint256 score, uint256 maxPayment - ) external view returns (uint256) { + ) external view override returns (uint256) { return 1; } - function getMembershipHistoryLength() external view returns (uint256) { - return 0; - } } diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 6930d5a1283..931ef839d0c 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -70,7 +70,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { carbonOffsettingPartner = actor("carbonOffsettingPartner"); communityRewardFund = actor("communityRewardFund"); - deployCodeTo("Registry.sol", abi.encode(false), REGISTRY_ADDRESS); + deployCodeTo("MockRegistry.sol", abi.encode(false), REGISTRY_ADDRESS); deployCodeTo("ScoreManager.sol", abi.encode(false), scoreManagerAddress); @@ -93,6 +93,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { celoToken.setBalanceOf(address(celoUnreleasedTreasure), L2_INITIAL_STASH_BALANCE); celoUnreleasedTreasure.setRegistry(REGISTRY_ADDRESS); + validators.setRegistry(REGISTRY_ADDRESS); sortedOracles.setMedianRate(address(stableToken), stableAmountForRate); @@ -109,6 +110,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { } function initializeEpochManagerSystem() public { + deployCodeTo("MockRegistry.sol", abi.encode(false), PROXY_ADMIN_ADDRESS); vm.prank(epochManagerEnabler); epochManager.initializeSystem(firstEpochNumber, firstEpochBlock, firstElected); From 1d4eaa4be0bb7832d3cb1641363434ab4951113c Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:00:10 -0400 Subject: [PATCH 41/69] clean up --- .../governance/test/MockElection.sol | 87 ------------------- .../devchain/migration/Migration.t.sol | 2 - 2 files changed, 89 deletions(-) delete mode 100644 packages/protocol/contracts-0.8/governance/test/MockElection.sol diff --git a/packages/protocol/contracts-0.8/governance/test/MockElection.sol b/packages/protocol/contracts-0.8/governance/test/MockElection.sol deleted file mode 100644 index 043a2af095e..00000000000 --- a/packages/protocol/contracts-0.8/governance/test/MockElection.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.7 <0.8.20; - -import "../../../contracts-0.8/common/IsL2Check.sol"; - -/** - * @title Holds a list of addresses of validators - */ -contract MockElection08 is IsL2Check { - mapping(address => bool) public isIneligible; - mapping(address => bool) public isEligible; - mapping(address => bool) public allowedToVoteOverMaxNumberOfGroups; - address[] public electedValidators; - uint256 active; - uint256 total; - - function markGroupIneligible(address account) external { - isIneligible[account] = true; - } - - function markGroupEligible(address account, address, address) external onlyL1 { - isEligible[account] = true; - } - - function setActiveVotes(uint256 value) external { - active = value; - } - - function setTotalVotes(uint256 value) external { - total = value; - } - - function setElectedValidators(address[] calldata _electedValidators) external { - electedValidators = _electedValidators; - } - - function vote(address, uint256, address, address) external onlyL1 returns (bool) { - return true; - } - - function activate(address) external onlyL1 returns (bool) { - return true; - } - - function revokeAllActive(address, address, address, uint256) external returns (bool) { - return true; - } - - function revokeActive(address, uint256, address, address, uint256) external returns (bool) { - return true; - } - - function revokePending(address, uint256, address, address, uint256) external returns (bool) { - return true; - } - - function forceDecrementVotes( - address, - uint256 value, - address[] calldata, - address[] calldata, - uint256[] calldata - ) external returns (uint256) { - this.setActiveVotes(this.getActiveVotes() - value); - return value; - } - - function getTotalVotes() external view returns (uint256) { - return total; - } - - function getActiveVotes() external view returns (uint256) { - return active; - } - - function getTotalVotesByAccount(address) external view returns (uint256) { - return 0; - } - - function electValidatorSigners() external view returns (address[] memory) { - return electedValidators; - } - - function setAllowedToVoteOverMaxNumberOfGroups(address account, bool flag) public onlyL1 { - allowedToVoteOverMaxNumberOfGroups[account] = flag; - } -} diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index 491ad7a77c0..5770766dadb 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -225,8 +225,6 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { blockTravel(vm, 43200); timeTravel(vm, DAY); - uint256 _currentEpoch = epochManager.getCurrentEpochNumber(); - epochManager.startNextEpochProcess(); (, , , uint256 _currentRewardsBlock) = epochManager.getCurrentEpoch(); From 43ae99350a8e80f41e531f2f53562bed5c699511 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:48:53 -0400 Subject: [PATCH 42/69] ++ mintStable test --- .../governance/validators/Validators.t.sol | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol b/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol index 460bd56f9f9..e6ae766024e 100644 --- a/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol +++ b/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol @@ -3430,6 +3430,33 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { } } +contract ValidatorsTest_MintStableToEpochManager is ValidatorsTest { + function test_Reverts_WhenL1() public { + vm.expectRevert("This method is not supported in L1."); + validators.mintStableToEpochManager(5); + } + + function test_Reverts_WhenCalledByOtherThanEpochManager() public { + _whenL2(); + vm.expectRevert("only registered contract"); + validators.mintStableToEpochManager(5); + } + function test_Reverts_WhenMintAmountIsZero() public { + _whenL2(); + vm.expectRevert("mint amount is zero."); + vm.prank(address(epochManager)); + validators.mintStableToEpochManager(0); + } + + function test_ShouldMintStableToEpochManager() public { + _whenL2(); + vm.prank(address(epochManager)); + validators.mintStableToEpochManager(5); + + assertEq(stableToken.balanceOf(address(epochManager)), 5); + } +} + contract ValidatorsTest_ForceDeaffiliateIfValidator is ValidatorsTest { function setUp() public { super.setUp(); From de06b4e098f4ecfc324e96a8f93eb328638212a1 Mon Sep 17 00:00:00 2001 From: soloseng <102702451+soloseng@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:52:11 -0400 Subject: [PATCH 43/69] -- TODO; compiles test when filtering --- packages/protocol/contracts-0.8/common/EpochManager.sol | 1 - packages/protocol/contracts-0.8/governance/Validators.sol | 1 - packages/protocol/test-sol/devchain/migration/Migration.t.sol | 1 - .../protocol/test-sol/unit/governance/voting/Election.t.sol | 3 ++- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 0316da8fce2..c5450e1c294 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -321,7 +321,6 @@ contract EpochManager is totalRewards += validatorReward; } // Mint all cUSD required for payment and the corresponding CELO - // TODO(soloseng): add test to check that epoch manager received funds. validators.mintStableToEpochManager(totalRewards); // this should have a setter for the oracle. diff --git a/packages/protocol/contracts-0.8/governance/Validators.sol b/packages/protocol/contracts-0.8/governance/Validators.sol index dcd31636717..23c438c29f6 100644 --- a/packages/protocol/contracts-0.8/governance/Validators.sol +++ b/packages/protocol/contracts-0.8/governance/Validators.sol @@ -647,7 +647,6 @@ contract Validators is group.slashInfo.lastSlashed = block.timestamp; } - // TODO(soloseng): add test to check that this function can only mint to epoch manager. function mintStableToEpochManager( uint256 amount ) external onlyL2 nonReentrant onlyRegisteredContract(EPOCH_MANAGER_REGISTRY_ID) { diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index 5770766dadb..488df1f6380 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -218,7 +218,6 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { epochManager.initializeSystem(100, block.number, firstElected); } - // XXX(soloseng): fails because EpochManager is not yet permissioned by stableToken to mint function test_SetsCurrentRewardBlock() public { _MockL2Migration(validatorsList); diff --git a/packages/protocol/test-sol/unit/governance/voting/Election.t.sol b/packages/protocol/test-sol/unit/governance/voting/Election.t.sol index c4ba6faaf15..e055288f0b0 100644 --- a/packages/protocol/test-sol/unit/governance/voting/Election.t.sol +++ b/packages/protocol/test-sol/unit/governance/voting/Election.t.sol @@ -7,6 +7,7 @@ import { TestConstants } from "@test-sol/constants.sol"; import { Utils } from "@test-sol/utils.sol"; import "@celo-contracts/common/FixidityLib.sol"; +import "@celo-contracts/common/Registry.sol"; import "@celo-contracts/governance/Election.sol"; import "@celo-contracts/governance/test/MockLockedGold.sol"; import "@celo-contracts/governance/test/MockValidators.sol"; @@ -162,6 +163,7 @@ contract ElectionTest is Utils, TestConstants { } function _whenL2() public { + blockTravel(ph.epochSize() + 1); uint256 l1EpochNumber = election.getEpochNumber(); address[] memory _elected = new address[](2); @@ -217,7 +219,6 @@ contract ElectionTest_SetElectabilityThreshold is ElectionTest { } } -// TODO(soloseng): need to update epochNumber for L2, to make it !=0 contract ElectionTest_SetElectabilityThreshold_L2 is ElectionTest { function test_shouldSetElectabilityThreshold() public { _whenL2(); From 15a52900713e1f374faf58d2b974d780e684ef52 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Fri, 13 Sep 2024 11:21:09 +0200 Subject: [PATCH 44/69] E2E test with 3 groups with 2 validators each --- .../contracts-0.8/common/EpochManager.sol | 4 +- .../contracts-0.8/governance/Validators.sol | 2 +- .../protocol/migrations_sol/Migration.s.sol | 98 ++++++++++--------- .../migrations_sol/migrationsConfig.json | 12 ++- .../devchain/e2e/common/EpochManager.t.sol | 86 +++++++++++++--- 5 files changed, 138 insertions(+), 64 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 53b821d47bc..6ec9a9e1ac9 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -207,7 +207,9 @@ contract EpochManager is require(epochProcessing.toProcessGroups == groups.length, "number of groups does not match"); - for (uint i = 0; i < groups.length; i++) { + // since we are adding values it makes sense to start from the end + for (uint ii = groups.length; ii > 0; ii--) { + uint256 i = ii - 1; // checks that group is actually from elected group require(processedGroups[groups[i]], "group not processed"); // by doing this, we avoid processing a group twice diff --git a/packages/protocol/contracts-0.8/governance/Validators.sol b/packages/protocol/contracts-0.8/governance/Validators.sol index 35d559db5e5..91f13df9d58 100644 --- a/packages/protocol/contracts-0.8/governance/Validators.sol +++ b/packages/protocol/contracts-0.8/governance/Validators.sol @@ -530,7 +530,7 @@ contract Validators is } /** - * @notice Adds the first member to a group's list of members and marks it eligible for election. + * @notice Adds the first member to a group's list of members and marks the group eligible for election. * @param validator The validator to add to the group * @param lesser The address of the group that has received fewer votes than this group. * @param greater The address of the group that has received more votes than this group. diff --git a/packages/protocol/migrations_sol/Migration.s.sol b/packages/protocol/migrations_sol/Migration.s.sol index 473a3731ea0..2b346dfff4d 100644 --- a/packages/protocol/migrations_sol/Migration.s.sol +++ b/packages/protocol/migrations_sol/Migration.s.sol @@ -1127,27 +1127,19 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { (bytes memory ecdsaPubKey, , , ) = _generateEcdsaPubKeyWithSigner(accountAddress, validatorKey); getValidators().registerValidator(ecdsaPubKey, newBlsPublicKey, newBlsPop); getValidators().affiliate(groupToAffiliate); - console.log("Done registering validatora"); + console.log("Done registering validators"); vm.stopBroadcast(); return accountAddress; } function getValidatorKeyIndex( + uint256 groupCount, uint256 groupIndex, uint256 validatorIndex, uint256 membersInAGroup ) public returns (uint256) { - return groupIndex * membersInAGroup + validatorIndex + 1; - } - - function getValidatorKeyFromGroupGroup( - uint256[] memory keys, - uint256 groupIndex, - uint256 validatorIndex, - uint256 membersInAGroup - ) public returns (uint256) { - return keys[getValidatorKeyIndex(groupIndex, validatorIndex, membersInAGroup)]; + return groupCount + groupIndex * membersInAGroup + validatorIndex; } function registerValidatorGroup( @@ -1243,48 +1235,62 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { ); } - uint256 validatorGroup0Key = valKeys[0]; + uint256 groupCount = 3; + console.log("groupCount", groupCount); - address groupAddress = registerValidatorGroup( - validatorGroup0Key, - maxGroupSize * validatorLockedGoldRequirements, - commission, - json - ); + address[] memory groups = new address[](groupCount); - console.log(" * Registering ${group.valKeys.length} validators ..."); + // register 3 validator groups + for (uint256 groupIndex = 0; groupIndex < groupCount; groupIndex++) { + address groupAddress = registerValidatorGroup( + valKeys[groupIndex], + maxGroupSize * validatorLockedGoldRequirements, + commission, + json + ); + groups[groupIndex] = groupAddress; + console.log("registered group: ", groupAddress); + } + + console.log(" * Registering validators ... Count: ", valKeys.length - groupCount); // Split the validator keys into groups that will fit within the max group size. - uint256 amountOfGroups = Math.ceilDiv(valKeys.length, maxGroupSize); + // uint256 amountOfGroups = Math.ceilDiv(valKeys.length - groupCount, maxGroupSize); + // console.log("Amount of groups: ", amountOfGroups); // TODO change name of variable amount of groups for amount in group - for (uint256 validatorIndex = 0; validatorIndex < amountOfGroups; validatorIndex++) { - console.log("Validator key index", getValidatorKeyIndex(0, validatorIndex, maxGroupSize)); - console.log("Registering validator #: ", validatorIndex); - address validator = registerValidator( - validatorIndex, - getValidatorKeyFromGroupGroup(valKeys, 0, validatorIndex, maxGroupSize), - validatorLockedGoldRequirements, - groupAddress - ); - // TODO start broadcast - console.log("Adding to group..."); - - vm.startBroadcast(validatorGroup0Key); - if (validatorIndex == 0) { - getValidators().addFirstMember(validator, address(0), address(0)); - console.log("Making group vote for itself"); - getElection().vote( - groupAddress, - getLockedGold().getAccountNonvotingLockedGold(groupAddress), - address(0), - address(0) + for (uint256 groupIndex = 0; groupIndex < groupCount; groupIndex++) { + address groupAddress = groups[groupIndex]; + console.log("Registering members for group: ", groupAddress); + for (uint256 validatorIndex = 0; validatorIndex < maxGroupSize; validatorIndex++) { + uint256 validatorKeyIndex = getValidatorKeyIndex(groupCount, groupIndex, validatorIndex, maxGroupSize); + console.log("Registering validator #: ", validatorIndex); + address validator = registerValidator( + validatorIndex, + valKeys[validatorKeyIndex], + validatorLockedGoldRequirements, + groupAddress ); - } else { - // unimplemented - console.log("WARNING: case not implemented"); - } + // TODO start broadcast + console.log("Adding to group..."); + + vm.startBroadcast(groups[groupIndex]); + address greater = groupIndex == 0 ? address(0) : groups[groupIndex - 1]; - vm.stopBroadcast(); + if (validatorIndex == 0) { + getValidators().addFirstMember(validator, address(0), greater); + console.log("Making group vote for itself"); + } else { + getValidators().addMember(validator); + } + getElection().vote( + groupAddress, + validatorLockedGoldRequirements, + address(0), + greater + ); + + vm.stopBroadcast(); + } } } } diff --git a/packages/protocol/migrations_sol/migrationsConfig.json b/packages/protocol/migrations_sol/migrationsConfig.json index 59d9f67f220..ac17b20838d 100644 --- a/packages/protocol/migrations_sol/migrationsConfig.json +++ b/packages/protocol/migrations_sol/migrationsConfig.json @@ -67,7 +67,7 @@ "commissionUpdateDelay": 51840, "commissionUpdateDelay_help": "(3 * DAY) / 5", - "maxGroupSize": 5, + "maxGroupSize": 2, "slashingMultiplierResetPeriod": 2592000, "slashingPenaltyResetPeriod_help": "30 * DAY", "downtimeGracePeriod": 0, @@ -76,7 +76,15 @@ "groupName": "cLabs", "commission": 100000000000000000000000, "votesRatioOfLastVsFirstGroup": 2000000000000000000000000, - "valKeys": ["0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d","0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a"] + "valKeys": ["0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", +"0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", +"0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", +"0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", +"0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba", +"0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e", +"0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", +"0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", +"0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6"] }, "election": { "minElectableValidators": 1, diff --git a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol index 6a234607dab..0bcb3b79d37 100644 --- a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol @@ -9,6 +9,7 @@ import { IEpochManager } from "@celo-contracts/common/interfaces/IEpochManager.s import "@celo-contracts-8/common/FeeCurrencyDirectory.sol"; import "@test-sol/utils/ECDSAHelper08.sol"; +import "@openzeppelin/contracts8/utils/structs/EnumerableSet.sol"; contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { address epochManagerOwner; @@ -16,12 +17,18 @@ contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { address[] firstElected; uint256 epochDuration; + uint256[] groupScore = [5e23, 7e23, 1e24]; struct VoterWithPK { address voter; uint256 privateKey; } + struct GroupWithVotes { + address group; + uint256 votes; + } + mapping(address => uint256) addressToPrivateKeys; mapping(address => VoterWithPK) validatorToVoter; @@ -38,21 +45,34 @@ contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { } function activateValidators() public { - uint256[] memory valKeys = new uint256[](2); + uint256[] memory valKeys = new uint256[](9); valKeys[0] = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d; valKeys[1] = 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a; + valKeys[2] = 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6; + valKeys[3] = 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a; + valKeys[4] = 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba; + valKeys[5] = 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e; + valKeys[6] = 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356; + valKeys[7] = 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97; + valKeys[8] = 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6; for (uint256 i = 0; i < valKeys.length; i++) { address account = vm.addr(valKeys[i]); addressToPrivateKeys[account] = valKeys[i]; } + + address[] memory registeredValidators = getValidators().getRegisteredValidators(); - for (uint256 i = 0; i < registeredValidators.length; i++) { - (, , address validatorGroup, , ) = getValidators().getValidator(registeredValidators[i]); + travelEpochL1(vm); travelEpochL1(vm); travelEpochL1(vm); travelEpochL1(vm); + for (uint256 i = 0; i < registeredValidators.length; i++) { + (, , address validatorGroup, , ) = getValidators().getValidator(registeredValidators[i]); + if (getElection().getPendingVotesForGroup(validatorGroup) == 0) { + continue; + } vm.startPrank(validatorGroup); election.activate(validatorGroup); vm.stopPrank(); @@ -149,7 +169,10 @@ contract E2E_EpochManager_StartNextEpochProcess is E2E_EpochManager { } contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { + using EnumerableSet for EnumerableSet.AddressSet; + address[] groups; + EnumerableSet.AddressSet internal originalyElected; function setUp() public override { super.setUp(); @@ -164,24 +187,43 @@ contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { groups = getValidators().getRegisteredValidatorGroups(); - vm.prank(scoreManager.owner()); - scoreManager.setGroupScore(groups[0], 1e24); + address scoreManagerOwner = scoreManager.owner(); + vm.startPrank(scoreManagerOwner); + scoreManager.setGroupScore(groups[0], groupScore[0]); + scoreManager.setGroupScore(groups[1], groupScore[1]); + scoreManager.setGroupScore(groups[2], groupScore[2]); + vm.stopPrank(); } function test_shouldFinishNextEpochProcessing() public { uint256[] memory groupActiveBalances = new uint256[](groups.length); - for (uint256 i = 0; i < groups.length; i++) { - groupActiveBalances[i] = election.getActiveVotesForGroup(groups[i]); + + GroupWithVotes[] memory groupWithVotes = new GroupWithVotes[](groups.length); + + (,,uint256 totalRewardsVote,,) = epochManager.getEpochProcessingState(); + + (address[] memory groupsEligible, uint256[] memory values) = election.getTotalVotesForEligibleValidatorGroups(); + + for (uint256 i = 0; i < groupsEligible.length; i++) { + groupActiveBalances[i] = election.getActiveVotesForGroup(groupsEligible[i]); + groupWithVotes[i] = GroupWithVotes(groupsEligible[i], values[i] + election.getGroupEpochRewards(groupsEligible[i], totalRewardsVote, groupScore[i])); } - address[] memory lessers = new address[](1); - lessers[0] = address(0); + sort(groupWithVotes); + + address[] memory lessers = new address[](groups.length); + address[] memory greaters = new address[](groups.length); - address[] memory greaters = new address[](1); - greaters[0] = address(0); + for (uint256 i = 0; i < groups.length; i++) { + lessers[i] = i == 0 ? address(0) : groupWithVotes[i - 1].group; + greaters[i] = i == groups.length - 1 ? address(0) : groupWithVotes[i + 1].group; + } uint256 currentEpoch = epochManager.getCurrentEpochNumber(); address[] memory currentlyElected = epochManager.getElected(); + for (uint256 i = 0; i < currentlyElected.length; i++) { + originalyElected.add(currentlyElected[i]); + } epochManager.finishNextEpochProcess(groups, lessers, greaters); @@ -190,11 +232,27 @@ contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { address[] memory newlyElected = epochManager.getElected(); for (uint256 i = 0; i < currentlyElected.length; i++) { - assertEq(currentlyElected[i], newlyElected[i]); + assertEq(originalyElected.contains(currentlyElected[i]), true); } - for (uint256 i = 0; i < groups.length; i++) { - assertGt(election.getActiveVotesForGroup(groups[i]), groupActiveBalances[i]); + for (uint256 i = 0; i < groupsEligible.length; i++) { + // assertEq(election.getActiveVotesForGroup(groupsEligible[i]), groupWithVotes[i].votes); TODO: This doesn't work since the vote proportion changes during updating of previous groups. Are we ok with this? + assertGt(election.getActiveVotesForGroup(groupsEligible[i]), groupActiveBalances[i]); } } + + // Bubble sort algorithm since it is a small array + function sort(GroupWithVotes[] memory items) public { + uint length = items.length; + for (uint i = 0; i < length; i++) { + for (uint j = 0; j < length - 1; j++) { + if (items[j].votes > items[j + 1].votes) { + // Swap + GroupWithVotes memory temp = items[j]; + items[j] = items[j + 1]; + items[j + 1] = temp; + } + } + } + } } From 84f4349bc9467edcc98b98a96b592b018fa669d7 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Fri, 13 Sep 2024 12:28:33 +0200 Subject: [PATCH 45/69] fix for rewards computation --- .../contracts-0.8/common/EpochManager.sol | 31 ++++++++++++------- .../devchain/e2e/common/EpochManager.t.sol | 2 +- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 6ec9a9e1ac9..b3d33d57dc3 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -50,9 +50,14 @@ contract EpochManager is uint256 private currentEpochNumber; address[] public elected; + struct ProcessedGroup { + bool processed; + uint256 epochRewards; + } + // TODO this should be able to get deleted easily // maybe even having it in a stadalone contract - mapping(address => bool) public processedGroups; + mapping(address => ProcessedGroup) public processedGroups; EpochProcessState public epochProcessing; mapping(uint256 => Epoch) private epochs; @@ -199,9 +204,16 @@ contract EpochManager is for (uint i = 0; i < elected.length; i++) { address group = getValidators().getValidatorsGroup(elected[i]); - if (!processedGroups[group]) { + if (!processedGroups[group].processed) { epochProcessing.toProcessGroups++; - processedGroups[group] = true; + uint256 groupScore = getScoreReader().getGroupScore(group); + // We need to precompute epoch rewards for each group since computation depends on total active votes for all groups. + uint256 epochRewards = getElection().getGroupEpochRewards( + group, + epochProcessing.totalRewardsVoter, + groupScore + ); + processedGroups[group] = ProcessedGroup(true, epochRewards); } } @@ -210,18 +222,13 @@ contract EpochManager is // since we are adding values it makes sense to start from the end for (uint ii = groups.length; ii > 0; ii--) { uint256 i = ii - 1; + ProcessedGroup storage processedGroup = processedGroups[groups[i]]; // checks that group is actually from elected group - require(processedGroups[groups[i]], "group not processed"); + require(processedGroup.processed, "group not processed"); + getElection().distributeEpochRewards(groups[i], processedGroup.epochRewards, lessers[i], greaters[i]); + // by doing this, we avoid processing a group twice delete processedGroups[groups[i]]; - // TODO what happens to uptime? - uint256 groupScore = getScoreReader().getGroupScore(groups[i]); - uint256 epochRewards = getElection().getGroupEpochRewards( - groups[i], - epochProcessing.totalRewardsVoter, - groupScore - ); - getElection().distributeEpochRewards(groups[i], epochRewards, lessers[i], greaters[i]); } getCeloUnreleasedTreasure().release( registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID), diff --git a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol index 0bcb3b79d37..0278fca9d3e 100644 --- a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol @@ -236,7 +236,7 @@ contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { } for (uint256 i = 0; i < groupsEligible.length; i++) { - // assertEq(election.getActiveVotesForGroup(groupsEligible[i]), groupWithVotes[i].votes); TODO: This doesn't work since the vote proportion changes during updating of previous groups. Are we ok with this? + assertEq(election.getActiveVotesForGroup(groupsEligible[i]), groupWithVotes[i].votes); assertGt(election.getActiveVotesForGroup(groupsEligible[i]), groupActiveBalances[i]); } } From 17c5884237324fd7e7c836f39a298710c7438576 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Fri, 13 Sep 2024 13:48:28 +0200 Subject: [PATCH 46/69] lint --- .../contracts-0.8/common/EpochManager.sol | 7 ++- .../contracts/governance/Election.sol | 2 +- .../protocol/migrations_sol/Migration.s.sol | 22 ++++---- .../devchain/e2e/common/EpochManager.t.sol | 51 ++++++++++--------- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index b3d33d57dc3..c59cf8e4f9e 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -225,7 +225,12 @@ contract EpochManager is ProcessedGroup storage processedGroup = processedGroups[groups[i]]; // checks that group is actually from elected group require(processedGroup.processed, "group not processed"); - getElection().distributeEpochRewards(groups[i], processedGroup.epochRewards, lessers[i], greaters[i]); + getElection().distributeEpochRewards( + groups[i], + processedGroup.epochRewards, + lessers[i], + greaters[i] + ); // by doing this, we avoid processing a group twice delete processedGroups[groups[i]]; diff --git a/packages/protocol/contracts/governance/Election.sol b/packages/protocol/contracts/governance/Election.sol index c3450315c56..91e022d0979 100644 --- a/packages/protocol/contracts/governance/Election.sol +++ b/packages/protocol/contracts/governance/Election.sol @@ -153,7 +153,7 @@ contract Election is ); event EpochRewardsDistributedToVoters(address indexed group, uint256 value); - modifier onlyVmOrPermitted(address permittedAddress) { + modifier onlyVmOrPermitted(address permittedAddress) { if (isL2()) require(msg.sender == permittedAddress, "Only permitted address can call"); else { require(msg.sender == address(0), "Only VM can call"); diff --git a/packages/protocol/migrations_sol/Migration.s.sol b/packages/protocol/migrations_sol/Migration.s.sol index 2b346dfff4d..b1a4fda4505 100644 --- a/packages/protocol/migrations_sol/Migration.s.sol +++ b/packages/protocol/migrations_sol/Migration.s.sol @@ -1134,7 +1134,7 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { } function getValidatorKeyIndex( - uint256 groupCount, + uint256 groupCount, uint256 groupIndex, uint256 validatorIndex, uint256 membersInAGroup @@ -1158,7 +1158,7 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { vm.stopBroadcast(); } - function _generateEcdsaPubKeyWithSigner( + function _generateEcdsaPubKeyWithSigner( address _validator, uint256 _signerPk ) internal returns (bytes memory ecdsaPubKey, uint8 v, bytes32 r, bytes32 s) { @@ -1169,7 +1169,7 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { ecdsaPubKey = addressToPublicKey(addressHash, v, r, s); } - function addressToPublicKey( + function addressToPublicKey( bytes32 message, uint8 _v, bytes32 _r, @@ -1261,8 +1261,13 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { for (uint256 groupIndex = 0; groupIndex < groupCount; groupIndex++) { address groupAddress = groups[groupIndex]; console.log("Registering members for group: ", groupAddress); - for (uint256 validatorIndex = 0; validatorIndex < maxGroupSize; validatorIndex++) { - uint256 validatorKeyIndex = getValidatorKeyIndex(groupCount, groupIndex, validatorIndex, maxGroupSize); + for (uint256 validatorIndex = 0; validatorIndex < maxGroupSize; validatorIndex++) { + uint256 validatorKeyIndex = getValidatorKeyIndex( + groupCount, + groupIndex, + validatorIndex, + maxGroupSize + ); console.log("Registering validator #: ", validatorIndex); address validator = registerValidator( validatorIndex, @@ -1282,12 +1287,7 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { } else { getValidators().addMember(validator); } - getElection().vote( - groupAddress, - validatorLockedGoldRequirements, - address(0), - greater - ); + getElection().vote(groupAddress, validatorLockedGoldRequirements, address(0), greater); vm.stopBroadcast(); } diff --git a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol index 0278fca9d3e..b2334ec3d60 100644 --- a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol @@ -61,18 +61,16 @@ contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { addressToPrivateKeys[account] = valKeys[i]; } - - address[] memory registeredValidators = getValidators().getRegisteredValidators(); - travelEpochL1(vm); - travelEpochL1(vm); - travelEpochL1(vm); - travelEpochL1(vm); + travelEpochL1(vm); + travelEpochL1(vm); + travelEpochL1(vm); + travelEpochL1(vm); for (uint256 i = 0; i < registeredValidators.length; i++) { (, , address validatorGroup, , ) = getValidators().getValidator(registeredValidators[i]); - if (getElection().getPendingVotesForGroup(validatorGroup) == 0) { - continue; - } + if (getElection().getPendingVotesForGroup(validatorGroup) == 0) { + continue; + } vm.startPrank(validatorGroup); election.activate(validatorGroup); vm.stopPrank(); @@ -200,13 +198,18 @@ contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { GroupWithVotes[] memory groupWithVotes = new GroupWithVotes[](groups.length); - (,,uint256 totalRewardsVote,,) = epochManager.getEpochProcessingState(); + (, , uint256 totalRewardsVote, , ) = epochManager.getEpochProcessingState(); - (address[] memory groupsEligible, uint256[] memory values) = election.getTotalVotesForEligibleValidatorGroups(); + (address[] memory groupsEligible, uint256[] memory values) = election + .getTotalVotesForEligibleValidatorGroups(); for (uint256 i = 0; i < groupsEligible.length; i++) { groupActiveBalances[i] = election.getActiveVotesForGroup(groupsEligible[i]); - groupWithVotes[i] = GroupWithVotes(groupsEligible[i], values[i] + election.getGroupEpochRewards(groupsEligible[i], totalRewardsVote, groupScore[i])); + groupWithVotes[i] = GroupWithVotes( + groupsEligible[i], + values[i] + + election.getGroupEpochRewards(groupsEligible[i], totalRewardsVote, groupScore[i]) + ); } sort(groupWithVotes); @@ -241,18 +244,18 @@ contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { } } - // Bubble sort algorithm since it is a small array - function sort(GroupWithVotes[] memory items) public { - uint length = items.length; - for (uint i = 0; i < length; i++) { - for (uint j = 0; j < length - 1; j++) { - if (items[j].votes > items[j + 1].votes) { - // Swap - GroupWithVotes memory temp = items[j]; - items[j] = items[j + 1]; - items[j + 1] = temp; - } - } + // Bubble sort algorithm since it is a small array + function sort(GroupWithVotes[] memory items) public { + uint length = items.length; + for (uint i = 0; i < length; i++) { + for (uint j = 0; j < length - 1; j++) { + if (items[j].votes > items[j + 1].votes) { + // Swap + GroupWithVotes memory temp = items[j]; + items[j] = items[j + 1]; + items[j + 1] = temp; + } } } + } } From 9ddb5225719b4b45f282fa2d9ba87399068401b8 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Fri, 13 Sep 2024 17:24:03 +0200 Subject: [PATCH 47/69] anvil migration rename --- .../{3_1_score_manager.ts => 26_101_score_manager.ts} | 0 ..._epoch_manager_enabler.ts => 26_102_epoch_manager_enabler.ts} | 0 .../{3_3_epoch_manager.ts => 26_103_epoch_manager.ts} | 0 .../protocol/test-sol/devchain/e2e/common/EpochManager.t.sol | 1 - 4 files changed, 1 deletion(-) rename packages/protocol/migrations_ts/{3_1_score_manager.ts => 26_101_score_manager.ts} (100%) rename packages/protocol/migrations_ts/{3_2_epoch_manager_enabler.ts => 26_102_epoch_manager_enabler.ts} (100%) rename packages/protocol/migrations_ts/{3_3_epoch_manager.ts => 26_103_epoch_manager.ts} (100%) diff --git a/packages/protocol/migrations_ts/3_1_score_manager.ts b/packages/protocol/migrations_ts/26_101_score_manager.ts similarity index 100% rename from packages/protocol/migrations_ts/3_1_score_manager.ts rename to packages/protocol/migrations_ts/26_101_score_manager.ts diff --git a/packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts b/packages/protocol/migrations_ts/26_102_epoch_manager_enabler.ts similarity index 100% rename from packages/protocol/migrations_ts/3_2_epoch_manager_enabler.ts rename to packages/protocol/migrations_ts/26_102_epoch_manager_enabler.ts diff --git a/packages/protocol/migrations_ts/3_3_epoch_manager.ts b/packages/protocol/migrations_ts/26_103_epoch_manager.ts similarity index 100% rename from packages/protocol/migrations_ts/3_3_epoch_manager.ts rename to packages/protocol/migrations_ts/26_103_epoch_manager.ts diff --git a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol index 6c6e756e64a..99a9bd82b98 100644 --- a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol @@ -129,7 +129,6 @@ contract E2E_EpochManager_StartNextEpochProcess is E2E_EpochManager { activateValidators(); whenL2(vm); - validatorsArray = getValidators().getRegisteredValidators(); groups = getValidators().getRegisteredValidatorGroups(); From 48cf98c3a9fdd659f93ef8a52d3b49eda01d0e7b Mon Sep 17 00:00:00 2001 From: pahor167 Date: Fri, 13 Sep 2024 17:31:21 +0200 Subject: [PATCH 48/69] remove setEpochMangerEnabler --- .../contracts-0.8/common/EpochManager.sol | 9 --------- .../test-sol/unit/common/EpochManager.t.sol | 15 --------------- .../unit/governance/voting/Election.t.sol | 7 ------- 3 files changed, 31 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 2721fd0317d..1dbd58a5475 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -109,15 +109,6 @@ contract EpochManager is epochManagerEnabler = _epochManagerEnabler; } - /** - * @notice Sets the address of the Epoch Manager Enabler. - * @param _epochManagerEnabler The address of the Epoch Manager Enabler. - */ - function setEpochMangerEnabler(address _epochManagerEnabler) external onlyOwner { - require(_epochManagerEnabler != address(0), "EpochManagerEnabler address is required"); - epochManagerEnabler = _epochManagerEnabler; - } - // DESIGNDESICION(XXX): we assume that the first epoch on the L2 starts as soon as the system is initialized // to minimize amount of "limbo blocks" the network should stop relatively close to an epoch number (but wigh enough time) // to have time to call the function EpochInitializer.migrateEpochAndValidators() diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index dfdf7fb78f4..c3c0fd75801 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -241,18 +241,3 @@ contract EpochManagerTest_startNextEpochProcess is EpochManagerTest { assertEq(reserveBalanceAfter, reserveBalanceBefore + 4); } } - -contract EpochManagerTest_setEpochMangerEnabler is EpochManagerTest { - function test_setEpochMangerEnabler() public { - vm.prank(epochManager.owner()); - address newEpochManagerEnabler = actor("newEpochManagerEnabler"); - epochManager.setEpochMangerEnabler(newEpochManagerEnabler); - assertEq(epochManager.epochManagerEnabler(), newEpochManagerEnabler); - } - - function test_Reverts_WhenNotCalledByEpochManagerEnabler() public { - vm.expectRevert("Ownable: caller is not the owner"); - vm.prank(nonOwner); - epochManager.setEpochMangerEnabler(actor("newEpochManagerEnabler")); - } -} diff --git a/packages/protocol/test-sol/unit/governance/voting/Election.t.sol b/packages/protocol/test-sol/unit/governance/voting/Election.t.sol index e055288f0b0..3ac0251451c 100644 --- a/packages/protocol/test-sol/unit/governance/voting/Election.t.sol +++ b/packages/protocol/test-sol/unit/governance/voting/Election.t.sol @@ -2621,13 +2621,6 @@ contract ElectionTest_DistributeEpochRewards is ElectionTest { assertEq(election.getActiveVotesForGroupByAccount(group, voter), voteValue + rewardValue); } - function test_Revert_DistributeEpochRewards_WhenL2() public { - _whenL2(); - vm.expectRevert("This method is no longer supported in L2."); - vm.prank(address(0)); - election.distributeEpochRewards(group, rewardValue, address(0), address(0)); - } - function test_ShouldIncrementAccountTotalVotesForGroup_WhenThereIsSingleGroupWithActiveVotes() public { From 28bf1ff471ff0f0cc8fe9080c672c7f81a0493f5 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 16 Sep 2024 10:53:28 +0200 Subject: [PATCH 49/69] truffle build fix --- .../protocol/contracts-0.8/common/test/MockRegistry.sol | 6 +++--- .../contracts-0.8/governance/test/ValidatorsMock08.sol | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/test/MockRegistry.sol b/packages/protocol/contracts-0.8/common/test/MockRegistry.sol index cda7d7d133b..eb42d084be4 100644 --- a/packages/protocol/contracts-0.8/common/test/MockRegistry.sol +++ b/packages/protocol/contracts-0.8/common/test/MockRegistry.sol @@ -4,9 +4,9 @@ pragma solidity >=0.8.7 <0.8.20; import "@openzeppelin/contracts8/utils/math/SafeMath.sol"; import "@openzeppelin/contracts8/access/Ownable.sol"; -import "@celo-contracts/common/interfaces/IRegistry.sol"; -import "@celo-contracts/common/interfaces/IRegistryInitializer.sol"; -import "@celo-contracts/common/Initializable.sol"; +import "../../../contracts/common/interfaces/IRegistry.sol"; +import "../../../contracts/common/interfaces/IRegistryInitializer.sol"; +import "../../../contracts/common/Initializable.sol"; /** * @title Routes identifiers to addresses. diff --git a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol index c2d7fdf3d2c..bf0843078e1 100644 --- a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol +++ b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol @@ -4,8 +4,6 @@ pragma solidity >=0.8.7 <0.8.20; import "../Validators.sol"; import "../../../contracts/common/FixidityLib.sol"; -import "forge-std-8/console2.sol"; - /** * @title A wrapper around Validators that exposes onlyVm functions for testing. */ From e5ffbf1af0f221fd16fc3d6bd672e0ef0526d860 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 16 Sep 2024 11:45:52 +0200 Subject: [PATCH 50/69] initializeEpochManagerSystem --- .../protocol/migrations_sol/MigrationL2.s.sol | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/protocol/migrations_sol/MigrationL2.s.sol b/packages/protocol/migrations_sol/MigrationL2.s.sol index 45878f1bc9e..f680562f31c 100644 --- a/packages/protocol/migrations_sol/MigrationL2.s.sol +++ b/packages/protocol/migrations_sol/MigrationL2.s.sol @@ -3,6 +3,9 @@ pragma solidity >=0.8.7 <0.8.20; import { Script } from "forge-std-8/Script.sol"; import { MigrationsConstants } from "@migrations-sol/constants.sol"; +// Foundry imports +import "forge-std/console.sol"; + import "@celo-contracts/common/FixidityLib.sol"; import "@celo-contracts-8/common/UsingRegistry.sol"; @@ -18,6 +21,8 @@ contract MigrationL2 is Script, MigrationsConstants, UsingRegistry { setupUsingRegistry(); dealToCeloUnreleasedTreasure(); + initializeEpochManagerSystem(); + vm.stopBroadcast(); } @@ -29,4 +34,15 @@ contract MigrationL2 is Script, MigrationsConstants, UsingRegistry { function dealToCeloUnreleasedTreasure() public { vm.deal(address(getCeloUnreleasedTreasure()), 1_000_000 ether); } + + function initializeEpochManagerSystem() public { + console.log("Initialize Epoch Manager System"); + address[] memory firstElected = getValidators().getRegisteredValidators(); + IEpochManager epochManager = getEpochManager(); + address epochManagerEnabler = epochManager.epochManagerEnabler(); + vm.stopBroadcast(); + vm.prank(epochManagerEnabler); + epochManager.initializeSystem(1, 1, firstElected); + vm.startBroadcast(DEPLOYER_ACCOUNT); + } } From 96363fca7735c65d36cb2c4e1b495b4b2b299845 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 16 Sep 2024 15:31:54 +0200 Subject: [PATCH 51/69] migration test fix --- .../devchain/migration/Migration.t.sol | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index 488df1f6380..6f1f3fef4ff 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -13,10 +13,13 @@ import "@celo-contracts/common/interfaces/ICeloToken.sol"; import "@celo-contracts/common/interfaces/IAccounts.sol"; import "@celo-contracts/common/interfaces/IEpochManager.sol"; import "@celo-contracts/common/interfaces/IEpochManagerEnabler.sol"; +import "@celo-contracts/common/interfaces/ICeloUnreleasedTreasure.sol"; +import "@celo-contracts/governance/interfaces/IElection.sol"; import "@celo-contracts/governance/interfaces/IValidators.sol"; import "@celo-contracts-8/common/interfaces/IPrecompiles.sol"; +import "@celo-contracts-8/common/interfaces/IScoreManager.sol"; contract IntegrationTest is Test, TestConstants, Utils08 { IRegistry registry = IRegistry(REGISTRY_ADDRESS); @@ -142,6 +145,9 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { IValidators validatorsContract; IEpochManager epochManager; IEpochManagerEnabler epochManagerEnabler; + IScoreManager scoreManager; + IElection election; + ICeloUnreleasedTreasure celoUnreleasedTreasure; address reserveAddress; address unreleasedTreasury; @@ -151,6 +157,10 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { uint256 firstEpochBlock = 100; address[] firstElected; address[] validatorsList; + address[] groupList; + + uint256[] groupScore = [5e23, 7e23, 1e24]; + uint256[] validatorScore = [1e23, 1e23, 1e23, 1e23, 1e23, 1e23]; function setUp() public override { super.setUp(); @@ -159,6 +169,7 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { validatorsContract = IValidators(registry.getAddressForStringOrDie("Validators")); validatorsList = validatorsContract.getRegisteredValidators(); + groupList = validatorsContract.getRegisteredValidatorGroups(); unreleasedTreasury = registry.getAddressForStringOrDie("CeloUnreleasedTreasure"); reserveAddress = registry.getAddressForStringOrDie("Reserve"); @@ -177,6 +188,47 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { epochManagerEnabler = IEpochManagerEnabler( registry.getAddressForStringOrDie("EpochManagerEnabler") ); + scoreManager = IScoreManager(registry.getAddressForStringOrDie("ScoreManager")); + election = IElection(registry.getAddressForStringOrDie("Election")); + celoUnreleasedTreasure = ICeloUnreleasedTreasure( + registry.getAddressForStringOrDie("CeloUnreleasedTreasure") + ); + + address scoreManagerOwner = scoreManager.owner(); + vm.startPrank(scoreManagerOwner); + + scoreManager.setGroupScore(groupList[0], groupScore[0]); + scoreManager.setGroupScore(groupList[1], groupScore[1]); + scoreManager.setGroupScore(groupList[2], groupScore[2]); + + scoreManager.setValidatorScore(validatorsList[0], validatorScore[0]); + scoreManager.setValidatorScore(validatorsList[1], validatorScore[1]); + scoreManager.setValidatorScore(validatorsList[2], validatorScore[2]); + scoreManager.setValidatorScore(validatorsList[3], validatorScore[3]); + scoreManager.setValidatorScore(validatorsList[4], validatorScore[4]); + scoreManager.setValidatorScore(validatorsList[5], validatorScore[5]); + + vm.stopPrank(); + + activateValidators(); + vm.deal(address(celoUnreleasedTreasure), 100_000_000 ether); + } + + function activateValidators() public { + address[] memory registeredValidators = validatorsContract.getRegisteredValidators(); + travelEpochL1(vm); + travelEpochL1(vm); + travelEpochL1(vm); + travelEpochL1(vm); + for (uint256 i = 0; i < registeredValidators.length; i++) { + (, , address validatorGroup, , ) = validatorsContract.getValidator(registeredValidators[i]); + if (election.getPendingVotesForGroup(validatorGroup) == 0) { + continue; + } + vm.startPrank(validatorGroup); + election.activate(validatorGroup); + vm.stopPrank(); + } } function test_IsSetupCorrect() public { @@ -228,7 +280,7 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { (, , , uint256 _currentRewardsBlock) = epochManager.getCurrentEpoch(); - assertEq(_currentRewardsBlock, block.number - 1); + assertEq(_currentRewardsBlock, block.number); } function _MockL2Migration(address[] memory _validatorsList) internal { From 812604d3b6ad5f609b10c8d36e5c0e32972d3512 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 16 Sep 2024 15:32:32 +0200 Subject: [PATCH 52/69] prettify --- packages/protocol/test-sol/devchain/migration/Migration.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index 6f1f3fef4ff..8b40b51f33f 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -214,7 +214,7 @@ contract EpochManagerIntegrationTest is IntegrationTest, MigrationsConstants { vm.deal(address(celoUnreleasedTreasure), 100_000_000 ether); } - function activateValidators() public { + function activateValidators() public { address[] memory registeredValidators = validatorsContract.getRegisteredValidators(); travelEpochL1(vm); travelEpochL1(vm); From abdbae44c80247fcb67ea6d209e630ea16b46fbb Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 16 Sep 2024 15:52:41 +0200 Subject: [PATCH 53/69] removal of logging --- .../protocol/test-sol/devchain/e2e/common/EpochManager.t.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol index 99a9bd82b98..6f5b433830b 100644 --- a/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/devchain/e2e/common/EpochManager.t.sol @@ -10,7 +10,6 @@ import { IEpochManager } from "@celo-contracts/common/interfaces/IEpochManager.s import "@celo-contracts-8/common/FeeCurrencyDirectory.sol"; import "@test-sol/utils/ECDSAHelper08.sol"; import "@openzeppelin/contracts8/utils/structs/EnumerableSet.sol"; -import "forge-std/console.sol"; contract E2E_EpochManager is Test, Devchain, Utils08, ECDSAHelper08 { address epochManagerOwner; @@ -197,7 +196,6 @@ contract E2E_EpochManager_FinishNextEpochProcess is E2E_EpochManager { EnumerableSet.AddressSet internal originalyElected; function setUp() public override { - console.log("ininininininini E2E_EpochManager_FinishNextEpochProcess"); super.setUp(); activateValidators(); whenL2(vm); From 55bd69b4a43e40b0a0f120b732096443d8f90754 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 16 Sep 2024 15:53:45 +0200 Subject: [PATCH 54/69] removal of logging2 --- .../protocol/test-sol/unit/stability/FeeCurrencyAdapter.t.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/protocol/test-sol/unit/stability/FeeCurrencyAdapter.t.sol b/packages/protocol/test-sol/unit/stability/FeeCurrencyAdapter.t.sol index 13f13bd6d97..44a754e231c 100644 --- a/packages/protocol/test-sol/unit/stability/FeeCurrencyAdapter.t.sol +++ b/packages/protocol/test-sol/unit/stability/FeeCurrencyAdapter.t.sol @@ -130,7 +130,6 @@ contract FeeCurrencyAdapter_Initialize is FeeCurrencyAdapterTest { function test_ShouldSucceed_WhenExpectedDecimalsAreMoreThenDecimals_Fuzz(uint8 amount) public { vm.assume(amount > 6); vm.assume(amount < 50); - console.log("amount", amount); feeCurrencyAdapterForFuzzyTests.initialize(address(feeCurrency), "adapter", "ad", amount); } @@ -303,7 +302,6 @@ contract FeeCurrencyAdapter_CreditGasFees is FeeCurrencyAdapterTest { function creditFuzzHelper(uint8 expectedDigits, uint256 multiplier) public { uint256 originalAmount = 1000; uint256 amount = originalAmount * multiplier; - console.log("amount", amount); address secondAddress = actor("secondAddress"); address thirdAddress = actor("thirdAddress"); From fe9183112daa249da5cbed1dbbd6b14c9e26ed2f Mon Sep 17 00:00:00 2001 From: pahor167 <47992132+pahor167@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:31:29 +0200 Subject: [PATCH 55/69] EpochManagerEnabler version --- .../contracts-0.8/common/EpochManagerEnabler.sol | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol b/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol index ba33773b9b9..4fa0541d089 100644 --- a/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol +++ b/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol @@ -60,6 +60,17 @@ contract EpochManagerEnabler is Initializable, UsingPrecompiles, UsingRegistry { } } + /** + * @notice Returns the storage, major, minor, and patch version of the contract. + * @return Storage version of the contract. + * @return Major version of the contract. + * @return Minor version of the contract. + * @return Patch version of the contract. + */ + function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) { + return (1, 1, 0, 0); + } + function getFirstBlockOfEpoch(uint256 currentEpoch) external view returns (uint256) { return _getFirstBlockOfEpoch(currentEpoch); } From 2c5a95fbc9032b52f3b9f764c5b1158f8bd89fce Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 16 Sep 2024 20:29:36 +0200 Subject: [PATCH 56/69] Enable epoch manager in devchain --- .../common/EpochManagerEnabler.sol | 6 +- .../interfaces/IEpochManagerEnabler.sol | 1 + .../protocol/migrations_sol/Migration.s.sol | 20 +++++++ .../protocol/migrations_sol/MigrationL2.s.sol | 12 ++-- .../create_and_migrate_anvil_devchain.sh | 11 +++- .../create_and_migrate_anvil_l2_devchain.sh | 15 ++--- .../scripts/foundry/deploy_precompiles.sh | 10 +++- .../protocol/scripts/foundry/start_anvil.sh | 1 + .../test-sol/devchain/ImportPrecompiles.t.sol | 2 + .../devchain/migration/Migration.t.sol | 1 + ...NumberValidatorsInCurrentSetPrecompile.sol | 32 +++++++++++ ...rSignerAddressFromCurrentSetPrecompile.sol | 57 +++++++++++++++++++ .../unit/common/ImportPrecompiles.t.sol | 2 + 13 files changed, 148 insertions(+), 22 deletions(-) create mode 100644 packages/protocol/test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol create mode 100644 packages/protocol/test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol diff --git a/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol b/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol index 4fa0541d089..c6031314c81 100644 --- a/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol +++ b/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol @@ -11,6 +11,7 @@ import "../../contracts/governance/interfaces/IEpochRewards.sol"; contract EpochManagerEnabler is Initializable, UsingPrecompiles, UsingRegistry { uint256 public lastKnownEpochNumber; + uint256 public lastKnownFirstBlockOfEpoch; address[] public lastKnownElectedAccounts; /** @@ -33,10 +34,11 @@ contract EpochManagerEnabler is Initializable, UsingPrecompiles, UsingRegistry { */ function initEpochManager() external onlyL2 { require(lastKnownEpochNumber != 0, "lastKnownEpochNumber not set."); + require(lastKnownFirstBlockOfEpoch != 0, "lastKnownFirstBlockOfEpoch not set."); require(lastKnownElectedAccounts.length > 0, "lastKnownElectedAccounts not set."); getEpochManager().initializeSystem( lastKnownEpochNumber, - _getFirstBlockOfEpoch(lastKnownEpochNumber), + lastKnownFirstBlockOfEpoch, lastKnownElectedAccounts ); } @@ -48,8 +50,8 @@ contract EpochManagerEnabler is Initializable, UsingPrecompiles, UsingRegistry { lastKnownEpochNumber = getEpochNumber(); uint256 numberElectedValidators = numberValidatorsInCurrentSet(); - lastKnownElectedAccounts = new address[](numberElectedValidators); + lastKnownFirstBlockOfEpoch = _getFirstBlockOfEpoch(lastKnownEpochNumber); for (uint256 i = 0; i < numberElectedValidators; i++) { // TODO: document how much gas this takes for 110 signers diff --git a/packages/protocol/contracts/common/interfaces/IEpochManagerEnabler.sol b/packages/protocol/contracts/common/interfaces/IEpochManagerEnabler.sol index bfd969402f9..c245dac581a 100644 --- a/packages/protocol/contracts/common/interfaces/IEpochManagerEnabler.sol +++ b/packages/protocol/contracts/common/interfaces/IEpochManagerEnabler.sol @@ -4,4 +4,5 @@ pragma solidity >=0.5.13 <0.9.0; interface IEpochManagerEnabler { function initEpochManager() external; function getEpochNumber() external returns (uint256); + function captureEpochAndValidators() external; } diff --git a/packages/protocol/migrations_sol/Migration.s.sol b/packages/protocol/migrations_sol/Migration.s.sol index b1a4fda4505..93735304ce7 100644 --- a/packages/protocol/migrations_sol/Migration.s.sol +++ b/packages/protocol/migrations_sol/Migration.s.sol @@ -27,6 +27,7 @@ import "@celo-contracts/common/interfaces/IFeeHandler.sol"; import "@celo-contracts/common/interfaces/IFeeHandlerInitializer.sol"; import "@celo-contracts/common/interfaces/IFeeCurrencyWhitelist.sol"; import "@celo-contracts/common/interfaces/IAccounts.sol"; +import "@celo-contracts/common/interfaces/IEpochManagerEnabler.sol"; import "@celo-contracts/governance/interfaces/ILockedGoldInitializer.sol"; import "@celo-contracts/governance/interfaces/IValidatorsInitializer.sol"; import "@celo-contracts/governance/interfaces/IElectionInitializer.sol"; @@ -249,6 +250,12 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { // Functions with broadcast with different addresses // Validators needs to lock, which can be only used by the msg.sender electValidators(json); + + vm.startBroadcast(DEPLOYER_ACCOUNT); + + captureEpochManagerEnablerValidators(); + + vm.stopBroadcast(); } /** @@ -944,6 +951,7 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { abi.encodeWithSelector(IEpochManagerEnablerInitializer.initialize.selector, REGISTRY_ADDRESS) ); } + function migrateScoreManager() public { deployProxiedContract( "ScoreManager", @@ -1293,4 +1301,16 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { } } } + + function captureEpochManagerEnablerValidators() public { + address numberValidatorsInCurrentSetPrecompileAddress = 0x00000000000000000000000000000000000000f9; + numberValidatorsInCurrentSetPrecompileAddress.call(abi.encodeWithSignature("setNumberOfValidators()")); + + address validatorSignerAddressFromCurrentSetPrecompileAddress = 0x00000000000000000000000000000000000000fa; + validatorSignerAddressFromCurrentSetPrecompileAddress.call(abi.encodeWithSignature("setValidators()")); + + address epochManagerEnabler = registry.getAddressForString("EpochManagerEnabler"); + IEpochManagerEnabler epochManagerEnablerContract = IEpochManagerEnabler(epochManagerEnabler); + epochManagerEnablerContract.captureEpochAndValidators(); + } } diff --git a/packages/protocol/migrations_sol/MigrationL2.s.sol b/packages/protocol/migrations_sol/MigrationL2.s.sol index f680562f31c..6147a4c3507 100644 --- a/packages/protocol/migrations_sol/MigrationL2.s.sol +++ b/packages/protocol/migrations_sol/MigrationL2.s.sol @@ -8,6 +8,7 @@ import "forge-std/console.sol"; import "@celo-contracts/common/FixidityLib.sol"; import "@celo-contracts-8/common/UsingRegistry.sol"; +import "../../contracts/common/interfaces/IEpochManagerEnabler.sol"; contract MigrationL2 is Script, MigrationsConstants, UsingRegistry { using FixidityLib for FixidityLib.Fraction; @@ -36,13 +37,12 @@ contract MigrationL2 is Script, MigrationsConstants, UsingRegistry { } function initializeEpochManagerSystem() public { - console.log("Initialize Epoch Manager System"); + console.log("Initializing EpochManager system"); address[] memory firstElected = getValidators().getRegisteredValidators(); IEpochManager epochManager = getEpochManager(); - address epochManagerEnabler = epochManager.epochManagerEnabler(); - vm.stopBroadcast(); - vm.prank(epochManagerEnabler); - epochManager.initializeSystem(1, 1, firstElected); - vm.startBroadcast(DEPLOYER_ACCOUNT); + address epochManagerEnablerAddress = epochManager.epochManagerEnabler(); + + IEpochManagerEnabler epochManagerEnabler = IEpochManagerEnabler(epochManagerEnablerAddress); + epochManagerEnabler.initEpochManager(); } } diff --git a/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh b/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh index 149cc3d7bea..865c8ac854d 100755 --- a/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh +++ b/packages/protocol/scripts/foundry/create_and_migrate_anvil_devchain.sh @@ -67,6 +67,11 @@ echo "Migration script total elapsed time: $ELAPSED_TIME seconds" # this helps to make sure that devchain state is actually being saved sleep 1 -# Rename devchain artifact and remove unused directory -mv $ANVIL_FOLDER/state.json $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME -rm -rf $ANVIL_FOLDER +if [[ "${KEEP_DEVCHAIN_FOLDER:-}" == "true" ]]; then + cp $ANVIL_FOLDER/state.json $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME + echo "Keeping devchain folder as per flag." +else + # Rename devchain artifact and remove unused directory + mv $ANVIL_FOLDER/state.json $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME + rm -rf $ANVIL_FOLDER +fi diff --git a/packages/protocol/scripts/foundry/create_and_migrate_anvil_l2_devchain.sh b/packages/protocol/scripts/foundry/create_and_migrate_anvil_l2_devchain.sh index 3abbe0d2fbd..869397c2b39 100755 --- a/packages/protocol/scripts/foundry/create_and_migrate_anvil_l2_devchain.sh +++ b/packages/protocol/scripts/foundry/create_and_migrate_anvil_l2_devchain.sh @@ -4,13 +4,12 @@ set -euo pipefail # Read environment variables and constants source $PWD/scripts/foundry/constants.sh +export KEEP_DEVCHAIN_FOLDER=true + # Generate and run L1 devchain echo "Generating and running L1 devchain before activating L2..." source $PWD/scripts/foundry/create_and_migrate_anvil_devchain.sh -# Backup L1 state before applying L2 migrations so it can be published to NPM -cp $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME $TMP_FOLDER/backup_$L1_DEVCHAIN_FILE_NAME - # Activate L2 by deploying arbitrary bytecode to the proxy admin address. # Note: This can't be done from the migration script ARBITRARY_BYTECODE=$(cast format-bytes32-string "L2 is activated") @@ -50,12 +49,8 @@ forge script \ $NON_INTERACTIVE \ --rpc-url $ANVIL_RPC_URL || { echo "Migration script failed"; exit 1; } -# Save L2 state so it can published to NPM -cp $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME $TMP_FOLDER/$L2_DEVCHAIN_FILE_NAME +# # Save L2 state so it can published to NPM +mv $ANVIL_FOLDER/state.json $TMP_FOLDER/$L2_DEVCHAIN_FILE_NAME echo "Saved anvil L2 state to $TMP_FOLDER/$L2_DEVCHAIN_FILE_NAME" -# Restore L1 state from backup so it can be published to NPM as well -cp $TMP_FOLDER/backup_$L1_DEVCHAIN_FILE_NAME $TMP_FOLDER/$L1_DEVCHAIN_FILE_NAME - -# Delete backup -rm $TMP_FOLDER/backup_$L1_DEVCHAIN_FILE_NAME +rm -rf $ANVIL_FOLDER diff --git a/packages/protocol/scripts/foundry/deploy_precompiles.sh b/packages/protocol/scripts/foundry/deploy_precompiles.sh index f87b77761f1..1ebbae44a1d 100755 --- a/packages/protocol/scripts/foundry/deploy_precompiles.sh +++ b/packages/protocol/scripts/foundry/deploy_precompiles.sh @@ -13,4 +13,12 @@ cast rpc anvil_setCode --rpc-url $ANVIL_RPC_URL $EpochSizeAddress $EpochSizeByte ProofOfPossesionAddress=0x00000000000000000000000000000000000000fb ProofOfPossesionBytecode=`cat ./out/ProofOfPossesionPrecompile.sol/ProofOfPossesionPrecompile.json | jq -r '.deployedBytecode.object'` -cast rpc anvil_setCode --rpc-url $ANVIL_RPC_URL $ProofOfPossesionAddress $ProofOfPossesionBytecode \ No newline at end of file +cast rpc anvil_setCode --rpc-url $ANVIL_RPC_URL $ProofOfPossesionAddress $ProofOfPossesionBytecode + +NumberValidatorsInCurrentSetPrecompileAddress=0x00000000000000000000000000000000000000f9 +NumberValidatorsInCurrentSetPrecompileBytecode=`cat ./out/NumberValidatorsInCurrentSetPrecompile.sol/NumberValidatorsInCurrentSetPrecompile.json | jq -r '.deployedBytecode.object'` +cast rpc anvil_setCode --rpc-url $ANVIL_RPC_URL $NumberValidatorsInCurrentSetPrecompileAddress $NumberValidatorsInCurrentSetPrecompileBytecode + +ValidatorSignerAddressFromCurrentSetAddress=0x00000000000000000000000000000000000000fa +ValidatorSignerAddressFromCurrentSetBytecode=`cat ./out/ValidatorSignerAddressFromCurrentSetPrecompile.sol/ValidatorSignerAddressFromCurrentSetPrecompile.json | jq -r '.deployedBytecode.object'` +cast rpc anvil_setCode --rpc-url $ANVIL_RPC_URL $ValidatorSignerAddressFromCurrentSetAddress $ValidatorSignerAddressFromCurrentSetBytecode diff --git a/packages/protocol/scripts/foundry/start_anvil.sh b/packages/protocol/scripts/foundry/start_anvil.sh index 342b3c8d043..ec802d5d980 100755 --- a/packages/protocol/scripts/foundry/start_anvil.sh +++ b/packages/protocol/scripts/foundry/start_anvil.sh @@ -17,6 +17,7 @@ cp $PWD/migrations_sol/README.md $TMP_FOLDER/README.md if nc -z localhost $ANVIL_PORT; then echo "Port already used" kill $(lsof -t -i:$ANVIL_PORT) + sleep 5 echo "Killed previous Anvil" fi diff --git a/packages/protocol/test-sol/devchain/ImportPrecompiles.t.sol b/packages/protocol/test-sol/devchain/ImportPrecompiles.t.sol index 3c0040b0ab2..a976098c20a 100644 --- a/packages/protocol/test-sol/devchain/ImportPrecompiles.t.sol +++ b/packages/protocol/test-sol/devchain/ImportPrecompiles.t.sol @@ -3,5 +3,7 @@ pragma solidity >=0.8.7 <0.8.20; // this file only exists so that foundry compiles this contracts import "@test-sol/precompiles/ProofOfPossesionPrecompile.sol"; import "@test-sol/precompiles/EpochSizePrecompile.sol"; +import "@test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol"; +import "@test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol"; contract ImportPrecompiles {} diff --git a/packages/protocol/test-sol/devchain/migration/Migration.t.sol b/packages/protocol/test-sol/devchain/migration/Migration.t.sol index 8b40b51f33f..2cd404e2483 100644 --- a/packages/protocol/test-sol/devchain/migration/Migration.t.sol +++ b/packages/protocol/test-sol/devchain/migration/Migration.t.sol @@ -6,6 +6,7 @@ import "celo-foundry-8/Test.sol"; import { Utils08 } from "@test-sol/utils08.sol"; import { TestConstants } from "@test-sol/constants.sol"; import { MigrationsConstants } from "@migrations-sol/constants.sol"; +import { FeeCurrencyDirectory } from "@celo-contracts-8/common/FeeCurrencyDirectory.sol"; import "@celo-contracts/common/interfaces/IRegistry.sol"; import "@celo-contracts/common/interfaces/IProxy.sol"; diff --git a/packages/protocol/test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol b/packages/protocol/test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol new file mode 100644 index 00000000000..c9de7ff16ac --- /dev/null +++ b/packages/protocol/test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol @@ -0,0 +1,32 @@ +// TODO move this to test folder +pragma solidity >=0.8.7 <0.8.20; + +import "forge-std/console.sol"; +import "@celo-contracts/common/interfaces/IRegistry.sol"; +import "@celo-contracts/governance/interfaces/IValidators.sol"; + +contract NumberValidatorsInCurrentSetPrecompile { + address constant ADDRESS = address(0xff - 6); + + uint256 public NumberOfValidators = 1; + + address internal constant registryAddress = 0x000000000000000000000000000000000000ce10; + + receive() external payable {} + + fallback(bytes calldata) external payable returns (bytes memory) { + return abi.encodePacked(NumberOfValidators); + } + + function setNumberOfValidators() external{ + IRegistry registry = IRegistry(registryAddress); + address validatorsAddress = registry.getAddressForString("Validators"); + IValidators validatorsContract = IValidators(validatorsAddress); + address[] memory registeredValidators = validatorsContract.getRegisteredValidators(); + NumberOfValidators = registeredValidators.length; + } + + function getAddress() public pure returns (address) { + return ADDRESS; + } +} diff --git a/packages/protocol/test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol b/packages/protocol/test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol new file mode 100644 index 00000000000..4a32ff3d420 --- /dev/null +++ b/packages/protocol/test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol @@ -0,0 +1,57 @@ +// TODO move this to test folder +pragma solidity >=0.8.7 <0.8.20; + +import "forge-std/console.sol"; +import "@celo-contracts/common/interfaces/IRegistry.sol"; +import "@celo-contracts/governance/interfaces/IValidators.sol"; + +contract ValidatorSignerAddressFromCurrentSetPrecompile { + address constant ADDRESS = address(0xff - 5); + + uint256 public constant EPOCH_SIZE = 100; + + address[] validators; + + address internal constant registryAddress = 0x000000000000000000000000000000000000ce10; + + receive() external payable {} + + fallback(bytes calldata input) external payable returns (bytes memory) { + uint256 index = getUint256FromBytes(input, 0); + return abi.encodePacked(uint256(uint160(validators[index]))); + } + + function getAddress() public pure returns (address) { + return ADDRESS; + } + + function getUint256FromBytes(bytes memory bs, uint256 start) internal pure returns (uint256) { + return uint256(getBytes32FromBytes(bs, start)); + } + + function setValidators() external{ + IRegistry registry = IRegistry(registryAddress); + address validatorsAddress = registry.getAddressForString("Validators"); + IValidators validatorsContract = IValidators(validatorsAddress); + address[] memory registeredValidators = validatorsContract.getRegisteredValidators(); + for (uint256 i = 0; i < registeredValidators.length; i++) { + validators.push(registeredValidators[i]); + } + } + + /** + * @notice Converts bytes to bytes32. + * @param bs byte[] data + * @param start offset into byte data to convert + * @return bytes32 data + */ + function getBytes32FromBytes(bytes memory bs, uint256 start) internal pure returns (bytes32) { + require(bs.length >= start + 32, "slicing out of range"); + bytes32 x; + assembly { + x := mload(add(bs, add(start, 32))) + } + return x; + } + +} diff --git a/packages/protocol/test-sol/unit/common/ImportPrecompiles.t.sol b/packages/protocol/test-sol/unit/common/ImportPrecompiles.t.sol index 3c0040b0ab2..a976098c20a 100644 --- a/packages/protocol/test-sol/unit/common/ImportPrecompiles.t.sol +++ b/packages/protocol/test-sol/unit/common/ImportPrecompiles.t.sol @@ -3,5 +3,7 @@ pragma solidity >=0.8.7 <0.8.20; // this file only exists so that foundry compiles this contracts import "@test-sol/precompiles/ProofOfPossesionPrecompile.sol"; import "@test-sol/precompiles/EpochSizePrecompile.sol"; +import "@test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol"; +import "@test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol"; contract ImportPrecompiles {} From 13510fd8d0e5c5ca4cdf72658cb7f4c8279cfe38 Mon Sep 17 00:00:00 2001 From: pahor167 Date: Mon, 16 Sep 2024 20:31:21 +0200 Subject: [PATCH 57/69] lint --- packages/protocol/migrations_sol/Migration.s.sol | 8 ++++++-- .../NumberValidatorsInCurrentSetPrecompile.sol | 2 +- .../ValidatorSignerAddressFromCurrentSetPrecompile.sol | 3 +-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/protocol/migrations_sol/Migration.s.sol b/packages/protocol/migrations_sol/Migration.s.sol index 93735304ce7..1ec082a8623 100644 --- a/packages/protocol/migrations_sol/Migration.s.sol +++ b/packages/protocol/migrations_sol/Migration.s.sol @@ -1304,10 +1304,14 @@ contract Migration is Script, UsingRegistry, MigrationsConstants { function captureEpochManagerEnablerValidators() public { address numberValidatorsInCurrentSetPrecompileAddress = 0x00000000000000000000000000000000000000f9; - numberValidatorsInCurrentSetPrecompileAddress.call(abi.encodeWithSignature("setNumberOfValidators()")); + numberValidatorsInCurrentSetPrecompileAddress.call( + abi.encodeWithSignature("setNumberOfValidators()") + ); address validatorSignerAddressFromCurrentSetPrecompileAddress = 0x00000000000000000000000000000000000000fa; - validatorSignerAddressFromCurrentSetPrecompileAddress.call(abi.encodeWithSignature("setValidators()")); + validatorSignerAddressFromCurrentSetPrecompileAddress.call( + abi.encodeWithSignature("setValidators()") + ); address epochManagerEnabler = registry.getAddressForString("EpochManagerEnabler"); IEpochManagerEnabler epochManagerEnablerContract = IEpochManagerEnabler(epochManagerEnabler); diff --git a/packages/protocol/test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol b/packages/protocol/test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol index c9de7ff16ac..44e651a073f 100644 --- a/packages/protocol/test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol +++ b/packages/protocol/test-sol/precompiles/NumberValidatorsInCurrentSetPrecompile.sol @@ -18,7 +18,7 @@ contract NumberValidatorsInCurrentSetPrecompile { return abi.encodePacked(NumberOfValidators); } - function setNumberOfValidators() external{ + function setNumberOfValidators() external { IRegistry registry = IRegistry(registryAddress); address validatorsAddress = registry.getAddressForString("Validators"); IValidators validatorsContract = IValidators(validatorsAddress); diff --git a/packages/protocol/test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol b/packages/protocol/test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol index 4a32ff3d420..f2ed9c7ade8 100644 --- a/packages/protocol/test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol +++ b/packages/protocol/test-sol/precompiles/ValidatorSignerAddressFromCurrentSetPrecompile.sol @@ -29,7 +29,7 @@ contract ValidatorSignerAddressFromCurrentSetPrecompile { return uint256(getBytes32FromBytes(bs, start)); } - function setValidators() external{ + function setValidators() external { IRegistry registry = IRegistry(registryAddress); address validatorsAddress = registry.getAddressForString("Validators"); IValidators validatorsContract = IValidators(validatorsAddress); @@ -53,5 +53,4 @@ contract ValidatorSignerAddressFromCurrentSetPrecompile { } return x; } - } From 6011483c022700af9ab7ae0285ae673560a723e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 13:41:05 +0200 Subject: [PATCH 58/69] Rolled back contracts/identity/FederatedAttestations.sol added by mistake --- .../identity/FederatedAttestations.sol | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/packages/protocol/contracts/identity/FederatedAttestations.sol b/packages/protocol/contracts/identity/FederatedAttestations.sol index 502d91a927d..93bf3a9f559 100644 --- a/packages/protocol/contracts/identity/FederatedAttestations.sol +++ b/packages/protocol/contracts/identity/FederatedAttestations.sol @@ -1,13 +1,5 @@ pragma solidity ^0.5.13; -// RPC_URL="https://rpc.sepolia.mantle.xyz" -// DEPLOYED_CONTRACT_ADDRESS="0x8751845c21C4681C37a23a40467B6150f248f9B8" -// forge create FederatedAttestations --constructor-args false --from 0x2C302520E6B344d8396BF3011862046287ef88c7 --private-key 780f3eb0c27a899480b859d36237eba28315750b549eb0cc553cee5cdd92e904 --rpc-url $RPC_URL --etherscan-api-key --verify -// cast send $DEPLOYED_CONTRACT_ADDRESS "initialize()" --from 0x2C302520E6B344d8396BF3011862046287ef88c7 --private-key 780f3eb0c27a899480b859d36237eba28315750b549eb0cc553cee5cdd92e904 --rpc-url $RPC_URL -// cast call $DEPLOYED_CONTRACT_ADDRESS "initialized()(bool)" --rpc-url $RPC_URL -// cast send $DEPLOYED_CONTRACT_ADDRESS "registerAttestationAsIssuer(bytes32 identifier, address account, uint64 issuedOn)" 0x1234000000000000000000000000000000000000000000000000000000000000 0x2C302520E6B344d8396BF3011862046287ef88c7 1725659872 --from 0x2C302520E6B344d8396BF3011862046287ef88c7 --private-key 780f3eb0c27a899480b859d36237eba28315750b549eb0cc553cee5cdd92e904 --rpc-url $RPC_URL -// cast call $DEPLOYED_CONTRACT_ADDRESS "lookupAttestations(bytes32 identifier, address[] calldata trustedIssuers) returns (uint256[] memory countsPerIssuer, address[] memory accounts, address[] memory signers, uint64[] memory issuedOns,uint64[] memory publishedOns)" 0x1234000000000000000000000000000000000000000000000000000000000000 "[0x2C302520E6B344d8396BF3011862046287ef88c7]" --rpc-url $RPC_URL - import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; @@ -19,7 +11,7 @@ import "../common/interfaces/ICeloVersionedContract.sol"; import "../common/Initializable.sol"; import "../common/UsingRegistryV2.sol"; -// import "../common/Signatures.sol"; +import "../common/Signatures.sol"; /** * @title Contract mapping identifiers to accounts @@ -302,21 +294,20 @@ contract FederatedAttestations is bytes32 r, bytes32 s ) public view { - revert("unimplemented"); // attestationSignerToAccount instead of isSigner allows the issuer to act as its own signer - // require( - // getAccounts().attestationSignerToAccount(signer) == issuer, - // "Signer is not a currently authorized AttestationSigner for the issuer" - // ); - // bytes32 structHash = getUniqueAttestationHash(identifier, issuer, account, signer, issuedOn); - // address guessedSigner = Signatures.getSignerOfTypedDataHash( - // eip712DomainSeparator, - // structHash, - // v, - // r, - // s - // ); - // require(guessedSigner == signer, "Signature is invalid"); + require( + getAccounts().attestationSignerToAccount(signer) == issuer, + "Signer is not a currently authorized AttestationSigner for the issuer" + ); + bytes32 structHash = getUniqueAttestationHash(identifier, issuer, account, signer, issuedOn); + address guessedSigner = Signatures.getSignerOfTypedDataHash( + eip712DomainSeparator, + structHash, + v, + r, + s + ); + require(guessedSigner == signer, "Signature is invalid"); } function getUniqueAttestationHash( From 776f864a25595417b46ec4b5a880d85fbf30364f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 13:55:47 +0200 Subject: [PATCH 59/69] removed duplicated function --- .../contracts-0.8/governance/Validators.sol | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/protocol/contracts-0.8/governance/Validators.sol b/packages/protocol/contracts-0.8/governance/Validators.sol index 98226d9e44a..dbd60d6b26e 100644 --- a/packages/protocol/contracts-0.8/governance/Validators.sol +++ b/packages/protocol/contracts-0.8/governance/Validators.sol @@ -652,19 +652,6 @@ contract Validators is group.slashInfo.lastSlashed = block.timestamp; } - function mintStableToEpochManager( - uint256 amount - ) external onlyL2 nonReentrant onlyRegisteredContract(EPOCH_MANAGER_REGISTRY_ID) { - require(amount > 0, "mint amount is zero."); - require( - IStableToken(getStableToken()).mint( - registry.getAddressForOrDie(EPOCH_MANAGER_REGISTRY_ID), - amount - ), - "mint failed to epoch manager" - ); - } - /** * @notice Allows the EpochManager contract to mint stable token for itself. * @param amount The amount to be minted. From a152a09f8e52d5c5f560176740780257c4e48ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 14:02:45 +0200 Subject: [PATCH 60/69] Fix tests --- packages/protocol/contracts-0.8/common/EpochManager.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index 1a21cbf0f97..abc89f2c38e 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -55,8 +55,6 @@ contract EpochManager is uint256 epochRewards; } - // TODO this should be able to get deleted easily - // maybe even having it in a stadalone contract mapping(address => ProcessedGroup) public processedGroups; EpochProcessState public epochProcessing; @@ -183,7 +181,6 @@ contract EpochManager is address[] calldata lessers, address[] calldata greaters ) external nonReentrant { - // TODO complete this function require(isOnEpochProcess(), "Epoch process is not started"); // finalize epoch // TODO last block should be the block before and timestamp from previous block From f5a2cb86427d457d4915b45c0927276c322b409a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 14:06:49 +0200 Subject: [PATCH 61/69] lint --- .../contracts-0.8/common/EpochManager.sol | 10 +++++----- .../common/EpochManagerEnabler.sol | 8 ++++---- .../common/test/MockCeloToken.sol | 18 +++++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index abc89f2c38e..ee086c1b163 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -43,6 +43,11 @@ contract EpochManager is uint256 toProcessGroups; } + struct ProcessedGroup { + bool processed; + uint256 epochRewards; + } + // the length of an epoch in seconds uint256 public epochDuration; @@ -50,11 +55,6 @@ contract EpochManager is uint256 private currentEpochNumber; address[] public elected; - struct ProcessedGroup { - bool processed; - uint256 epochRewards; - } - mapping(address => ProcessedGroup) public processedGroups; EpochProcessState public epochProcessing; diff --git a/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol b/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol index c6031314c81..d3bd71e0c6e 100644 --- a/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol +++ b/packages/protocol/contracts-0.8/common/EpochManagerEnabler.sol @@ -62,6 +62,10 @@ contract EpochManagerEnabler is Initializable, UsingPrecompiles, UsingRegistry { } } + function getFirstBlockOfEpoch(uint256 currentEpoch) external view returns (uint256) { + return _getFirstBlockOfEpoch(currentEpoch); + } + /** * @notice Returns the storage, major, minor, and patch version of the contract. * @return Storage version of the contract. @@ -73,10 +77,6 @@ contract EpochManagerEnabler is Initializable, UsingPrecompiles, UsingRegistry { return (1, 1, 0, 0); } - function getFirstBlockOfEpoch(uint256 currentEpoch) external view returns (uint256) { - return _getFirstBlockOfEpoch(currentEpoch); - } - function _getFirstBlockOfEpoch(uint256 currentEpoch) internal view returns (uint256) { uint256 blockToCheck = block.number - 1; uint256 blockEpochNumber = getEpochNumberOfBlock(blockToCheck); diff --git a/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol b/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol index 8574c9ee7d0..74baea164c6 100644 --- a/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol +++ b/packages/protocol/contracts-0.8/common/test/MockCeloToken.sol @@ -34,15 +34,6 @@ contract MockCeloToken08 { return _transfer(from, to, amount); } - function _transfer(address from, address to, uint256 amount) internal returns (bool) { - if (balances[from] < amount) { - return false; - } - balances[from] -= amount; - balances[to] += amount; - return true; - } - function setBalanceOf(address a, uint256 value) external { balances[a] = value; } @@ -54,4 +45,13 @@ contract MockCeloToken08 { function totalSupply() public view returns (uint256) { return totalSupply_; } + + function _transfer(address from, address to, uint256 amount) internal returns (bool) { + if (balances[from] < amount) { + return false; + } + balances[from] -= amount; + balances[to] += amount; + return true; + } } From 95a6b6567f2d75999ff1698eaf66744f8c292e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 14:15:22 +0200 Subject: [PATCH 62/69] Fixed tests and moved ValidatorsMock08 to solidity test folder --- packages/protocol/test-sol/unit/common/EpochManager.t.sol | 2 +- .../unit/governance/mock}/ValidatorsMock08.sol | 4 ++-- .../test-sol/unit/governance/validators/Validators.t.sol | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) rename packages/protocol/{contracts-0.8/governance/test => test-sol/unit/governance/mock}/ValidatorsMock08.sol (85%) diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 73b7c8a680b..556c60885d9 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -18,7 +18,7 @@ import "@celo-contracts/stability/test/MockSortedOracles.sol"; import "@celo-contracts/common/interfaces/IRegistry.sol"; import { EpochRewardsMock08 } from "@celo-contracts-8/governance/test/EpochRewardsMock.sol"; -import { ValidatorsMock08 } from "@celo-contracts-8/governance/test/ValidatorsMock08.sol"; +import { ValidatorsMock08 } from "@test-sol/unit/governance/mock/ValidatorsMock08.sol"; import { MockCeloUnreleasedTreasure } from "@celo-contracts-8/common/test/MockCeloUnreleasedTreasure.sol"; contract EpochManagerTest is Test, TestConstants, Utils08 { diff --git a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol b/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock08.sol similarity index 85% rename from packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol rename to packages/protocol/test-sol/unit/governance/mock/ValidatorsMock08.sol index ff9b7c778da..6d73e3e7f7a 100644 --- a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock08.sol +++ b/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock08.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.7 <0.8.20; -import "../Validators.sol"; -import "../../../contracts/common/FixidityLib.sol"; +import "@celo-contracts-8/governance/Validators.sol"; +import "@celo-contracts/common/FixidityLib.sol"; /** * @title A wrapper around Validators that exposes onlyVm functions for testing. diff --git a/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol b/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol index 18229719cfc..c86dc8b46ce 100644 --- a/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol +++ b/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol @@ -3441,9 +3441,8 @@ contract ValidatorsTest_MintStableToEpochManager is ValidatorsTest { vm.expectRevert("only registered contract"); validators.mintStableToEpochManager(5); } - function test_Reverts_WhenMintAmountIsZero() public { + function test_WhenMintAmountIsZero() public { _whenL2(); - vm.expectRevert("mint amount is zero."); vm.prank(address(epochManager)); validators.mintStableToEpochManager(0); } From 69b3bd88454cb00bd7aaf1928e42359ac6f912ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 14:38:30 +0200 Subject: [PATCH 63/69] Added release data --- packages/protocol/contracts-0.8/common/EpochManager.sol | 2 +- .../protocol/releaseData/initializationData/release12.json | 3 ++- packages/protocol/test-sol/unit/common/EpochManager.t.sol | 6 +++--- .../mock/{ValidatorsMock08.sol => ValidatorsMock.sol} | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) rename packages/protocol/test-sol/unit/governance/mock/{ValidatorsMock08.sol => ValidatorsMock.sol} (93%) diff --git a/packages/protocol/contracts-0.8/common/EpochManager.sol b/packages/protocol/contracts-0.8/common/EpochManager.sol index ee086c1b163..430f1ffa740 100644 --- a/packages/protocol/contracts-0.8/common/EpochManager.sol +++ b/packages/protocol/contracts-0.8/common/EpochManager.sol @@ -183,7 +183,7 @@ contract EpochManager is ) external nonReentrant { require(isOnEpochProcess(), "Epoch process is not started"); // finalize epoch - // TODO last block should be the block before and timestamp from previous block + // last block should be the block before and timestamp from previous block epochs[currentEpochNumber].lastBlock = block.number - 1; // start new epoch currentEpochNumber++; diff --git a/packages/protocol/releaseData/initializationData/release12.json b/packages/protocol/releaseData/initializationData/release12.json index 4805f4b66ed..e16d1f7f045 100644 --- a/packages/protocol/releaseData/initializationData/release12.json +++ b/packages/protocol/releaseData/initializationData/release12.json @@ -1,5 +1,6 @@ { "FeeCurrencyDirectory": [], "CeloUnreleasedTreasure": ["0x000000000000000000000000000000000000ce10"], - "EpochManager": ["0x000000000000000000000000000000000000ce10", 86400, "0xD533Ca259b330c7A88f74E000a3FaEa2d63B7972", "0x0000000000000000000000000000000000000000"] + "EpochManager": ["0x000000000000000000000000000000000000ce10", 86400, "0xD533Ca259b330c7A88f74E000a3FaEa2d63B7972", "0x0000000000000000000000000000000000000000"], + "EpochManagerEnabler": ["0x000000000000000000000000000000000000ce10"] } diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 556c60885d9..70fdd8743a8 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -18,7 +18,7 @@ import "@celo-contracts/stability/test/MockSortedOracles.sol"; import "@celo-contracts/common/interfaces/IRegistry.sol"; import { EpochRewardsMock08 } from "@celo-contracts-8/governance/test/EpochRewardsMock.sol"; -import { ValidatorsMock08 } from "@test-sol/unit/governance/mock/ValidatorsMock08.sol"; +import { ValidatorsMock } from "@test-sol/unit/governance/mock/ValidatorsMock.sol"; import { MockCeloUnreleasedTreasure } from "@celo-contracts-8/common/test/MockCeloUnreleasedTreasure.sol"; contract EpochManagerTest is Test, TestConstants, Utils08 { @@ -27,7 +27,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { MockStableToken08 stableToken; EpochRewardsMock08 epochRewards; - ValidatorsMock08 validators; + ValidatorsMock validators; address epochManagerEnabler; address carbonOffsettingPartner; @@ -55,7 +55,7 @@ contract EpochManagerTest is Test, TestConstants, Utils08 { epochManager = new EpochManager(true); sortedOracles = new MockSortedOracles(); epochRewards = new EpochRewardsMock08(); - validators = new ValidatorsMock08(); + validators = new ValidatorsMock(); stableToken = new MockStableToken08(); celoToken = new MockCeloToken08(); celoUnreleasedTreasure = new MockCeloUnreleasedTreasure(); diff --git a/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock08.sol b/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol similarity index 93% rename from packages/protocol/test-sol/unit/governance/mock/ValidatorsMock08.sol rename to packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol index 6d73e3e7f7a..f4f192ba617 100644 --- a/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock08.sol +++ b/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol @@ -7,7 +7,7 @@ import "@celo-contracts/common/FixidityLib.sol"; /** * @title A wrapper around Validators that exposes onlyVm functions for testing. */ -contract ValidatorsMock08 is Validators(true) { +contract ValidatorsMock is Validators(true) { function updateValidatorScoreFromSigner(address signer, uint256 uptime) external override {} function distributeEpochPaymentsFromSigner( From f477f7441bb244a3557912f4cbbdcc7757370301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 14:42:36 +0200 Subject: [PATCH 64/69] Deleted prints in release script --- packages/protocol/scripts/truffle/make-release.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/protocol/scripts/truffle/make-release.ts b/packages/protocol/scripts/truffle/make-release.ts index af7911955b2..440fd8a4566 100644 --- a/packages/protocol/scripts/truffle/make-release.ts +++ b/packages/protocol/scripts/truffle/make-release.ts @@ -118,9 +118,6 @@ const deployImplementation = async ( // without this delay it sometimes fails with ProviderError await delay(getRandomNumber(1, 1000)) - console.log('gas update in2') - console.log('dryRun', dryRun) - const bytecodeSize = (Contract.bytecode.length - 2) / 2 console.log('Bytecode size in bytes:', bytecodeSize) From 409339380148ce1a68ecc56c35275b3d40f7d352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 15:55:03 +0200 Subject: [PATCH 65/69] Removed unnecesary mocking --- .../governance/test/ValidatorsMock.sol | 21 ------------- .../governance/test/MockValidators.sol | 3 ++ .../unit/governance/mock/ValidatorsMock.sol | 9 ------ .../governance/validators/Validators.t.sol | 30 +++++++++++++++++-- 4 files changed, 30 insertions(+), 33 deletions(-) delete mode 100644 packages/protocol/contracts-0.8/governance/test/ValidatorsMock.sol diff --git a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock.sol b/packages/protocol/contracts-0.8/governance/test/ValidatorsMock.sol deleted file mode 100644 index ea32349aab1..00000000000 --- a/packages/protocol/contracts-0.8/governance/test/ValidatorsMock.sol +++ /dev/null @@ -1,21 +0,0 @@ -pragma solidity >=0.8.7 <0.8.20; - -import "../Validators.sol"; -import "../../../contracts/common/FixidityLib.sol"; - -/** - * @title A wrapper around Validators that exposes onlyVm functions for testing. - */ -contract ValidatorsMock is Validators(true) { - function updateValidatorScoreFromSigner(address signer, uint256 uptime) external override { - return _updateValidatorScoreFromSigner(signer, uptime); - } - - function distributeEpochPaymentsFromSigner( - address signer, - uint256 maxPayment - ) external override returns (uint256) { - allowOnlyL1(); - return _distributeEpochPaymentsFromSigner(signer, maxPayment); - } -} diff --git a/packages/protocol/contracts/governance/test/MockValidators.sol b/packages/protocol/contracts/governance/test/MockValidators.sol index 97cf017a9a3..4cc03323a61 100644 --- a/packages/protocol/contracts/governance/test/MockValidators.sol +++ b/packages/protocol/contracts/governance/test/MockValidators.sol @@ -4,6 +4,9 @@ import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "../../../contracts-0.8/common/IsL2Check.sol"; +// Mocks Validators, compatible with 0.5 +// For forge tests, can be avoided with calls to deployCodeTo + /** * @title Holds a list of addresses of validators */ diff --git a/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol b/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol index f4f192ba617..4550cd02fd4 100644 --- a/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol +++ b/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol @@ -8,15 +8,6 @@ import "@celo-contracts/common/FixidityLib.sol"; * @title A wrapper around Validators that exposes onlyVm functions for testing. */ contract ValidatorsMock is Validators(true) { - function updateValidatorScoreFromSigner(address signer, uint256 uptime) external override {} - - function distributeEpochPaymentsFromSigner( - address signer, - uint256 maxPayment - ) external override returns (uint256) { - return 0; - } - function computeEpochReward( address account, uint256 score, diff --git a/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol b/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol index c86dc8b46ce..f66b9ad11b7 100644 --- a/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol +++ b/packages/protocol/test-sol/unit/governance/validators/Validators.t.sol @@ -2873,6 +2873,7 @@ contract ValidatorsTest_UpdateValidatorScoreFromSigner is ValidatorsTest { ) .unwrap(); + vm.prank(address(0)); validators.updateValidatorScoreFromSigner(validator, uptime.unwrap()); (, , , uint256 _actualScore, ) = validators.getValidator(validator); @@ -2881,6 +2882,7 @@ contract ValidatorsTest_UpdateValidatorScoreFromSigner is ValidatorsTest { } function test_ShouldUpdateValidatorScore_WhenValidatorHasNonZeroScore() public { + vm.prank(address(0)); validators.updateValidatorScoreFromSigner(validator, uptime.unwrap()); uint256 _expectedScore = FixidityLib @@ -2903,6 +2905,7 @@ contract ValidatorsTest_UpdateValidatorScoreFromSigner is ValidatorsTest { ) .unwrap(); + vm.prank(address(0)); validators.updateValidatorScoreFromSigner(validator, uptime.unwrap()); (, , , uint256 _actualScore, ) = validators.getValidator(validator); @@ -2911,6 +2914,7 @@ contract ValidatorsTest_UpdateValidatorScoreFromSigner is ValidatorsTest { function test_Reverts_WhenUptimeGreaterThan1() public { uptime = FixidityLib.add(FixidityLib.fixed1(), FixidityLib.newFixedFraction(1, 10)); + vm.prank(address(0)); vm.expectRevert("Uptime cannot be larger than one"); validators.updateValidatorScoreFromSigner(validator, uptime.unwrap()); } @@ -3240,26 +3244,31 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { ) ); + vm.prank(address(0)); validators.updateValidatorScoreFromSigner(validator, uptime.unwrap()); } function test_Reverts_WhenValidatorAndGroupMeetBalanceRequirements_WhenL2() public { _whenL2(); + vm.prank(address(0)); vm.expectRevert("This method is no longer supported in L2."); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); } function test_ShouldPayValidator_WhenValidatorAndGroupMeetBalanceRequirements() public { + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(validator), expectedValidatorPayment); } function test_ShouldPayGroup_WhenValidatorAndGroupMeetBalanceRequirements() public { + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(group), expectedGroupPayment); } function test_ShouldPayDelegatee_WhenValidatorAndGroupMeetBalanceRequirements() public { + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(paymentDelegatee), expectedDelegatedPayment); } @@ -3267,7 +3276,8 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { function test_ShouldReturnTheExpectedTotalPayment_WhenValidatorAndGroupMeetBalanceRequirements() public { - validators.distributeEpochPaymentsFromSigner(validator, maxPayment); + // validators.distributeEpochPaymentsFromSigner(validator, maxPayment); + vm.prank(address(0)); assertEq( validators.distributeEpochPaymentsFromSigner(validator, maxPayment), expectedTotalPayment @@ -3283,6 +3293,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { vm.prank(validator); accounts.deletePaymentDelegation(); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(validator), expectedValidatorPayment); } @@ -3296,7 +3307,8 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { vm.prank(validator); accounts.deletePaymentDelegation(); - validators.distributeEpochPaymentsFromSigner(validator, maxPayment); + // validators.distributeEpochPaymentsFromSigner(validator, maxPayment); + vm.prank(address(0)); assertEq( validators.distributeEpochPaymentsFromSigner(validator, maxPayment), expectedTotalPayment @@ -3312,6 +3324,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { vm.prank(validator); accounts.deletePaymentDelegation(); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(group), expectedGroupPayment); } @@ -3319,6 +3332,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { function test_shouldPayValidatorOnlyHalf_WhenSlashingMultiplierIsHalved() public { vm.prank(paymentDelegatee); validators.halveSlashingMultiplier(group); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(validator), halfExpectedValidatorPayment); @@ -3327,6 +3341,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { function test_shouldPayGroupOnlyHalf_WhenSlashingMultiplierIsHalved() public { vm.prank(paymentDelegatee); validators.halveSlashingMultiplier(group); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(group), halfExpectedGroupPayment); @@ -3335,6 +3350,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { function test_shouldPayDelegateeOnlyHalf_WhenSlashingMultiplierIsHalved() public { vm.prank(paymentDelegatee); validators.halveSlashingMultiplier(group); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(paymentDelegatee), halfExpectedDelegatedPayment); @@ -3343,8 +3359,8 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { function test_shouldReturnHalfExpectedTotalPayment_WhenSlashingMultiplierIsHalved() public { vm.prank(paymentDelegatee); validators.halveSlashingMultiplier(group); - validators.distributeEpochPaymentsFromSigner(validator, maxPayment); + vm.prank(address(0)); assertEq( validators.distributeEpochPaymentsFromSigner(validator, maxPayment), halfExpectedTotalPayment @@ -3357,6 +3373,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { originalValidatorLockedGoldRequirements.value.sub(11) ); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(validator), 0); } @@ -3367,6 +3384,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { originalValidatorLockedGoldRequirements.value.sub(11) ); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(group), 0); } @@ -3377,6 +3395,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { originalValidatorLockedGoldRequirements.value.sub(11) ); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(paymentDelegatee), 0); } @@ -3387,6 +3406,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { originalValidatorLockedGoldRequirements.value.sub(11) ); + vm.prank(address(0)); assertEq(validators.distributeEpochPaymentsFromSigner(validator, maxPayment), 0); } @@ -3396,6 +3416,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { originalGroupLockedGoldRequirements.value.sub(11) ); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(validator), 0); } @@ -3406,6 +3427,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { originalGroupLockedGoldRequirements.value.sub(11) ); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(group), 0); } @@ -3416,6 +3438,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { originalGroupLockedGoldRequirements.value.sub(11) ); + vm.prank(address(0)); validators.distributeEpochPaymentsFromSigner(validator, maxPayment); assertEq(stableToken.balanceOf(paymentDelegatee), 0); } @@ -3426,6 +3449,7 @@ contract ValidatorsTest_DistributeEpochPaymentsFromSigner is ValidatorsTest { originalGroupLockedGoldRequirements.value.sub(11) ); + vm.prank(address(0)); assertEq(validators.distributeEpochPaymentsFromSigner(validator, maxPayment), 0); } } From fc278cbf50e4868bfc3fde036a7e69c2b7b2973c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 16:15:47 +0200 Subject: [PATCH 66/69] Force compilation of validator --- packages/protocol/package.json | 2 +- .../unit/governance/mock/CompileValidatorMock.t.sol | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 packages/protocol/test-sol/unit/governance/mock/CompileValidatorMock.t.sol diff --git a/packages/protocol/package.json b/packages/protocol/package.json index 01d242474b5..e9210652a2c 100644 --- a/packages/protocol/package.json +++ b/packages/protocol/package.json @@ -10,7 +10,7 @@ "lint:sol": "solhint --version && solhint './contracts/**/*.sol' && solhint './contracts-0.8/**/*.sol'", "lint": "yarn run lint:ts && yarn run lint:sol", "clean": "rm -rf ./types/typechain && rm -rf build/* && rm -rf .0x-artifacts/* && rm -rf migrations/*.js* && rm -rf migrations_ts/*.js* && rm -rf test/**/*.js* && rm -f lib/*.js* && rm -f lib/**/*.js* && rm -f scripts/*.js* && yarn clean:foundry", - "clean:foundry": "rm -rf cache out", + "clean:foundry": "forge clean && rm -rf cache out", "test": "rm test/**/*.js ; node runTests.js", "test:scripts": "yarn ts-node scripts/run-scripts-tests.ts --testPathPattern=scripts/", "quicktest": "./scripts/bash/quicktest.sh", diff --git a/packages/protocol/test-sol/unit/governance/mock/CompileValidatorMock.t.sol b/packages/protocol/test-sol/unit/governance/mock/CompileValidatorMock.t.sol new file mode 100644 index 00000000000..053ddcb93b0 --- /dev/null +++ b/packages/protocol/test-sol/unit/governance/mock/CompileValidatorMock.t.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.7 <0.8.20; + +import "celo-foundry-8/Test.sol"; + +// here only to forge compile of ValidatorsMock +import "./ValidatorsMock.sol"; + +contract DowntimeSlasherMock is Test { + function test_nop() public {} +} From 5bf0d8583f5387c908ba80392f39d3290d114f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 16:40:58 +0200 Subject: [PATCH 67/69] moved mocks to right path --- packages/protocol/test-sol/unit/common/EpochManager.t.sol | 2 +- .../{mock => validators/mocks}/CompileValidatorMock.t.sol | 5 ++++- .../governance/{mock => validators/mocks}/ValidatorsMock.sol | 0 3 files changed, 5 insertions(+), 2 deletions(-) rename packages/protocol/test-sol/unit/governance/{mock => validators/mocks}/CompileValidatorMock.t.sol (71%) rename packages/protocol/test-sol/unit/governance/{mock => validators/mocks}/ValidatorsMock.sol (100%) diff --git a/packages/protocol/test-sol/unit/common/EpochManager.t.sol b/packages/protocol/test-sol/unit/common/EpochManager.t.sol index 70fdd8743a8..9de13060519 100644 --- a/packages/protocol/test-sol/unit/common/EpochManager.t.sol +++ b/packages/protocol/test-sol/unit/common/EpochManager.t.sol @@ -18,7 +18,7 @@ import "@celo-contracts/stability/test/MockSortedOracles.sol"; import "@celo-contracts/common/interfaces/IRegistry.sol"; import { EpochRewardsMock08 } from "@celo-contracts-8/governance/test/EpochRewardsMock.sol"; -import { ValidatorsMock } from "@test-sol/unit/governance/mock/ValidatorsMock.sol"; +import { ValidatorsMock } from "@test-sol/unit/governance/validators/mocks/ValidatorsMock.sol"; import { MockCeloUnreleasedTreasure } from "@celo-contracts-8/common/test/MockCeloUnreleasedTreasure.sol"; contract EpochManagerTest is Test, TestConstants, Utils08 { diff --git a/packages/protocol/test-sol/unit/governance/mock/CompileValidatorMock.t.sol b/packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorMock.t.sol similarity index 71% rename from packages/protocol/test-sol/unit/governance/mock/CompileValidatorMock.t.sol rename to packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorMock.t.sol index 053ddcb93b0..a278ce2d1f7 100644 --- a/packages/protocol/test-sol/unit/governance/mock/CompileValidatorMock.t.sol +++ b/packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorMock.t.sol @@ -2,10 +2,13 @@ pragma solidity >=0.8.7 <0.8.20; import "celo-foundry-8/Test.sol"; +import "forge-std/console.sol"; // here only to forge compile of ValidatorsMock import "./ValidatorsMock.sol"; contract DowntimeSlasherMock is Test { - function test_nop() public {} + function test_nop() public { + console.log("nop"); + } } diff --git a/packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol b/packages/protocol/test-sol/unit/governance/validators/mocks/ValidatorsMock.sol similarity index 100% rename from packages/protocol/test-sol/unit/governance/mock/ValidatorsMock.sol rename to packages/protocol/test-sol/unit/governance/validators/mocks/ValidatorsMock.sol From df7a9e8979f4d5c7eccc4df060cea4f145395358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 16:52:28 +0200 Subject: [PATCH 68/69] Fixed tests --- .../CompileValidatorMock.t.sol | 4 ++-- .../mocks/CompileValidatorIntegrationMock.t.sol | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) rename packages/protocol/test-sol/{unit/governance/validators/mocks => integration}/CompileValidatorMock.t.sol (69%) create mode 100644 packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorIntegrationMock.t.sol diff --git a/packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorMock.t.sol b/packages/protocol/test-sol/integration/CompileValidatorMock.t.sol similarity index 69% rename from packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorMock.t.sol rename to packages/protocol/test-sol/integration/CompileValidatorMock.t.sol index a278ce2d1f7..a4a8aa9930f 100644 --- a/packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorMock.t.sol +++ b/packages/protocol/test-sol/integration/CompileValidatorMock.t.sol @@ -5,9 +5,9 @@ import "celo-foundry-8/Test.sol"; import "forge-std/console.sol"; // here only to forge compile of ValidatorsMock -import "./ValidatorsMock.sol"; +import "@test-sol/unit/governance/validators/mocks/ValidatorsMock.sol"; -contract DowntimeSlasherMock is Test { +contract CompileValidatorMock is Test { function test_nop() public { console.log("nop"); } diff --git a/packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorIntegrationMock.t.sol b/packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorIntegrationMock.t.sol new file mode 100644 index 00000000000..e7ce8a53559 --- /dev/null +++ b/packages/protocol/test-sol/unit/governance/validators/mocks/CompileValidatorIntegrationMock.t.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.7 <0.8.20; + +import "celo-foundry-8/Test.sol"; +import "forge-std/console.sol"; + +// here only to forge compile of ValidatorsMock +import "@test-sol/unit/governance/validators/mocks/ValidatorsMock.sol"; + +contract CompileValidatorIntegrationMock is Test { + function test_nop() public { + console.log("nop"); + } +} From 1d62d5f0138489772297495e78ab5b9d7bb1fbeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Volpe?= Date: Tue, 17 Sep 2024 17:03:56 +0200 Subject: [PATCH 69/69] Added ScoreManager to releaseData/initializationData/release12.json --- .../protocol/releaseData/initializationData/release12.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/protocol/releaseData/initializationData/release12.json b/packages/protocol/releaseData/initializationData/release12.json index e16d1f7f045..635895d47e0 100644 --- a/packages/protocol/releaseData/initializationData/release12.json +++ b/packages/protocol/releaseData/initializationData/release12.json @@ -1,6 +1,7 @@ { - "FeeCurrencyDirectory": [], "CeloUnreleasedTreasure": ["0x000000000000000000000000000000000000ce10"], "EpochManager": ["0x000000000000000000000000000000000000ce10", 86400, "0xD533Ca259b330c7A88f74E000a3FaEa2d63B7972", "0x0000000000000000000000000000000000000000"], - "EpochManagerEnabler": ["0x000000000000000000000000000000000000ce10"] + "EpochManagerEnabler": ["0x000000000000000000000000000000000000ce10"], + "ScoreManager": [], + "FeeCurrencyDirectory": [] }