From 9bece8a9cb0099c1a1fcdbc6b31e7d0661b0540e Mon Sep 17 00:00:00 2001 From: Sam Vitello Date: Thu, 22 Feb 2018 17:09:06 -0500 Subject: [PATCH 1/4] update createdAt and ruledAt timestamps --- src/abstractWrappers/Disputes.js | 169 +++++++++++++++++++------- src/abstractWrappers/Notifications.js | 66 ++++------ src/kleros.js | 3 +- src/utils/StoreProviderWrapper.js | 8 +- src/utils/Web3Wrapper.js | 2 + 5 files changed, 164 insertions(+), 84 deletions(-) diff --git a/src/abstractWrappers/Disputes.js b/src/abstractWrappers/Disputes.js index d5df842..04a274e 100644 --- a/src/abstractWrappers/Disputes.js +++ b/src/abstractWrappers/Disputes.js @@ -28,6 +28,7 @@ class Disputes extends AbstractWrapper { contractAddress = arbitratorAddress, address = account ) => { + console.log("adding dispute for " + address) const disputeId = event.args._disputeID.toNumber() const disputeData = await this.getDataForDispute( contractAddress, @@ -36,7 +37,12 @@ class Disputes extends AbstractWrapper { ) // if listener is a party in dispute add to store if (disputeData.partyA === address || disputeData.partyB === address) { - await this._updateStoreForDispute(contractAddress, disputeId, address) + console.log("should be for partyA") + const blockNumber = event.blockNumber + const block = this._Arbitrator._Web3Wrapper.getBlock(blockNumber) + + // add new dispute with timestamp + const dispute = await this._updateStoreForDispute(contractAddress, disputeId, address, block.timestamp) } } @@ -97,6 +103,95 @@ class Disputes extends AbstractWrapper { ) } + addDisputeRulingHandler = async ( + arbitratorAddress, + account, + callback + ) => { + if (!this._eventListener) return + + const _disputeRulingHandler = async ( + event, + contractAddress = arbitratorAddress, + address = account, + notificationCallback = callback + ) => { + console.log("in handler") + const newPeriod = event.args._period.toNumber() + const txHash = event.transactionHash + // send appeal possible notifications + if (newPeriod === PERIODS.APPEAL) { + console.log("doing the do") + this._checkArbitratorWrappersSet() + const userProfile = await this._StoreProvider.getUserProfile(address) + // contract data + const arbitratorData = await this._Arbitrator.getData(contractAddress, address) + const currentDisputes = [] + let disputeId = 0 + const currentSession = arbitratorData.session + + let dispute + while (1) { + // iterate over all disputes (FIXME inefficient) + try { + dispute = await this._Arbitrator.getDispute(contractAddress, disputeId) + if (dispute.arbitratedContract === NULL_ADDRESS) break + // session + number of appeals + const disputeSession = dispute.firstSession + dispute.numberOfAppeals + // if dispute not in current session skip + if (disputeSession !== currentSession) { + disputeId++ + dispute = await this._Arbitrator.getDispute(contractAddress, disputeId) + continue + } + + const ruling = await this._Arbitrator.currentRulingForDispute(contractAddress, disputeId) + + if (_.findIndex(userProfile.disputes, dispute => { + return (dispute.disputeId === disputeId && dispute.arbitratorAddress === contractAddress) + }) >= 0) { + await this._StoreProvider.newNotification( + address, + txHash, + disputeId, // use disputeId instead of logIndex since it doens't have its own event + NOTIFICATION_TYPES.APPEAL_POSSIBLE, + 'A ruling has been made. Appeal is possible', + { + disputeId, + contractAddress, + ruling + } + ) + // get ruledAt from block timestamp + const blockNumber = event.blockNumber + const block = this._Arbitrator._Web3Wrapper.getBlock(blockNumber) + // add ruledAt to store + await this._updateStoreForDispute(contractAddress, disputeId, address, null, block.timestamp) + + if (callback) { + const userProfile = await this._StoreProvider.getUserProfile(address) + const notification = _.filter(userProfile.notifications, notification => { + return (notification.txHash === txHash && notification.logIndex === disputeId) + }) + + if (notification) { + callback(notification[0]) + } + } + } + // check next dispute + disputeId += 1 + } catch (e) { + // getDispute(n) throws an error if index out of range + break + } + } + } + } + + await this._eventListener.registerArbitratorEvent('NewPeriod', _disputeRulingHandler) + } + // **************************** // // * Public * // // **************************** // @@ -123,7 +218,6 @@ class Disputes extends AbstractWrapper { ) if (!txHash) throw new Error('unable to pay arbitration fee for party A') - await this._storeNewDispute(arbitrableContractAddress, account) return txHash } catch (err) { throw new Error(err) @@ -151,39 +245,14 @@ class Disputes extends AbstractWrapper { ) if (!txHash) throw new Error('unable to pay arbitration fee for party B') - await this._storeNewDispute(arbitrableContractAddress, account) return txHash } /** - * If there is a dispute in contract update store. - * @param {string} arbitrableContractAddress - The arbitrable contract's address. - * @param {string} account - The account. - */ - _storeNewDispute = async (arbitrableContractAddress, account) => { - this._checkArbitratorWrappersSet() - this._checkArbitrableWrappersSet() - - const arbitrableContractData = await this._ArbitrableContract.getData( - arbitrableContractAddress - ) - - if ( - arbitrableContractData.status === contractConstants.STATUS.DISPUTE_CREATED - ) { - await this._updateStoreForDispute( - arbitrableContractData.arbitrator, - arbitrableContractData.disputeId, - account - ) - } - } - - /** - * Get disputes for user with extra data from arbitrated transaction and store. - * @param {string} arbitratorAddress - Address of Kleros contract. - * @param {string} account - Address of user. - * @returns {object[]} - Dispute data objects for user. + * Get disputes for user with extra data from arbitrated transaction and store + * @param {string} arbitratorAddress address of Kleros contract + * @param {string} account address of user + * @return {object[]} dispute data objects for user */ getDisputesForUser = async (arbitratorAddress, account) => { // FIXME don't like having to call this every fnc @@ -400,12 +469,18 @@ class Disputes extends AbstractWrapper { } /** - * update store with new dispute data - * @param {string} arbitratorAddress Address address of arbitrator contract - * @param {int} disputeId index of dispute - * @param {string} account address of party to update dispute or - */ - _updateStoreForDispute = async (arbitratorAddress, disputeId, account) => { + * update store with new dispute data + * @param {string} arbitratorAddress Address address of arbitrator contract + * @param {int} disputeId index of dispute + * @param {string} account address of party to update dispute or + */ + _updateStoreForDispute = async ( + arbitratorAddress, + disputeId, + account, + createdAt, + ruledAt + ) => { const disputeData = await this.getDataForDispute( arbitratorAddress, disputeId, @@ -425,7 +500,9 @@ class Disputes extends AbstractWrapper { disputeData.fee, disputeData.information, disputeData.justification, - disputeData.resolutionOptions + disputeData.resolutionOptions, + createdAt ? createdAt : disputeData.createdAt, + ruledAt ? ruledAt : disputeData.ruledAt ).body // update profile for account @@ -435,9 +512,11 @@ class Disputes extends AbstractWrapper { disputeData.arbitratorAddress, disputeData.disputeId, disputeData.votes.length > 0, - false, - 0 + disputeData.hasRuled, + disputeData.netPNK ? disputeData.netPNK : 0 ) + + return dispute } /** @@ -561,6 +640,8 @@ class Disputes extends AbstractWrapper { let votes = [] let hasRuled = false let netPNK = 0 + let createdAt + let ruledAt if (account) { votes = await this.getVotesForJuror(arbitratorAddress, disputeId, account) try { @@ -572,6 +653,8 @@ class Disputes extends AbstractWrapper { isJuror = userData.isJuror hasRuled = userData.hasRuled netPNK = userData.netPNK + createdAt = userData.createdAt + ruledAt = userData.ruledAt // eslint-disable-next-line no-unused-vars } catch (err) { // fetching dispute will fail if it hasn't been added to the store yet. this is ok we can just not return store data @@ -622,8 +705,10 @@ class Disputes extends AbstractWrapper { hasRuled, ruling, evidence, - netPNK - } + netPNK, + ruledAt, + createdAt + }) } } diff --git a/src/abstractWrappers/Notifications.js b/src/abstractWrappers/Notifications.js index e3b35c3..8402979 100644 --- a/src/abstractWrappers/Notifications.js +++ b/src/abstractWrappers/Notifications.js @@ -160,46 +160,34 @@ class Notifications extends AbstractWrapper { } // Repartition and execute - if (currentPeriod === arbitratorConstants.PERIOD.EXECUTE) { - await Promise.all( - userProfile.disputes.map(async dispute => { - const disputeData = await this._Arbitrator.getDispute( - dispute.arbitratorAddress, - dispute.disputeId - ) - - if ( - disputeData.firstSession + disputeData.numberOfAppeals === - currentSession - ) { - if (disputeData.state <= disputeConstants.STATE.RESOLVING) { - notifications.push( - this._createNotification( - notificationConstants.TYPE.CAN_REPARTITION, - 'Ready to repartition dispute', - { - disputeId: dispute.disputeId, - arbitratorAddress: dispute.arbitratorAddress - } - ) - ) - } else if ( - disputeData.state === disputeConstants.STATE.EXECUTABLE - ) { - notifications.push( - this._createNotification( - notificationConstants.TYPE.CAN_EXECUTE, - 'Ready to execute dispute', - { - disputeId: dispute.disputeId, - arbitratorAddress: dispute.arbitratorAddress - } - ) - ) - } + if (currentPeriod === PERIODS.EXECUTE) { + console.log("Starting....") + await Promise.all(userProfile.disputes.map(async dispute => { + const disputeData = await this._Arbitrator.getDispute(dispute.arbitratorAddress, dispute.disputeId) + if (disputeData.firstSession + disputeData.numberOfAppeals === currentSession) { + if (disputeData.state <= DISPUTE_STATES.RESOLVING) { + notifications.push(this._createNotification( + NOTIFICATION_TYPES.CAN_REPARTITION, + "Ready to repartition dispute", + { + disputeId: dispute.disputeId, + arbitratorAddress: dispute.arbitratorAddress + } + )) + console.log("did stuff") + } else if (disputeData.state === DISPUTE_STATES.EXECUTABLE) { + notifications.push(this._createNotification( + NOTIFICATION_TYPES.CAN_EXECUTE, + "Ready to execute dispute", + { + disputeId: dispute.disputeId, + arbitratorAddress: dispute.arbitratorAddress + } + )) } - }) - ) + } + })) + console.log("Done....") } return notifications diff --git a/src/kleros.js b/src/kleros.js index bcd9dba..e159866 100644 --- a/src/kleros.js +++ b/src/kleros.js @@ -85,7 +85,8 @@ class Kleros { await this.disputes.addDisputeEventListener(arbitratorAddress, account) await this.disputes.addTokenShiftToJurorProfileEventListener( arbitratorAddress, - account + account, + callback ) await this.notifications.registerNotificationListeners( arbitratorAddress, diff --git a/src/utils/StoreProviderWrapper.js b/src/utils/StoreProviderWrapper.js index 96f44db..e03bf43 100644 --- a/src/utils/StoreProviderWrapper.js +++ b/src/utils/StoreProviderWrapper.js @@ -218,7 +218,9 @@ class StoreProviderWrapper { fee, information, justification, - resolutionOptions + resolutionOptions, + createdAt, + ruledAt ) => { const httpResponse = await this._makeRequest( 'POST', @@ -238,7 +240,9 @@ class StoreProviderWrapper { fee, information, justification, - resolutionOptions + resolutionOptions, + createdAt, + ruledAt }) ) diff --git a/src/utils/Web3Wrapper.js b/src/utils/Web3Wrapper.js index e42a585..bbe065c 100644 --- a/src/utils/Web3Wrapper.js +++ b/src/utils/Web3Wrapper.js @@ -32,6 +32,8 @@ class Web3Wrapper { blockNumber = () => this._web3.eth.blockNumber + getBlock = () => this._web3.eth.getBlock + doesContractExistAtAddressAsync = async address => { const code = await this._web3.eth.getCode(address) // Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients From 8e9cafa1e75c621298fea7af1b5e067e5c5115f2 Mon Sep 17 00:00:00 2001 From: Sam Vitello Date: Tue, 27 Feb 2018 16:52:03 -0500 Subject: [PATCH 2/4] feat(disputes): createdAt and ruledAt timestamps added in events --- src/abstractWrappers/Disputes.js | 193 ++++++++++++++++---------- src/abstractWrappers/Notifications.js | 65 +++++---- src/constants/eth.js | 2 +- src/kleros.js | 5 + src/utils/StoreProviderWrapper.js | 5 +- src/utils/Web3Wrapper.js | 2 +- tests/kleros.test.js | 35 +++-- 7 files changed, 185 insertions(+), 122 deletions(-) diff --git a/src/abstractWrappers/Disputes.js b/src/abstractWrappers/Disputes.js index 04a274e..1dc421f 100644 --- a/src/abstractWrappers/Disputes.js +++ b/src/abstractWrappers/Disputes.js @@ -2,7 +2,7 @@ import _ from 'lodash' import * as ethConstants from '../constants/eth' import * as arbitratorConstants from '../constants/arbitrator' -import * as contractConstants from '../constants/contract' +import * as notificationConstants from '../constants/notification' import AbstractWrapper from './AbstractWrapper' @@ -28,7 +28,6 @@ class Disputes extends AbstractWrapper { contractAddress = arbitratorAddress, address = account ) => { - console.log("adding dispute for " + address) const disputeId = event.args._disputeID.toNumber() const disputeData = await this.getDataForDispute( contractAddress, @@ -37,12 +36,16 @@ class Disputes extends AbstractWrapper { ) // if listener is a party in dispute add to store if (disputeData.partyA === address || disputeData.partyB === address) { - console.log("should be for partyA") const blockNumber = event.blockNumber const block = this._Arbitrator._Web3Wrapper.getBlock(blockNumber) // add new dispute with timestamp - const dispute = await this._updateStoreForDispute(contractAddress, disputeId, address, block.timestamp) + await this._updateStoreForDispute( + contractAddress, + disputeId, + address, + block.timestamp * 1000 + ) } } @@ -103,11 +106,13 @@ class Disputes extends AbstractWrapper { ) } - addDisputeRulingHandler = async ( - arbitratorAddress, - account, - callback - ) => { + /** + * Event listener that sends notification when a dispute has been ruled on. + * @param {string} arbitratorAddress - The arbitrator contract's address. + * @param {string} account - The users eth account. + * @param {function} callback - function to be called when event is triggered. + */ + addDisputeRulingHandler = async (arbitratorAddress, account, callback) => { if (!this._eventListener) return const _disputeRulingHandler = async ( @@ -116,17 +121,17 @@ class Disputes extends AbstractWrapper { address = account, notificationCallback = callback ) => { - console.log("in handler") const newPeriod = event.args._period.toNumber() const txHash = event.transactionHash // send appeal possible notifications - if (newPeriod === PERIODS.APPEAL) { - console.log("doing the do") + if (newPeriod === arbitratorConstants.PERIOD.APPEAL) { this._checkArbitratorWrappersSet() const userProfile = await this._StoreProvider.getUserProfile(address) // contract data - const arbitratorData = await this._Arbitrator.getData(contractAddress, address) - const currentDisputes = [] + const arbitratorData = await this._Arbitrator.getData( + contractAddress, + address + ) let disputeId = 0 const currentSession = arbitratorData.session @@ -134,54 +139,81 @@ class Disputes extends AbstractWrapper { while (1) { // iterate over all disputes (FIXME inefficient) try { - dispute = await this._Arbitrator.getDispute(contractAddress, disputeId) - if (dispute.arbitratedContract === NULL_ADDRESS) break - // session + number of appeals - const disputeSession = dispute.firstSession + dispute.numberOfAppeals - // if dispute not in current session skip - if (disputeSession !== currentSession) { - disputeId++ - dispute = await this._Arbitrator.getDispute(contractAddress, disputeId) - continue - } - - const ruling = await this._Arbitrator.currentRulingForDispute(contractAddress, disputeId) - - if (_.findIndex(userProfile.disputes, dispute => { - return (dispute.disputeId === disputeId && dispute.arbitratorAddress === contractAddress) - }) >= 0) { - await this._StoreProvider.newNotification( - address, - txHash, - disputeId, // use disputeId instead of logIndex since it doens't have its own event - NOTIFICATION_TYPES.APPEAL_POSSIBLE, - 'A ruling has been made. Appeal is possible', - { - disputeId, - contractAddress, - ruling - } - ) - // get ruledAt from block timestamp - const blockNumber = event.blockNumber - const block = this._Arbitrator._Web3Wrapper.getBlock(blockNumber) - // add ruledAt to store - await this._updateStoreForDispute(contractAddress, disputeId, address, null, block.timestamp) - - if (callback) { - const userProfile = await this._StoreProvider.getUserProfile(address) - const notification = _.filter(userProfile.notifications, notification => { - return (notification.txHash === txHash && notification.logIndex === disputeId) - }) - - if (notification) { - callback(notification[0]) - } - } - } - // check next dispute - disputeId += 1 - } catch (e) { + dispute = await this._Arbitrator.getDispute( + contractAddress, + disputeId + ) + if (dispute.arbitratedContract === ethConstants.NULL_ADDRESS) break + // session + number of appeals + const disputeSession = + dispute.firstSession + dispute.numberOfAppeals + // if dispute not in current session skip + if (disputeSession !== currentSession) { + disputeId++ + dispute = await this._Arbitrator.getDispute( + contractAddress, + disputeId + ) + continue + } + + const ruling = await this._Arbitrator.currentRulingForDispute( + contractAddress, + disputeId + ) + + if ( + _.findIndex( + userProfile.disputes, + dispute => + dispute.disputeId === disputeId && + dispute.arbitratorAddress === contractAddress + ) >= 0 + ) { + await this._StoreProvider.newNotification( + address, + txHash, + disputeId, // use disputeId instead of logIndex since it doens't have its own event + notificationConstants.TYPE.APPEAL_POSSIBLE, + 'A ruling has been made. Appeal is possible', + { + disputeId, + contractAddress, + ruling + } + ) + // get ruledAt from block timestamp + const blockNumber = event.blockNumber + const block = this._Arbitrator._Web3Wrapper.getBlock(blockNumber) + // add ruledAt to store + await this._updateStoreForDispute( + contractAddress, + disputeId, + address, + null, + block.timestamp * 1000 + ) + + if (notificationCallback) { + const userProfile = await this._StoreProvider.getUserProfile( + address + ) + const notification = _.filter( + userProfile.notifications, + notification => + notification.txHash === txHash && + notification.logIndex === disputeId + ) + + if (notification) { + notificationCallback(notification[0]) + } + } + } + // check next dispute + disputeId += 1 + // eslint-disable-next-line no-unused-vars + } catch (err) { // getDispute(n) throws an error if index out of range break } @@ -189,7 +221,10 @@ class Disputes extends AbstractWrapper { } } - await this._eventListener.registerArbitratorEvent('NewPeriod', _disputeRulingHandler) + await this._eventListener.registerArbitratorEvent( + 'NewPeriod', + _disputeRulingHandler + ) } // **************************** // @@ -252,7 +287,7 @@ class Disputes extends AbstractWrapper { * Get disputes for user with extra data from arbitrated transaction and store * @param {string} arbitratorAddress address of Kleros contract * @param {string} account address of user - * @return {object[]} dispute data objects for user + * @returns {object[]} dispute data objects for user */ getDisputesForUser = async (arbitratorAddress, account) => { // FIXME don't like having to call this every fnc @@ -450,8 +485,8 @@ class Disputes extends AbstractWrapper { /** * Gets the deadline for an arbitrator's period, which is also the deadline for all its disputes. * @param {string} arbitratorAddress - The address of the arbitrator contract. - * @param {number} [period=arbitratorConstants.PERIOD.VOTE] - The period to get the deadline for. - * @returns {Date} - A date object. + * @param {number} [period=PERIODS.VOTE] - The period to get the deadline for. + * @returns {number} - epoch timestamp */ getDeadlineForDispute = async ( arbitratorAddress, @@ -469,11 +504,14 @@ class Disputes extends AbstractWrapper { } /** - * update store with new dispute data - * @param {string} arbitratorAddress Address address of arbitrator contract - * @param {int} disputeId index of dispute - * @param {string} account address of party to update dispute or - */ + * update store with new dispute data + * @param {string} arbitratorAddress Address address of arbitrator contract + * @param {int} disputeId index of dispute + * @param {string} account address of party to update dispute or + * @param {number} createdAt epoch timestamp of when dispute was created + * @param {number} ruledAt epoch timestamp of when dispute was ruled on + * @returns {object} updated dispute object + */ _updateStoreForDispute = async ( arbitratorAddress, disputeId, @@ -488,10 +526,11 @@ class Disputes extends AbstractWrapper { ) // update dispute - await this._StoreProvider.updateDispute( + const dispute = await this._StoreProvider.updateDispute( disputeData.disputeId, disputeData.arbitratorAddress, disputeData.hash, + disputeData.arbitrableContractAddress, disputeData.partyA, disputeData.partyB, disputeData.title, @@ -501,9 +540,9 @@ class Disputes extends AbstractWrapper { disputeData.information, disputeData.justification, disputeData.resolutionOptions, - createdAt ? createdAt : disputeData.createdAt, - ruledAt ? ruledAt : disputeData.ruledAt - ).body + createdAt || disputeData.createdAt, + ruledAt || disputeData.ruledAt + ) // update profile for account await this._StoreProvider.updateDisputeProfile( @@ -645,7 +684,7 @@ class Disputes extends AbstractWrapper { if (account) { votes = await this.getVotesForJuror(arbitratorAddress, disputeId, account) try { - const userData = await this.getUserDisputeFromStore( + const userData = await this._StoreProvider.getDisputeData( arbitratorAddress, disputeId, account @@ -708,7 +747,7 @@ class Disputes extends AbstractWrapper { netPNK, ruledAt, createdAt - }) + } } } diff --git a/src/abstractWrappers/Notifications.js b/src/abstractWrappers/Notifications.js index 8402979..4e5b6c0 100644 --- a/src/abstractWrappers/Notifications.js +++ b/src/abstractWrappers/Notifications.js @@ -160,34 +160,45 @@ class Notifications extends AbstractWrapper { } // Repartition and execute - if (currentPeriod === PERIODS.EXECUTE) { - console.log("Starting....") - await Promise.all(userProfile.disputes.map(async dispute => { - const disputeData = await this._Arbitrator.getDispute(dispute.arbitratorAddress, dispute.disputeId) - if (disputeData.firstSession + disputeData.numberOfAppeals === currentSession) { - if (disputeData.state <= DISPUTE_STATES.RESOLVING) { - notifications.push(this._createNotification( - NOTIFICATION_TYPES.CAN_REPARTITION, - "Ready to repartition dispute", - { - disputeId: dispute.disputeId, - arbitratorAddress: dispute.arbitratorAddress - } - )) - console.log("did stuff") - } else if (disputeData.state === DISPUTE_STATES.EXECUTABLE) { - notifications.push(this._createNotification( - NOTIFICATION_TYPES.CAN_EXECUTE, - "Ready to execute dispute", - { - disputeId: dispute.disputeId, - arbitratorAddress: dispute.arbitratorAddress - } - )) + if (currentPeriod === arbitratorConstants.PERIOD.EXECUTE) { + await Promise.all( + userProfile.disputes.map(async dispute => { + const disputeData = await this._Arbitrator.getDispute( + dispute.arbitratorAddress, + dispute.disputeId + ) + if ( + disputeData.firstSession + disputeData.numberOfAppeals === + currentSession + ) { + if (disputeData.state <= disputeConstants.STATE.RESOLVING) { + notifications.push( + this._createNotification( + notificationConstants.TYPE.CAN_REPARTITION, + 'Ready to repartition dispute', + { + disputeId: dispute.disputeId, + arbitratorAddress: dispute.arbitratorAddress + } + ) + ) + } else if ( + disputeData.state === disputeConstants.STATE.EXECUTABLE + ) { + notifications.push( + this._createNotification( + notificationConstants.TYPE.CAN_EXECUTE, + 'Ready to execute dispute', + { + disputeId: dispute.disputeId, + arbitratorAddress: dispute.arbitratorAddress + } + ) + ) + } } - } - })) - console.log("Done....") + }) + ) } return notifications diff --git a/src/constants/eth.js b/src/constants/eth.js index 857efe7..4724b63 100644 --- a/src/constants/eth.js +++ b/src/constants/eth.js @@ -1,5 +1,5 @@ export const LOCALHOST_ETH_PROVIDER = 'http://localhost:8545' -export const LOCALHOST_STORE_PROVIDER = 'https://kleros.in' +export const LOCALHOST_STORE_PROVIDER = 'http://localhost:3001' export const NULL_ADDRESS = '0x' diff --git a/src/kleros.js b/src/kleros.js index e159866..4cbc6b5 100644 --- a/src/kleros.js +++ b/src/kleros.js @@ -88,6 +88,11 @@ class Kleros { account, callback ) + await this.disputes.addDisputeRulingHandler( + arbitratorAddress, + account, + callback + ) await this.notifications.registerNotificationListeners( arbitratorAddress, account, diff --git a/src/utils/StoreProviderWrapper.js b/src/utils/StoreProviderWrapper.js index e03bf43..c318396 100644 --- a/src/utils/StoreProviderWrapper.js +++ b/src/utils/StoreProviderWrapper.js @@ -80,7 +80,7 @@ class StoreProviderWrapper { return httpResponse } - getDisputeData = async (userAddress, arbitratorAddress, disputeId) => { + getDisputeData = async (arbitratorAddress, disputeId, userAddress) => { const userProfile = await this.getUserProfile(userAddress) if (!userProfile) throw new Error(`No profile found for address: ${userAddress}`) @@ -91,7 +91,6 @@ class StoreProviderWrapper { o.arbitratorAddress === arbitratorAddress && o.disputeId === disputeId ) - if (_.isEmpty(disputeData)) return null const httpResponse = await this._makeRequest( 'GET', `${this._storeUri}/arbitrators/${arbitratorAddress}/disputes/${disputeId}` @@ -245,7 +244,6 @@ class StoreProviderWrapper { ruledAt }) ) - return httpResponse } @@ -306,7 +304,6 @@ class StoreProviderWrapper { data }) ) - return httpResponse } } diff --git a/src/utils/Web3Wrapper.js b/src/utils/Web3Wrapper.js index bbe065c..a2025a1 100644 --- a/src/utils/Web3Wrapper.js +++ b/src/utils/Web3Wrapper.js @@ -32,7 +32,7 @@ class Web3Wrapper { blockNumber = () => this._web3.eth.blockNumber - getBlock = () => this._web3.eth.getBlock + getBlock = blockNumber => this._web3.eth.getBlock(blockNumber) doesContractExistAtAddressAsync = async address => { const code = await this._web3.eth.getCode(address) diff --git a/tests/kleros.test.js b/tests/kleros.test.js index 8c51f51..83468d1 100644 --- a/tests/kleros.test.js +++ b/tests/kleros.test.js @@ -580,7 +580,7 @@ describe('Kleros', () => { }) let newState - // pass state so juror1s are selected + // 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) @@ -687,6 +687,7 @@ describe('Kleros', () => { // delay 1 second await delaySecond() + // move to execute period await KlerosInstance.arbitrator.passPeriod(klerosCourt.address, other) // stateful notifications @@ -700,13 +701,13 @@ describe('Kleros', () => { notificationConstants.TYPE.CAN_REPARTITION ) - partyBStatefullNotifications = await KlerosInstance.notifications.getStatefulNotifications( + let partyAStatefullNotifications = await KlerosInstance.notifications.getStatefulNotifications( klerosCourt.address, - partyB, + partyA, false ) - expect(partyBStatefullNotifications.length).toEqual(1) - expect(partyBStatefullNotifications[0].notificationType).toEqual( + expect(partyAStatefullNotifications.length).toEqual(1) + expect(partyAStatefullNotifications[0].notificationType).toEqual( notificationConstants.TYPE.CAN_REPARTITION ) @@ -731,13 +732,13 @@ describe('Kleros', () => { notificationConstants.TYPE.CAN_EXECUTE ) - partyBStatefullNotifications = await KlerosInstance.notifications.getStatefulNotifications( + partyAStatefullNotifications = await KlerosInstance.notifications.getStatefulNotifications( klerosCourt.address, - partyB, + partyA, false ) - expect(partyBStatefullNotifications.length).toEqual(1) - expect(partyBStatefullNotifications[0].notificationType).toEqual( + expect(partyAStatefullNotifications.length).toEqual(1) + expect(partyAStatefullNotifications[0].notificationType).toEqual( notificationConstants.TYPE.CAN_EXECUTE ) @@ -779,12 +780,12 @@ describe('Kleros', () => { ) expect(juror1StatefullNotifications.length).toEqual(0) - partyBStatefullNotifications = await KlerosInstance.notifications.getStatefulNotifications( + partyAStatefullNotifications = await KlerosInstance.notifications.getStatefulNotifications( klerosCourt.address, - partyB, + partyA, false ) - expect(partyBStatefullNotifications.length).toEqual(0) + expect(partyAStatefullNotifications.length).toEqual(0) expect(notifications.length).toBeTruthy() // partyA got notifications @@ -854,6 +855,16 @@ describe('Kleros', () => { KlerosInstance.eventListener.stopWatchingArbitratorEvents( klerosCourt.address ) + + // make sure createdAt set + const disputeData = await KlerosInstance.disputes.getDataForDispute( + klerosCourt.address, + 0, + partyA + ) + + expect(disputeData.createdAt).toBeTruthy() + expect(disputeData.ruledAt).toBeTruthy() }, 80000 ) From 3656d335a19da60e82381d322b69994d1447400e Mon Sep 17 00:00:00 2001 From: Sam Vitello Date: Tue, 27 Feb 2018 17:09:41 -0500 Subject: [PATCH 3/4] feat(disputes): submittedAt timestamp for evidence --- README.md | 2 +- src/constants/eth.js | 2 +- src/utils/StoreProviderWrapper.js | 10 ++++++---- tests/kleros.test.js | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e0ab2cd..8ee99cc 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@

+ NPM Version Build Status - npm version Coverage Status Dependencies Dev Dependencies diff --git a/src/constants/eth.js b/src/constants/eth.js index 4724b63..857efe7 100644 --- a/src/constants/eth.js +++ b/src/constants/eth.js @@ -1,5 +1,5 @@ export const LOCALHOST_ETH_PROVIDER = 'http://localhost:8545' -export const LOCALHOST_STORE_PROVIDER = 'http://localhost:3001' +export const LOCALHOST_STORE_PROVIDER = 'https://kleros.in' export const NULL_ADDRESS = '0x' diff --git a/src/utils/StoreProviderWrapper.js b/src/utils/StoreProviderWrapper.js index c318396..706d15f 100644 --- a/src/utils/StoreProviderWrapper.js +++ b/src/utils/StoreProviderWrapper.js @@ -21,9 +21,8 @@ class StoreProviderWrapper { let body = null try { body = JSON.parse(httpRequest.responseText) - } catch (err) { - console.log(err) - } + // eslint-disable-next-line no-unused-vars + } catch (err) {} resolve({ body: body, status: httpRequest.status @@ -153,13 +152,16 @@ class StoreProviderWrapper { } addEvidenceContract = async (address, account, name, description, url) => { + // get timestamp for submission + const submittedAt = new Date().getTime() const httpResponse = await this._makeRequest( 'POST', `${this._storeUri}/${account}/contracts/${address}/evidence`, JSON.stringify({ name, description, - url + url, + submittedAt }) ) diff --git a/tests/kleros.test.js b/tests/kleros.test.js index 83468d1..d788b5d 100644 --- a/tests/kleros.test.js +++ b/tests/kleros.test.js @@ -537,7 +537,6 @@ describe('Kleros', () => { expect(resolutionOptions.length).toEqual(2) // add an evidence for partyA - // FIXME use arbitrableTransaction const testName = 'test name' const testDesc = 'test description' const testURL = 'http://test.com' @@ -563,6 +562,7 @@ describe('Kleros', () => { ) expect(contractStoreData.evidences[0].url).toBe(testURL) + expect(contractStoreData.evidences[0].submittedAt).toBeTruthy() // check initial state of contract // FIXME var must be more explicit From f9eae71df35c9be3e5bb2d5b6b6804f836b23ecb Mon Sep 17 00:00:00 2001 From: epiqueras Date: Tue, 27 Feb 2018 17:03:36 -0800 Subject: [PATCH 4/4] chore(release): 0.0.62 --- CHANGELOG.md | 25 +++++++++++++++++++++++++ package.json | 15 ++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 914bf2b..ea99c10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +## 0.0.62 (2018-02-28) + + +### Bug Fixes + +* **getDeadlineForDispute:** fix wrong computation and return date object ([7ee05f5](https://github.com/kleros/kleros-api/commit/7ee05f5)) +* skip broken test assertions ([d210c53](https://github.com/kleros/kleros-api/commit/d210c53)) +* test suite ([98b777d](https://github.com/kleros/kleros-api/commit/98b777d)) + + +### Features + +* normalize token units ([d0d40f8](https://github.com/kleros/kleros-api/commit/d0d40f8)) +* **disputes:** build voteCounters and PNKRepartitions from getters ([ba48e67](https://github.com/kleros/kleros-api/commit/ba48e67)) +* **disputes:** change approach to getting netPNK and votesCounter ([366340f](https://github.com/kleros/kleros-api/commit/366340f)) +* **disputes:** createdAt and ruledAt timestamps added in events ([8e9cafa](https://github.com/kleros/kleros-api/commit/8e9cafa)) +* **disputes:** remove netPNK until events are fixed ([255bf03](https://github.com/kleros/kleros-api/commit/255bf03)) +* **disputes:** return appealsRepartitioned ([1246968](https://github.com/kleros/kleros-api/commit/1246968)) +* **disputes:** return deadline as epoch in ms instead of a date object ([90d4856](https://github.com/kleros/kleros-api/commit/90d4856)) +* **disputes:** return dispute status ([32db45c](https://github.com/kleros/kleros-api/commit/32db45c)) +* **disputes:** submittedAt timestamp for evidence ([3656d33](https://github.com/kleros/kleros-api/commit/3656d33)) + + + ## 0.0.61 (2018-02-27) diff --git a/package.json b/package.json index 4a1bb38..3e17dd1 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,12 @@ { "name": "kleros-api", - "version": "0.0.61", - "description": - "A Javascript library that makes it easy to build relayers and other DApps that use the Kleros protocol.", - "keywords": ["Blockchain", "Ethereum", "Kleros"], + "version": "0.0.62", + "description": "A Javascript library that makes it easy to build relayers and other DApps that use the Kleros protocol.", + "keywords": [ + "Blockchain", + "Ethereum", + "Kleros" + ], "homepage": "https://kleros.io", "repository": "github:kleros/kleros-api", "bugs": "https://github.com/kleros/kleros-api/issues", @@ -28,7 +31,9 @@ "build": "webpack --env.NODE_ENV=production -p" }, "commitlint": { - "extends": ["@commitlint/config-conventional"] + "extends": [ + "@commitlint/config-conventional" + ] }, "devDependencies": { "babel-core": "^6.26.0",