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

Feat/validate evidence #154

Merged
merged 5 commits into from
Jul 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@
"dependencies": {
"babel-runtime": "^6.26.0",
"eth-sig-util": "^1.4.2",
"ethereumjs-util": "^5.2.0",
"ethjs": "^0.4.0",
"kleros": "^0.0.6",
"kleros-interaction": "^0.0.17",
"kleros-interaction": "^0.0.18",
"lodash": "^4.17.4",
"minimetoken": "^0.2.0",
"truffle-contract": "^2.0.5",
Expand Down
111 changes: 37 additions & 74 deletions src/contracts/abstractions/Arbitrable.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import Eth from 'ethjs'

import getContractAddress from '../../utils/getContractAddress'

import AbstractContract from '../AbstractContract'

/**
Expand All @@ -17,76 +21,87 @@ class ArbitrableContract extends AbstractContract {
* @param {string} partyB - Ethereum address of the other party in the contract.
* @param {bytes} arbitratorExtraData - Extra data for the arbitrator.
* @param {string} email - Email address of the contract creator (default empty string).
* @param {string} title - Title of the contract (default empty string).
* @param {string} description - Description of what the contract is about (default empty string).
* @param {...any} args - Extra arguments for the contract.
* @returns {object | Error} - The contract object or an error.
*/
deploy = async (
account,
value,
hashContract,
arbitratorAddress,
timeout,
partyB,
arbitratorExtraData = '',
email = '',
title = '',
description = '',
metaEvidence = {},
...args
) => {
const web3Provider = this._contractImplementation.getWeb3Provider()
const eth = new Eth(web3Provider)
const txCount = await eth.getTransactionCount(account)
// determine the contract address WARNING if the nonce changes this will produce a different address
const contractAddress = getContractAddress(account, txCount)
const metaEvidenceUri = this._StoreProvider.getMetaEvidenceUri(
account,
contractAddress
)
const contractInstance = await this._contractImplementation.constructor.deploy(
account,
value,
hashContract,
arbitratorAddress,
timeout,
partyB,
arbitratorExtraData,
this._contractImplementation.getWeb3Provider(),
metaEvidenceUri,
web3Provider,
...args
)

if (contractInstance.address !== contractAddress)
throw new Error('Contract address does not match meta-evidence uri')

const newContract = await this._StoreProvider.updateContract(
account,
contractInstance.address,
{
hashContract,
partyA: account,
partyB,
arbitrator: arbitratorAddress,
timeout,
email,
title,
description
metaEvidence
}
)

return newContract
}

/**
* Submit evidence.
* Submit evidence. FIXME should we determine the hash for the user?
* @param {string} account - ETH address of user.
* @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, name, description = '', url) => {
const txHash = await this._contractImplementation.submitEvidence(
submitEvidence = async (account, name, description, url, hash) => {
const contractAddress = this._contractImplementation.contractAddress
// get the index of the new evidence
const evidenceIndex = await this._StoreProvider.addEvidenceContract(
contractAddress,
account,
name,
description,
url
url,
hash
)

await this._StoreProvider.addEvidenceContract(
this._contractImplementation.contractAddress,
// construct the unique URI
const evidenceUri = this._StoreProvider.getEvidenceUri(
account,
name,
description,
url
contractAddress,
evidenceIndex
)
const txHash = await this._contractImplementation.submitEvidence(
account,
evidenceUri
)

return txHash
Expand All @@ -104,40 +119,6 @@ class ArbitrableContract extends AbstractContract {
return userProfile.contracts
}

/**
* Get evidence for contract.
* @param {string} contractAddress - Address of arbitrable contract.
* @returns {object[]} - Array of evidence objects.
*/
getEvidenceForArbitrableContract = async () => {
const arbitrableContractData = await this._contractImplementation.getData()
const partyAContractData = await this._StoreProvider.getContractByAddress(
arbitrableContractData.partyA,
this._contractImplementation.contractAddress
)
const partyBContractData = await this._StoreProvider.getContractByAddress(
arbitrableContractData.partyB,
this._contractImplementation.contractAddress
)

const partyAEvidence = (partyAContractData
? partyAContractData.evidence
: []
).map(evidence => {
evidence.submitter = arbitrableContractData.partyA
return evidence
})
const partyBEvidence = (partyBContractData
? partyBContractData.evidence
: []
).map(evidence => {
evidence.submitter = arbitrableContractData.partyB
return evidence
})

return partyAEvidence.concat(partyBEvidence)
}

/**
* Fetch all data from the store on the current contract.
* @returns {object} - Store data for contract.
Expand All @@ -151,24 +132,6 @@ class ArbitrableContract extends AbstractContract {
this._contractImplementation.contractAddress
)
}

/**
* Get data from the store and contract for Arbitrable Contract.
* @param {string} account - ETH address of user.
* @returns {object} - Contract data.
*/
getData = async account => {
const contractData = await this._contractImplementation.getData()

let storeData = {}
if (account)
storeData = await this._StoreProvider.getContractByAddress(
account,
this._contractImplementation.contractAddress
)

return Object.assign({}, storeData, contractData)
}
}

export default ArbitrableContract
104 changes: 104 additions & 0 deletions src/contracts/implementations/arbitrable/Arbitrable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import _ from 'lodash'

import ContractImplementation from '../../ContractImplementation'
import EventListener from '../../../utils/EventListener'
import httpRequest from '../../../utils/httpRequest'

/**
* Provides interaction with standard Arbitrable contracts
*/
class Arbitrable extends ContractImplementation {
/**
* Constructor ArbitrableTransaction.
* @param {object} web3Provider instance
* @param {string} contractAddress of the contract
*/
constructor(web3Provider, contractArtifact, contractAddress) {
super(web3Provider, contractArtifact, contractAddress)
}

/**
* Get the meta evidence for the contract. Arbitrable Transaction can only have
* one meta-evidence that is submitted on contract creation. Look up meta-evidence event
* and make an http request to the resource.
*/
getMetaEvidence = async () => {
const metaEvidenceLog = await EventListener.getEventLogs(
this,
'MetaEvidence',
0,
'latest',
{ _metaEvidenceID: 0 }
)

if (!metaEvidenceLog[0]) return {} // NOTE better to throw errors for missing meta-evidence?

const metaEvidenceUri = metaEvidenceLog[0].args._evidence
// FIXME caching issue need a query param to fetch from AWS
const metaEvidenceResponse = await httpRequest(
'GET',
metaEvidenceUri + '?nocache'
)

if (metaEvidenceResponse.status >= 400)
throw new Error(`Unable to fetch meta-evidence at ${metaEvidenceUri}`)
return metaEvidenceResponse.body || metaEvidenceResponse
}

/**
* Get the evidence submitted in a dispute.
*/
getEvidence = async () => {
await this.loadContract()
const arbitratorAddress = await this.contractInstance.arbitrator()
await this.loadContract()
const disputeId = (await this.contractInstance.disputeID()).toNumber()

// No evidence yet as there is no dispute
if (_.isNull(disputeId)) return []

const evidenceLogs = await EventListener.getEventLogs(
this,
'Evidence',
0,
'latest',
{ _disputeID: disputeId, _arbitrator: arbitratorAddress }
)

// TODO verify hash and data are valid if hash exists
return Promise.all(
evidenceLogs.map(async evidenceLog => {
const evidenceURI = evidenceLog.args._evidence
const evidence = await httpRequest('GET', evidenceURI)
const submittedAt = (await this._Web3Wrapper.getBlock(
evidenceLog.blockNumber
)).timestamp
return {
...evidence.body,
...{ submittedBy: evidenceLog.args._party, submittedAt }
}
})
)
}

/**
* Fetch all standard contract data.
*/
getContractData = async () => {
await this.loadContract()

const [metaEvidence, partyA, partyB] = await Promise.all([
this.getMetaEvidence(),
this.contractInstance.partyA(),
this.contractInstance.partyB()
])

return {
partyA,
partyB,
metaEvidence
}
}
}

export default Arbitrable
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import ArbitrablePermissionListArtifact from 'kleros-interaction/build/contracts/ArbitrablePermissionList'

import * as ethConstants from '../../../constants/eth'
import Arbitrable from './Arbitrable'
import deployContractAsync from '../../../utils/deployContractAsync'

/**
* Provides interaction with an Arbitrable Transaction contract deployed on the blockchain.
*/
class ArbitrablePermissionList extends Arbitrable {
/**
* Constructor ArbitrableTransaction.
* @param {object} web3Provider instance
* @param {string} contractAddress of the contract
*/
constructor(web3Provider, contractAddress) {
super(web3Provider, ArbitrablePermissionListArtifact, contractAddress)
}

/**
* Deploy ArbitrablePermissionList. TODO
* @param {object} account Ethereum account (default account[0])
* @param {number} value funds to be placed in contract
* @param {object} web3Provider web3 provider object
* @returns {object} truffle-contract Object | err The deployed contract or an error
*/
// static deploy = async (
// account,
// value = ethConstants.TRANSACTION.VALUE,
// web3Provider
// ) => {
// // const contractDeployed = await deployContractAsync()
// //
// // return contractDeployed
// }

getItemByDisputeId = async disputeId => {
await this.loadContract()

return this.contractInstance.disputeIDToItem(disputeId)
}
}

export default ArbitrablePermissionList
Loading