Skip to content

Commit

Permalink
agreements: implement intergration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
facuspagnuolo committed Apr 22, 2020
1 parent 4e58952 commit fea4106
Show file tree
Hide file tree
Showing 15 changed files with 549 additions and 57 deletions.
1 change: 1 addition & 0 deletions apps/agreement/contracts/Agreement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ contract Agreement is IArbitrable, IForwarder, AragonApp {
challenge.state = ChallengeState.Settled;
_unchallengeBalance(submitter, unchallengedAmount);
_slashBalance(submitter, challenger, slashedAmount);
_transferCollateralTokens(challenger, setting.challengeCollateral);
_returnArbitratorFees(challenge);
emit ActionSettled(_actionId, slashedAmount);
}
Expand Down
43 changes: 43 additions & 0 deletions apps/agreement/contracts/test/mocks/TokenBalanceOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pragma solidity ^0.4.24;

import "@aragon/os/contracts/acl/IACLOracle.sol";
import "@aragon/os/contracts/lib/token/ERC20.sol";


contract TokenBalanceOracle is IACLOracle {
string private constant ERROR_SENDER_ZERO = "TOKEN_BALANCE_ORACLE_SENDER_ZERO";
string private constant ERROR_SENDER_TOO_BIG = "TOKEN_BALANCE_ORACLE_SENDER_TOO_BIG";
string private constant ERROR_SENDER_MISSING = "TOKEN_BALANCE_ORACLE_SENDER_MISSING";
string private constant ERROR_TOKEN_NOT_CONTRACT = "TOKEN_BALANCE_ORACLE_TOKEN_NOT_CONTRACT";

uint8 private constant ORACLE_PARAM_ID = 203;

enum Op { NONE, EQ, NEQ, GT, LT, GTE, LTE, RET, NOT, AND, OR, XOR, IF_ELSE }

ERC20 public token;
uint256 public minBalance;

constructor(ERC20 _token, uint256 _minBalance) public {
token = _token;
minBalance = _minBalance;
}

function canPerform(address, address, bytes32, uint256[] _how) external view returns (bool) {
require(_how.length > 0, ERROR_SENDER_MISSING);
require(_how[0] < 2**160, ERROR_SENDER_TOO_BIG);
require(_how[0] != 0, ERROR_SENDER_ZERO);

address sender = address(_how[0]);

uint256 senderBalance = token.balanceOf(sender);
return senderBalance >= minBalance;
}

function getPermissionParam() external view returns (uint256) {
return _paramsTo256(ORACLE_PARAM_ID, uint8(Op.EQ), uint240(address(this)));
}

function _paramsTo256(uint8 _id,uint8 _op, uint240 _value) private pure returns (uint256) {
return (uint256(_id) << 248) + (uint256(_op) << 240) + _value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ contract ArbitratorMock is IArbitrator {
dispute.ruling = _ruling;
}

function setFees(ERC20 _feeToken, uint256 _feeAmount) external {
feeToken = _feeToken;
feeAmount = _feeAmount;
}

function getDisputeFees() public view returns (address, ERC20, uint256) {
return (address(this), feeToken, feeAmount);
}
Expand Down
8 changes: 4 additions & 4 deletions apps/agreement/test/agreement_cancel.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,11 @@ contract('Agreement', ([_, submitter, someone]) => {
itCannotBeCancelled()
})
})
})

context('when the given action does not exist', () => {
it('reverts', async () => {
await assertRevert(agreement.cancel({ actionId: 0 }), ERRORS.ERROR_ACTION_DOES_NOT_EXIST)
context('when the given action does not exist', () => {
it('reverts', async () => {
await assertRevert(agreement.cancel({ actionId: 0 }), ERRORS.ERROR_ACTION_DOES_NOT_EXIST)
})
})
})
})
10 changes: 5 additions & 5 deletions apps/agreement/test/agreement_challenge.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,13 +352,13 @@ contract('Agreement', ([_, submitter, challenger, someone]) => {
})
})
})
})

context('when the challenger does not have permissions', () => {
const challenger = someone
context('when the challenger does not have permissions', () => {
const challenger = someone

it('reverts', async () => {
await assertRevert(agreement.challenge({ actionId: 0, challenger }), ERRORS.ERROR_AUTH_FAILED)
it('reverts', async () => {
await assertRevert(agreement.challenge({ actionId: 0, challenger }), ERRORS.ERROR_AUTH_FAILED)
})
})
})
})
88 changes: 80 additions & 8 deletions apps/agreement/test/agreement_dispute.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const ERRORS = require('./helpers/utils/errors')
const EVENTS = require('./helpers/utils/events')
const { bigExp } = require('./helpers/lib/numbers')
const { assertBn } = require('./helpers/lib/assertBn')
const { assertRevert } = require('@aragon/test-helpers/assertThrow')
const { getEventArgument } = require('@aragon/test-helpers/events')
Expand Down Expand Up @@ -90,7 +91,7 @@ contract('Agreement', ([_, someone, submitter, challenger]) => {
})

context('when the challenge was not answered', () => {
const itDisputesTheChallengeProperly = () => {
const itDisputesTheChallengeProperly = (extraTestCases = () => {}) => {
context('when the submitter has approved the missing arbitration fees', () => {
beforeEach('approve half arbitration fees', async () => {
const amount = await agreement.missingArbitrationFees(actionId)
Expand Down Expand Up @@ -211,6 +212,8 @@ contract('Agreement', ([_, someone, submitter, challenger]) => {
assert.isFalse(canClaimSettlement, 'action settlement can be claimed')
assert.isFalse(canExecute, 'action can be executed')
})

extraTestCases()
})

context('when the sender is the challenger', () => {
Expand Down Expand Up @@ -252,24 +255,93 @@ contract('Agreement', ([_, someone, submitter, challenger]) => {
})
}

const itDisputesTheChallengeProperlyDespiteArbitrationFees = () => {
context('when the arbitration fees did not change', () => {
itDisputesTheChallengeProperly(() => {
it('transfers the arbitration fees to the arbitrator', async () => {
const { feeToken, feeAmount } = await agreement.arbitratorFees()
const missingArbitrationFees = await agreement.missingArbitrationFees(actionId)

const previousSubmitterBalance = await feeToken.balanceOf(submitter)
const previousAgreementBalance = await feeToken.balanceOf(agreement.address)
const previousArbitratorBalance = await feeToken.balanceOf(agreement.arbitrator.address)

await agreement.dispute({ actionId, from: submitter, arbitrationFees })

const currentSubmitterBalance = await feeToken.balanceOf(submitter)
assertBn(currentSubmitterBalance, previousSubmitterBalance.sub(missingArbitrationFees), 'submitter balance does not match')

const currentAgreementBalance = await feeToken.balanceOf(agreement.address)
assertBn(currentAgreementBalance, previousAgreementBalance.sub(feeAmount.sub(missingArbitrationFees)), 'agreement balance does not match')

const currentArbitratorBalance = await feeToken.balanceOf(agreement.arbitrator.address)
assertBn(currentArbitratorBalance, previousArbitratorBalance.add(feeAmount), 'arbitrator balance does not match')
})
})
})

context('when the arbitration fees changed', () => {
let previousFeeToken, previousHalfFeeAmount, newArbitrationFeeToken, newArbitrationFeeAmount = bigExp(191919, 18)

beforeEach('change arbitration fees', async () => {
previousFeeToken = await agreement.arbitratorToken()
previousHalfFeeAmount = await agreement.halfArbitrationFees()
newArbitrationFeeToken = await deployer.deployToken({ name: 'New Arbitration Token', symbol: 'NAT', decimals: 18 })
await agreement.arbitrator.setFees(newArbitrationFeeToken.address, newArbitrationFeeAmount)
})

itDisputesTheChallengeProperly(() => {
it('transfers the arbitration fees to the arbitrator', async () => {
const previousSubmitterBalance = await newArbitrationFeeToken.balanceOf(submitter)
const previousAgreementBalance = await newArbitrationFeeToken.balanceOf(agreement.address)
const previousArbitratorBalance = await newArbitrationFeeToken.balanceOf(agreement.arbitrator.address)

await agreement.dispute({ actionId, from: submitter, arbitrationFees })

const currentSubmitterBalance = await newArbitrationFeeToken.balanceOf(submitter)
assertBn(currentSubmitterBalance, previousSubmitterBalance.sub(newArbitrationFeeAmount), 'submitter balance does not match')

const currentAgreementBalance = await newArbitrationFeeToken.balanceOf(agreement.address)
assertBn(currentAgreementBalance, previousAgreementBalance, 'agreement balance does not match')

const currentArbitratorBalance = await newArbitrationFeeToken.balanceOf(agreement.arbitrator.address)
assertBn(currentArbitratorBalance, previousArbitratorBalance.add(newArbitrationFeeAmount), 'arbitrator balance does not match')
})

it('returns the previous arbitration fees to the challenger', async () => {
const previousAgreementBalance = await previousFeeToken.balanceOf(agreement.address)
const previousChallengerBalance = await previousFeeToken.balanceOf(challenger)

await agreement.dispute({ actionId, from: submitter, arbitrationFees })

const currentAgreementBalance = await previousFeeToken.balanceOf(agreement.address)
assertBn(currentAgreementBalance, previousAgreementBalance.sub(previousHalfFeeAmount), 'agreement balance does not match')

const currentChallengerBalance = await previousFeeToken.balanceOf(challenger)
assertBn(currentChallengerBalance, previousChallengerBalance.add(previousHalfFeeAmount), 'challenger balance does not match')
})
})
})
}

context('at the beginning of the answer period', () => {
itDisputesTheChallengeProperly()
itDisputesTheChallengeProperlyDespiteArbitrationFees()
})

context('in the middle of the answer period', () => {
beforeEach('move before settlement period end date', async () => {
await agreement.moveBeforeEndOfSettlementPeriod(actionId)
})

itDisputesTheChallengeProperly()
itDisputesTheChallengeProperlyDespiteArbitrationFees()
})

context('at the end of the answer period', () => {
beforeEach('move to the settlement period end date', async () => {
await agreement.moveToEndOfSettlementPeriod(actionId)
})

itDisputesTheChallengeProperly()
itDisputesTheChallengeProperlyDespiteArbitrationFees()
})

context('after the answer period', () => {
Expand Down Expand Up @@ -357,11 +429,11 @@ contract('Agreement', ([_, someone, submitter, challenger]) => {
itCannotBeDisputed()
})
})
})

context('when the given action does not exist', () => {
it('reverts', async () => {
await assertRevert(agreement.dispute({ actionId: 0 }), ERRORS.ERROR_ACTION_DOES_NOT_EXIST)
context('when the given action does not exist', () => {
it('reverts', async () => {
await assertRevert(agreement.dispute({ actionId: 0 }), ERRORS.ERROR_ACTION_DOES_NOT_EXIST)
})
})
})
})
8 changes: 4 additions & 4 deletions apps/agreement/test/agreement_evidence.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,11 @@ contract('Agreement', ([_, someone, submitter, challenger]) => {
itCannotSubmitEvidenceForNonExistingDispute()
})
})
})

context('when the given action does not exist', () => {
it('reverts', async () => {
await assertRevert(agreement.submitEvidence({ actionId: 0, from: submitter }), ERRORS.ERROR_ACTION_DOES_NOT_EXIST)
context('when the given action does not exist', () => {
it('reverts', async () => {
await assertRevert(agreement.submitEvidence({ actionId: 0, from: submitter }), ERRORS.ERROR_ACTION_DOES_NOT_EXIST)
})
})
})
})
12 changes: 6 additions & 6 deletions apps/agreement/test/agreement_gas_cost.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ contract('Agreement', ([_, signer]) => {
}

context('stake', () => {
itCostsAtMost(176e3, () => agreement.stake({ signer }))
itCostsAtMost(175e3, () => agreement.stake({ signer }))
})

context('unstake', () => {
Expand Down Expand Up @@ -47,7 +47,7 @@ contract('Agreement', ([_, signer]) => {
({ actionId } = await agreement.schedule({}))
})

itCostsAtMost(355e3, () => agreement.challenge({ actionId }))
itCostsAtMost(353e3, () => agreement.challenge({ actionId }))
})

context('settle', () => {
Expand All @@ -56,7 +56,7 @@ contract('Agreement', ([_, signer]) => {
await agreement.challenge({ actionId })
})

itCostsAtMost(153e3, () => agreement.settle({ actionId }))
itCostsAtMost(240e3, () => agreement.settle({ actionId }))
})

context('dispute', () => {
Expand All @@ -76,15 +76,15 @@ contract('Agreement', ([_, signer]) => {
})

context('in favor of the submitter', () => {
itCostsAtMost(205e3, () => agreement.executeRuling({ actionId, ruling: RULINGS.IN_FAVOR_OF_SUBMITTER }))
itCostsAtMost(200e3, () => agreement.executeRuling({ actionId, ruling: RULINGS.IN_FAVOR_OF_SUBMITTER }))
})

context('in favor of the challenger', () => {
itCostsAtMost(220e3, () => agreement.executeRuling({ actionId, ruling: RULINGS.IN_FAVOR_OF_CHALLENGER }))
itCostsAtMost(215e3, () => agreement.executeRuling({ actionId, ruling: RULINGS.IN_FAVOR_OF_CHALLENGER }))
})

context('refused', () => {
itCostsAtMost(205e3, () => agreement.executeRuling({ actionId, ruling: RULINGS.REFUSED }))
itCostsAtMost(200e3, () => agreement.executeRuling({ actionId, ruling: RULINGS.REFUSED }))
})
})
})
Expand Down
Loading

0 comments on commit fea4106

Please sign in to comment.