diff --git a/README.md b/README.md
index 8ee99cc..0c45b99 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,4 @@
-
- Kleros API
-
+# Kleros API
@@ -15,55 +13,83 @@
-> This repository contains a Javascript library that makes it easy to build Relayers and other DApps that use the Kleros protocol.
+> This repository contains a Javascript library that provides methods to interact with Kleros arbitrator
+ and Arbitrable contracts. It can be used to develop Relayers or DApps that use Kleros smart contracts.
## Installation
+```
+yarn add kleros-api
+```
-We assume that you have node and yarn installed.
+## Basic Usage
-```sh
-yarn install
-```
+See the full API docs [here](https://kleros.io/kleros-api/).
-## Test
+The base Kleros object initializes all of the different kleros api's with the contract
+addresses you pass. This object is useful if your application interacts with both arbitrators,
+arbitrable contracts and uses an off chain store to provide metadata on the different disputes
+for the UI.
-```sh
-yarn run ganache-cli
-yarn test
```
+// pay arbitration fee.
+import Kleros from 'kleros-api'
-## Develop
+const KlerosInstance = new Kleros(
+ ETH_PROVIDER, // ethereum provider object
+ KLEROS_STORE_URI, // uri of off chain storage e.g. https://kleros.in
+ ARITRATOR_CONTRACT_ADDRESS, // address of a deployed Kleros arbitrator contract
+ ARBITRABLE_CONTRACT_ADDRESS // address of a deployed arbitrable transaction contract
+)
-```sh
-yarn start
+KlerosInstance.arbitrable.payArbitrationFeeByPartyA() // pay arbitration fee for an arbitrable contract
```
-## Build
+You can also use the specific api that best suits your needs.
-```sh
-yarn run build
+```
+// deploy a new contract and pay the arbitration fee.
+import ArbitrableTransaction from 'kleros-api/contracts/implementations/arbitrable/ArbitrableTransaction'
+
+// deploy methods are static
+const contractInstance = ArbitrableTransaction.deploy(
+ "0x67a3f2BB8B4B2060875Bd6543156401B817bEd22", // users address
+ 0.15, // amount of ETH to escrow
+ "0x0", // hash of the off chain contract
+ "0x3af76ef44932695a33ba2af52018cd24a74c904f", // arbitrator address
+ 3600, // number of seconds until there is a timeout
+ "0x0474b723bd4986808366E0DcC2E301515Aa742B4", // the other party in the contract
+ "0x0", // extra data in bytes. This can be used to interact with the arbitrator contract
+ ETH_PROVIDER, // provider object to be used to interact with the network
+ )
+
+const address = contractInstance.address // get the address of your newly created contract
+
+const ArbitrableTransactionInstance = new ArbitrableTransaction(address) // instantiate instance of the api
+
+ArbitrableTransactionInstance.payArbitrationFeeByPartyA() // pay arbitration fee
```
-## Event Listeners
+## Development
-For notifications and event based updates, the api uses event listeners. In order to register and start listening to events, use these methods:
+If you want to contribute to our api or modify it for your usage
-##### Quick Start
+## Setup
-To register all events and start the listener, call:
+We assume that you have node and yarn installed.
```sh
-KlerosInstance.watchForEvents(arbitratorAddress, account, callback)
+yarn install
```
-params:
+## Test
-* arbitratorAddress: Address of arbitrator contract. Needed to update the store for disputes.
-* account: Address used for notification callbacks. If an address is provided, push notifications will only be sent for notifications that involve the address. If it is omitted and a callback is included, all notifications will be pushed.
-* callback: Function to be called for push notifications.
+```sh
+yarn run ganache-cli
+yarn test
+```
-##### Stop Listener
+## Build
```sh
-KlerosInstance.eventListener.stopWatchingArbitratorEvents(arbitratorAddress)
+yarn run build
```
diff --git a/src/constants/arbitrator.js b/constants/arbitrator.js
similarity index 100%
rename from src/constants/arbitrator.js
rename to constants/arbitrator.js
diff --git a/src/constants/contract.js b/constants/contract.js
similarity index 100%
rename from src/constants/contract.js
rename to constants/contract.js
diff --git a/src/constants/dispute.js b/constants/dispute.js
similarity index 100%
rename from src/constants/dispute.js
rename to constants/dispute.js
diff --git a/src/constants/error.js b/constants/error.js
similarity index 100%
rename from src/constants/error.js
rename to constants/error.js
diff --git a/src/constants/eth.js b/constants/eth.js
similarity index 100%
rename from src/constants/eth.js
rename to constants/eth.js
diff --git a/src/constants/notification.js b/constants/notification.js
similarity index 100%
rename from src/constants/notification.js
rename to constants/notification.js
diff --git a/deploy_docs.sh b/deploy_docs.sh
new file mode 100755
index 0000000..8a1ee70
--- /dev/null
+++ b/deploy_docs.sh
@@ -0,0 +1,18 @@
+# Remove old docs dir
+rm -rf docs || exit 0;
+# Build docs
+yarn run docs;
+
+# Set up new directory
+mkdir ../esdocs;
+cp -r docs/* ../esdocs/;
+
+# github pages. must be run by user with ssh write access to kleros-api
+cd ../esdocs;
+git init;
+git add .;
+git commit -m "Deploy to GitHub Pages";
+git push --force --quiet "git@github.com:kleros/kleros-api.git" master:gh-pages;
+
+# cleanup
+rm -rf ../esdocs;
diff --git a/package.json b/package.json
index c5d8315..c474da0 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"license": "MIT",
"private": false,
"scripts": {
+ "docs": "esdoc",
"prettify": "kleros-scripts prettify",
"lint": "kleros-scripts lint:js --config ./.eslintrc.js",
"ganache": "ganache-cli -a 15",
diff --git a/src/contracts/AbstractContract.js b/src/contracts/AbstractContract.js
index 7f8187e..1fb4f62 100644
--- a/src/contracts/AbstractContract.js
+++ b/src/contracts/AbstractContract.js
@@ -3,6 +3,11 @@ import _ from 'lodash'
import isRequired from '../utils/isRequired'
import delegateCalls from '../utils/delegateCalls'
+/**
+ * Abstract Contract holds a contract implementation to make calls to the blockchain but
+ * also includes methods that interact with the off chain store. NOTE all methods that
+ * the underlying contract implementation expose can be called directly from an Abstract contract.
+ */
class AbstractContract {
/**
* AbstractContract wraps an implementation instance to provide access to higher level
diff --git a/src/contracts/ContractImplementation.js b/src/contracts/ContractImplementation.js
index 57a27bf..02d303d 100644
--- a/src/contracts/ContractImplementation.js
+++ b/src/contracts/ContractImplementation.js
@@ -2,9 +2,13 @@ import contract from 'truffle-contract'
import _ from 'lodash'
import isRequired from '../utils/isRequired'
-import * as errorConstants from '../constants/error'
+import * as errorConstants from '../../constants/error'
import Web3Wrapper from '../utils/Web3Wrapper'
+/**
+ * ContractImplementation is a parent class for on chain contracts. It loads the contract from the
+ * blockchain and exposes the contract instance for use by the child.
+ */
class ContractImplementation {
constructor(
web3Provider = isRequired('web3Provider'),
@@ -120,6 +124,10 @@ class ContractImplementation {
}
}
+ /**
+ * Create a new Promise to be used in loading the contract.
+ * @returns {Promise} - Resolves to contract instance.
+ */
_newLoadingPromise = () =>
new Promise((resolve, reject) => {
this._contractLoadedResolver = resolve
@@ -127,7 +135,10 @@ class ContractImplementation {
})
// we have getters so that abstract classes can provide public access to implementations variables
- getContractInstance = () => this.contractInstance
+ /**
+ * Get the contract address for the currently instantiated contract.
+ * @returns {string} - The address of the contract.
+ */
getContractAddress = () => this.contractAddress
}
diff --git a/src/contracts/abstractions/Arbitrable.js b/src/contracts/abstractions/Arbitrable.js
index 113b0ca..2081335 100644
--- a/src/contracts/abstractions/Arbitrable.js
+++ b/src/contracts/abstractions/Arbitrable.js
@@ -1,7 +1,10 @@
import AbstractContract from '../AbstractContract'
/**
- * Arbitrable Contract API.
+ * 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 {
/**
diff --git a/src/contracts/abstractions/Arbitrator.js b/src/contracts/abstractions/Arbitrator.js
index aca5dd9..ae38277 100644
--- a/src/contracts/abstractions/Arbitrator.js
+++ b/src/contracts/abstractions/Arbitrator.js
@@ -1,10 +1,13 @@
import _ from 'lodash'
-import * as arbitratorConstants from '../../constants/arbitrator'
+import * as arbitratorConstants from '../../../constants/arbitrator'
import AbstractContract from '../AbstractContract'
/**
- * Arbitrator API.
+ * Arbitrator Abstract Contarct API. This wraps an arbitrator contract. It provides
+ * interaction with both the off chain store as well as the arbitrator instance. All
+ * arbitrator methods from the supplied contract implementation can be called from this
+ * object.
*/
class Arbitrator extends AbstractContract {
/**
diff --git a/src/contracts/implementations/PNK/PinakionPOC.js b/src/contracts/implementations/PNK/PinakionPOC.js
index 916ff29..eb66599 100644
--- a/src/contracts/implementations/PNK/PinakionPOC.js
+++ b/src/contracts/implementations/PNK/PinakionPOC.js
@@ -1,17 +1,17 @@
import PinakionPOCArtifact from 'kleros/build/contracts/PinakionPOC' // FIXME: mock
import _ from 'lodash'
-import * as ethConstants from '../../../constants/eth'
-import * as errorConstants from '../../../constants/error'
+import * as ethConstants from '../../../../constants/eth'
+import * as errorConstants from '../../../../constants/error'
import ContractImplementation from '../../ContractImplementation'
import deployContractAsync from '../../../utils/deployContractAsync'
/**
- * Kleros API
+ * Provides interaction with a PinakionPOC contract deployed on the blockchain.
*/
class PinakionPOC extends ContractImplementation {
/**
- * Constructor Kleros.
+ * Constructor PinakionPOC.
* @param {object} web3Provider - web3 instance.
* @param {string} contractAddress - of the contract (optionnal).
*/
@@ -20,7 +20,7 @@ class PinakionPOC extends ContractImplementation {
}
/**
- * Kleros deploy.
+ * Deploy a new instance of PinakionPOC.
* @param {string} account - account of user
* @param {object} web3Provider - web3 provider object
* @returns {object} - 'truffle-contract' Object | err The contract object or error deploy.
@@ -37,7 +37,7 @@ class PinakionPOC extends ContractImplementation {
}
/**
- * change the kleros contract in the PNK contract.
+ * Change the kleros contract variable in instance of PinakionPOC.
* @param {string} klerosAddress - Address of Kleros POC contract.
* @param {string} account - Address of user.
* @returns {object} - The result transaction object.
@@ -60,7 +60,7 @@ class PinakionPOC extends ContractImplementation {
}
/**
- * transfer ownership of the PNK contract to the kleros POC contract.
+ * Transfer ownership of the PNK contract to the kleros POC contract.
* @param {string} klerosAddress - Address of Kleros POC contract.
* @param {string} account - Address of user.
* @returns {object} - The result transaction object.
diff --git a/src/contracts/implementations/RNG/BlockHashRNG.js b/src/contracts/implementations/RNG/BlockHashRNG.js
index 94512d7..fe289c9 100644
--- a/src/contracts/implementations/RNG/BlockHashRNG.js
+++ b/src/contracts/implementations/RNG/BlockHashRNG.js
@@ -1,16 +1,16 @@
import BlockHashRNGArtifact from 'kleros-interaction/build/contracts/BlockHashRNG'
import _ from 'lodash'
-import * as ethConstants from '../../../constants/eth'
+import * as ethConstants from '../../../../constants/eth'
import ContractImplementation from '../../ContractImplementation'
import deployContractAsync from '../../../utils/deployContractAsync'
/**
- * Kleros API
+ * Provides interaction with an instance of BlockHashRNG.
*/
class BlockHashRNG extends ContractImplementation {
/**
- * Constructor Kleros.
+ * Constructor BlockHashRNG.
* @param {object} web3Provider - instance
* @param {string} contractAddress - of the contract (optionnal)
*/
@@ -19,7 +19,7 @@ class BlockHashRNG extends ContractImplementation {
}
/**
- * Kleros deploy.
+ * BlockHashRNG deploy.
* @param {string} account - users account
* @param {object} web3Provider - web3 provider object
* @returns {object} - truffle-contract Object | err The contract object or error deploy
diff --git a/src/contracts/implementations/RNG/index.js b/src/contracts/implementations/RNG/index.js
index 6e89814..44d9eab 100644
--- a/src/contracts/implementations/RNG/index.js
+++ b/src/contracts/implementations/RNG/index.js
@@ -1,3 +1,3 @@
-import _BlockHashRNG from './BlockHashRNG'
+import BlockHashRNG from './BlockHashRNG'
-export const BlockHashRNG = _BlockHashRNG
+export { BlockHashRNG }
diff --git a/src/contracts/implementations/arbitrable/ArbitrableTransaction.js b/src/contracts/implementations/arbitrable/ArbitrableTransaction.js
index 12ab61f..7772689 100644
--- a/src/contracts/implementations/arbitrable/ArbitrableTransaction.js
+++ b/src/contracts/implementations/arbitrable/ArbitrableTransaction.js
@@ -1,14 +1,14 @@
import arbitrableTransactionArtifact from 'kleros-interaction/build/contracts/ArbitrableTransaction'
import _ from 'lodash'
-import * as ethConstants from '../../../constants/eth'
-import * as contractConstants from '../../../constants/contract'
-import * as errorConstants from '../../../constants/error'
+import * as ethConstants from '../../../../constants/eth'
+import * as contractConstants from '../../../../constants/contract'
+import * as errorConstants from '../../../../constants/error'
import ContractImplementation from '../../ContractImplementation'
import deployContractAsync from '../../../utils/deployContractAsync'
/**
- * ArbitrableTransaction API
+ * Provides interaction with an Arbitrable Transaction contract deployed on the blockchain.
*/
class ArbitrableTransaction extends ContractImplementation {
/**
@@ -217,7 +217,6 @@ class ArbitrableTransaction extends ContractImplementation {
/**
* Get ruling options from dispute via event
- * FIXME this can be an abstract method as it is in the standard
* @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
diff --git a/src/contracts/implementations/arbitrator/KlerosPOC.js b/src/contracts/implementations/arbitrator/KlerosPOC.js
index 594bc32..8975934 100644
--- a/src/contracts/implementations/arbitrator/KlerosPOC.js
+++ b/src/contracts/implementations/arbitrator/KlerosPOC.js
@@ -1,18 +1,18 @@
import klerosArtifact from 'kleros/build/contracts/KlerosPOC'
import _ from 'lodash'
-import * as ethConstants from '../../../constants/eth'
-import * as errorConstants from '../../../constants/error'
-import * as arbitratorConstants from '../../../constants/arbitrator'
+import * as ethConstants from '../../../../constants/eth'
+import * as errorConstants from '../../../../constants/error'
+import * as arbitratorConstants from '../../../../constants/arbitrator'
import ContractImplementation from '../../ContractImplementation'
import deployContractAsync from '../../../utils/deployContractAsync'
/**
- * Kleros API
+ * Provides interaction with a KlerosPOC contract on the blockchain.
*/
class KlerosPOC extends ContractImplementation {
/**
- * Constructor Kleros.
+ * Create new KlerosPOC Implementation.
* @param {object} web3Provider - web3 instance.
* @param {string} contractAddress - Address of the KlerosPOC contract.
*/
@@ -21,7 +21,7 @@ class KlerosPOC extends ContractImplementation {
}
/**
- * STATIC: Deploy a kleros instance
+ * STATIC: Deploy a KlerosPOC contract on the blockchain.
* @param {string} rngAddress address of random number generator contract
* @param {string} pnkAddress address of pinakion contract
* @param {number[]} timesPerPeriod array of 5 ints indicating the time limit for each period of contract
@@ -52,7 +52,7 @@ class KlerosPOC extends ContractImplementation {
}
/**
- * Use Arbitrator.buyPNK
+ * Purchase PNK.
* @param {string} amount - The number of pinakion to buy.
* @param {string} account - The address of the user.
* @returns {object} - The result transaction object.
@@ -113,7 +113,6 @@ class KlerosPOC extends ContractImplementation {
/**
* Activate Pinakion tokens to be eligible to be a juror.
- * FIXME use estimateGas
* @param {string} amount - number of tokens to activate.
* @param {string} account - address of user.
* @returns {object} - PNK balance.
@@ -141,7 +140,7 @@ class KlerosPOC extends ContractImplementation {
}
/**
- * Fetch the cost of arbitration
+ * Fetch the cost of arbitration.
* @param {bytes} contractExtraData - extra data from arbitrable contract.
* @returns {number} - The cost of arbitration.
*/
diff --git a/src/kleros.js b/src/kleros.js
index d652d7e..4da8e8b 100644
--- a/src/kleros.js
+++ b/src/kleros.js
@@ -5,6 +5,13 @@ import * as contracts from './contracts'
import * as resources from './resources'
import EventListener from './utils/EventListener'
+/**
+ * The Kleros Api provides access to the full suite of functionality. It will initialize
+ * contract instances for you when possible and creates an object that you can use to
+ * call all of the other api modules. If you are only going to be interacting with
+ * specific apis, or you don't want certain functionality such as the off chain store,
+ * you might find it easier to initialze a specific instance of the api you want.
+ */
class Kleros {
web3Wrapper = {}
@@ -19,7 +26,7 @@ class Kleros {
* @param {string} ethereumProvider - The Web3.js Provider instance you would like the
* Kleros.js library to use for interacting with the
* Ethereum network.
- * @param {string} storeUri - The storage provider uri used to
+ * @param {string} storeUri - The storage provider uri used to
* get metadata from the cloud for the UI. e.g. Kleros-Store,
* IPFS, Swarm etc.
* @param {string} arbitratorAddress - Address of the arbitrator contract we should
@@ -73,11 +80,18 @@ class Kleros {
)
}
- setArbitrableContractAddress = contractAddress =>
+ /**
+ * Set a new arbitrable contract for Kleros instance of arbitrableContracts
+ * @param {string} contractAddress - Address of arbitrable contract
+ */
+ setArbitrableContractAddress = contractAddress => {
this.arbitrableContracts.setContractInstance(contractAddress)
+ }
/**
- * Entry point to set up all event listerners and to start the events watcher
+ * Bootstraps an EventListener and adds all Kleros handlers for event logs. Use
+ * this if you want to watch the chain for notifications, or are using the off chain
+ * store for metadata.
* @param {string} account Address of the user
* @param {function} callback The function to be called once a notification
*/
@@ -106,7 +120,14 @@ class Kleros {
}
/**
- * set store provider in all high level wrappers
+ * Stop watching for events on the Arbitrator initialized in the Kleros Instance.
+ */
+ stopWatchingForEvents = () => {
+ this.eventListener.stopWatchingForEvents(this.arbitrator)
+ }
+
+ /**
+ * Sets the store provider uri for all higher level apis in the Kleros Instance.
* @param {string} storeUri - The URI that the store provider will use
*/
setStoreProvider = storeUri => {
diff --git a/src/resources/Disputes.js b/src/resources/Disputes.js
index 0002c44..7fa18c8 100644
--- a/src/resources/Disputes.js
+++ b/src/resources/Disputes.js
@@ -1,12 +1,12 @@
import _ from 'lodash'
-import * as arbitratorConstants from '../constants/arbitrator'
-import * as disputeConstants from '../constants/dispute'
+import * as arbitratorConstants from '../../constants/arbitrator'
+import * as disputeConstants from '../../constants/dispute'
import isRequired from '../utils/isRequired'
/**
- * Disputes API.
- * Requires Store Provider to be set to call methods.
+ * Disputes API. Provides cross arbitrator and arbitrable contracts functionality.
+ * Requires Store Provider to be set.
*/
class Disputes {
constructor(
@@ -44,6 +44,11 @@ class Disputes {
// * Events * //
// **************************** //
+ /**
+ * Method to register all dispute handlers to an EventListener.
+ * @param {object} eventListener - The EventListener instance. See utils/EventListener.js.
+ * @param {string} account - The address of the user.
+ */
registerStoreUpdateEventListeners = (
eventListener = isRequired('eventListener'),
account = isRequired('account')
@@ -66,7 +71,7 @@ class Disputes {
}
/**
- * Store dispute in store upon creation
+ * Event listener handler that stores dispute in store upon creation
* @param {string} event - The event log.
*/
_storeNewDisputeHandler = async event => {
@@ -110,7 +115,7 @@ class Disputes {
}
/**
- * Add or substract the stored Net PNK won/lost for a juror.
+ * Event listener handler that add or substract the stored Net PNK won/lost for a juror.
* @param {string} event - The event log.
* @param {string} account - The account.
*/
@@ -146,7 +151,7 @@ class Disputes {
}
/**
- * Event listener that updates ruled at timestamp
+ * Event listener handler that updates ruled at timestamp
* @param {object} event - The event log.
* @param {string} account - The users eth account.
*/
@@ -198,7 +203,7 @@ class Disputes {
}
/**
- * Event listener that sets the deadline for an appeal
+ * Event listener handler that sets the deadline for an appeal
* @param {object} event - The event log.
* @param {string} account - The users eth account.
*/
@@ -249,11 +254,11 @@ class Disputes {
// * Public * //
// **************************** //
/**
- * Get data for a dispute.
+ * Get data for a dispute. This method provides data from the store as well as both
+ * arbitrator and arbitrable contracts. Used to get all relevant data on a dispute.
* @param {number} disputeId - The dispute's ID.
* @param {string} account - The juror's address.
* @returns {object} - Data object for the dispute that uses data from the contract and the store.
- * TODO: Should we return what we have in the store even if dispute is not in the contract?
*/
getDataForDispute = async (disputeId, account) => {
const arbitratorAddress = this._ArbitratorInstance.getContractAddress()
diff --git a/src/resources/Notifications.js b/src/resources/Notifications.js
index edf45ae..9f8cc79 100644
--- a/src/resources/Notifications.js
+++ b/src/resources/Notifications.js
@@ -1,13 +1,14 @@
import _ from 'lodash'
-import * as arbitratorConstants from '../constants/arbitrator'
-import * as notificationConstants from '../constants/notification'
-import * as disputeConstants from '../constants/dispute'
-import { MISSING_STORE_PROVIDER } from '../constants/error'
+import * as arbitratorConstants from '../../constants/arbitrator'
+import * as notificationConstants from '../../constants/notification'
+import * as disputeConstants from '../../constants/dispute'
+import { MISSING_STORE_PROVIDER } from '../../constants/error'
import isRequired from '../utils/isRequired'
/**
- * Notifications API.
+ * Notifications API. Use this object to fetch notifications from the store, register
+ * event log handlers to update store and send push notifications.
*/
class Notifications {
constructor(
@@ -46,7 +47,7 @@ class Notifications {
// **************************** //
/**
- * register event handlers for the arbitrator instance.
+ * Register event handlers for the arbitrator instance.
* @param {string} account - Filter notifications for account.
* @param {object} eventListener - Event Listener that will fetch logs and call callbacks
* @param {function} callback - If we want notifications to be "pushed" provide a callback function to call when a new notification is created.
@@ -99,7 +100,7 @@ class Notifications {
*/
if (currentPeriod === arbitratorConstants.PERIOD.ACTIVATION) {
// FIXME use estimateGas
- const contractInstance = this._ArbitratorInstance.getContractInstance()
+ const contractInstance = await this._ArbitratorInstance.loadContract()
const lastActivatedSession = (await contractInstance.jurors(
account
))[2].toNumber()
@@ -435,8 +436,7 @@ class Notifications {
}
/**
- * Handler for TokenShift event
- * Sends notification informing
+ * Handler for TokenShift event.
* NOTE: you will get a notification for each vote. So a juror that has 3 votes will receive 3 notifications
* @param {object} event - The event log.
* @param {string} account - The user account.
diff --git a/src/utils/EventListener.js b/src/utils/EventListener.js
index 79b53cf..ad98745 100644
--- a/src/utils/EventListener.js
+++ b/src/utils/EventListener.js
@@ -2,8 +2,13 @@ import _ from 'lodash'
import PromiseQueue from '../utils/PromiseQueue'
import isRequired from '../utils/isRequired'
-import * as errorConstants from '../constants/error'
+import * as errorConstants from '../../constants/error'
+/**
+ * EventListener is used to watch events on the blockchain for a set of contracts.
+ * Handlers for specific events can be added. When an event log is found EventListener
+ * will fire all handlers registered for the contract.
+ */
class EventListener {
/**
* Listen for events in contract and handles callbacks with registered event handlers.
@@ -24,7 +29,7 @@ class EventListener {
}
/**
- * Fetch all logs from contractInstance in range.
+ * Fetch all logs from contractInstance in a block range.
* @param {object} contractImplementationInstance - Contract Implementation instance.
* @param {number} firstBlock - Lower bound of search range.
* @param {number} lastBlock - Upper bound of search range.
@@ -52,7 +57,7 @@ class EventListener {
)
/**
- * Fetch all logs from contractInstance for event in range.
+ * Fetch logs from contractInstance for a specific event in a block range.
* @param {object} contractImplementationInstance - contract Implementation instance.
* @param {string} eventName - Name of the event.
* @param {number} firstBlock - Lower bound of search range.
@@ -82,7 +87,7 @@ class EventListener {
)
/**
- * Add contract instance to poll for events.
+ * Add a contract instance to watch for new event logs.
* @param {object} contractImplementationInstance - Contract Implementation instance
*/
addContractImplementation = contractImplementationInstance => {
@@ -93,7 +98,7 @@ class EventListener {
}
/**
- * Remove contract instance. Will also remove all handlers.
+ * Remove contract instance being watched. Will also remove all handlers.
* @param {string} contractImplementationInstance - contract implementation instance
*/
removeContractInstance = (
@@ -118,7 +123,7 @@ class EventListener {
}
/**
- * Add event handler that will be called when event is broadcasted.
+ * Add event handler that will be called when event log is found.
* @param {string} contractImplementationInstance - Contract implementation instance
* @param {string} eventName - Name of event.
* @param {function} handler - Function to be called when event is consumed.
@@ -135,7 +140,7 @@ class EventListener {
}
/**
- * Watch for events on each contract instance. Call registered handlers on logs
+ * Watch for events on all contract instances. Call registered handlers when logs are found.
* @param {number} fromBlock - A block number can be passed to catch up on missed logs
* @returns {Promise} - Promise resolves when all watchers have been started
*/
@@ -169,7 +174,7 @@ class EventListener {
)
/**
- * Stop listening on contract. If no contractAddress supplied it stops all listeners
+ * Stop listening on contract. If no contractAddress supplied it stops all listeners.
* @param {string} contractImplementationInstance - Address of the contract to stop watching
*/
stopWatchingForEvents = contractImplementationInstance => {
diff --git a/src/utils/PromiseQueue.js b/src/utils/PromiseQueue.js
index d86edb2..03d683f 100644
--- a/src/utils/PromiseQueue.js
+++ b/src/utils/PromiseQueue.js
@@ -1,3 +1,7 @@
+/**
+ * Chain promises so that they are evaluated in order.
+ * @returns {object} - The promise queue object.
+ */
const PromiseQueue = () => {
let promise = Promise.resolve()
diff --git a/src/utils/StoreProviderWrapper.js b/src/utils/StoreProviderWrapper.js
index 0bbf65e..e386e0e 100644
--- a/src/utils/StoreProviderWrapper.js
+++ b/src/utils/StoreProviderWrapper.js
@@ -1,15 +1,29 @@
import _ from 'lodash'
-import * as errorConstants from '../constants/error'
+import * as errorConstants from '../../constants/error'
import PromiseQueue from './PromiseQueue'
+/**
+ * A wrapper for interacting with Kleros Store.
+ */
class StoreProviderWrapper {
+ /**
+ * Create a new instance of StoreProviderWrapper.
+ * @param {string} storeProviderUri - The uri of kleros store.
+ */
constructor(storeProviderUri) {
this._storeUri = storeProviderUri
this._storeQueue = new PromiseQueue()
}
+ /**
+ * Helper method for sending an http request to kleros store.
+ * @param {string} verb - HTTP verb to be used in request. E.g. GET, POST, PUT.
+ * @param {string} uri - The uri to send the request to.
+ * @param {string} body - json string of the body.
+ * @returns {Promise} request promise that resolves to the HTTP response.
+ */
_makeRequest = (verb, uri, body = null) => {
const httpRequest = new XMLHttpRequest()
return new Promise((resolve, reject) => {
@@ -56,7 +70,7 @@ class StoreProviderWrapper {
/**
* If we know we are waiting on some other write before we want to read we can add a read request to the end of the queue.
* @param {string} uri uri to hit
- * @returns {promise} promise of the result function
+ * @returns {Promise} promise of the result function
*/
queueReadRequest = uri =>
this._storeQueue.fetch(() => this._makeRequest('GET', uri))
@@ -65,6 +79,11 @@ class StoreProviderWrapper {
// * Read * //
// **************************** //
+ /**
+ * Fetch stored user profile.
+ * @param {string} userAddress - Address of user.
+ * @returns {object} - a response object.
+ */
getUserProfile = async userAddress => {
const httpResponse = await this._makeRequest(
'GET',
@@ -74,6 +93,14 @@ class StoreProviderWrapper {
return httpResponse.body
}
+ /**
+ * Get all stored data from a dispute. This includes data from the user profile as well
+ * as the user agnostic dispute data stored separately.
+ * @param {string} arbitratorAddress - Address of arbitrator contract.
+ * @param {number} disputeId - Index of the dispute.
+ * @param {string} userAddress - Address of user.
+ * @returns {object} - a response object.
+ */
getDisputeData = async (arbitratorAddress, disputeId, userAddress) => {
const userProfile = await this.getUserProfile(userAddress)
if (!userProfile)
@@ -92,17 +119,12 @@ class StoreProviderWrapper {
return Object.assign({}, httpResponse.body, disputeData[0])
}
- getContractByHash = async (userAddress, hash) => {
- const userProfile = await this.getUserProfile(userAddress)
- if (!userProfile)
- throw new Error(errorConstants.PROFILE_NOT_FOUND(userAddress))
-
- let contractData = _.filter(userProfile.contracts, o => o.hash === hash)
-
- if (contractData.length === 0) return null
- return contractData[0]
- }
-
+ /**
+ * Fetch stored data on a contract for a user.
+ * @param {string} userAddress - Address of the user.
+ * @param {string} addressContract - The address of the contract.
+ * @returns {object} - Contact data.
+ */
getContractByAddress = async (userAddress, addressContract) => {
const userProfile = await this.getUserProfile(userAddress)
if (!userProfile)
@@ -116,8 +138,13 @@ class StoreProviderWrapper {
return contract[0]
}
- getDisputesForUser = async address => {
- const userProfile = await this.getUserProfile(address)
+ /**
+ * Fetch stored disputes for a user.
+ * @param {string} userAddress - Address of user.
+ * @returns {object} - a response object.
+ */
+ getDisputesForUser = async userAddress => {
+ const userProfile = await this.getUserProfile(userAddress)
if (!userProfile) return []
const disputes = []
@@ -139,12 +166,23 @@ class StoreProviderWrapper {
return disputes
}
- getLastBlock = async account => {
- const userProfile = await this.getUserProfile(account)
+ /**
+ * Fetch the last block seen for a user. This is commonly used with EventListerer.
+ * @param {string} userAddress - Address of user.
+ * @returns {number} The last block number.
+ */
+ getLastBlock = async userAddress => {
+ const userProfile = await this.getUserProfile(userAddress)
return userProfile.lastBlock || 0
}
+ /**
+ * Fetch user agnostic data stored on a dispute
+ * @param {string} arbitratorAddress - The address of the arbitrator contract.
+ * @param {number} disputeId - The index of the dispute.
+ * @returns {object} - a response object.
+ */
getDispute = async (arbitratorAddress, disputeId) => {
const httpResponse = await this._makeRequest(
'GET',
@@ -158,36 +196,20 @@ class StoreProviderWrapper {
// * Write * //
// **************************** //
- resetUserProfile = async account => {
- const getBodyFn = () =>
- new Promise(resolve =>
- resolve(
- JSON.stringify({
- account
- })
- )
- )
-
- return this.queueWriteRequest(
- getBodyFn,
- 'POST',
- `${this._storeUri}/${account}`
- )
- }
-
/**
- * Update user profile. NOTE: This should only be used for session and lastBlock. It is dangerous to overwrite arrays
- * @param {string} account users account
- * @param {object} params object containing kwargs to update
- * @returns {promise} resulting profile
+ * Update user profile. WARNING: This should only be used for session and lastBlock.
+ * Overwriting arrays of unstructured data can lead to data loss.
+ * @param {string} userAddress - users userAddress
+ * @param {object} params - object containing kwargs to update
+ * @returns {promise} - resulting profile
*/
- updateUserProfile = (account, params = {}) => {
+ updateUserProfile = (userAddress, params = {}) => {
const getBodyFn = async () => {
- const currentProfile = (await this.getUserProfile(account)) || {}
+ const currentProfile = (await this.getUserProfile(userAddress)) || {}
delete currentProfile._id
delete currentProfile.created_at
- params.address = account
+ params.address = userAddress
return JSON.stringify({ ...currentProfile, ...params })
}
@@ -195,35 +217,44 @@ class StoreProviderWrapper {
return this.queueWriteRequest(
getBodyFn,
'POST',
- `${this._storeUri}/${account}`
+ `${this._storeUri}/${userAddress}`
)
}
/**
- * Set up a new user profile if one does not exist
- * @param {string} account user's address
- * @returns {object} users existing or created profile
+ * Set up a new user profile if one does not exist.
+ * @param {string} userAddress - user's address
+ * @returns {object} - users existing or created profile
*/
- setUpUserProfile = async account => {
- let userProfile = await this.getUserProfile(account)
+ setUpUserProfile = async userAddress => {
+ let userProfile = await this.getUserProfile(userAddress)
if (_.isNull(userProfile)) {
- this.updateUserProfile(account, {})
- userProfile = await this.queueReadRequest(`${this._storeUri}/${account}`)
+ this.updateUserProfile(userAddress, {})
+ userProfile = await this.queueReadRequest(
+ `${this._storeUri}/${userAddress}`
+ )
}
return userProfile
}
- updateContract = (account, address, params) => {
+ /**
+ * Update the stored data on a contract for a user.
+ * @param {string} userAddress - The user's address.
+ * @param {string} contractAddress - The address of the contract.
+ * @param {object} params - Params we want to update.
+ * @returns {Promise} - The resulting contract data.
+ */
+ updateContract = (userAddress, contractAddress, params) => {
const getBodyFn = async () => {
let currentContractData = await this.getContractByAddress(
- account,
- address
+ userAddress,
+ contractAddress
)
if (!currentContractData) currentContractData = {}
delete currentContractData._id
- params.address = address
+ params.address = contractAddress
return JSON.stringify({ ...currentContractData, ...params })
}
@@ -231,11 +262,27 @@ class StoreProviderWrapper {
return this.queueWriteRequest(
getBodyFn,
'POST',
- `${this._storeUri}/${account}/contracts/${address}`
+ `${this._storeUri}/${userAddress}/contracts/${contractAddress}`
)
}
- addEvidenceContract = (address, account, name, description, url) => {
+ /**
+ * Adds new evidence to the store for a users contract. NOTE this will only update the
+ * 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} name - Name of evidence.
+ * @param {string} description - Description of evidence.
+ * @param {string} url - A link to the evidence.
+ * @returns {Promise} - The resulting evidence data.
+ */
+ addEvidenceContract = (
+ contractAddress,
+ userAddress,
+ name,
+ description,
+ url
+ ) => {
// get timestamp for submission
const submittedAt = new Date().getTime()
@@ -254,13 +301,26 @@ class StoreProviderWrapper {
return this.queueWriteRequest(
getBodyFn,
'POST',
- `${this._storeUri}/${account}/contracts/${address}/evidence`
+ `${this._storeUri}/${userAddress}/contracts/${contractAddress}/evidence`
)
}
- updateDisputeProfile = (account, arbitratorAddress, disputeId, params) => {
+ /**
+ * Update stored dispute data for a user.
+ * @param {string} userAddress - The address of the user.
+ * @param {string} arbitratorAddress - The address of the arbitrator contract.
+ * @param {number} disputeId - The index of the dispute.
+ * @param {object} params - The dispute data we are updating.
+ * @returns {Promise} The resulting dispute data.
+ */
+ updateDisputeProfile = (
+ userAddress,
+ arbitratorAddress,
+ disputeId,
+ params
+ ) => {
const getBodyFn = async () => {
- const userProfile = await this.getUserProfile(account)
+ const userProfile = await this.getUserProfile(userAddress)
const disputeIndex = _.filter(
userProfile.disputes,
@@ -283,10 +343,17 @@ class StoreProviderWrapper {
'POST',
`${
this._storeUri
- }/${account}/arbitrators/${arbitratorAddress}/disputes/${disputeId}`
+ }/${userAddress}/arbitrators/${arbitratorAddress}/disputes/${disputeId}`
)
}
+ /**
+ * Update the user agnostic data on a dispute.
+ * @param {string} arbitratorAddress - The address of the arbitrator contract.
+ * @param {number} disputeId - The index of the dispute.
+ * @param {object} params - The data we are updating.
+ * @returns {Promise} The resulting dispute data.
+ */
updateDispute = async (arbitratorAddress, disputeId, params) => {
const getBodyFn = async () => {
const currentDispute =
@@ -307,8 +374,19 @@ class StoreProviderWrapper {
)
}
+ /**
+ * Create a new notification in the store.
+ * @param {string} userAddress - The address of the user.
+ * @param {string} txHash - The transaction hash which produced this event log. Used as an identifier.
+ * @param {number} logIndex - The index of the log in the transaction. Used as an identifier.
+ * @param {number} notificationType - The type of the notification. See constants/notification.
+ * @param {string} message - The message to be stored with the notification.
+ * @param {object} data - Any extra data stored with the notification.
+ * @param {boolean} read - If the notification has been read or not.
+ * @returns {Promise} - The resulting notification.
+ */
newNotification = async (
- account,
+ userAddress,
txHash,
logIndex,
notificationType,
@@ -332,13 +410,26 @@ class StoreProviderWrapper {
return this.queueWriteRequest(
getBodyFn,
'POST',
- `${this._storeUri}/${account}/notifications/${txHash}`
+ `${this._storeUri}/${userAddress}/notifications/${txHash}`
)
}
- markNotificationAsRead = async (account, txHash, logIndex, isRead = true) => {
+ /**
+ * Create a new notification in the store.
+ * @param {string} userAddress - The address of the user.
+ * @param {string} txHash - The transaction hash which produced this event log. Used as an identifier.
+ * @param {number} logIndex - The index of the log in the transaction. Used as an identifier.
+ * @param {boolean} isRead - If the notification has been read or not.
+ * @returns {Promise} - The resulting notification.
+ */
+ markNotificationAsRead = async (
+ userAddress,
+ txHash,
+ logIndex,
+ isRead = true
+ ) => {
const getBodyFn = async () => {
- const userProfile = await this.getUserProfile(account)
+ const userProfile = await this.getUserProfile(userAddress)
const notificationIndex = await _.findIndex(
userProfile.notifications,
@@ -358,7 +449,7 @@ class StoreProviderWrapper {
return this.queueWriteRequest(
getBodyFn,
'POST',
- `${this._storeUri}/${account}`
+ `${this._storeUri}/${userAddress}`
)
}
}
diff --git a/src/utils/deployContractAsync.js b/src/utils/deployContractAsync.js
index 33de985..82f66f3 100644
--- a/src/utils/deployContractAsync.js
+++ b/src/utils/deployContractAsync.js
@@ -1,12 +1,12 @@
import contract from 'truffle-contract'
-import * as ethConstants from '../constants/eth'
-import { UNABLE_TO_DEPLOY_CONTRACT } from '../constants/error'
+import * as ethConstants from '../../constants/eth'
+import { UNABLE_TO_DEPLOY_CONTRACT } from '../../constants/error'
import isRequired from './isRequired'
/**
- * Deploy contract.
+ * Deploy a contract on the Ethereum network using the contract artifact.
* @param {string} account - The account to deploy it under.
* @param {number} value - The value to send.
* @param {object} artifact - JSON artifact of the contract.
diff --git a/src/utils/isRequired.js b/src/utils/isRequired.js
index bb3e974..51c083e 100644
--- a/src/utils/isRequired.js
+++ b/src/utils/isRequired.js
@@ -1,5 +1,10 @@
-import { MISSING_PARAMETERS } from '../constants/error'
+import { MISSING_PARAMETERS } from '../../constants/error'
+/**
+ * Used as the default parameter for an arguemnt that is considered required. It will
+ * throw an error if the argument is not supplied by the user.
+ * @param {string} name - The name of the missing argument.
+ */
const isRequired = name => {
throw new Error(MISSING_PARAMETERS(name))
}
diff --git a/tests/integration/EventListener.test.js b/tests/integration/EventListener.test.js
index 590dd23..7433e86 100644
--- a/tests/integration/EventListener.test.js
+++ b/tests/integration/EventListener.test.js
@@ -2,7 +2,7 @@ import Web3 from 'web3'
import KlerosPOC from '../../src/contracts/implementations/arbitrator/KlerosPOC'
import EventListener from '../../src/utils/EventListener'
-import * as ethConstants from '../../src/constants/eth'
+import * as ethConstants from '../../constants/eth'
import setUpContracts from '../helpers/setUpContracts'
import waitNotifications from '../helpers/waitNotifications'
import delaySecond from '../helpers/delaySecond'
diff --git a/tests/integration/contracts.test.js b/tests/integration/contracts.test.js
index f83b66c..3e9b340 100644
--- a/tests/integration/contracts.test.js
+++ b/tests/integration/contracts.test.js
@@ -2,8 +2,8 @@ import Web3 from 'web3'
import KlerosPOC from '../../src/contracts/implementations/arbitrator/KlerosPOC'
import ArbitrableTransaction from '../../src/contracts/implementations/arbitrable/ArbitrableTransaction'
-import * as ethConstants from '../../src/constants/eth'
-import * as errorConstants from '../../src/constants/error'
+import * as ethConstants from '../../constants/eth'
+import * as errorConstants from '../../constants/error'
import setUpContracts from '../helpers/setUpContracts'
import delaySecond from '../helpers/delaySecond'
diff --git a/tests/integration/disputeResolution.test.js b/tests/integration/disputeResolution.test.js
index fc19127..a836d18 100644
--- a/tests/integration/disputeResolution.test.js
+++ b/tests/integration/disputeResolution.test.js
@@ -3,8 +3,8 @@ import Web3 from 'web3'
import KlerosPOC from '../../src/contracts/implementations/arbitrator/KlerosPOC'
import ArbitrableTransaction from '../../src/contracts/implementations/arbitrable/ArbitrableTransaction'
import Notifications from '../../src/resources/Notifications'
-import * as ethConstants from '../../src/constants/eth'
-import * as notificationConstants from '../../src/constants/notification'
+import * as ethConstants from '../../constants/eth'
+import * as notificationConstants from '../../constants/notification'
import setUpContracts from '../helpers/setUpContracts'
import delaySecond from '../helpers/delaySecond'