Skip to content

Commit

Permalink
Update VotingReputation to use extension manager
Browse files Browse the repository at this point in the history
  • Loading branch information
kronosapiens committed Sep 16, 2020
1 parent b8d78ea commit 9b4f9e3
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 111 deletions.
10 changes: 7 additions & 3 deletions contracts/colony/ColonyRoles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ contract ColonyRoles is ColonyStorage {
);
}

function getUserRoles(address who, uint256 where) public view returns (bytes32) {
return ColonyAuthority(address(authority)).getUserRoles(who, where);
function getUserRoles(address _user, uint256 _domain) public view returns (bytes32) {
return ColonyAuthority(address(authority)).getUserRoles(_user, _domain);
}
}

function getCapabilityRoles(bytes4 _sig) public view returns (bytes32) {
return ColonyAuthority(address(authority)).getCapabilityRoles(address(this), _sig);
}
}
4 changes: 2 additions & 2 deletions contracts/extensions/ColonyExtension.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
pragma solidity 0.5.8;
pragma experimental ABIEncoderV2;

import "../common/EtherRouter.sol";
import "../colony/IColony.sol";
import "./../common/EtherRouter.sol";
import "./../colony/IColony.sol";


contract ColonyExtension is DSAuth {
Expand Down
38 changes: 29 additions & 9 deletions contracts/extensions/VotingReputation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ import "./../common/ERC20Extended.sol";
import "./../patriciaTree/PatriciaTreeProofs.sol";
import "./../tokenLocking/ITokenLocking.sol";

import "./ColonyExtension.sol";

contract VotingReputation is DSMath, PatriciaTreeProofs {

contract VotingReputation is ColonyExtension, DSMath, PatriciaTreeProofs {

// Events
event ExtensionInitialised();
event ExtensionDeprecated();
event MotionCreated(uint256 indexed motionId, address creator, uint256 indexed domainId);
event MotionStaked(uint256 indexed motionId, address indexed staker, uint256 indexed vote, uint256 amount);
event MotionVoteSubmitted(uint256 indexed motionId, address indexed voter);
Expand Down Expand Up @@ -93,7 +94,17 @@ contract VotingReputation is DSMath, PatriciaTreeProofs {
uint256 revealPeriod; // Length of time for revealing votes
uint256 escalationPeriod; // Length of time for escalating after a vote

constructor(address _colony) public {
/// @notice Return the version number
/// @return The version number
function version() public pure returns (uint256) {
return 1;
}

/// @notice Install the extension
/// @param _colony Base colony for the installation
function install(address _colony) public {
require(address(colony) == address(0x0), "extension-already-installed");

colony = IColony(_colony);
colonyNetwork = IColonyNetwork(colony.getColonyNetwork());
tokenLocking = ITokenLocking(colonyNetwork.getTokenLocking());
Expand Down Expand Up @@ -121,7 +132,11 @@ contract VotingReputation is DSMath, PatriciaTreeProofs {
)
public
{
require(colony.hasUserRole(msg.sender, 1, ColonyDataTypes.ColonyRole.Root), "voting-rep-user-not-root");
require(
colony.hasUserRole(msg.sender, 1, ColonyDataTypes.ColonyRole.Root),
"voting-rep-user-not-root"
);

require(state == ExtensionState.Deployed, "voting-rep-already-initialised");

require(_totalStakeFraction <= WAD / 2, "voting-rep-greater-than-half-wad");
Expand Down Expand Up @@ -151,13 +166,17 @@ contract VotingReputation is DSMath, PatriciaTreeProofs {
emit ExtensionInitialised();
}

/// @notice Deprecate the extension, prevening new motions from being created
function deprecate() public {
require(colony.hasUserRole(msg.sender, 1, ColonyDataTypes.ColonyRole.Root), "voting-rep-user-not-root");
/// @notice Called when upgrading the extension
function finishUpgrade() public auth {}

state = ExtensionState.Deprecated;
/// @notice Called when deprecating (or undeprecating) the extension
function deprecate(bool _deprecated) public auth {
deprecated = _deprecated;
}

emit ExtensionDeprecated();
/// @notice Called when uninstalling the extension
function uninstall() public auth {
selfdestruct(address(uint160(address(colony))));
}

// Data structures
Expand Down Expand Up @@ -803,6 +822,7 @@ contract VotingReputation is DSMath, PatriciaTreeProofs {
bytes32[] memory _siblings
)
internal
undeprecated
{
require(state == ExtensionState.Active, "voting-rep-not-active");
require(_altTarget != address(colony), "voting-rep-alt-target-cannot-be-base-colony");
Expand Down
48 changes: 0 additions & 48 deletions contracts/extensions/VotingReputationFactory.sol

This file was deleted.

86 changes: 37 additions & 49 deletions test/extensions/voting-rep.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,21 @@ import {
giveUserCLNYTokensAndStake,
} from "../../helpers/test-data-generator";

import { setupEtherRouter } from "../../helpers/upgradable-contracts";

import PatriciaTree from "../../packages/reputation-miner/patricia";

const { expect } = chai;
chai.use(bnChai(web3.utils.BN));

const TokenLocking = artifacts.require("TokenLocking");
const IReputationMiningCycle = artifacts.require("IReputationMiningCycle");
const TokenLocking = artifacts.require("TokenLocking");
const VotingReputation = artifacts.require("VotingReputation");
const VotingReputationFactory = artifacts.require("VotingReputationFactory");
const Resolver = artifacts.require("Resolver");

const VOTING_REPUTATION = soliditySha3("VotingReputation");

contract("Voting Reputation", (accounts) => {
contract.only("Voting Reputation", (accounts) => {
let colony;
let token;
let domain1;
Expand All @@ -46,7 +50,6 @@ contract("Voting Reputation", (accounts) => {
let tokenLocking;

let voting;
let votingFactory;

let reputationTree;

Expand Down Expand Up @@ -113,7 +116,10 @@ contract("Voting Reputation", (accounts) => {
const tokenLockingAddress = await colonyNetwork.getTokenLocking();
tokenLocking = await TokenLocking.at(tokenLockingAddress);

votingFactory = await VotingReputationFactory.new();
const votingImplementation = await VotingReputation.new();
const resolver = await Resolver.new();
await setupEtherRouter("VotingReputation", { VotingReputation: votingImplementation.address }, resolver);
await metaColony.addExtension(VOTING_REPUTATION, resolver.address);
});

beforeEach(async () => {
Expand All @@ -126,8 +132,8 @@ contract("Voting Reputation", (accounts) => {
domain2 = await colony.getDomain(2);
domain3 = await colony.getDomain(3);

await votingFactory.deployExtension(colony.address);
const votingAddress = await votingFactory.deployedExtensions(colony.address);
await colony.installExtension(VOTING_REPUTATION, 1);
const votingAddress = await colonyNetwork.getExtensionInstallation(VOTING_REPUTATION, colony.address);
voting = await VotingReputation.at(votingAddress);

await voting.initialise(
Expand Down Expand Up @@ -232,50 +238,38 @@ contract("Voting Reputation", (accounts) => {
return soliditySha3(`0x${action.slice(preamble, preamble + 64 * 4)}${"0".repeat(64)}${action.slice(preamble + 64 * 5, action.length)}`);
}

describe("deploying the extension", async () => {
it("can install the extension factory once if root and uninstall", async () => {
({ colony } = await setupRandomColony(colonyNetwork));
await checkErrorRevert(votingFactory.deployExtension(colony.address, { from: USER1 }), "colony-extension-user-not-root");
await votingFactory.deployExtension(colony.address, { from: USER0 });
await checkErrorRevert(votingFactory.deployExtension(colony.address, { from: USER0 }), "colony-extension-already-deployed");
await votingFactory.removeExtension(colony.address, { from: USER0 });
});
describe("managing the extension", async () => {
it("can install the extension manually", async () => {
voting = await VotingReputation.new();
await voting.install(colony.address);

await checkErrorRevert(voting.install(colony.address), "extension-already-installed");

it("can query for initisalisation values", async () => {
const totalStakeFraction = await voting.getTotalStakeFraction();
const voterRewardFraction = await voting.getVoterRewardFraction();
const userMinStakeFraction = await voting.getUserMinStakeFraction();
const maxVoteFraction = await voting.getMaxVoteFraction();
await voting.finishUpgrade();
await voting.deprecate(true);
await voting.uninstall();
});

const stakePeriod = await voting.getStakePeriod();
const submitPeriod = await voting.getSubmitPeriod();
const revealPeriod = await voting.getRevealPeriod();
const escalationPeriod = await voting.getEscalationPeriod();
it("can install the extension with the extension manager", async () => {
({ colony } = await setupRandomColony(colonyNetwork));
await colony.installExtension(VOTING_REPUTATION, 1, { from: USER0 });

expect(totalStakeFraction).to.eq.BN(TOTAL_STAKE_FRACTION);
expect(voterRewardFraction).to.eq.BN(VOTER_REWARD_FRACTION);
expect(userMinStakeFraction).to.eq.BN(USER_MIN_STAKE_FRACTION);
expect(maxVoteFraction).to.eq.BN(MAX_VOTE_FRACTION);
await checkErrorRevert(colony.installExtension(VOTING_REPUTATION, 1, { from: USER0 }), "colony-network-extension-already-installed");
await checkErrorRevert(colony.uninstallExtension(VOTING_REPUTATION, { from: USER1 }), "ds-auth-unauthorized");

expect(stakePeriod).to.eq.BN(STAKE_PERIOD);
expect(submitPeriod).to.eq.BN(SUBMIT_PERIOD);
expect(revealPeriod).to.eq.BN(REVEAL_PERIOD);
expect(escalationPeriod).to.eq.BN(ESCALATION_PERIOD);
await colony.uninstallExtension(VOTING_REPUTATION, { from: USER0 });
});

it("can deprecate the extension if root", async () => {
const action = await encodeTxData(colony, "makeTask", [1, UINT256_MAX, FAKE, 1, 0, 0]);
await voting.createRootMotion(ADDRESS_ZERO, action, domain1Key, domain1Value, domain1Mask, domain1Siblings);
await checkErrorRevert(colony.deprecateExtension(VOTING_REPUTATION, true, { from: USER2 }), "ds-auth-unauthorized");

// Must be root
await checkErrorRevert(voting.deprecate({ from: USER2 }), "voting-rep-user-not-root");

await voting.deprecate();
await colony.deprecateExtension(VOTING_REPUTATION, true);

// Cant make new motions!
const action = await encodeTxData(colony, "makeTask", [1, UINT256_MAX, FAKE, 1, 0, 0]);
await checkErrorRevert(
voting.createRootMotion(ADDRESS_ZERO, action, domain1Key, domain1Value, domain1Mask, domain1Siblings),
"voting-rep-not-active"
"colony-extension-deprecated"
);
});

Expand All @@ -285,10 +279,8 @@ contract("Voting Reputation", (accounts) => {
});

it("cannot initialise with invalid values", async () => {
await votingFactory.removeExtension(colony.address, { from: USER0 });
await votingFactory.deployExtension(colony.address);
const votingAddress = await votingFactory.deployedExtensions(colony.address);
voting = await VotingReputation.at(votingAddress);
voting = await VotingReputation.new();
await voting.install(colony.address);

await checkErrorRevert(voting.initialise(HALF.addn(1), HALF, WAD, WAD, YEAR, YEAR, YEAR, YEAR), "voting-rep-greater-than-half-wad");
await checkErrorRevert(voting.initialise(HALF, HALF.addn(1), WAD, WAD, YEAR, YEAR, YEAR, YEAR), "voting-rep-greater-than-half-wad");
Expand Down Expand Up @@ -1692,12 +1684,8 @@ contract("Voting Reputation", (accounts) => {
});

it("can skip the staking phase if no new stake is required", async () => {
// Deploy a new extension with no voter compensation
await votingFactory.removeExtension(colony.address, { from: USER0 });
await votingFactory.deployExtension(colony.address, { from: USER0 });
const votingAddress = await votingFactory.deployedExtensions(colony.address);
voting = await VotingReputation.at(votingAddress);

voting = await VotingReputation.new();
await voting.install(colony.address);
await colony.setArbitrationRole(1, UINT256_MAX, voting.address, 1, true);

await voting.initialise(
Expand Down

0 comments on commit 9b4f9e3

Please sign in to comment.