diff --git a/protocol/governance/cannonfile.toml b/protocol/governance/cannonfile.toml index 554df7dd86..3d6c036506 100644 --- a/protocol/governance/cannonfile.toml +++ b/protocol/governance/cannonfile.toml @@ -11,10 +11,10 @@ defaultValue = "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" defaultValue = "governance" [setting.wormhole_core] -defaultValue = "0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B" # mainnet ethereum https://docs.wormhole.com/wormhole/reference/constants +defaultValue = "0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4" # snaxchain https://explorer.snaxchain.io/address/0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4 [setting.wormhole_relayer] -defaultValue = "0x27428DD2d3DD32A4D7f7C497eAaa23130d894911" # mainnet ethereum https://docs.wormhole.com/wormhole/reference/constants +defaultValue = "0x27428DD2d3DD32A4D7f7C497eAaa23130d894911" # snaxchain https://explorer.snaxchain.io/address/0x27428DD2d3DD32A4D7f7C497eAaa23130d894911 [setting.initial_council_member] defaultValue = "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" diff --git a/protocol/governance/contracts/interfaces/IElectionModule.sol b/protocol/governance/contracts/interfaces/IElectionModule.sol index ff9b10e285..ed76b65c34 100644 --- a/protocol/governance/contracts/interfaces/IElectionModule.sol +++ b/protocol/governance/contracts/interfaces/IElectionModule.sol @@ -137,24 +137,6 @@ interface IElectionModule is IElectionModuleSatellite { // View functions // --------------------------------------- - /// @notice Shows the current epoch schedule dates - function getEpochSchedule() external view returns (Epoch.Data memory epoch); - - /// @notice Shows the settings for the current election - function getElectionSettings() external view returns (ElectionSettings.Data memory settings); - - /// @notice Shows the settings for the next election - function getNextElectionSettings() - external - view - returns (ElectionSettings.Data memory settings); - - /// @notice Returns the index of the current epoch. The first epoch's index is 1 - function getEpochIndex() external view returns (uint256); - - /// @notice Returns the current period type: Administration, Nomination, Voting, Evaluation - function getCurrentPeriod() external view returns (uint256); - /// @notice Shows if a candidate has been nominated in the current epoch function isNominated(address candidate) external view returns (bool); @@ -188,6 +170,9 @@ interface IElectionModule is IElectionModuleSatellite { uint256 electionId ) external pure returns (Ballot.Data memory); + /// @notice Returns the number of ballots in the current election + function getNumOfBallots() external view returns (uint256); + /// @notice Returns the number of votes a candidate received. Requires the election to be partially or totally evaluated function getCandidateVotes(address candidate) external view returns (uint256); diff --git a/protocol/governance/contracts/interfaces/IElectionModuleSatellite.sol b/protocol/governance/contracts/interfaces/IElectionModuleSatellite.sol index f4ffbffd66..d285729cfb 100644 --- a/protocol/governance/contracts/interfaces/IElectionModuleSatellite.sol +++ b/protocol/governance/contracts/interfaces/IElectionModuleSatellite.sol @@ -3,6 +3,8 @@ pragma solidity ^0.8.0; import {IWormhole} from "@synthetixio/core-modules/contracts/interfaces/IWormhole.sol"; import {IWormholeRelayer} from "@synthetixio/core-modules/contracts/interfaces/IWormholeRelayer.sol"; +import {ElectionSettings} from "../storage/ElectionSettings.sol"; +import {Epoch} from "../storage/Epoch.sol"; /// @title Election module council with minimal logic to be deployed on Satellite chains interface IElectionModuleSatellite { @@ -71,6 +73,28 @@ interface IElectionModuleSatellite { /// @notice Allows to withdraw a casted vote on the current network function withdrawVote() external payable; + // --------------------------------------- + // View functions + // --------------------------------------- + + /// @notice Returns the current period type: Administration, Nomination, Voting, Evaluation + function getCurrentPeriod() external view returns (uint256); + + /// @notice Shows the current epoch schedule dates + function getEpochSchedule() external view returns (Epoch.Data memory epoch); + + /// @notice Shows the settings for the current election + function getElectionSettings() external view returns (ElectionSettings.Data memory settings); + + /// @notice Shows the settings for the next election + function getNextElectionSettings() + external + view + returns (ElectionSettings.Data memory settings); + + /// @notice Returns the index of the current epoch. The first epoch's index is 1 + function getEpochIndex() external view returns (uint256); + /// @dev Burn the council tokens from the given members; receiving end of members dismissal via Wormhole function _recvDismissMembers(address[] calldata membersToDismiss, uint256 epochIndex) external; diff --git a/protocol/governance/contracts/interfaces/ISnapshotVotePowerModule.sol b/protocol/governance/contracts/interfaces/ISnapshotVotePowerModule.sol index 352f693f42..fcc6757403 100644 --- a/protocol/governance/contracts/interfaces/ISnapshotVotePowerModule.sol +++ b/protocol/governance/contracts/interfaces/ISnapshotVotePowerModule.sol @@ -24,4 +24,10 @@ interface ISnapshotVotePowerModule { ) external returns (uint256 votingPower); function getPreparedBallot(address voter) external view returns (uint256 power); + + function getVotingPowerForUser( + address snapshotContract, + address voter, + uint256 periodId + ) external view returns (uint256); } diff --git a/protocol/governance/contracts/modules/core/ElectionModule.sol b/protocol/governance/contracts/modules/core/ElectionModule.sol index 896e0a2019..21127b9dbf 100644 --- a/protocol/governance/contracts/modules/core/ElectionModule.sol +++ b/protocol/governance/contracts/modules/core/ElectionModule.sol @@ -151,7 +151,7 @@ contract ElectionModule is IElectionModule, ElectionModuleSatellite, ElectionTal uint64 newEpochEndDate ) external payable override { OwnableStorage.onlyOwner(); - Council.onlyInPeriod(Epoch.ElectionPeriod.Administration); + Council.onlyInPeriods(Epoch.ElectionPeriod.Administration, Epoch.ElectionPeriod.Nomination); Council.Data storage council = Council.load(); Epoch.Data storage currentEpoch = council.getCurrentEpoch(); @@ -197,7 +197,7 @@ contract ElectionModule is IElectionModule, ElectionModuleSatellite, ElectionTal uint64 maxDateAdjustmentTolerance ) external override { OwnableStorage.onlyOwner(); - Council.onlyInPeriod(Epoch.ElectionPeriod.Administration); + Council.onlyInPeriods(Epoch.ElectionPeriod.Administration, Epoch.ElectionPeriod.Nomination); Council.load().getNextElectionSettings().setElectionSettings( epochSeatCount, @@ -474,42 +474,6 @@ contract ElectionModule is IElectionModule, ElectionModuleSatellite, ElectionTal }); } - /// @inheritdoc IElectionModule - function getEpochSchedule() external view override returns (Epoch.Data memory epoch) { - return Council.load().getCurrentEpoch(); - } - - /// @inheritdoc IElectionModule - function getElectionSettings() - external - view - override - returns (ElectionSettings.Data memory settings) - { - return Council.load().getCurrentElectionSettings(); - } - - /// @inheritdoc IElectionModule - function getNextElectionSettings() - external - view - override - returns (ElectionSettings.Data memory settings) - { - return Council.load().getNextElectionSettings(); - } - - /// @inheritdoc IElectionModule - function getEpochIndex() external view override returns (uint256) { - return Council.load().currentElectionId; - } - - /// @inheritdoc IElectionModule - function getCurrentPeriod() external view override returns (uint256) { - // solhint-disable-next-line numcast/safe-cast - return uint256(Council.load().getCurrentEpoch().getCurrentPeriod()); - } - /// @inheritdoc IElectionModule function isNominated(address candidate) external view override returns (bool) { return Council.load().getCurrentElection().nominees.contains(candidate); @@ -555,6 +519,11 @@ contract ElectionModule is IElectionModule, ElectionModuleSatellite, ElectionTal return Ballot.load(electionId, voter, chainId).votedCandidates; } + /// @inheritdoc IElectionModule + function getNumOfBallots() external view override returns (uint256) { + return Council.load().getCurrentElection().ballotPtrs.length(); + } + /// @inheritdoc IElectionModule function isElectionEvaluated() public view override returns (bool) { return Council.load().getCurrentElection().evaluated; diff --git a/protocol/governance/contracts/modules/core/ElectionModuleSatellite.sol b/protocol/governance/contracts/modules/core/ElectionModuleSatellite.sol index 698dd07e2f..0b89582623 100644 --- a/protocol/governance/contracts/modules/core/ElectionModuleSatellite.sol +++ b/protocol/governance/contracts/modules/core/ElectionModuleSatellite.sol @@ -15,6 +15,7 @@ import {ElectionCredentials} from "../../submodules/election/ElectionCredentials import {Ballot} from "../../storage/Ballot.sol"; import {CouncilMembers} from "../../storage/CouncilMembers.sol"; import {Council} from "../../storage/Council.sol"; +import {ElectionSettings} from "../../storage/ElectionSettings.sol"; import {Epoch} from "../../storage/Epoch.sol"; contract ElectionModuleSatellite is @@ -153,6 +154,42 @@ contract ElectionModuleSatellite is emit VoteWithdrawnSent(sender); } + /// @inheritdoc IElectionModuleSatellite + function getCurrentPeriod() external view override returns (uint256) { + // solhint-disable-next-line numcast/safe-cast + return uint256(Council.load().getCurrentEpoch().getCurrentPeriod()); + } + + /// @inheritdoc IElectionModuleSatellite + function getEpochSchedule() external view override returns (Epoch.Data memory epoch) { + return Council.load().getCurrentEpoch(); + } + + /// @inheritdoc IElectionModuleSatellite + function getElectionSettings() + external + view + override + returns (ElectionSettings.Data memory settings) + { + return Council.load().getCurrentElectionSettings(); + } + + /// @inheritdoc IElectionModuleSatellite + function getNextElectionSettings() + external + view + override + returns (ElectionSettings.Data memory settings) + { + return Council.load().getNextElectionSettings(); + } + + /// @inheritdoc IElectionModuleSatellite + function getEpochIndex() external view override returns (uint256) { + return Council.load().currentElectionId; + } + function _recvDismissMembers( address[] calldata membersToDismiss, uint256 epochIndex diff --git a/protocol/governance/contracts/modules/core/SnapshotVotePowerModule.sol b/protocol/governance/contracts/modules/core/SnapshotVotePowerModule.sol index 538172bd5c..3a661e0f52 100644 --- a/protocol/governance/contracts/modules/core/SnapshotVotePowerModule.sol +++ b/protocol/governance/contracts/modules/core/SnapshotVotePowerModule.sol @@ -82,6 +82,20 @@ contract SnapshotVotePowerModule is ISnapshotVotePowerModule { return SnapshotVotePower.load(snapshotContract).epochs[electionId].snapshotId; } + /// @dev WARNING: this function is for the frontend to get the voting power of a voter, not for the contract to use + function getVotingPowerForUser( + address snapshotContract, + address voter, + uint256 periodId + ) external view override returns (uint256) { + uint256 snapshotAmount = ISnapshotRecord(snapshotContract).balanceOfOnPeriod( + voter, + periodId + ); + SnapshotVotePower.Data storage snapshotVotePower = SnapshotVotePower.load(snapshotContract); + return SnapshotVotePower.calculateVotingPower(snapshotVotePower, snapshotAmount); + } + function prepareBallotWithSnapshot( address snapshotContract, address voter diff --git a/protocol/governance/contracts/storage/Council.sol b/protocol/governance/contracts/storage/Council.sol index 718c32844b..1e1bfbc16d 100644 --- a/protocol/governance/contracts/storage/Council.sol +++ b/protocol/governance/contracts/storage/Council.sol @@ -10,7 +10,7 @@ library Council { using Epoch for Epoch.Data; using ElectionSettings for ElectionSettings.Data; - error NotCallableInCurrentPeriod(); + error NotCallableInCurrentPeriod(Epoch.ElectionPeriod currentPeriod); error InvalidEpochConfiguration(uint256 code, uint64 v1, uint64 v2); error ChangesCurrentPeriod(); @@ -75,7 +75,7 @@ library Council { function onlyInPeriod(Epoch.ElectionPeriod period) internal view { Epoch.ElectionPeriod currentPeriod = getCurrentEpoch(load()).getCurrentPeriod(); if (currentPeriod != period) { - revert NotCallableInCurrentPeriod(); + revert NotCallableInCurrentPeriod(currentPeriod); } } @@ -86,7 +86,7 @@ library Council { ) internal view { Epoch.ElectionPeriod currentPeriod = getCurrentEpoch(load()).getCurrentPeriod(); if (currentPeriod != period1 && currentPeriod != period2) { - revert NotCallableInCurrentPeriod(); + revert NotCallableInCurrentPeriod(currentPeriod); } } diff --git a/utils/common-config/hardhat.config.ts b/utils/common-config/hardhat.config.ts index 9f2898cdfb..2ecbabff5c 100644 --- a/utils/common-config/hardhat.config.ts +++ b/utils/common-config/hardhat.config.ts @@ -116,6 +116,13 @@ const config = { process.env.NETWORK_ENDPOINT || `https://testnet.snaxchain.io/${process.env.SNAXCHAIN_API_KEY}`, accounts: process.env.DEPLOYER_PRIVATE_KEY ? [process.env.DEPLOYER_PRIVATE_KEY] : [], + chainId: 13001, + }, + ['snaxchain']: { + url: + process.env.NETWORK_ENDPOINT || + `https://mainnet.snaxchain.io/${process.env.SNAXCHAIN_API_KEY}`, + accounts: process.env.DEPLOYER_PRIVATE_KEY ? [process.env.DEPLOYER_PRIVATE_KEY] : [], chainId: 2192, }, },