diff --git a/package.json b/package.json index c548110..f1b6942 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "ethereumjs-util": "^5.2.0", "ethjs": "^0.4.0", "kleros": "^0.0.6", - "kleros-interaction": "^0.0.22", + "kleros-interaction": "^0.0.24", "lodash": "^4.17.4", "minimetoken": "^0.2.0", "truffle-contract": "^2.0.5", diff --git a/src/constants/contract.js b/src/constants/contract.js index 922c9d7..813d408 100644 --- a/src/constants/contract.js +++ b/src/constants/contract.js @@ -1,7 +1,7 @@ export const STATUS = { NO_DISPUTE: 0, - WAITING_PARTY_A: 1, - WAITING_PARTY_B: 2, + WAITING_SELLER: 1, + WAITING_BUYER: 2, DISPUTE_CREATED: 3, RESOLVED: 4 } diff --git a/src/constants/error.js b/src/constants/error.js index 4efd5ce..9154153 100644 --- a/src/constants/error.js +++ b/src/constants/error.js @@ -51,12 +51,15 @@ export const DISPUTE_DOES_NOT_EXIST = disputeID => `Dispute ${disputeID} does not exist` // ArbitrableTransaction +export const UNABLE_TO_CREATE_TRANSACTION = + 'Unable to create a new transaction.' 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_REIMBURSE_BUYER = 'Unable to reimburse the buyer.' export const UNABLE_TO_CALL_TIMEOUT = 'Unable to call timeout.' export const CONTRACT_IS_NOT_WAITING_ON_OTHER_PARTY = 'Unable to call timeout, because the contract is not waiting on the other party.' diff --git a/src/contracts/abstractions/MultipleArbitrable.js b/src/contracts/abstractions/MultipleArbitrable.js new file mode 100644 index 0000000..17e243e --- /dev/null +++ b/src/contracts/abstractions/MultipleArbitrable.js @@ -0,0 +1,59 @@ +import AbstractContract from '../AbstractContract' + +/** + * Arbitrable Abstract Contarct API. This wraps an arbitrable contract. It provides + * interaction with both the off chain store as well as the arbitrable instance. All + * arbitrable methods from the supplied contract implementation can be called from this + * object. + */ +class ArbitrableContract extends AbstractContract { + /** + * Submit evidence. FIXME should we determine the hash for the user? + * @param {string} account - ETH address of user. + * @param {string} arbitrableTransactionId - Id of the arbitrable transaction. + * @param {string} name - Name of evidence. + * @param {string} description - Description of evidence. + * @param {string} url - A link to an evidence using its URI. + * @param {string} hash - A hash of the evidence at the URI. No hash if content is dynamic + * @returns {string} - txHash Hash transaction. + */ + submitEvidence = async ( + account, + arbitrableTransactionId, + name, + description, + url, + hash + ) => { + const contractAddress = this._contractImplementation.contractAddress + + // get the index of the new evidence + const evidenceIndex = await this._StoreProvider.addEvidenceContract( + contractAddress, + arbitrableTransactionId, + account, + name, + description, + url, + hash + ) + + // construct the unique URI + const evidenceUri = this._StoreProvider.getEvidenceUri( + account, + contractAddress, + arbitrableTransactionId, + evidenceIndex + ) + + const txHash = await this._contractImplementation.submitEvidence( + account, + arbitrableTransactionId, + evidenceUri + ) + + return txHash + } +} + +export default ArbitrableContract diff --git a/src/contracts/implementations/arbitrable/Arbitrable.js b/src/contracts/implementations/arbitrable/Arbitrable.js index 518efba..063bdf0 100644 --- a/src/contracts/implementations/arbitrable/Arbitrable.js +++ b/src/contracts/implementations/arbitrable/Arbitrable.js @@ -26,7 +26,7 @@ class Arbitrable extends ContractImplementation { * and make an http request to the resource. * @returns {object} The metaEvidence object */ - getMetaEvidence = async () => { + getMetaEvidence = async (metaEvidenceID = 0) => { if (this.metaEvidenceCache[this.contractAddress]) return this.metaEvidenceCache[this.contractAddress] @@ -35,7 +35,7 @@ class Arbitrable extends ContractImplementation { 'MetaEvidence', 0, 'latest', - { _metaEvidenceID: 0 } + { _metaEvidenceID: metaEvidenceID } ) if (!metaEvidenceLog[0]) return {} // NOTE better to throw errors for missing meta-evidence? @@ -88,6 +88,19 @@ class Arbitrable extends ContractImplementation { }) ) } + + /** + * Fetch all standard contract data. + */ + getContractData = async () => { + await this.loadContract() + + const [metaEvidence] = await Promise.all([this.getMetaEvidence()]) + + return { + metaEvidence + } + } } export default Arbitrable diff --git a/src/contracts/implementations/arbitrable/MultipleArbitrableTransaction.js b/src/contracts/implementations/arbitrable/MultipleArbitrableTransaction.js new file mode 100644 index 0000000..e9a8edd --- /dev/null +++ b/src/contracts/implementations/arbitrable/MultipleArbitrableTransaction.js @@ -0,0 +1,364 @@ +import multipleArbitrableTransactionArtifact from 'kleros-interaction/build/contracts/MultipleArbitrableTransaction' +import _ from 'lodash' + +import * as contractConstants from '../../../constants/contract' +import * as errorConstants from '../../../constants/error' +import deployContractAsync from '../../../utils/deployContractAsync' + +import Arbitrable from './Arbitrable' + +/** + * Provides interaction with an Arbitrable Transaction contract deployed on the blockchain. + */ +class MultipleArbitrableTransaction extends Arbitrable { + /** + * Constructor ArbitrableTransaction. + * @param {object} web3Provider instance + * @param {string} contractAddress of the contract + */ + constructor(web3Provider, contractAddress) { + super(web3Provider, multipleArbitrableTransactionArtifact, contractAddress) + + this.arbitrableTransactionId = null + } + + /** + * Deploy MultipleArbitrableTransaction. + * @param {object} account Ethereum account + * @param {object} web3Provider web3 provider object + * @returns {object} truffle-contract Object | err The deployed contract or an error + */ + static deploy = async (account, web3Provider) => { + const contractDeployed = await deployContractAsync( + account, + 0, + multipleArbitrableTransactionArtifact, + web3Provider + ) + + return contractDeployed + } + + /** + * Create MultipleArbitrableTransaction. + * @param {object} account Ethereum account + * @param {string} arbitratorAddress The address of the arbitrator contract + * @param {object} seller Seller Ethereum account + * @param {number} value funds to be placed in contract + * @param {number} timeout Time (seconds) after which a party automatically loose a dispute. (default 3600) + * @param {bytes} arbitratorExtraData Extra data for the arbitrator. (default empty string) + * @param {string} metaEvidenceUri Uri meta-evidence. (default empty string) + * @returns {object} truffle-contract Object | err The deployed contract or an error + */ + createArbitrableTransaction = async ( + account, + arbitratorAddress, + seller, + value, + timeout = 3600, + arbitratorExtraData = 0x0, + metaEvidenceUri + ) => { + await this.loadContract() + + try { + const estimateGas = await this.contractInstance.createTransaction.estimateGas( + arbitratorAddress, + timeout, + seller, + arbitratorExtraData, + metaEvidenceUri, + { + from: account, + value: this._Web3Wrapper.toWei(value, 'ether') + } + ) + + return this.contractInstance.createTransaction( + arbitratorAddress, + timeout, + seller, + arbitratorExtraData, + metaEvidenceUri, + { + from: account, + value: this._Web3Wrapper.toWei(value, 'ether'), + gas: estimateGas + } + ) + } catch (err) { + console.error(err) + throw new Error(errorConstants.UNABLE_TO_CREATE_TRANSACTION) + } + } + + /** + * Pay the seller. To be called when the good is delivered or the service rendered. + * @param {string} account - Ethereum account. + * @param {number} arbitrableTransactionId - The index of the transaction. + * @param {amount} amount - Part or all of the amount of the good or the service. + * @returns {object} - The result transaction object. + */ + pay = async ( + account, + arbitrableTransactionId, + amount + ) => { + await this.loadContract() + + try { + return this.contractInstance.pay(arbitrableTransactionId, amount, { + from: account, + value: 0 + }) + } catch (err) { + console.error(err) + throw new Error(errorConstants.UNABLE_TO_PAY_SELLER) + } + } + + /** + * Reimburse the seller. To be called when the good is not delivered or the service rendered. + * @param {string} account - Ethereum account. + * @param {number} arbitrableTransactionId - The index of the transaction. + * @param {amount} amount - Part or all of the amount of the good or the service. + * @returns {object} - The result transaction object. + */ + reimburse = async ( + account, + arbitrableTransactionId, + amount + ) => { + await this.loadContract() + + try { + return this.contractInstance.reimburse(arbitrableTransactionId, amount, { + from: account, + value: 0 + }) + } catch (err) { + console.error(err) + throw new Error(errorConstants.UNABLE_TO_REIMBURSE_BUYER) + } + } + + /** + * Pay the arbitration fee to raise a dispute. To be called by the buyer. + * @param {string} account - Ethereum account. + * @param {number} arbitrableTransactionId - The index of the transaction. + * @param {number} arbitrationCost - Arbitration cost. + * @returns {object} - The result transaction object. + */ + payArbitrationFeeByBuyer = async ( + account, + arbitrableTransactionId, + arbitrationCost + ) => { + await this.loadContract() + + try { + return this.contractInstance.payArbitrationFeeByBuyer( + arbitrableTransactionId, + { + from: account, + value: this._Web3Wrapper.toWei(arbitrationCost, 'ether') + } + ) + } catch (err) { + console.error(err) + throw new Error(errorConstants.UNABLE_TO_PAY_ARBITRATION_FEE) + } + } + + /** + * Pay the arbitration fee to raise a dispute. To be called by the seller. + * @param {string} account Ethereum account. + * @param {number} arbitrableTransactionId - The index of the transaction. + * @returns {object} - The result transaction object. + */ + payArbitrationFeeBySeller = async ( + account, + arbitrableTransactionId + ) => { + await this.loadContract() + + const transactionArbitrableData0 = await this.getData(0) + + try { + return this.contractInstance.payArbitrationFeeBySeller( + arbitrableTransactionId, + { + from: account, + value: this._Web3Wrapper.toWei( + transactionArbitrableData0.sellerFee, + 'ether' + ) + } + ) + } catch (err) { + console.error(err) + throw new Error(errorConstants.UNABLE_TO_PAY_ARBITRATION_FEE) + } + } + + /** + * Submit evidence. + * @param {string} account ETH address of user. + * @param {number} arbitrableTransactionId - The index of the transaction. + * @param {string} url A link to an evidence using its URI. + * @returns {string} txHash Hash transaction. + */ + submitEvidence = async ( + account, + arbitrableTransactionId, + url + ) => { + await this.loadContract() + + const txHashObj = await this.contractInstance.submitEvidence( + arbitrableTransactionId, + url, + { + from: account, + value: 0 + } + ) + + return txHashObj.tx + } + + /** + * Call by buyer if seller is timeout + * @param {string} account ETH address of user + * @param {number} arbitrableTransactionId - The index of the transaction. + * @returns {object} The result transaction object. + */ + callTimeOutBuyer = async ( + account, + arbitrableTransactionId + ) => { + await this.loadContract() + + const transactionArbitrableData = await this.getData( + arbitrableTransactionId + ) + + const status = transactionArbitrableData.status + const timeout = transactionArbitrableData.timeout + const lastInteraction = transactionArbitrableData.lastInteraction + + if (status !== contractConstants.STATUS.WAITING_SELLER) { + throw new Error(errorConstants.CONTRACT_IS_NOT_WAITING_ON_OTHER_PARTY) + } else if (Math.trunc(Date.now() / 1000) <= lastInteraction + timeout) { + throw new Error(errorConstants.TIMEOUT_NOT_REACHED) + } + + try { + return this.contractInstance.timeOutByBuyer(arbitrableTransactionId, { + from: account, + value: 0 + }) + } catch (err) { + console.error(err) + throw new Error(errorConstants.UNABLE_TO_CALL_TIMEOUT) + } + } + + /** + * Call by seller if buyer is timeout. + * @param {string} account - ETH address of user. + * @param {number} arbitrableTransactionId - The index of the transaction. + * @param {string} contractAddress - ETH address of contract. + * @returns {object} The result transaction object. + */ + callTimeOutSeller = async ( + account, + arbitrableTransactionId + ) => { + await this.loadContract() + + const status = await this.contractInstance.status() + const timeout = await this.contractInstance.timeout() + const lastInteraction = await this.contractInstance.lastInteraction() + + if (status !== contractConstants.STATUS.WAITING_BUYER) { + throw new Error(errorConstants.CONTRACT_IS_NOT_WAITING_ON_OTHER_PARTY) + } else if (Date.now() >= lastInteraction + timeout) { + throw new Error(errorConstants.TIMEOUT_NOT_REACHED) + } + + try { + return this.contractInstance.timeOutBySeller(arbitrableTransactionId, { + from: account, + value: 0 + }) + } catch (err) { + console.error(err) + throw new Error(errorConstants.UNABLE_TO_CALL_TIMEOUT) + } + } + + /** + * Appeal an appealable ruling. + * @param {string} account Ethereum account. + * @param {number} arbitrableTransactionId - The index of the transaction. + * @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(0), + arbitrableTransactionId, + extraData = 0x0, + appealCost = 0.3 + ) => { + await this.loadContract() + + try { + return this.contractInstance.appeal(arbitrableTransactionId, extraData, { + from: account, + value: this._Web3Wrapper.toWei(appealCost, 'ether') + }) + } catch (err) { + console.error(err) + throw new Error(errorConstants.UNABLE_TO_RAISE_AN_APPEAL) + } + } + + /** + * Set the arbitrable transaction id + * @param {number} arbitrableTransactionId - The index of the transaction. + * @returns {object} Object Data of the contract. + */ + setArbitrableTransactionId = arbitrableTransactionId => + (this.arbitrableTransactionId = arbitrableTransactionId) + + /** + * Data of the contract + * @param {number} arbitrableTransactionId - The index of the transaction. + * @returns {object} Object Data of the contract. + */ + getData = async arbitrableTransactionId => { + await this.loadContract() + + const arbitrableTransaction = await this.contractInstance.transactions( + arbitrableTransactionId + ) + + return { + seller: arbitrableTransaction[0], + buyer: arbitrableTransaction[1], + amount: arbitrableTransaction[2].toNumber(), + timeout: arbitrableTransaction[3].toNumber(), + disputeId: arbitrableTransaction[4].toNumber(), + arbitrator: arbitrableTransaction[5], + arbitratorExtraData: arbitrableTransaction[6], + sellerFee: this._Web3Wrapper.fromWei(arbitrableTransaction[7], 'ether'), + buyerFee: this._Web3Wrapper.fromWei(arbitrableTransaction[8], 'ether'), + lastInteraction: arbitrableTransaction[9].toNumber(), + status: arbitrableTransaction[10].toNumber() + } + } +} + +export default MultipleArbitrableTransaction diff --git a/src/contracts/implementations/arbitrable/index.js b/src/contracts/implementations/arbitrable/index.js index 1b58991..36c43cb 100644 --- a/src/contracts/implementations/arbitrable/index.js +++ b/src/contracts/implementations/arbitrable/index.js @@ -1,4 +1,9 @@ import ArbitrableTransaction from './ArbitrableTransaction' +import MultipleArbitrableTransaction from './MultipleArbitrableTransaction' import ArbitrablePermissionList from './ArbitrablePermissionList' -export { ArbitrableTransaction, ArbitrablePermissionList } +export { + ArbitrableTransaction, + MultipleArbitrableTransaction, + ArbitrablePermissionList +} diff --git a/src/kleros.js b/src/kleros.js index bd4fad9..3f1486a 100644 --- a/src/kleros.js +++ b/src/kleros.js @@ -52,7 +52,7 @@ class Kleros { ethereumProvider, arbitratorAddress ) - const _arbitrableTransaction = new contracts.implementations.arbitrable.ArbitrableTransaction( + const _arbitrableTransaction = new contracts.implementations.arbitrable.MultipleArbitrableTransaction( ethereumProvider, arbitrableContractAddress ) @@ -61,7 +61,7 @@ class Kleros { ethereumProvider, arbitratorAddress ) - const _arbitrableTransactionInternal = new contracts.implementations.arbitrable.ArbitrableTransaction( + const _arbitrableTransactionInternal = new contracts.implementations.arbitrable.MultipleArbitrableTransaction( ethereumProvider, arbitrableContractAddress ) diff --git a/src/utils/StoreProviderWrapper.js b/src/utils/StoreProviderWrapper.js index 335dd77..d400c62 100644 --- a/src/utils/StoreProviderWrapper.js +++ b/src/utils/StoreProviderWrapper.js @@ -44,29 +44,24 @@ class StoreProviderWrapper { queueReadRequest = uri => this._storeQueue.fetch(() => httpRequest('GET', uri)) - /** - * Fetch the URI where metaEvidence in the kleros store should be stored. - * @param {string} userAddress - The users ETH address. - * @param {string} contractAddress - The address of the arbitrable contract. - * @returns {stirng} - The URI where metaEvidence in the kleros store should be stored. - */ - getMetaEvidenceUri = (userAddress, contractAddress) => + getMetaEvidenceUri = ( + userAddress, + contractAddress, + arbitrableTransactionIndex + ) => `${ this._storeUri - }/${userAddress}/contracts/${contractAddress}/meta-evidence` + }/${userAddress}/contracts/${contractAddress}/arbitrable-transaction/${arbitrableTransactionIndex}/meta-evidence` - /** - * Fetch the URI where evidence in the kleros store should be stored. - * @param {string} userAddress - The users ETH address. - * @param {string} contractAddress - The address of the arbitrable contract. - * @param {number} evidenceIndex - The index of the evidence. - * Should be returned when evidence is added to the store - * @returns {stirng} - The URI where evidence in the kleros store should be stored. - */ - getEvidenceUri = (userAddress, contractAddress, evidenceIndex) => + getEvidenceUri = ( + userAddress, + contractAddress, + arbitrableTransactionIndex, + evidenceIndex + ) => `${ this._storeUri - }/${userAddress}/contracts/${contractAddress}/evidence/${evidenceIndex}` + }/${userAddress}/contracts/${contractAddress}/arbitrable-transaction/${arbitrableTransactionIndex}/evidence/${evidenceIndex}` // **************************** // // * Read * // @@ -265,6 +260,7 @@ class StoreProviderWrapper { * stored evidence for the specified user, not all parties of the dispute. * @param {string} contractAddress - Address of the contract * @param {string} userAddress - Address of the user. + * @param {string} arbitrableTransactionIndex - Id of the arbitrable transaction. * @param {string} name - Name of evidence. * @param {string} description - Description of evidence. * @param {string} url - A link to the evidence. @@ -274,6 +270,7 @@ class StoreProviderWrapper { addEvidenceContract = async ( contractAddress, userAddress, + arbitrableTransactionIndex, name, description, url, @@ -294,7 +291,9 @@ class StoreProviderWrapper { const response = await this.queueWriteRequest( getBodyFn, 'POST', - `${this._storeUri}/${userAddress}/contracts/${contractAddress}/evidence` + `${ + this._storeUri + }/${userAddress}/contracts/${contractAddress}/arbitrable-transaction/${arbitrableTransactionIndex}/evidence` ) if (response.status !== 201) diff --git a/tests/helpers/setUpContracts.js b/tests/helpers/setUpContracts.js index cdda9f9..359a921 100644 --- a/tests/helpers/setUpContracts.js +++ b/tests/helpers/setUpContracts.js @@ -2,7 +2,7 @@ import BlockHashRNG from '../../src/contracts/implementations/RNG/BlockHashRNG' import MiniMePinakion from '../../src/contracts/implementations/PNK/MiniMePinakion' import TokenFactory from '../../src/contracts/implementations/PNK/TokenFactory' import KlerosPOC from '../../src/contracts/implementations/arbitrator/KlerosPOC' -import ArbitrableTransaction from '../../src/contracts/implementations/arbitrable/ArbitrableTransaction' +import MultipleArbitrableTransaction from '../../src/contracts/implementations/arbitrable/MultipleArbitrableTransaction' const setUpContracts = async ( provider, @@ -41,16 +41,11 @@ const setUpContracts = async ( klerosPOCParams.account ) - const contractArbitrableTransaction = await ArbitrableTransaction.deploy( + const contractArbitrableTransaction = await MultipleArbitrableTransaction.deploy( arbitrableContractParams.partyA, - arbitrableContractParams.value, - klerosCourt.address, - arbitrableContractParams.timeout, - arbitrableContractParams.partyB, - arbitrableContractParams.extraData, - arbitrableContractParams.metaEvidenceUri, provider ) + return [ klerosCourt.address, contractArbitrableTransaction.address, diff --git a/tests/integration/contracts.test.js b/tests/integration/contracts.test.js index a501e5d..88e3d88 100644 --- a/tests/integration/contracts.test.js +++ b/tests/integration/contracts.test.js @@ -1,7 +1,7 @@ import Web3 from 'web3' import KlerosPOC from '../../src/contracts/implementations/arbitrator/KlerosPOC' -import ArbitrableTransaction from '../../src/contracts/implementations/arbitrable/ArbitrableTransaction' +import MultipleArbitrableTransaction from '../../src/contracts/implementations/arbitrable/MultipleArbitrableTransaction' import * as ethConstants from '../../src/constants/eth' import * as errorConstants from '../../src/constants/error' import setUpContracts from '../helpers/setUpContracts' @@ -46,7 +46,7 @@ describe('Contracts', () => { value: 0, timeout: 1, extraData: '', - metaEvidenceUri: 'https://test-meta-evidence.com' + metaEvidenceUri: 'https://my-meta-evidence.ipfs.io' } }) @@ -137,31 +137,55 @@ describe('Contracts', () => { expect(klerosCourtData.rngContractAddress).toEqual(rngAddress) expect(klerosCourtData.period).toEqual(0) expect(klerosCourtData.session).toEqual(1) - // // arbitrable contract - const ArbitrableTransactionInstanceInstance = new ArbitrableTransaction( - provider, + }, + 10000 + ) + it( + 'create a arbitrable transaction', + async () => { + const [ + klerosPOCAddress, arbitrableContractAddress + ] = await setUpContracts( + provider, + klerosPOCData, + arbitrableContractData ) - const contractArbitrableTransactionData = await ArbitrableTransactionInstanceInstance.getData( - arbitrableContractAddress, - partyA - ) - expect(contractArbitrableTransactionData.address).toEqual( + expect(klerosPOCAddress).toBeDefined() + expect(arbitrableContractAddress).toBeDefined() + + // arbitrable contract + const ArbitrableTransactionInstance = new MultipleArbitrableTransaction( + provider, arbitrableContractAddress ) - expect(contractArbitrableTransactionData.arbitrator).toEqual( - klerosPOCAddress - ) - expect(contractArbitrableTransactionData.timeout).toEqual( - arbitrableContractData.timeout - ) - expect(contractArbitrableTransactionData.partyA).toEqual( - arbitrableContractData.partyA + + await ArbitrableTransactionInstance.createArbitrableTransaction( + arbitrableContractData.partyA, + klerosPOCAddress, + arbitrableContractData.partyB, + arbitrableContractData.value, + arbitrableContractData.timeout, + arbitrableContractData.extraData, + arbitrableContractData.metaEvidenceUri ) - expect(contractArbitrableTransactionData.partyB).toEqual( - arbitrableContractData.partyB + + const transactionArbitrable0 = await ArbitrableTransactionInstance.getData( + 0 ) + + expect(transactionArbitrable0.seller).toEqual(arbitrableContractData.partyB) + expect(transactionArbitrable0.buyer).toEqual(arbitrableContractData.partyA) + expect(transactionArbitrable0.amount).toEqual(arbitrableContractData.value) + expect(transactionArbitrable0.timeout).toEqual(arbitrableContractData.timeout) + expect(transactionArbitrable0.disputeId).toEqual(0) + expect(transactionArbitrable0.arbitrator).toEqual(klerosPOCAddress) + expect(transactionArbitrable0.arbitratorExtraData).toEqual('0x') + expect(transactionArbitrable0.sellerFee).toEqual(0) + expect(transactionArbitrable0.buyerFee).toEqual(0) + expect(transactionArbitrable0.lastInteraction).toBeDefined() + expect(transactionArbitrable0.status).toEqual(0) }, 10000 ) @@ -180,24 +204,37 @@ describe('Contracts', () => { expect(klerosPOCAddress).toBeDefined() expect(arbitrableContractAddress).toBeDefined() - // FIXME use arbitrableTransaction - const ArbitrableTransactionInstance = new ArbitrableTransaction( + const ArbitrableTransactionInstanceInstance = new MultipleArbitrableTransaction( provider, arbitrableContractAddress ) - const arbitrableContractInstance = await ArbitrableTransactionInstance.loadContract() - const partyApaysPartyB = await arbitrableContractInstance.pay({ - from: partyA - }) - expect(partyApaysPartyB.tx).toEqual( + // create a arbitrable transaction + await ArbitrableTransactionInstanceInstance.createArbitrableTransaction( + arbitrableContractData.partyA, + klerosPOCAddress, + arbitrableContractData.partyB, + arbitrableContractData.value, + arbitrableContractData.timeout, + arbitrableContractData.extraData, + arbitrableContractData.metaEvidenceUri + ) + + // buyer pays the seller + const transactionArbitrable0 = await ArbitrableTransactionInstanceInstance.pay( + arbitrableContractData.partyA, + 0, + arbitrableContractData.value + ) + + expect(transactionArbitrable0.tx).toEqual( expect.stringMatching(/^0x[a-f0-9]{64}$/) ) // tx hash }, 50000 ) it( - 'dispute with a timeout call by partyA', + 'dispute with a timeout call by the buyer', async () => { const [ klerosPOCAddress, @@ -210,42 +247,46 @@ describe('Contracts', () => { expect(klerosPOCAddress).toBeDefined() expect(arbitrableContractAddress).toBeDefined() - // return a bigint - // FIXME use arbitrableTransaction - const ArbitrableTransactionInstance = new ArbitrableTransaction( + const ArbitrableTransactionInstanceInstance = new MultipleArbitrableTransaction( provider, arbitrableContractAddress ) - const arbitrableContractInstance = await ArbitrableTransactionInstance.loadContract() - const partyAFeeContractInstance = await arbitrableContractInstance.partyAFee() - // return bytes - // FIXME use arbitrableTransaction - let extraDataContractInstance = await arbitrableContractInstance.arbitratorExtraData() + // create a arbitrable transaction + await ArbitrableTransactionInstanceInstance.createArbitrableTransaction( + arbitrableContractData.partyA, + klerosPOCAddress, + arbitrableContractData.partyB, + arbitrableContractData.value, + arbitrableContractData.timeout, + arbitrableContractData.extraData, + arbitrableContractData.metaEvidenceUri + ) const KlerosInstance = new KlerosPOC(provider, klerosPOCAddress) // return a bigint with the default value : 10000 wei fees in ether const arbitrationCost = await KlerosInstance.getArbitrationCost( - extraDataContractInstance + arbitrableContractData.extraData ) - // raise dispute party A - const raiseDisputeByPartyATxObj = await ArbitrableTransactionInstance.payArbitrationFeeByPartyA( - partyA, - arbitrationCost - - web3.fromWei(partyAFeeContractInstance, 'ether').toNumber() + // buyer A pays fee + const raiseDisputeByBuyerTxObj = await ArbitrableTransactionInstanceInstance.payArbitrationFeeByBuyer( + arbitrableContractData.partyA, + 0, + arbitrationCost ) - expect(raiseDisputeByPartyATxObj.tx).toEqual( + + expect(raiseDisputeByBuyerTxObj.tx).toEqual( expect.stringMatching(/^0x[a-f0-9]{64}$/) ) // tx hash - await delaySecond() - // call timeout by partyA - // TODO should test the api not directly the truffle contract - const txHashTimeOutByPartyA = await arbitrableContractInstance.timeOutByPartyA( - { from: partyA } + await delaySecond(2) + // call timeout by the buyer + const txHashTimeOutByBuyer = await ArbitrableTransactionInstanceInstance.callTimeOutBuyer( + arbitrableContractData.partyA, + 0 ) - expect(txHashTimeOutByPartyA.tx).toEqual( + expect(txHashTimeOutByBuyer.tx).toEqual( expect.stringMatching(/^0x[a-f0-9]{64}$/) ) // tx hash }, @@ -268,13 +309,22 @@ describe('Contracts', () => { const KlerosPOCInstance = new KlerosPOC(provider, klerosPOCAddress) - // return a bigint - // FIXME use arbitrableTransaction - const ArbitrableTransactionInstance = new ArbitrableTransaction( + const ArbitrableTransactionInstanceInstance = new MultipleArbitrableTransaction( provider, arbitrableContractAddress ) + // create a arbitrable transaction + await ArbitrableTransactionInstanceInstance.createArbitrableTransaction( + arbitrableContractData.partyA, + klerosPOCAddress, + arbitrableContractData.partyB, + arbitrableContractData.value, + arbitrableContractData.timeout, + arbitrableContractData.extraData, + arbitrableContractData.metaEvidenceUri + ) + // ****** Juror side (activate token) ****** // // jurors buy PNK @@ -299,39 +349,33 @@ describe('Contracts', () => { // ****** 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 + const arbitrationCost = await klerosPOCInstance.getArbitrationCost( + arbitrableContractData.extraData ) - // raise dispute party A - const raiseDisputeByPartyATxObj = await ArbitrableTransactionInstance.payArbitrationFeeByPartyA( - partyA, - arbitrationCost.minus(partyAFeeContractInstance) + // buyer A pays fee + const raiseDisputeByBuyerTxObj = await ArbitrableTransactionInstanceInstance.payArbitrationFeeByBuyer( + arbitrableContractData.partyA, + 0, + arbitrationCost ) - expect(raiseDisputeByPartyATxObj.tx).toEqual( + + expect(raiseDisputeByBuyerTxObj.tx).toEqual( expect.stringMatching(/^0x[a-f0-9]{64}$/) ) // tx hash - // raise dispute party B - const raiseDisputeByPartyBTxObj = await ArbitrableTransactionInstance.payArbitrationFeeByPartyB( - partyB, - arbitrationCost.minus(partyBFeeContractInstance) + // seller pays fee + const raiseDisputeBySellerTxObj = await ArbitrableTransactionInstanceInstance.payArbitrationFeeBySeller( + arbitrableContractData.partyB, + 0, + arbitrationCost ) - expect(raiseDisputeByPartyBTxObj.tx).toEqual( + + expect(raiseDisputeBySellerTxObj.tx).toEqual( expect.stringMatching(/^0x[a-f0-9]{64}$/) ) // tx hash + // ****** Juror side (pass period) ****** // let newPeriod @@ -387,13 +431,14 @@ describe('Contracts', () => { const appealCost = await KlerosPOCInstance.getAppealCost( 0, - extraDataContractInstance + arbitrableContractData.extraData ) // raise appeal party A - const raiseAppealByPartyATxObj = await ArbitrableTransactionInstance.appeal( + const raiseAppealByPartyATxObj = await ArbitrableTransactionInstanceInstance.appeal( partyA, - appealCost, - extraDataContractInstance + 0, + arbitrableContractData.extraData, + appealCost ) expect(raiseAppealByPartyATxObj.tx).toEqual( expect.stringMatching(/^0x[a-f0-9]{64}$/)