Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add satellites NFT distribution #1787

Merged
merged 4 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {Epoch} from "../storage/Epoch.sol";

/// @title Module for electing a council, represented by a set of NFT holders
interface IElectionModule {
error NotMothership();
error AlreadyNominated();
error ElectionAlreadyEvaluated();
error ElectionNotEvaluated();
Expand Down
50 changes: 30 additions & 20 deletions protocol/governance/contracts/modules/core/BaseElectionModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@

uint256 private constant _CROSSCHAIN_GAS_LIMIT = 100000;

/// @dev Used to allow certain functions to only be executed on the "mothership" chain.
/// The mothership is considered to be the first chain id in the supported networks list.
modifier onlyMothership() {
if (CrossChain.load().getSupportedNetworks()[0] != block.chainid.to64()) {
revert NotMothership();
}

_;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed this in favor of CrossChain.onlyOnChainAt(0); helper fn


function initOrUpdateElectionSettings(
address[] memory initialCouncil,
uint8 minimumActiveMembers,
Expand All @@ -49,6 +39,7 @@
uint64 nominationPeriodDuration,
uint64 votingPeriodDuration
) external override {
// TODO: initialization should be called only on mothership and broadcasted?
OwnableStorage.onlyOwner();

_initOrUpdateElectionSettings(
Expand Down Expand Up @@ -153,6 +144,8 @@
uint64 newVotingPeriodStartDate,
uint64 newEpochEndDate
) external override {
// TODO: onlyOnMothership?

OwnableStorage.onlyOwner();
Council.onlyInPeriod(Council.ElectionPeriod.Administration);
Council.Data storage council = Council.load();
Expand Down Expand Up @@ -180,6 +173,8 @@
uint64 votingPeriodDuration,
uint64 maxDateAdjustmentTolerance
) external override {
// TODO: onlyOnMothership?

OwnableStorage.onlyOwner();
Council.onlyInPeriod(Council.ElectionPeriod.Administration);

Expand All @@ -194,6 +189,8 @@
}

function dismissMembers(address[] calldata membersToDismiss) external override {
// TODO: onlyOnMothership?

OwnableStorage.onlyOwner();

Council.Data storage store = Council.load();
Expand All @@ -219,9 +216,12 @@
}

function nominate() public virtual override {
SetUtil.AddressSet storage nominees = Council.load().getCurrentElection().nominees;
// TODO: onlyOnMothership?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am in favor of keeping it simple and ensuring nominate is only callable on the mothership


Council.onlyInPeriod(Council.ElectionPeriod.Nomination);

SetUtil.AddressSet storage nominees = Council.load().getCurrentElection().nominees;

if (nominees.contains(msg.sender)) revert AlreadyNominated();

nominees.add(msg.sender);
Expand All @@ -232,6 +232,8 @@
}

function withdrawNomination() external override {
// TODO: onlyOnMothership?

SetUtil.AddressSet storage nominees = Council.load().getCurrentElection().nominees;
Council.onlyInPeriod(Council.ElectionPeriod.Nomination);

Expand Down Expand Up @@ -276,17 +278,15 @@

CrossChain.Data storage cc = CrossChain.load();
cc.transmit(
cc.getSupportedNetworks()[0],
cc.getChainIdAt(0),
abi.encodeWithSelector(this._recvCast.selector, msg.sender, block.chainid, ballot),
_CROSSCHAIN_GAS_LIMIT
);
}

function _recvCast(
address voter,
uint256 precinct,
Ballot.Data calldata ballot
) external onlyMothership {
function _recvCast(address voter, uint256 precinct, Ballot.Data calldata ballot) external {
CrossChain.onlyOnChainAt(0);
CrossChain.onlyCrossChain();
Council.onlyInPeriod(Council.ElectionPeriod.Vote);

_validateCandidates(ballot.votedCandidates);
Expand All @@ -307,11 +307,12 @@

election.ballotPtrs.push(ballotPtr);

emit VoteRecorded(msg.sender, precinct, currentElectionId, ballot.votingPower);
emit VoteRecorded(voter, precinct, currentElectionId, ballot.votingPower);
}

/// @dev ElectionTally needs to be extended to specify how votes are counted
function evaluate(uint numBallots) external override onlyMothership {
function evaluate(uint numBallots) external override {
CrossChain.onlyOnChainAt(0);
Council.onlyInPeriod(Council.ElectionPeriod.Evaluation);

Election.Data storage election = Council.load().getCurrentElection();
Expand All @@ -336,7 +337,8 @@
}

/// @dev Burns previous NFTs and mints new ones
function resolve() public virtual override onlyMothership {
function resolve() public virtual override {
CrossChain.onlyOnChainAt(0);
Council.onlyInPeriod(Council.ElectionPeriod.Evaluation);

Council.Data storage store = Council.load();
Expand All @@ -358,6 +360,14 @@
// TODO: Broadcast message to distribute the new NFTs on all chains
}

function _recvResolve(address voter, uint256 precinct, Ballot.Data calldata ballot) external {

Check warning on line 363 in protocol/governance/contracts/modules/core/BaseElectionModule.sol

View workflow job for this annotation

GitHub Actions / lint

Variable "voter" is unused

Check warning on line 363 in protocol/governance/contracts/modules/core/BaseElectionModule.sol

View workflow job for this annotation

GitHub Actions / lint

Variable "precinct" is unused

Check warning on line 363 in protocol/governance/contracts/modules/core/BaseElectionModule.sol

View workflow job for this annotation

GitHub Actions / lint

Variable "ballot" is unused
CrossChain.onlyOnChainAt(0);
CrossChain.onlyCrossChain();
Council.onlyInPeriod(Council.ElectionPeriod.Vote);

// TODO: update voting store, distribute nfts
}

function getEpochSchedule() external view override returns (Epoch.Data memory epoch) {
return Council.load().getCurrentElection().epoch;
}
Expand Down
2 changes: 1 addition & 1 deletion protocol/governance/contracts/storage/Council.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ library Council {
// Council token id's by council member address
mapping(address => uint) councilTokenIds;
// id of the current epoch
uint currentElectionId;
uint256 currentElectionId;
}

enum ElectionPeriod {
Expand Down
1 change: 1 addition & 0 deletions protocol/governance/contracts/storage/Election.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ library Election {
SetUtil.AddressSet winners;
// List of all ballot ids in this election
bytes32[] ballotPtrs;
// Total votes count for a given candidate
mapping(address => uint256) candidateVoteTotals;
}

Expand Down
19 changes: 15 additions & 4 deletions utils/core-modules/contracts/storage/CrossChain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ library CrossChain {

error NotCcipRouter(address);
error UnsupportedNetwork(uint64);
error InvalidNetwork(uint64);
error InsufficientCcipFee(uint256 requiredAmount, uint256 availableAmount);
error InvalidMessage();

Expand Down Expand Up @@ -91,12 +92,22 @@ library CrossChain {
}
}

function onlyOnChainAt(uint64 chainIndex) internal view {
if (getChainIdAt(load(), chainIndex) != block.chainid.to64()) {
revert InvalidNetwork(block.chainid.to64());
}
}

function getChainIdAt(Data storage self, uint64 index) internal view returns (uint64) {
return self.supportedNetworks.valueAt(index + 1).to64();
}

function getSupportedNetworks(Data storage self) internal view returns (uint64[] memory) {
SetUtil.UintSet storage supportedNetworks = self.supportedNetworks;
uint256 supportedNetworksLength = supportedNetworks.length();
uint64[] memory chains = new uint64[](supportedNetworksLength);
for (uint i = 0; i < supportedNetworksLength; i++) {
uint64 chainId = supportedNetworks.values()[i].to64();
uint256[] memory supportedChains = supportedNetworks.values();
uint64[] memory chains = new uint64[](supportedChains.length);
for (uint i = 0; i < supportedChains.length; i++) {
uint64 chainId = supportedChains[i].to64();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved supportedNetworks.values() outside of the loop for gas love

chains[i] = chainId;
}
return chains;
Expand Down
Loading