Skip to content
This repository has been archived by the owner on Jun 30, 2022. It is now read-only.

Commit

Permalink
feat(appeal): add appeal feature
Browse files Browse the repository at this point in the history
  • Loading branch information
n1c01a5 authored and satello committed Jun 6, 2018
1 parent 43e8618 commit f6f15bc
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/constants/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const UNABLE_TO_ACTIVATE_PNK =
'Unable to activate PNK, are you sure you have enough?'
export const UNABLE_TO_FETCH_ARBITRATION_COST =
'Unable to fetch arbitration cost.'
export const UNABLE_TO_FETCH_APPEAL_COST = 'Unable to fetch appeal cost.'
export const UNABLE_TO_FETCH_TIME_PER_PERIOD = 'Unable to fetch time per period'
export const UNABLE_TO_PASS_PERIOD = 'Unable to pass period.'
export const UNABLE_TO_FETCH_DISPUTE = 'Unable to fetch dispute.'
Expand All @@ -52,6 +53,8 @@ export const DISPUTE_DOES_NOT_EXIST = disputeId =>
// ArbitrableTransaction
export const UNABLE_TO_PAY_ARBITRATION_FEE =
'Unable to pay fee, are you sure you have enough PNK?'
export const UNABLE_TO_RAISE_AN_APPEAL =
'Unable to raise appeal, are you sure you are in the appeal period?'
export const UNABLE_TO_PAY_SELLER =
'Unable to pay the seller, are you sure you have enough ETH?'
export const UNABLE_TO_CALL_TIMEOUT = 'Unable to call timeout.'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class ArbitrableTransaction extends ContractImplementation {
/**
* Pay the arbitration fee to raise a dispute. To be called by the party A.
* @param {string} account - Ethereum account (default account[0]).
* @param {number} arbitrationCost - Amount to pay the arbitrator. (default 10000 wei).
* @param {number} arbitrationCost - Amount to pay the arbitrator. (default 0.15 ether).
* @returns {object} - The result transaction object.
*/
payArbitrationFeeByPartyA = async (
Expand Down Expand Up @@ -215,6 +215,32 @@ class ArbitrableTransaction extends ContractImplementation {
}
}

/**
* Appeal an appealable ruling.
* @param {string} account Ethereum account (default account[1]).
* @param {bytes} extraData for the arbitrator appeal procedure.
* @param {number} appealCost Amount to pay the arbitrator. (default 0.35 ether).
* @returns {object} - The result transaction object.
*/
appeal = async (
account = this._Web3Wrapper.getAccount(1),
extraData = 0x0,
appealCost = 0.35
) => {
await this.loadContract()

try {
return this.contractInstance.appeal(extraData, {
from: account,
gas: ethConstants.TRANSACTION.GAS,
value: this._Web3Wrapper.toWei(appealCost, 'ether')
})
} catch (err) {
console.error(err)
throw new Error(errorConstants.UNABLE_TO_RAISE_AN_APPEAL)
}
}

/**
* Get ruling options from dispute via event
* @param {string} arbitratorAddress address of arbitrator contract
Expand Down
22 changes: 22 additions & 0 deletions src/contracts/implementations/arbitrator/KlerosPOC.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,28 @@ class KlerosPOC extends ContractImplementation {
}
}

/**
* Fetch the cost of appeal.
* @param {number} disputeId - index of the dispute.
* @param {bytes} contractExtraData - extra data from arbitrable contract.
* @returns {number} - The cost of appeal.
*/
getAppealCost = async (disputeId, contractExtraData) => {
await this.loadContract()

try {
const appealCost = await this.contractInstance.appealCost(
disputeId,
contractExtraData
)

return this._Web3Wrapper.fromWei(appealCost, 'ether')
} catch (err) {
console.error(err)
throw new Error(errorConstants.UNABLE_TO_FETCH_APPEAL_COST)
}
}

/**
* Call contract to move on to the next period.
* @param {string} account - address of user.
Expand Down
159 changes: 159 additions & 0 deletions tests/integration/contracts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import delaySecond from '../helpers/delaySecond'
describe('Contracts', () => {
let partyA
let partyB
let jurorContract1
let jurorContract2
let other
let web3
let klerosPOCData
Expand All @@ -28,6 +30,10 @@ describe('Contracts', () => {
partyB = web3.eth.accounts[1]
other = web3.eth.accounts[2]

// these accounts are not used
jurorContract1 = web3.eth.accounts[11]
jurorContract2 = web3.eth.accounts[12]

klerosPOCData = {
timesPerPeriod: [1, 1, 1, 1, 1], // activation, draw, vote, appeal, execution (seconds)
account: other,
Expand Down Expand Up @@ -245,5 +251,158 @@ describe('Contracts', () => {
},
50000
)
it(
'dispute with an appeal call by partyA',
async () => {
// deploy klerosPOC and arbitrableContract contracts
const [
klerosPOCAddress,
arbitrableContractAddress
] = await setUpContracts(
provider,
klerosPOCData,
arbitrableContractData
)
expect(klerosPOCAddress).toBeDefined()
expect(arbitrableContractAddress).toBeDefined()

const KlerosPOCInstance = new KlerosPOC(provider, klerosPOCAddress)

// return a bigint
// FIXME use arbitrableTransaction
const ArbitrableTransactionInstance = new ArbitrableTransaction(
provider,
arbitrableContractAddress
)

// ****** Juror side (activate token) ****** //

// jurors buy PNK
const buyPNKJurors = await Promise.all([
KlerosPOCInstance.buyPNK(1, jurorContract1),
await KlerosPOCInstance.buyPNK(1, jurorContract2)
])

const newBalance = await KlerosPOCInstance.getPNKBalance(jurorContract1)

expect(newBalance.tokenBalance).toEqual(1)

// activate PNK jurors
if (buyPNKJurors) {
await KlerosPOCInstance.activatePNK(1, jurorContract1)
await KlerosPOCInstance.activatePNK(1, jurorContract2)
}

// load klerosPOC
const klerosPOCInstance = await KlerosPOCInstance.loadContract()

// ****** Parties side (raise dispute) ****** //

const arbitrableContractInstance = await ArbitrableTransactionInstance.loadContract()

const partyAFeeContractInstance = await arbitrableContractInstance.partyAFee()
const partyBFeeContractInstance = await arbitrableContractInstance.partyBFee()

// return bytes
// FIXME use arbitrableTransaction
let extraDataContractInstance = await arbitrableContractInstance.arbitratorExtraData()

const KlerosInstance = new KlerosPOC(provider, klerosPOCAddress)
// return a bigint with the default value : 10000 wei fees in ether
const arbitrationCost = await KlerosInstance.getArbitrationCost(
extraDataContractInstance
)

// raise dispute party A
const raiseDisputeByPartyATxObj = await ArbitrableTransactionInstance.payArbitrationFeeByPartyA(
partyA,
arbitrationCost -
web3.fromWei(partyAFeeContractInstance, 'ether').toNumber()
)
expect(raiseDisputeByPartyATxObj.tx).toEqual(
expect.stringMatching(/^0x[a-f0-9]{64}$/)
) // tx hash

// raise dispute party B
const raiseDisputeByPartyBTxObj = await ArbitrableTransactionInstance.payArbitrationFeeByPartyB(
partyB,
arbitrationCost -
web3.fromWei(partyBFeeContractInstance, 'ether').toNumber()
)
expect(raiseDisputeByPartyBTxObj.tx).toEqual(
expect.stringMatching(/^0x[a-f0-9]{64}$/)
) // tx hash

// ****** Juror side (pass period) ****** //

let newPeriod
// pass state so jurors are selected
for (let i = 1; i < 3; i++) {
// NOTE we need to make another block before we can generate the random number. Should not be an issue on main nets where avg block time < period length
if (i === 2)
web3.eth.sendTransaction({
from: partyA,
to: partyB,
value: 10000,
data: '0x'
})
await delaySecond()
await KlerosPOCInstance.passPeriod()

newPeriod = await KlerosPOCInstance.getPeriod()
expect(newPeriod).toEqual(i)
}

let drawA = []
let drawB = []
for (let i = 1; i <= 3; i++) {
if (
await KlerosPOCInstance.isJurorDrawnForDispute(0, i, jurorContract1)
) {
drawA.push(i)
} else {
drawB.push(i)
}
}

const rulingJuror1 = 2 // vote for partyB
await KlerosPOCInstance.submitVotes(
0,
rulingJuror1,
drawA,
jurorContract1
)

const rulingJuror2 = 2 // vote for partyB
await KlerosPOCInstance.submitVotes(
0,
rulingJuror2,
drawB,
jurorContract2
)

await delaySecond()
await KlerosPOCInstance.passPeriod(other)

const currentRuling = await klerosPOCInstance.currentRuling(0)
expect(`${currentRuling}`).toEqual('2') // partyB wins

const appealCost = await KlerosPOCInstance.getAppealCost(
0,
extraDataContractInstance
)

// raise appeal party A
const raiseAppealByPartyATxObj = await ArbitrableTransactionInstance.appeal(
partyA,
extraDataContractInstance,
appealCost
)
expect(raiseAppealByPartyATxObj.tx).toEqual(
expect.stringMatching(/^0x[a-f0-9]{64}$/)
) // tx hash
},
50000
)
})
})

0 comments on commit f6f15bc

Please sign in to comment.