@unification-com/xfund-router v0.4.2
xFUND Router & Data Consumer Solidity Smart Contracts
A suite of smart contracts to enable data from external sources (such as Finchains.io) to be included in your smart contracts. The suite comprises of:
1) A deployed Router smart contract. This facilitates receiving and forwarding data requests, between Consumers and Providers, in addition to processing xFUND payments for data provision. 2) A ConsumerBase smart contract, which is integrated into your own smart contract in order for data requests to be initialised (via the Router), and data to be received (from a designated Provider)
The remainder of this README is aimed at developers who wish to develop and test the suite itself.
For an integration guide, and how to use the suite in your own smart contracts, please
see the Documentation
Development and Testing
Prerequisites
NodeJS
The openzeppelin/test-environment packages and dependencies require
NodeJS >= v8.9.4 and <= v12.18.3 (excluding v11) in order to correctly install.
We recommend using nvm to manage NodeJS
installations.
Yarn
Yarn is recommended for package management.
Compile
Run:
yarn installto install the Node packages and dependencies
Run:
npx truffle compileto compile smart contracts
Unit Tests
To run all tests:
yarn testRunning all tests will take a few minutes.
To run individual test files:
npx truffle test/[TEST_FILE]Test Coverage
yarn run coverageRunning unit test coverage will take a long time. Results are saved to
converage.json and ./coverage
Deployment & Interaction
Compile the contracts, if not already compiled:
npx truffle compileRun the truffle development console:
npx truffle developNote: Make a note of the address and private key for account[1]. This will be
required later for Data Provider interaction.
Deploy the smart contracts
Run the truffle migrations, within the development console:
truffle(develop)> migrateInteraction - as a Consumer
Within the truffle development console, load the contract instances, and accounts
ready for interaction
truffle(develop)> let accounts = await web3.eth.getAccounts()
truffle(develop)> let mockToken = await MockToken.deployed()
truffle(develop)> let mockConsumer = await MockConsumer.deployed()
truffle(develop)> let router = await Router.deployed()
truffle(develop)> let consumerOwner = accounts[0]
truffle(develop)> let provider = accounts[1]Initialisation
- Grab some tokens from the
MockTokensmart contract for theconsumerOwner. Run:
truffle(develop)> mockToken.gimme({from: consumerOwner})- Increase the
RouterToken allowance for theMockConsumercontract, so that the Router can hold and forward fees to the provider. Run:
truffle(develop)> mockConsumer.increaseRouterAllowance("115792089237316195423570985008687907853269984665640564039457584007913129639935", {from: consumerOwner})- Have the
providerregister withRouter, with a minimum fee of 0.1xFUNDMOCK:
truffle(develop)> router.registerAsProvider(100000000, {from: provider})- Transfer some
MOCKtokens to yourMockConsumersmart contract. Run:
truffle(develop)> mockToken.transfer(mockConsumer.address, 10000000000, {from: consumerOwner})This will send 10 MOCKs to the MockConsumer smart contract.
Requesting Data
First, check the current price in your MockConsumer contract. Run:
truffle(develop)> let priceBefore = await mockConsumer.price()
truffle(develop)> priceBefore.toString()The result should be 0.
Next, request some data from the provider. Run:
truffle(develop)> let endpoint = web3.utils.asciiToHex("BTC.GBP.PR.AVC.24H")
truffle(develop)> mockConsumer.getData(provider, 100000000, endpoint, {from: consumerOwner})Interaction - as a Provider
A Consumer requests data, but a provider Oracle needs to be running in order to fulfill requests.
Copy
example.provider.envto a.envfile, and modify the following values. TheCONTRACT_ADDRESSis the Router smart contract's address, and can be acquired by running:
truffle(develop)> router.addressThe values for WALLET_PKEY and WALLET_ADDRESS are whatever you noted down when initialising
truffle develop earlier.
CONTRACT_ADDRESS=
WALLET_PKEY=
WALLET_ADDRESS=Note: the CONTRACT_ADDRESS should be the address of the Router smart contract.
In a separate terminal, run:
npx sequelize-cli db:migrateto initialise the oracle's database. If required, run
npx sequelize-cli db:migrate:undo:allfirst to wipe the database.
Note: the default NODE_ENV environment is development. In the development environment,
the Oracle will initialise a local SQLite database and save it to provider-oracle/db/database.sqlite.
This is intended for rapid testing/development, and is not meant for extensive testing. To test
in a more realistic environment, install PostgreSQL and change the NODE_ENV in .env
to test. Configure the appropriate DB_ values in .env and re-run the above sequelize
commands to initialise the PostgreSQL database.
Run the oracle with:
yarn run dev:oracleThis will run, watching the Router smart contract for any DataRequested events. If
one is emitted, and the dataProvider value is the provider's wallet address, it will
grab the data, and call the Router's fulfillRequest function, which in turn forwards
the data to the requesting MockConsumer smart contract.
2021-03-08T11:36:23.293Z current Eth height 15
2021-03-08T11:36:23.302Z get supported pairs
2021-03-08T11:36:37.055Z watching DataRequested from block 0
2021-03-08T11:36:37.055Z BEGIN watchIncommingRequests
2021-03-08T11:36:37.056Z running watcher for DataRequested
2021-03-08T11:36:37.065Z watching RequestFulfilled from block 0
2021-03-08T11:36:37.066Z BEGIN watchIncommingFulfillments
2021-03-08T11:36:37.066Z running watcher for RequestFulfilled
2021-03-08T11:36:37.067Z watching RequestCancelled from block 0
2021-03-08T11:36:37.068Z BEGIN watchIncommingCancellations
2021-03-08T11:36:37.068Z running watcher for RequestCancelled
2021-03-08T11:36:37.069Z watching blocks for jobs to process from block 0
2021-03-08T11:36:37.070Z BEGIN fulfillRequests
2021-03-08T11:36:37.081Z running block watcher
2021-03-08T11:36:37.135Z watchEvent DataRequested connected 0x1
2021-03-08T11:36:37.136Z watchEvent RequestFulfilled connected 0x2
2021-03-08T11:36:37.142Z watchBlocks newBlockHeaders connected 0x3Note: The price returned by the Oracle is always standardised to actualPrice * (10 ** 18)
Check Price in MockConsumer
Depending on what is configured for the WAIT_CONFIRMATIONS in .env, you will need
to run the following command in the Truffle console a few times to mine blocks:
truffle(develop)> await web3.currentProvider.send({ jsonrpc: "2.0", method: "evm_mine", id: 12345 }, function(err, result) { return })This will force ganache-cli to mine new blocks until the required number of block confirmations
have been achieved for the Provider Oracle to process and fulfil the data request.
Once the provider has fulfilled the request, the price value should have been updated
in the MockConsumer smart contract. Run:
truffle(develop)> let priceAfter = await mockConsumer.price()
truffle(develop)> priceAfter.toString()The result should now be a non-zero
value, e.g. 36547117907180545000000.
Dev Notes
Verify contracts on Etherscan after deployment - set ETHERSCAN_API in .env, then run:
npx truffle run verify [ContractName] --network=[network]