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

Court: Polish main court contract functionality #103

Merged
merged 38 commits into from
Sep 19, 2019
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8221815
agreements: fix contract warnings
facuspagnuolo Aug 13, 2019
f6dc198
court: rename `appealConfirm` to `confirmAppeal`
facuspagnuolo Aug 13, 2019
3c4320e
court: rename `draftAjudicationRound` to `draft`
facuspagnuolo Aug 13, 2019
8d07709
court: organize functions
facuspagnuolo Aug 13, 2019
c02593a
court: drop redundant `areAllJurorsSettled` function
facuspagnuolo Aug 13, 2019
53ff9e3
court: improve and test heartbeat function
facuspagnuolo Aug 14, 2019
afa7228
court: fix terms initialization
facuspagnuolo Aug 22, 2019
79abd26
court: test disputes creation
facuspagnuolo Aug 26, 2019
79cb27c
tests: batch tests in different CI stages
facuspagnuolo Aug 27, 2019
0cb4d62
court: improve draft tests
facuspagnuolo Aug 27, 2019
c3dfa38
registry: drop duplicated activation tests
facuspagnuolo Aug 27, 2019
2e3cbbd
court: multiple enhancements and test
facuspagnuolo Aug 31, 2019
c0ed4d6
court: use appeal start term for appeal fees
facuspagnuolo Sep 4, 2019
4adbc9b
court: fix requested number of jurors when drafting
facuspagnuolo Sep 4, 2019
4f4e205
chore: ugprade test-helpers to v2.1.0
facuspagnuolo Sep 4, 2019
de43e00
court: improve inline documentation wording and typos
facuspagnuolo Sep 4, 2019
aadd973
court: clarify needed transitions fn comment
facuspagnuolo Sep 4, 2019
da166b3
court: rollback msg.sender check on confirm appeals
facuspagnuolo Sep 4, 2019
83a42d6
court: ensure disputes are always created for future terms
facuspagnuolo Sep 4, 2019
4ab7ae7
court: organize functions modifiers
facuspagnuolo Sep 4, 2019
23cc17e
court: improve first term start time check
facuspagnuolo Sep 5, 2019
5dccdf7
court: gas optimizations
facuspagnuolo Sep 6, 2019
a81c2d1
court: improve adjudication round checks
facuspagnuolo Sep 6, 2019
66194cc
court: draft sloads optimization
facuspagnuolo Sep 6, 2019
3480bc3
court: fix typo
facuspagnuolo Sep 6, 2019
1d84975
court: improve uint256 castings
facuspagnuolo Sep 6, 2019
8bb0168
court: optimize adjudication round validations
facuspagnuolo Sep 7, 2019
d71c47a
court: fix heartbeat court config fetch
facuspagnuolo Sep 17, 2019
87c7b3b
court: rename `_ensureAdjudicationState` to use `check` instead
facuspagnuolo Sep 17, 2019
12cb8ea
court: remove useless memoization in appeal settle
facuspagnuolo Sep 18, 2019
0f31a59
tests: improve wording and fix typos
facuspagnuolo Sep 18, 2019
cce6087
tests: minor enhancements
facuspagnuolo Sep 18, 2019
b953158
court: undo appeal skipped tests
facuspagnuolo Sep 18, 2019
f616da3
court: minor enhacements and optimizations
facuspagnuolo Sep 18, 2019
e470083
court: optimize drafting and improve tests
facuspagnuolo Sep 18, 2019
14da657
court: add appeal details getter
facuspagnuolo Sep 19, 2019
e2cac0b
court: improve appeals tests
facuspagnuolo Sep 19, 2019
234267f
court: add getter to tell dispute fees
facuspagnuolo Sep 19, 2019
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
26 changes: 23 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,28 @@ notifications:
email: false
node_js:
- '8'
env:
- TASK=test
before_script:
- npm prune
script: "npm run $TASK"
jobs:
include:
- stage: tests
script: npm test test/court/court-{initialize,accounting,terms,draft}.js
name: "Court Basics"
- stage: tests
script: npm test test/court/court-{disputes,voting,appeal,confirm-appeal}.js
name: "Court Disputes"
- stage: tests
script: npm test test/court/court-settle.js
name: "Court Settles"
- stage: tests
script: npm test test/registry/*.js
name: "Registry"
- stage: tests
script: npm test test/tree/*.js
name: "Tree"
- stage: tests
script: npm test test/voting/*.js
name: "Voting"
- stage: tests
script: npm test test/*.js
name: "Others"
11 changes: 4 additions & 7 deletions contracts/Agreement.sol
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
pragma solidity ^0.4.15;
pragma solidity ^0.4.24;

import "./standards/arbitration/Arbitrable.sol";


contract Agreement is Arbitrable { /* AragonApp/Trigger */
address[] parties;
address[] internal parties;

// TODO: Probably needs to be moved into an 'initialize()' function at some point
constructor(address _court, address[] _parties)
public
Arbitrable(_court) {

constructor(address _court, address[] _parties) public Arbitrable(_court) {
parties = _parties;
}

function canSubmitEvidence(uint256 _disputeId, address _submitter) public view returns (bool) {
function canSubmitEvidence(uint256 /* _disputeId */, address /* _submitter */) public view returns (bool) {
// TODO: should check court to see whether evidence can be submitted for this particular dispute at this point
uint256 partiesLength = parties.length;
for (uint256 i = 0; i < partiesLength; i++) {
Expand Down
4 changes: 2 additions & 2 deletions contracts/CRVoting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ contract CRVoting is Initializable, ICRVoting {
*/
function _ensureVoterWeightToCommit(uint256 _voteId, address _voter) internal returns (uint256) {
uint256 weight = uint256(owner.getVoterWeightToCommit(_voteId, _voter));
require(weight > uint256(0), ERROR_COMMIT_DENIED_BY_OWNER);
require(weight > 0, ERROR_COMMIT_DENIED_BY_OWNER);
return weight;
}

Expand All @@ -292,7 +292,7 @@ contract CRVoting is Initializable, ICRVoting {
*/
function _ensureVoterWeightToReveal(uint256 _voteId, address _voter) internal returns (uint256) {
uint256 weight = uint256(owner.getVoterWeightToReveal(_voteId, _voter));
require(weight > uint256(0), ERROR_REVEAL_DENIED_BY_OWNER);
require(weight > 0, ERROR_REVEAL_DENIED_BY_OWNER);
return weight;
}

Expand Down
1,937 changes: 1,152 additions & 785 deletions contracts/Court.sol

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions contracts/CourtAccounting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ contract CourtAccounting is IAccounting {
}

function assign(ERC20 _token, address _to, uint256 _amount) external onlyOwner {
// TODO: uncomment, we are testing with 0 fees for now
// require(_amount > 0, ERROR_DEPOSIT_AMOUNT_ZERO);
require(_amount > 0, ERROR_DEPOSIT_AMOUNT_ZERO);

balances[_token][_to] = balances[_token][_to].add(_amount);
emit Assign(address(_token), msg.sender, _to, _amount);
Expand Down
17 changes: 5 additions & 12 deletions contracts/CourtSubscriptions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "@aragon/os/contracts/common/IsContract.sol";
import "@aragon/os/contracts/lib/math/SafeMath.sol";
import "@aragon/os/contracts/common/TimeHelpers.sol";

import "./lib/PctHelpers.sol";
import "./standards/erc900/IJurorsRegistry.sol";
import "./standards/subscription/ISubscriptions.sol";
import "./standards/subscription/ISubscriptionsOwner.sol";
Expand All @@ -14,8 +15,8 @@ import "./standards/subscription/ISubscriptionsOwner.sol";
contract CourtSubscriptions is IsContract, ISubscriptions, TimeHelpers {
using SafeERC20 for ERC20;
using SafeMath for uint256;
using PctHelpers for uint256;

uint256 internal constant PCT_BASE = 10000; // ‱
uint64 internal constant START_TERM_ID = 1; // term 0 is for jurors onboarding

string internal constant ERROR_NOT_GOVERNOR = "SUB_NOT_GOVERNOR";
Expand Down Expand Up @@ -129,7 +130,7 @@ contract CourtSubscriptions is IsContract, ISubscriptions, TimeHelpers {

// governor fee
// as _periods and feeAmount are > 0, amountToPay will be > 0 and newLastPeriod > subscriber.lastPaymentPeriodId
uint256 governorFee = _pct4(amountToPay, governorSharePct);
uint256 governorFee = amountToPay.pct(governorSharePct);
accumulatedGovernorFees += governorFee;

// amount collected for the current period to share among jurors
Expand Down Expand Up @@ -352,7 +353,7 @@ contract CourtSubscriptions is IsContract, ISubscriptions, TimeHelpers {
}

function _setGovernorSharePct(uint16 _governorSharePct) internal {
require(_governorSharePct <= PCT_BASE, ERROR_OVERFLOW);
require(_governorSharePct <= PctHelpers.base(), ERROR_OVERFLOW);
governorSharePct = _governorSharePct;
}

Expand Down Expand Up @@ -443,7 +444,7 @@ contract CourtSubscriptions is IsContract, ISubscriptions, TimeHelpers {
require(newLastPeriodId <= _currentPeriodId || newLastPeriodId.sub(_currentPeriodId) < prePaymentPeriods, ERROR_TOO_MANY_PERIODS);

// delayedPeriods * _feeAmount * (1 + latePaymentPenaltyPct/PCT_BASE) + regularPeriods * _feeAmount
amountToPay = _pct4Increase(delayedPeriods.mul(_feeAmount), latePaymentPenaltyPct).add(regularPeriods.mul(_feeAmount));
amountToPay = delayedPeriods.mul(_feeAmount).pctIncrease(latePaymentPenaltyPct).add(regularPeriods.mul(_feeAmount));
}

function _getPeriodBalanceDetails(uint256 _periodId) internal view returns (uint64 periodBalanceCheckpoint, uint256 totalActiveBalance) {
Expand Down Expand Up @@ -485,12 +486,4 @@ contract CourtSubscriptions is IsContract, ISubscriptions, TimeHelpers {
// juror fee share
return _period.collectedFees.mul(jurorActiveBalance) / _totalActiveBalance;
}

function _pct4(uint256 _number, uint16 _pct) internal pure returns (uint256) {
return _number.mul(uint256(_pct)) / PCT_BASE;
}

function _pct4Increase(uint256 _number, uint16 _pct) internal pure returns (uint256) {
return _number.mul((PCT_BASE + uint256(_pct))) / PCT_BASE;
}
}
35 changes: 19 additions & 16 deletions contracts/JurorsRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ApproveAndCallFallBack } from "@aragon/apps-shared-minime/contracts/Min

import "./lib/BytesHelpers.sol";
import "./lib/HexSumTree.sol";
import "./lib/PctHelpers.sol";
import "./lib/JurorsTreeSortition.sol";
import "./standards/erc900/ERC900.sol";
import "./standards/erc900/IJurorsRegistry.sol";
Expand All @@ -18,6 +19,7 @@ import "./standards/erc900/IJurorsRegistryOwner.sol";
contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, ApproveAndCallFallBack {
using SafeERC20 for ERC20;
using SafeMath for uint256;
using PctHelpers for uint256;
using BytesHelpers for bytes;
using HexSumTree for HexSumTree.Tree;
using JurorsTreeSortition for HexSumTree.Tree;
Expand All @@ -35,7 +37,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
string internal constant ERROR_TOKEN_TRANSFER_FAILED = "JR_TOKEN_TRANSFER_FAILED";
string internal constant ERROR_TOKEN_APPROVE_NOT_ALLOWED = "JR_TOKEN_APPROVE_NOT_ALLOWED";

uint256 internal constant PCT_BASE = 10000; // ‱ = 1 / 10,000
// Address that will be used to burn juror tokens
address internal constant BURN_ACCOUNT = 0xdead;

/**
Expand Down Expand Up @@ -133,7 +135,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
_processDeactivationRequest(msg.sender, termId);

uint256 availableBalance = jurorsByAddress[msg.sender].availableBalance;
uint256 amountToActivate = _amount == uint256(0) ? availableBalance : _amount;
uint256 amountToActivate = _amount == 0 ? availableBalance : _amount;
require(amountToActivate > 0, ERROR_INVALID_ZERO_AMOUNT);
require(amountToActivate <= availableBalance, ERROR_INVALID_ACTIVATION_AMOUNT);

Expand All @@ -148,13 +150,13 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
uint64 termId = owner.ensureAndGetTermId();

uint256 unlockedActiveBalance = unlockedActiveBalanceOf(msg.sender);
uint256 amountToDeactivate = _amount == uint256(0) ? unlockedActiveBalance : _amount;
uint256 amountToDeactivate = _amount == 0 ? unlockedActiveBalance : _amount;
require(amountToDeactivate > 0, ERROR_INVALID_ZERO_AMOUNT);
require(amountToDeactivate <= unlockedActiveBalance, ERROR_INVALID_DEACTIVATION_AMOUNT);

// No need to use SafeMath here, we already checked values above
uint256 futureActiveBalance = unlockedActiveBalance - amountToDeactivate;
require(futureActiveBalance == uint256(0) || futureActiveBalance >= minActiveBalance, ERROR_INVALID_DEACTIVATION_AMOUNT);
require(futureActiveBalance == 0 || futureActiveBalance >= minActiveBalance, ERROR_INVALID_DEACTIVATION_AMOUNT);

_createDeactivationRequest(msg.sender, termId, amountToDeactivate);
}
Expand Down Expand Up @@ -213,7 +215,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
* 3. uint256 Number of seats already filled
* 4. uint256 Number of seats left to be filled
* 5. uint64 Number of jurors required for the draft
* 6. uint16 Percentage of the minimum active balance to be locked for the draft
* 6. uint16 Per ten thousand of the minimum active balance to be locked for the draft
*
* @return jurors List of jurors selected for the draft
* @return weights List of weights corresponding to each juror
Expand Down Expand Up @@ -323,7 +325,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
* @return True if the juror has enough unlocked tokens to be collected for the requested term, false otherwise
*/
function collectTokens(address _juror, uint256 _amount, uint64 _termId) external onlyOwner returns (bool) {
if (_amount == uint256(0)) {
if (_amount == 0) {
return true;
}

Expand All @@ -345,7 +347,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
// Note there's no need to use SafeMath here, amounts were already checked above
uint256 amountToReduce = _amount - unlockedActiveBalance;
_reduceDeactivationRequest(_juror, amountToReduce, _termId);
tree.set(juror.id, nextTermId, uint256(0));
tree.set(juror.id, nextTermId, 0);
} else {
tree.update(juror.id, nextTermId, _amount, false);
}
Expand Down Expand Up @@ -408,7 +410,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
*/
function activeBalanceOfAt(address _juror, uint64 _termId) external view returns (uint256) {
Juror storage juror = jurorsByAddress[_juror];
return _existsJuror(juror) ? tree.getItemAt(juror.id, _termId) : uint256(0);
return _existsJuror(juror) ? tree.getItemAt(juror.id, _termId) : 0;
}

/**
Expand Down Expand Up @@ -446,11 +448,12 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
* @return active Amount of active tokens of a juror
* @return available Amount of available tokens of a juror
* @return locked Amount of active tokens that are locked due to ongoing disputes
* @return pendingDeactivation Amount of active tokens that were requested for deactivation
*/
function balanceOf(address _juror) public view returns (uint256 active, uint256 available, uint256 locked, uint256 pendingDeactivation) {
Juror storage juror = jurorsByAddress[_juror];

active = _existsJuror(juror) ? tree.getItem(juror.id) : uint256(0);
active = _existsJuror(juror) ? tree.getItem(juror.id) : 0;
available = juror.availableBalance;
locked = juror.lockedBalance;
pendingDeactivation = juror.deactivationRequest.amount;
Expand Down Expand Up @@ -547,7 +550,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
// Note that we can use a zeroed term id to denote void here since we are storing
// the minimum allowed term to deactivate tokens which will always be at least 1
request.availableTermId = uint64(0);
request.amount = uint256(0);
request.amount = 0;
_updateAvailableBalanceOf(_juror, deactivationAmount, true);

emit JurorDeactivationProcessed(_juror, deactivationAvailableTermId, deactivationAmount, _termId);
Expand Down Expand Up @@ -644,7 +647,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
// We are not using a require here to avoid reverting in case any of the accounting maths reaches this point
// with a zeroed amount value. Instead, we are doing this validation in the external entry points such as
// stake, unstake, activate, deactivate, among others.
if (_amount == uint256(0)) {
if (_amount == 0) {
return;
}

Expand All @@ -665,7 +668,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
* @return Amount of active tokens of a juror that are not locked due to ongoing disputes
*/
function _unlockedActiveBalanceOf(Juror storage _juror) internal view returns (uint256) {
return _existsJuror(_juror) ? tree.getItem(_juror.id).sub(_juror.lockedBalance) : uint256(0);
return _existsJuror(_juror) ? tree.getItem(_juror.id).sub(_juror.lockedBalance) : 0;
}

/**
Expand All @@ -674,7 +677,7 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
* @return True if the given juror was already registered, false otherwise
*/
function _existsJuror(Juror storage _juror) internal view returns (bool) {
return _juror.id != uint256(0);
return _juror.id != 0;
}

/**
Expand All @@ -685,16 +688,16 @@ contract JurorsRegistry is Initializable, IsContract, IJurorsRegistry, ERC900, A
*/
function _deactivationRequestedAmountForTerm(Juror storage _juror, uint64 _termId) internal view returns (uint256) {
DeactivationRequest storage request = _juror.deactivationRequest;
return request.availableTermId == _termId ? request.amount : uint256(0);
return request.availableTermId == _termId ? request.amount : 0;
}

/**
* @dev Internal function to tell the fraction of minimum active tokens that must be locked for a draft
* @param _pct Percentage of the minimum active balance to be locked for a draft
* @param _pct Per ten thousand of the minimum active balance to be locked for a draft
* @return The fraction of minimum active tokens that must be locked for a draft
*/
function _draftLockAmount(uint16 _pct) internal view returns (uint256) {
return minActiveBalance * uint256(_pct) / PCT_BASE;
return minActiveBalance.pct(_pct);
}

/**
Expand Down
18 changes: 9 additions & 9 deletions contracts/lib/Checkpointing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ library Checkpointing {
*/
function getLast(History storage self) internal view returns (uint256) {
uint256 length = self.history.length;
if (length > uint256(0)) {
if (length > 0) {
return uint256(self.history[length - 1].value);
}

return uint256(0);
return 0;
}

/**
Expand Down Expand Up @@ -89,7 +89,7 @@ library Checkpointing {
*/
function _add192(History storage self, uint64 _time, uint192 _value) private {
uint256 length = self.history.length;
if (length == uint256(0) || self.history[self.history.length - 1].time < _time) {
if (length == 0 || self.history[self.history.length - 1].time < _time) {
// If there was no value registered or the given point in time is after the latest registered value,
// we can insert it to the history directly
self.history.push(Checkpoint(_time, _value));
Expand All @@ -113,8 +113,8 @@ library Checkpointing {
function _backwardsLinearSearch(History storage self, uint64 _time) private view returns (uint256) {
// If there was no value registered for the given history return simply zero
uint256 length = self.history.length;
if (length == uint256(0)) {
return uint256(0);
if (length == 0) {
return 0;
}

uint256 index = length - 1;
Expand All @@ -124,7 +124,7 @@ library Checkpointing {
checkpoint = self.history[index];
}

return checkpoint.time > _time ? uint256(0) : uint256(checkpoint.value);
return checkpoint.time > _time ? 0 : uint256(checkpoint.value);
}

/**
Expand All @@ -138,13 +138,13 @@ library Checkpointing {
function _binarySearch(History storage self, uint64 _time) private view returns (uint256) {
// If there was no value registered for the given history return simply zero
uint256 length = self.history.length;
if (length == uint256(0)) {
return uint256(0);
if (length == 0) {
return 0;
}

// If the requested time is previous to the first registered value, return zero to denote missing checkpoint
if (_time < self.history[0].time) {
return uint256(0);
return 0;
}

// Execute a binary search between the checkpointed times of the history
Expand Down
Loading