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

Proposal id mapping (optimistic) #20

Merged
merged 3 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
29 changes: 29 additions & 0 deletions DEPLOYMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Deployment list

## Mainnet

## Sepolia

On June 6th 2024:

```
Chain ID: 11155111

Deploying from: 0x424797Ed6d902E17b9180BFcEF452658e148e0Ab
Test voting token: 0xf7A8F99a1d0AFB3C95f80770223b00e062C6Ec19
Factory contract: 0x8c99CDb5567206660CA9b77C3B26C13F6C674952

DAO contract: 0x6C477915CC803518723d4Bdd5B2170cf38A57203

- Multisig plugin: 0x0fC611670228A61824c317926f30e8a2615aa1A3
- Emergency multisig plugin: 0x619d6661eA06b917e26694f23c5Bb32fa0456773
- Optimistic token voting plugin: 0xC9304930f6a4fB2DAe74A17032426Aa1E817897A

- Multisig plugin repository: 0x841E3dA30697C8FC7224a43952041001545a2443
- Emergency multisig plugin repository: 0x6E8578B1519a04BA9262CB633B06624f636D4795
- Optimistic token voting plugin repository: 0x58CA6f90edB98f9213353f456c685ABF253edAA7

Public key registry 0xadAb459A189AAaa17D4807805e6Fab55d3fb5C44
Delegation wall 0x0cE7f031BA69abFB404fE148dD09F597db8AB3a0
```

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The Security Council has a standard multisig plugin and an emergency variant. Th

[Learn more about Aragon OSx](#protocol-overview).

See [Deploying the DAO](#deploying-the-dao) below.
See [Deploying the DAO](#deploying-the-dao) below and check out the [latest deployments](./DEPLOYMENTS.md).

## Optimistic Token Voting plugin

Expand Down
4 changes: 2 additions & 2 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ contract Deploy is Script {
);

console.log("Chain ID:", block.chainid);
console.log("Deploying from:", vm.addr(vm.envUint("DEPLOYMENT_PRIVATE_KEY")));
console.log("");
console.log("Deploying from:", vm.addr(vm.envUint("DEPLOYMENT_PRIVATE_KEY")));

TaikoDaoFactory.DeploymentSettings memory settings;
if (block.chainid == 1) {
Expand All @@ -55,6 +55,7 @@ contract Deploy is Script {

// Print summary
console.log("Factory contract:", address(factory));
console.log("");
console.log("DAO contract:", address(daoDeployment.dao));
console.log("");

Expand Down Expand Up @@ -110,7 +111,6 @@ contract Deploy is Script {
address votingToken = createTestToken(multisigMembers, taikoBridgeAddress);

console.log("Test voting token:", votingToken);
console.log("");

settings = TaikoDaoFactory.DeploymentSettings({
// Taiko contract settings
Expand Down
8 changes: 8 additions & 0 deletions src/DelegationWall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ contract DelegationWall {

/// @dev Stores the data registered by the delegate candidates
mapping(address => Candidate) public candidates;

/// @dev Keeps track of the addresses that have been already registered, used to enumerate.
address[] public candidateAddresses;

Expand All @@ -33,6 +34,13 @@ contract DelegationWall {
emit CandidateRegistered(msg.sender, _contentUrl);
}

/// @notice Returns the list of candidate addresses registered
/// @dev Use this function to get all addresses in a single call. You can still call candidateAddresses[idx] to resolve them one by one.
function getCandidateAddresses() public view returns (address[] memory) {
return candidateAddresses;
}

/// @notice Returns the number of candidate entries available
function candidateCount() public view returns (uint256) {
return candidateAddresses.length;
}
Expand Down
7 changes: 6 additions & 1 deletion src/OptimisticTokenVotingPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ contract OptimisticTokenVotingPlugin is
/// @notice A mapping between proposal IDs and proposal information.
mapping(uint256 => Proposal) internal proposals;

/// @notice A mapping to enumerate proposal ID's by index
mapping(uint256 => uint256) public proposalIds;

/// @notice Emitted when the vetoing settings are updated.
/// @param minVetoRatio The minimum veto ratio needed to defeat the proposal, as a fraction of 1_000_000.
/// @param minDuration The minimum duration of the proposal vote in seconds.
Expand Down Expand Up @@ -358,6 +361,8 @@ contract OptimisticTokenVotingPlugin is
_actions: _actions,
_allowFailureMap: _allowFailureMap
});
// Index the ID to make it enumerable. Proposal ID's contain timestamps and cannot be iterated
proposalIds[proposalCount() - 1] = proposalId;

// Store proposal related information
Proposal storage proposal_ = proposals[proposalId];
Expand Down Expand Up @@ -549,5 +554,5 @@ contract OptimisticTokenVotingPlugin is
}

/// @notice This empty reserved space is put in place to allow future versions to add new variables without shifting down storage in the inheritance chain (see [OpenZeppelin's guide about storage gaps](https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps)).
uint256[45] private __gap;
uint256[44] private __gap;
}
17 changes: 14 additions & 3 deletions src/PublicKeyRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ pragma solidity ^0.8.17;
/// @author Aragon Association - 2024
/// @notice A smart contract where any wallet can register its own libsodium public key for encryption purposes
contract PublicKeyRegistry {
mapping(address => bytes32) internal publicKeys;
mapping(address => bytes32) public publicKeys;

/// @dev Allows to enumerate the wallets that have a public key registered
address[] public registeredWallets;

/// @notice Emitted when a public key is registered
event PublicKeyRegistered(address wallet, bytes32 publicKey);
Expand All @@ -19,9 +22,17 @@ contract PublicKeyRegistry {

publicKeys[msg.sender] = _publicKey;
emit PublicKeyRegistered(msg.sender, _publicKey);
registeredWallets.push(msg.sender);
}

/// @notice Returns the list of wallets that have registered a public key
/// @dev Use this function to get all addresses in a single call. You can still call registeredWallets[idx] to resolve them one by one.
function getRegisteredWallets() public view returns (address[] memory) {
return registeredWallets;
}

function getPublicKey(address _wallet) public view returns (bytes32) {
return publicKeys[_wallet];
/// @notice Returns the number of publicKey entries available
function registeredWalletCount() public view returns (uint256) {
return registeredWallets.length;
}
}
18 changes: 18 additions & 0 deletions test/DelegationWall.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,24 @@ contract EmergencyMultisigTest is AragonTest {
assertEq(wall.candidateAddresses(3), david, "Incorrect candidate address");
}

function test_ShouldLoadTheRegisteredAddresses() public {
vm.startPrank(alice);
wall.register("https://");
vm.startPrank(bob);
wall.register("https://taiko.xyz");
vm.startPrank(carol);
wall.register("https://x.com/carol");
vm.startPrank(david);
wall.register("https://defeat-goliath.org");

address[] memory candidates = wall.getCandidateAddresses();
assertEq(candidates.length, 4);
assertEq(candidates[0], alice);
assertEq(candidates[1], bob);
assertEq(candidates[2], carol);
assertEq(candidates[3], david);
}

function test_ShouldEmitAnEventWhenRegistering() public {
// Alice
vm.startPrank(alice);
Expand Down
39 changes: 39 additions & 0 deletions test/OptimisticTokenVotingPlugin.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,45 @@ contract OptimisticTokenVotingPluginTest is AragonTest {
assertEq(proposalId, expectedPid, "Should have created proposal 2");
}

function test_CreateProposalIncrementsTheProposalCounter() public {
IDAO.Action[] memory actions = new IDAO.Action[](0);
assertEq(optimisticPlugin.proposalCount(), 0);
optimisticPlugin.createProposal("", actions, 0, 10 days);
assertEq(optimisticPlugin.proposalCount(), 1);
optimisticPlugin.createProposal("ipfs://", actions, 0, 10 days);
assertEq(optimisticPlugin.proposalCount(), 2);
optimisticPlugin.createProposal("", actions, 255, 15 days);
assertEq(optimisticPlugin.proposalCount(), 3);
optimisticPlugin.createProposal("", actions, 127, 20 days);
assertEq(optimisticPlugin.proposalCount(), 4);
optimisticPlugin.createProposal("ipfs://meta", actions, 0, 10 days);
assertEq(optimisticPlugin.proposalCount(), 5);
optimisticPlugin.createProposal("", actions, 0, 100 days);
assertEq(optimisticPlugin.proposalCount(), 6);
}

function test_CreateProposalIndexesThePid() public {
uint256 expectedPid = uint256(block.timestamp) << 128 | uint256(block.timestamp + 10 days) << 64;

IDAO.Action[] memory actions = new IDAO.Action[](0);
// 1
assertEq(optimisticPlugin.proposalIds(0), 0);
optimisticPlugin.createProposal("", actions, 0, 10 days);
assertEq(optimisticPlugin.proposalIds(0), expectedPid);

// 2
expectedPid = uint256(block.timestamp) << 128 | uint256(block.timestamp + 100 days) << 64 | 1;
assertEq(optimisticPlugin.proposalIds(1), 0);
optimisticPlugin.createProposal("ipfs://meta", actions, 0, 100 days);
assertEq(optimisticPlugin.proposalIds(1), expectedPid);

// 3
expectedPid = uint256(block.timestamp) << 128 | uint256(block.timestamp + 50 days) << 64 | 2;
assertEq(optimisticPlugin.proposalIds(2), 0);
optimisticPlugin.createProposal("", actions, 0, 50 days);
assertEq(optimisticPlugin.proposalIds(2), expectedPid);
}

function test_CreateProposalEmitsAnEvent() public {
uint256 expectedPid = uint256(block.timestamp) << 128 | uint256(block.timestamp + 10 days) << 64;

Expand Down
83 changes: 72 additions & 11 deletions test/PublicKeyRegistry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,37 @@ contract EmergencyMultisigTest is AragonTest {
}

function test_ShouldRegisterAPublicKey() public {
assertEq(registry.getPublicKey(alice), 0x0000000000000000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(alice), 0x0000000000000000000000000000000000000000000000000000000000000000);

// Alice
vm.startPrank(alice);
registry.setPublicKey(0x1234000000000000000000000000000000000000000000000000000000000000);

assertEq(registry.getPublicKey(alice), 0x1234000000000000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(alice), 0x1234000000000000000000000000000000000000000000000000000000000000);

// Bob
vm.startPrank(bob);
registry.setPublicKey(0x0000567800000000000000000000000000000000000000000000000000000000);

assertEq(registry.getPublicKey(alice), 0x1234000000000000000000000000000000000000000000000000000000000000);
assertEq(registry.getPublicKey(bob), 0x0000567800000000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(alice), 0x1234000000000000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(bob), 0x0000567800000000000000000000000000000000000000000000000000000000);

// Carol
vm.startPrank(carol);
registry.setPublicKey(0x0000000090ab0000000000000000000000000000000000000000000000000000);

assertEq(registry.getPublicKey(alice), 0x1234000000000000000000000000000000000000000000000000000000000000);
assertEq(registry.getPublicKey(bob), 0x0000567800000000000000000000000000000000000000000000000000000000);
assertEq(registry.getPublicKey(carol), 0x0000000090ab0000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(alice), 0x1234000000000000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(bob), 0x0000567800000000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(carol), 0x0000000090ab0000000000000000000000000000000000000000000000000000);

// David
vm.startPrank(david);
registry.setPublicKey(0x000000000000cdef000000000000000000000000000000000000000000000000);

assertEq(registry.getPublicKey(alice), 0x1234000000000000000000000000000000000000000000000000000000000000);
assertEq(registry.getPublicKey(bob), 0x0000567800000000000000000000000000000000000000000000000000000000);
assertEq(registry.getPublicKey(carol), 0x0000000090ab0000000000000000000000000000000000000000000000000000);
assertEq(registry.getPublicKey(david), 0x000000000000cdef000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(alice), 0x1234000000000000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(bob), 0x0000567800000000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(carol), 0x0000000090ab0000000000000000000000000000000000000000000000000000);
assertEq(registry.publicKeys(david), 0x000000000000cdef000000000000000000000000000000000000000000000000);
}

function test_ShouldEmitARegistrationEvent() public {
Expand Down Expand Up @@ -102,4 +102,65 @@ contract EmergencyMultisigTest is AragonTest {
vm.expectRevert(abi.encodeWithSelector(AlreadySet.selector));
registry.setPublicKey(0x000000000000cdef000000000000000000000000000000000000000000000000);
}

function test_ShouldCountRegisteredCandidates() public {
assertEq(registry.registeredWalletCount(), 0, "Incorrect count");

// Alice
vm.startPrank(alice);
registry.setPublicKey(bytes32(uint256(1234)));
assertEq(registry.registeredWalletCount(), 1, "Incorrect count");

// Bob
vm.startPrank(bob);
registry.setPublicKey(bytes32(uint256(2345)));
assertEq(registry.registeredWalletCount(), 2, "Incorrect count");

// Carol
vm.startPrank(carol);
registry.setPublicKey(bytes32(uint256(3456)));
assertEq(registry.registeredWalletCount(), 3, "Incorrect count");

// David
vm.startPrank(david);
registry.setPublicKey(bytes32(uint256(4567)));
assertEq(registry.registeredWalletCount(), 4, "Incorrect count");
}

function test_ShouldEnumerateRegisteredCandidates() public {
// Register
vm.startPrank(alice);
registry.setPublicKey(bytes32(uint256(1234)));
vm.startPrank(bob);
registry.setPublicKey(bytes32(uint256(2345)));
vm.startPrank(carol);
registry.setPublicKey(bytes32(uint256(3456)));
vm.startPrank(david);
registry.setPublicKey(bytes32(uint256(4567)));

assertEq(registry.registeredWalletCount(), 4, "Incorrect count");

assertEq(registry.registeredWallets(0), alice);
assertEq(registry.registeredWallets(1), bob);
assertEq(registry.registeredWallets(2), carol);
assertEq(registry.registeredWallets(3), david);
}

function test_ShouldLoadTheRegisteredAddresses() public {
vm.startPrank(alice);
registry.setPublicKey(bytes32(uint256(1234)));
vm.startPrank(bob);
registry.setPublicKey(bytes32(uint256(2345)));
vm.startPrank(carol);
registry.setPublicKey(bytes32(uint256(3456)));
vm.startPrank(david);
registry.setPublicKey(bytes32(uint256(4567)));

address[] memory candidates = registry.getRegisteredWallets();
assertEq(candidates.length, 4);
assertEq(candidates[0], alice);
assertEq(candidates[1], bob);
assertEq(candidates[2], carol);
assertEq(candidates[3], david);
}
}