Skip to content
Permalink
Browse files

feat: split event based functions into base Arbitrable.js

  • Loading branch information...
satello committed Jul 25, 2018
1 parent 5ff4aee commit 9544efeb8261f72dbbb3386c268faebd3b2e038b
@@ -1,8 +1,9 @@
import AbstractContract from '../AbstractContract'
import Eth from 'ethjs'

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

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
@@ -39,7 +40,10 @@ class ArbitrableContract extends AbstractContract {
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 metaEvidenceUri = this._StoreProvider.getMetaEvidenceUri(
account,
contractAddress
)
const contractInstance = await this._contractImplementation.constructor.deploy(
account,
value,
@@ -61,8 +65,6 @@ class ArbitrableContract extends AbstractContract {
{
partyA: account,
partyB,
arbitrator: arbitratorAddress,
timeout,
email,
metaEvidence
}
@@ -92,7 +94,11 @@ class ArbitrableContract extends AbstractContract {
hash
)
// construct the unique URI
const evidenceUri = this._StoreProvider.getEvidenceUri(account, contractAddress, evidenceIndex)
const evidenceUri = this._StoreProvider.getEvidenceUri(
account,
contractAddress,
evidenceIndex
)
const txHash = await this._contractImplementation.submitEvidence(
account,
evidenceUri
@@ -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
@@ -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
@@ -4,15 +4,13 @@ import _ from 'lodash'
import * as ethConstants from '../../../constants/eth'
import * as contractConstants from '../../../constants/contract'
import * as errorConstants from '../../../constants/error'
import ContractImplementation from '../../ContractImplementation'
import Arbitrable from './Arbitrable'
import deployContractAsync from '../../../utils/deployContractAsync'
import EventListener from '../../../utils/EventListener'
import httpRequest from '../../../utils/httpRequest'

/**
* Provides interaction with an Arbitrable Transaction contract deployed on the blockchain.
*/
class ArbitrableTransaction extends ContractImplementation {
class ArbitrableTransaction extends Arbitrable {
/**
* Constructor ArbitrableTransaction.
* @param {object} web3Provider instance
@@ -59,72 +57,6 @@ class ArbitrableTransaction extends ContractImplementation {
return contractDeployed
}

/**
* 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
const metaEvidenceResponse = await httpRequest(
'GET',
metaEvidenceUri
)

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

/**
* 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 }
}
}))
}

/**
* Pay the party B. To be called when the good is delivered or the service rendered.
* @param {string} account - Ethereum account (default account[0]).
@@ -202,20 +134,14 @@ class ArbitrableTransaction extends ContractImplementation {
* @param {string} url A link to an evidence using its URI.
* @returns {string} txHash Hash transaction.
*/
submitEvidence = async (
account = this._Web3Wrapper.getAccount(0),
url
) => {
submitEvidence = async (account = this._Web3Wrapper.getAccount(0), url) => {
await this.loadContract()

const txHashObj = await this.contractInstance.submitEvidence(
url,
{
from: account,
gas: ethConstants.TRANSACTION.GAS,
value: 0
}
)
const txHashObj = await this.contractInstance.submitEvidence(url, {
from: account,
gas: ethConstants.TRANSACTION.GAS,
value: 0
})

return txHashObj.tx
}
@@ -307,56 +233,6 @@ class ArbitrableTransaction extends ContractImplementation {
}
}

/**
* Get ruling options from dispute via event
* @param {string} arbitratorAddress address of arbitrator contract
* @param {number} disputeId index of dispute
* @returns {object[]} an array of objects that specify the name and value of the resolution option
*/
getRulingOptions = async (arbitratorAddress, disputeId) => {
await this.loadContract()

// fetch dispute resolution options
const statusNumber = (await this.contractInstance.status()).toNumber()

// should this just be !== ?
if (statusNumber < contractConstants.STATUS.DISPUTE_CREATED) return []

// FIXME we should have a block number to start from so we don't have to rip through the entire chain
const disputeEvents = await new Promise((resolve, reject) => {
this.contractInstance
.Dispute({}, { fromBlock: 0, toBlock: 'latest' })
.get((error, eventResult) => {
if (error) reject(error)

resolve(eventResult)
})
})

const disputeOption = _.filter(disputeEvents, event => {
const optionDisputeId = event.args._disputeID.toNumber()
// filter by arbitrator address and disputeId
return (
event.args._arbitrator === arbitratorAddress &&
optionDisputeId === disputeId
)
})
// should only be 1 at this point
if (disputeOption.length !== 1) return []

const rulingOptions = disputeOption[0].args._rulingOptions.split(';')
let optionIndex = 0
const resolutionOptions = rulingOptions.map(option => {
optionIndex += 1
return {
name: option,
value: optionIndex
}
})

return resolutionOptions
}

/**
* Data of the contract
* @returns {object} Object Data of the contract.
@@ -1,3 +1,4 @@
import ArbitrableTransaction from './ArbitrableTransaction'
import ArbitrablePermissionList from './ArbitrablePermissionList'

export { ArbitrableTransaction }
export { ArbitrableTransaction, ArbitrablePermissionList }
Oops, something went wrong.

0 comments on commit 9544efe

Please sign in to comment.
You can’t perform that action at this time.