diff --git a/.gitmodules b/.gitmodules
index 0af557d..97bd8fb 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,3 +10,6 @@
[submodule "lib/ds-thing"]
path = lib/ds-thing
url = https://github.com/dapphub/ds-thing
+[submodule "lib/ds-math"]
+ path = lib/ds-math
+ url = https://github.com/dapphub/ds-math
diff --git a/lib/ds-math b/lib/ds-math
new file mode 160000
index 0000000..784079b
--- /dev/null
+++ b/lib/ds-math
@@ -0,0 +1 @@
+Subproject commit 784079b72c4d782b022b3e893a7c5659aa35971a
diff --git a/src/chief-v2.sol b/src/chief-v2.sol
new file mode 100644
index 0000000..a22866e
--- /dev/null
+++ b/src/chief-v2.sol
@@ -0,0 +1,86 @@
+pragma solidity >=0.5.0;
+
+import "ds-note/note.sol";
+import "ds-math/math.sol";
+
+contract TokenLike {
+ function transferFrom(address, address, uint) public returns (bool);
+}
+
+contract Chief is DSNote, DSMath {
+ // --- Init ---
+ constructor(address governanceToken_) public {
+ governanceToken = TokenLike(governanceToken_);
+ threshold = WAD / 2;
+ }
+
+ // --- Data ---
+ uint256 public threshold; // locked % needed to enact a proposal
+ TokenLike public governanceToken;
+ uint256 public locked; // total locked governanceToken
+ mapping(bytes32 => bool) public hasFired; // proposal => hasFired?
+ mapping(address => uint256) public balances; // guy => lockedGovHowMuch
+ mapping(address => bytes32) public picks; // guy => proposalHash
+ mapping(bytes32 => uint256) public votes; // proposalHash => votesHowMany
+
+ // --- Events ---
+ event Voted(
+ bytes32 indexed proposalHash,
+ address indexed voter,
+ uint256 weight
+ );
+ event Executed(
+ address caller,
+ bytes32 proposal,
+ address indexed app,
+ bytes data
+ );
+
+ // --- Voting Interface ---
+ function lock(uint256 wad) public note {
+ require(governanceToken.transferFrom(msg.sender, address(this), wad), "ds-chief-transfer-failed");
+ balances[msg.sender] = add(balances[msg.sender], wad);
+ locked = add(locked, wad);
+
+ bytes32 currPick = picks[msg.sender];
+ if (currPick != bytes32(0) && !hasFired[currPick])
+ votes[currPick] = add(votes[currPick], wad);
+ }
+ function free(uint256 wad) public note {
+ balances[msg.sender] = sub(balances[msg.sender], wad);
+ require(governanceToken.transferFrom(address(this), msg.sender, wad), "ds-chief-transfer-failed");
+ locked = sub(locked, wad);
+
+ bytes32 currPick = picks[msg.sender];
+ if (currPick != bytes32(0) && !hasFired[currPick])
+ votes[currPick] = sub(votes[currPick], wad);
+ }
+
+ function vote(bytes32 currPick) public {
+ require(!hasFired[currPick], "ds-chief-proposal-has-already-been-enacted");
+
+ uint256 weight = balances[msg.sender];
+ bytes32 prevPick = picks[msg.sender];
+
+ if (prevPick != bytes32(0) && !hasFired[prevPick])
+ votes[prevPick] = sub(votes[prevPick], weight);
+
+ votes[currPick] = add(votes[currPick], weight);
+ picks[msg.sender] = currPick;
+
+ emit Voted(currPick, msg.sender, weight);
+ }
+ function exec(address app, bytes memory data) public {
+ bytes32 proposal = keccak256(abi.encode(app, data));
+ require(!hasFired[proposal], "ds-chief-proposal-has-already-been-enacted");
+ require(votes[proposal] > wmul(locked, threshold), "ds-chief-proposal-does-not-pass-threshold");
+
+ assembly {
+ let ok := delegatecall(sub(gas, 5000), app, add(data, 0x20), mload(data), 0, 0)
+ if eq(ok, 0) { revert(0, 0) }
+ }
+
+ hasFired[proposal] = true;
+ emit Executed(msg.sender, proposal, app, data);
+ }
+}
diff --git a/src/chief-v2.t.sol b/src/chief-v2.t.sol
new file mode 100644
index 0000000..153fa4e
--- /dev/null
+++ b/src/chief-v2.t.sol
@@ -0,0 +1,180 @@
+pragma solidity >=0.5.0;
+
+import "ds-test/test.sol";
+import "ds-token/token.sol";
+
+import "./chief-v2.sol";
+
+contract Voter {
+ DSToken gov;
+ address chief;
+
+ constructor(DSToken gov_, address chief_) public {
+ gov = gov_;
+ chief = chief_;
+ }
+
+ function approveChief() public { gov.approve(chief); }
+
+ function tryLock(uint256 wad) public returns (bool ok) {
+ (ok, ) = chief.call(abi.encodeWithSignature(
+ "lock(uint256)", wad
+ ));
+ }
+
+ function tryFree(uint256 wad) public returns (bool ok) {
+ (ok, ) = chief.call(abi.encodeWithSignature(
+ "free(uint256)", wad
+ ));
+ }
+
+ function tryVote(bytes32 pick) public returns (bool ok) {
+ (ok, ) = chief.call(abi.encodeWithSignature(
+ "vote(bytes32)", pick
+ ));
+ }
+
+ function tryExec(address app, bytes memory data) public returns (bool ok) {
+ (ok, ) = chief.call(abi.encodeWithSignature(
+ "exec(address,bytes)", app, data
+ ));
+ }
+}
+
+contract Cache {
+ uint256 public val;
+ function set(uint256 val_) public { val = val_; }
+}
+
+contract CacheScript {
+ function setCache(address target, uint256 val) public {
+ Cache(target).set(val);
+ }
+}
+
+contract ThresholdScript {
+ uint256 public threshold;
+ function updateThreshold(uint val_) public {
+ threshold = val_;
+ }
+}
+
+
+contract ChiefTest is DSTest {
+ Chief chief;
+ DSToken gov;
+ Cache cache;
+
+ Voter ben;
+ Voter sam;
+ Voter ava;
+
+ function setUp() public {
+ gov = new DSToken("gov");
+ chief = new Chief(address(gov));
+ cache = new Cache();
+
+ ben = new Voter(gov, address(chief));
+ sam = new Voter(gov, address(chief));
+ ava = new Voter(gov, address(chief));
+ gov.mint(address(ben), 100 ether);
+ gov.mint(address(sam), 100 ether);
+ gov.mint(address(ava), 100 ether);
+ }
+
+ function test_sanity_setup_check() public {
+ assertEq(chief.threshold(), 10 ** 18 / 2);
+ assertEq(chief.locked(), 0);
+ assertEq(address(chief.governanceToken()), address(gov));
+ assertEq(chief.balances(address(ben)), 0);
+ assertEq(chief.picks(address(ben)), bytes32(0));
+
+ assertEq(cache.val(), 0);
+
+ assertEq(gov.balanceOf(address(ben)), 100 ether);
+ }
+
+ function test_lock_free() public {
+ // ben gives chief unlimited approvals over his gov token
+ ben.approveChief();
+
+ // ben locks some gov in chief
+ assertTrue(ben.tryLock(10 ether));
+ assertEq(chief.balances(address(ben)), 10 ether);
+ assertEq(chief.locked(), 10 ether);
+ assertTrue(ben.tryLock(1 ether));
+ assertEq(chief.balances(address(ben)), 11 ether);
+ assertEq(chief.locked(), 11 ether);
+
+ // ben frees the same amount of gov from chief
+ assertTrue(ben.tryFree(11 ether));
+ assertEq(chief.balances(address(ben)), 0);
+ assertEq(chief.locked(), 0);
+ }
+
+ function test_vote_exec() public {
+ ben.approveChief();
+ assertTrue(ben.tryLock(10 ether));
+
+ // create a useful contract for chief to delegatecall
+ CacheScript cacheScript = new CacheScript();
+ uint256 newVal = 123;
+
+ // create a proposal
+ bytes memory data = abi.encodeWithSignature(
+ "setCache(address,uint256)", cache, newVal
+ );
+ bytes32 proposal = keccak256(abi.encode(cacheScript, data));
+
+ // ben votes for the proposal
+ assertTrue(ben.tryVote(proposal));
+ assertEq(chief.picks(address(ben)), proposal);
+ assertEq(chief.votes(proposal), 10 ether);
+ assertTrue(!chief.hasFired(proposal));
+
+ // ben executes the proposal
+ assertEq(cache.val(), 0);
+ assertTrue(ben.tryExec(address(cacheScript), data));
+
+ // the proposal was successfully executed
+ assertEq(cache.val(), newVal);
+ assertTrue(chief.hasFired(proposal));
+
+ // the proposal can only be executed once
+ assertTrue(!ben.tryExec(address(cacheScript), data));
+ }
+
+ function test_modify_threshold() public {
+ ben.approveChief();
+ assertTrue(ben.tryLock(10 ether));
+
+ ThresholdScript thresholdScript = new ThresholdScript();
+ uint256 newThreshold = 10 ** 18;
+
+ uint256 oldThreshold = chief.threshold();
+ assertTrue(newThreshold != oldThreshold);
+
+ bytes memory data = abi.encodeWithSignature(
+ "updateThreshold(uint256)", newThreshold
+ );
+ bytes32 proposal = keccak256(abi.encode(thresholdScript, data));
+
+ assertTrue(ben.tryVote(proposal));
+ assertTrue(ben.tryExec(address(thresholdScript), data));
+ assertEq(chief.threshold(), newThreshold);
+ }
+
+ function test_fail_free_too_much() public {
+ ben.approveChief();
+ assertTrue( ben.tryLock(10 ether));
+ assertTrue(!ben.tryFree(11 ether));
+
+ sam.approveChief();
+ assertTrue( sam.tryLock(10 ether));
+ assertTrue( ben.tryFree(9 ether ));
+ assertTrue( ben.tryFree(1 ether ));
+
+ assertTrue(!ben.tryFree(1 ether ));
+ assertTrue( sam.tryFree(10 ether));
+ }
+}
diff --git a/src/chief.sol b/src/chief.sol
deleted file mode 100644
index 36bf9bd..0000000
--- a/src/chief.sol
+++ /dev/null
@@ -1,184 +0,0 @@
-// chief.sol - select an authority by consensus
-
-// Copyright (C) 2017 DappHub, LLC
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-pragma solidity >=0.4.23;
-
-import 'ds-token/token.sol';
-import 'ds-roles/roles.sol';
-import 'ds-thing/thing.sol';
-
-// The right way to use this contract is probably to mix it with some kind
-// of `DSAuthority`, like with `ds-roles`.
-// SEE DSChief
-contract DSChiefApprovals is DSThing {
- mapping(bytes32=>address[]) public slates;
- mapping(address=>bytes32) public votes;
- mapping(address=>uint256) public approvals;
- mapping(address=>uint256) public deposits;
- DSToken public GOV; // voting token that gets locked up
- DSToken public IOU; // non-voting representation of a token, for e.g. secondary voting mechanisms
- address public hat; // the chieftain's hat
-
- uint256 public MAX_YAYS;
-
- event Etch(bytes32 indexed slate);
-
- // IOU constructed outside this contract reduces deployment costs significantly
- // lock/free/vote are quite sensitive to token invariants. Caution is advised.
- constructor(DSToken GOV_, DSToken IOU_, uint MAX_YAYS_) public
- {
- GOV = GOV_;
- IOU = IOU_;
- MAX_YAYS = MAX_YAYS_;
- }
-
- function lock(uint wad)
- public
- note
- {
- GOV.pull(msg.sender, wad);
- IOU.mint(msg.sender, wad);
- deposits[msg.sender] = add(deposits[msg.sender], wad);
- addWeight(wad, votes[msg.sender]);
- }
-
- function free(uint wad)
- public
- note
- {
- deposits[msg.sender] = sub(deposits[msg.sender], wad);
- subWeight(wad, votes[msg.sender]);
- IOU.burn(msg.sender, wad);
- GOV.push(msg.sender, wad);
- }
-
- function etch(address[] memory yays)
- public
- note
- returns (bytes32 slate)
- {
- require( yays.length <= MAX_YAYS );
- requireByteOrderedSet(yays);
-
- bytes32 hash = keccak256(abi.encodePacked(yays));
- slates[hash] = yays;
- emit Etch(hash);
- return hash;
- }
-
- function vote(address[] memory yays) public returns (bytes32)
- // note both sub-calls note
- {
- bytes32 slate = etch(yays);
- vote(slate);
- return slate;
- }
-
- function vote(bytes32 slate)
- public
- note
- {
- uint weight = deposits[msg.sender];
- subWeight(weight, votes[msg.sender]);
- votes[msg.sender] = slate;
- addWeight(weight, votes[msg.sender]);
- }
-
- // like `drop`/`swap` except simply "elect this address if it is higher than current hat"
- function lift(address whom)
- public
- note
- {
- require(approvals[whom] > approvals[hat]);
- hat = whom;
- }
-
- function addWeight(uint weight, bytes32 slate)
- internal
- {
- address[] storage yays = slates[slate];
- for( uint i = 0; i < yays.length; i++) {
- approvals[yays[i]] = add(approvals[yays[i]], weight);
- }
- }
-
- function subWeight(uint weight, bytes32 slate)
- internal
- {
- address[] storage yays = slates[slate];
- for( uint i = 0; i < yays.length; i++) {
- approvals[yays[i]] = sub(approvals[yays[i]], weight);
- }
- }
-
- // Throws unless the array of addresses is a ordered set.
- function requireByteOrderedSet(address[] memory yays)
- internal
- pure
- {
- if( yays.length == 0 || yays.length == 1 ) {
- return;
- }
- for( uint i = 0; i < yays.length - 1; i++ ) {
- // strict inequality ensures both ordering and uniqueness
- require(uint(yays[i]) < uint(yays[i+1]));
- }
- }
-}
-
-
-// `hat` address is unique root user (has every role) and the
-// unique owner of role 0 (typically 'sys' or 'internal')
-contract DSChief is DSRoles, DSChiefApprovals {
-
- constructor(DSToken GOV, DSToken IOU, uint MAX_YAYS)
- DSChiefApprovals (GOV, IOU, MAX_YAYS)
- public
- {
- authority = this;
- owner = address(0);
- }
-
- function setOwner(address owner_) public {
- owner_;
- revert();
- }
-
- function setAuthority(DSAuthority authority_) public {
- authority_;
- revert();
- }
-
- function isUserRoot(address who)
- public view
- returns (bool)
- {
- return (who == hat);
- }
- function setRootUser(address who, bool enabled) public {
- who; enabled;
- revert();
- }
-}
-
-contract DSChiefFab {
- function newChief(DSToken gov, uint MAX_YAYS) public returns (DSChief chief) {
- DSToken iou = new DSToken('IOU');
- chief = new DSChief(gov, iou, MAX_YAYS);
- iou.setOwner(address(chief));
- }
-}
diff --git a/src/chief.t.sol b/src/chief.t.sol
deleted file mode 100644
index a3b668c..0000000
--- a/src/chief.t.sol
+++ /dev/null
@@ -1,409 +0,0 @@
-// chief.t.sol - test for chief.sol
-
-// Copyright (C) 2017 DappHub, LLC
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-pragma solidity >=0.4.23;
-
-import "ds-test/test.sol";
-import "ds-token/token.sol";
-import "ds-thing/thing.sol";
-
-import "./chief.sol";
-
-contract ChiefUser is DSThing {
- DSChief chief;
-
- constructor(DSChief chief_) public {
- chief = chief_;
- }
-
- function doTransferFrom(DSToken token, address from, address to,
- uint amount)
- public
- returns (bool)
- {
- return token.transferFrom(from, to, amount);
- }
-
- function doTransfer(DSToken token, address to, uint amount)
- public
- returns (bool)
- {
- return token.transfer(to, amount);
- }
-
- function doApprove(DSToken token, address recipient, uint amount)
- public
- returns (bool)
- {
- return token.approve(recipient, amount);
- }
-
- function doAllowance(DSToken token, address owner, address spender)
- public view
- returns (uint)
- {
- return token.allowance(owner, spender);
- }
-
- function doEtch(address[] memory guys) public returns (bytes32) {
- return chief.etch(guys);
- }
-
- function doVote(address[] memory guys) public returns (bytes32) {
- return chief.vote(guys);
- }
-
- function doVote(address[] memory guys, address lift_whom) public returns (bytes32) {
- bytes32 slate = chief.vote(guys);
- chief.lift(lift_whom);
- return slate;
- }
-
- function doVote(bytes32 id) public {
- chief.vote(id);
- }
-
- function doVote(bytes32 id, address lift_whom) public {
- chief.vote(id);
- chief.lift(lift_whom);
- }
-
- function doLift(address to_lift) public {
- chief.lift(to_lift);
- }
-
- function doLock(uint amt) public {
- chief.lock(amt);
- }
-
- function doFree(uint amt) public {
- chief.free(amt);
- }
-
- function doSetUserRole(address who, uint8 role, bool enabled) public {
- chief.setUserRole(who, role, enabled);
- }
-
- function doSetRoleCapability(uint8 role, address code, bytes4 sig, bool enabled) public {
- chief.setRoleCapability(role, code, sig, enabled);
- }
-
- function doSetPublicCapability(address code, bytes4 sig, bool enabled) public {
- chief.setPublicCapability(code, sig, enabled);
- }
-
- function authedFn() public view auth returns (bool) {
- return true;
- }
-}
-
-contract DSChiefTest is DSThing, DSTest {
- uint256 constant electionSize = 3;
-
- // c prefix: candidate
- address constant c1 = address(0x1);
- address constant c2 = address(0x2);
- address constant c3 = address(0x3);
- address constant c4 = address(0x4);
- address constant c5 = address(0x5);
- address constant c6 = address(0x6);
- address constant c7 = address(0x7);
- address constant c8 = address(0x8);
- address constant c9 = address(0x9);
- uint256 constant initialBalance = 1000 ether;
- uint256 constant uLargeInitialBalance = initialBalance / 3;
- uint256 constant uMediumInitialBalance = initialBalance / 4;
- uint256 constant uSmallInitialBalance = initialBalance / 5;
-
- DSChief chief;
- DSToken gov;
- DSToken iou;
-
- // u prefix: user
- ChiefUser uLarge;
- ChiefUser uMedium;
- ChiefUser uSmall;
-
- function setUp() public {
- gov = new DSToken("GOV");
- gov.mint(initialBalance);
-
- DSChiefFab fab = new DSChiefFab();
- chief = fab.newChief(gov, electionSize);
- iou = chief.IOU();
-
- uLarge = new ChiefUser(chief);
- uMedium = new ChiefUser(chief);
- uSmall = new ChiefUser(chief);
-
- assert(initialBalance > uLargeInitialBalance + uMediumInitialBalance +
- uSmallInitialBalance);
- assert(uLargeInitialBalance < uMediumInitialBalance + uSmallInitialBalance);
-
- gov.transfer(address(uLarge), uLargeInitialBalance);
- gov.transfer(address(uMedium), uMediumInitialBalance);
- gov.transfer(address(uSmall), uSmallInitialBalance);
- }
-
- function test_basic_sanity() public pure {
- assert(true);
- }
-
- function testFail_basic_sanity() public pure {
- assert(false);
- }
-
- function test_etch_returns_same_id_for_same_sets() public {
- address[] memory candidates = new address[](3);
- candidates[0] = c1;
- candidates[1] = c2;
- candidates[2] = c3;
-
- bytes32 id = uSmall.doEtch(candidates);
- assert(id != 0x0);
- assertEq32(id, uMedium.doEtch(candidates));
- }
-
- function test_size_zero_slate() public {
- address[] memory candidates = new address[](0);
- bytes32 id = uSmall.doEtch(candidates);
- uSmall.doVote(id);
- }
- function test_size_one_slate() public {
- address[] memory candidates = new address[](1);
- candidates[0] = c1;
- bytes32 id = uSmall.doEtch(candidates);
- uSmall.doVote(id);
- }
-
- function testFail_etch_requires_ordered_sets() public {
- address[] memory candidates = new address[](3);
- candidates[0] = c2;
- candidates[1] = c1;
- candidates[2] = c3;
-
- uSmall.doEtch(candidates);
- }
-
- function test_lock_debits_user() public {
- assert(gov.balanceOf(address(uLarge)) == uLargeInitialBalance);
-
- uint lockedAmt = uLargeInitialBalance / 10;
- uLarge.doApprove(gov, address(chief), lockedAmt);
- uLarge.doLock(lockedAmt);
-
- assert(gov.balanceOf(address(uLarge)) == uLargeInitialBalance - lockedAmt);
- }
-
- function test_changing_weight_after_voting() public {
- uint uLargeLockedAmt = uLargeInitialBalance / 2;
- uLarge.doApprove(iou, address(chief), uLargeLockedAmt);
- uLarge.doApprove(gov, address(chief), uLargeLockedAmt);
- uLarge.doLock(uLargeLockedAmt);
-
- address[] memory uLargeSlate = new address[](1);
- uLargeSlate[0] = c1;
- uLarge.doVote(uLargeSlate);
-
- assert(chief.approvals(c1) == uLargeLockedAmt);
-
- // Changing weight should update the weight of our candidate.
- uLarge.doFree(uLargeLockedAmt);
- assert(chief.approvals(c1) == 0);
-
- uLargeLockedAmt = uLargeInitialBalance / 4;
- uLarge.doApprove(gov, address(chief), uLargeLockedAmt);
- uLarge.doLock(uLargeLockedAmt);
-
- assert(chief.approvals(c1) == uLargeLockedAmt);
- }
-
- function test_voting_and_reordering() public {
- assert(gov.balanceOf(address(uLarge)) == uLargeInitialBalance);
-
- initial_vote();
-
- // Upset the order.
- uint uLargeLockedAmt = uLargeInitialBalance;
- uLarge.doApprove(gov, address(chief), uLargeLockedAmt);
- uLarge.doLock(uLargeLockedAmt);
-
- address[] memory uLargeSlate = new address[](1);
- uLargeSlate[0] = c3;
- uLarge.doVote(uLargeSlate);
- }
-
- function testFail_lift_while_out_of_order() public {
- initial_vote();
-
- // Upset the order.
- uSmall.doApprove(gov, address(chief), uSmallInitialBalance);
- uSmall.doLock(uSmallInitialBalance);
-
- address[] memory uSmallSlate = new address[](1);
- uSmallSlate[0] = c3;
- uSmall.doVote(uSmallSlate);
-
- uMedium.doFree(uMediumInitialBalance);
-
- chief.lift(c3);
- }
-
- function test_lift_half_approvals() public {
- initial_vote();
-
- // Upset the order.
- uSmall.doApprove(gov, address(chief), uSmallInitialBalance);
- uSmall.doLock(uSmallInitialBalance);
-
- address[] memory uSmallSlate = new address[](1);
- uSmallSlate[0] = c3;
- uSmall.doVote(uSmallSlate);
-
- uMedium.doApprove(iou, address(chief), uMediumInitialBalance);
- uMedium.doFree(uMediumInitialBalance);
-
- chief.lift(c3);
-
- assert(!chief.isUserRoot(c1));
- assert(!chief.isUserRoot(c2));
- assert(chief.isUserRoot(c3));
- }
-
- function testFail_voting_and_reordering_without_weight() public {
- assert(gov.balanceOf(address(uLarge)) == uLargeInitialBalance);
-
- initial_vote();
-
- // Vote without weight.
- address[] memory uLargeSlate = new address[](1);
- uLargeSlate[0] = c3;
- uLarge.doVote(uLargeSlate);
-
- // Attempt to update the elected set.
- chief.lift(c3);
- }
-
- function test_voting_by_slate_id() public {
- assert(gov.balanceOf(address(uLarge)) == uLargeInitialBalance);
-
- bytes32 slateID = initial_vote();
-
- // Upset the order.
- uLarge.doApprove(gov, address(chief), uLargeInitialBalance);
- uLarge.doLock(uLargeInitialBalance);
-
- address[] memory uLargeSlate = new address[](1);
- uLargeSlate[0] = c4;
- uLarge.doVote(uLargeSlate);
-
- // Update the elected set to reflect the new order.
- chief.lift(c4);
-
- // Now restore the old order using a slate ID.
- uSmall.doApprove(gov, address(chief), uSmallInitialBalance);
- uSmall.doLock(uSmallInitialBalance);
- uSmall.doVote(slateID);
-
- // Update the elected set to reflect the restored order.
- chief.lift(c1);
- }
-
- function testFail_non_hat_can_not_set_roles() public {
- uSmall.doSetUserRole(address(uMedium), 1, true);
- }
-
- function test_hat_can_set_roles() public {
- address[] memory slate = new address[](1);
- slate[0] = address(uSmall);
-
- // Upset the order.
- uLarge.doApprove(gov, address(chief), uLargeInitialBalance);
- uLarge.doLock(uLargeInitialBalance);
-
- uLarge.doVote(slate);
-
- // Update the elected set to reflect the new order.
- chief.lift(address(uSmall));
-
- uSmall.doSetUserRole(address(uMedium), 1, true);
- }
-
- function testFail_non_hat_can_not_role_capability() public {
- uSmall.doSetRoleCapability(1, address(uMedium), S("authedFn"), true);
- }
-
- function test_hat_can_set_role_capability() public {
- address[] memory slate = new address[](1);
- slate[0] = address(uSmall);
-
- // Upset the order.
- uLarge.doApprove(gov, address(chief), uLargeInitialBalance);
- uLarge.doLock(uLargeInitialBalance);
-
- uLarge.doVote(slate);
-
- // Update the elected set to reflect the new order.
- chief.lift(address(uSmall));
-
- uSmall.doSetRoleCapability(1, address(uLarge), S("authedFn()"), true);
- uSmall.doSetUserRole(address(this), 1, true);
-
- uLarge.setAuthority(chief);
- uLarge.setOwner(address(0));
- uLarge.authedFn();
- }
-
- function test_hat_can_set_public_capability() public {
- address[] memory slate = new address[](1);
- slate[0] = address(uSmall);
-
- // Upset the order.
- uLarge.doApprove(gov, address(chief), uLargeInitialBalance);
- uLarge.doLock(uLargeInitialBalance);
-
- uLarge.doVote(slate);
-
- // Update the elected set to reflect the new order.
- chief.lift(address(uSmall));
-
- uSmall.doSetPublicCapability(address(uLarge), S("authedFn()"), true);
-
- uLarge.setAuthority(chief);
- uLarge.setOwner(address(0));
- uLarge.authedFn();
- }
-
- function test_chief_no_owner() public {
- assertEq(chief.owner(), address(0));
- }
-
- function initial_vote() internal returns (bytes32 slateID) {
- uint uMediumLockedAmt = uMediumInitialBalance;
- uMedium.doApprove(gov, address(chief), uMediumLockedAmt);
- uMedium.doLock(uMediumLockedAmt);
-
- address[] memory uMediumSlate = new address[](3);
- uMediumSlate[0] = c1;
- uMediumSlate[1] = c2;
- uMediumSlate[2] = c3;
- slateID = uMedium.doVote(uMediumSlate);
-
- // Lift the chief.
- chief.lift(c1);
- }
-}