mirror of
https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-consumer.git
synced 2026-09-22 01:02:04 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a669fc6440 | ||
|
|
42ee03a6d9 | ||
|
|
733e8fd405 | ||
|
|
baee72c1c6 | ||
|
|
5c2ab8a8cf | ||
|
|
11618a796f | ||
|
|
025ae20704 | ||
|
|
5f6b98a1e5 | ||
|
|
e1f5e3fa9c | ||
|
|
fdf73610eb | ||
|
|
b09e77c079 | ||
|
|
d583acd6f3 | ||
|
|
079bd1bebc | ||
|
|
68ad2561b1 | ||
|
|
791d11e597 | ||
|
|
5489e76f55 | ||
|
|
a205f7967f | ||
|
|
346ba79929 | ||
|
|
14a9917670 | ||
|
|
e4fe851871 | ||
|
|
496a1dd07c | ||
|
|
a7b8ca9ad5 | ||
|
|
6eb16eb11a | ||
|
|
589b723629 | ||
|
|
5ec45ee9cb | ||
|
|
915d3563c2 | ||
|
|
9446efe1ae | ||
|
|
c573b71a23 | ||
|
|
1844f30dc5 | ||
|
|
b6ab2f02f4 | ||
|
|
b5c76aa5fe | ||
|
|
26c0611c51 | ||
|
|
3345160447 | ||
|
|
8d4984c4ac | ||
|
|
b2cc85df86 | ||
|
|
51977adad8 | ||
|
|
5c7e722808 | ||
|
|
03572e9c3d | ||
|
|
817b40c489 | ||
|
|
744cf60f90 |
Generated
+80
-5124
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -23,12 +23,12 @@
|
||||
},
|
||||
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-consumer",
|
||||
"dependencies": {
|
||||
"@psf/bch-js": "5.2.0",
|
||||
"@psf/bch-js": "5.3.2",
|
||||
"axios": "0.25.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"glob": "7.1.6",
|
||||
"ipfs": "0.60.0",
|
||||
"ipfs-coord": "6.8.10",
|
||||
"ipfs-coord": "7.1.6",
|
||||
"ipfs-http-client": "55.0.0",
|
||||
"jsonrpc-lite": "2.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
COMPOSE_PROJECT_NAME=bch-wallet-consumer
|
||||
@@ -250,8 +250,11 @@ class BchAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
async getTransactions (address) {
|
||||
// Get the transaction history for an address.
|
||||
async getTransactions (address, sortOrder = 'DESCENDING', page = 0) {
|
||||
try {
|
||||
console.log('Executing getTransaction() bch adapter')
|
||||
|
||||
// Throw an error if this IPFS node has not yet made a connection to a
|
||||
// wallet service provider.
|
||||
const selectedProvider =
|
||||
@@ -261,8 +264,10 @@ class BchAdapter {
|
||||
}
|
||||
|
||||
const rpcData = {
|
||||
endpoint: 'transactions',
|
||||
addresses: [address]
|
||||
endpoint: 'txHistory',
|
||||
address: address,
|
||||
sortOrder,
|
||||
page
|
||||
}
|
||||
|
||||
// Generate a UUID for the call.
|
||||
@@ -271,7 +276,7 @@ class BchAdapter {
|
||||
// Generate a JSON RPC command.
|
||||
const cmd = this.jsonrpc.request(rpcId, 'bch', rpcData)
|
||||
const cmdStr = JSON.stringify(cmd)
|
||||
// console.log('cmdStr: ', cmdStr)
|
||||
console.log('cmdStr: ', cmdStr)
|
||||
|
||||
// Send the RPC command to selected wallet service.
|
||||
const thisNode = this.ipfs.ipfsCoordAdapter.ipfsCoord.thisNode
|
||||
@@ -292,8 +297,13 @@ class BchAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
async getTransaction (txid) {
|
||||
// Get details on an array of TXIDs.
|
||||
async getTransaction (txids) {
|
||||
try {
|
||||
console.log(
|
||||
`Getting txData on these txids: ${JSON.stringify(txids, null, 2)}`
|
||||
)
|
||||
|
||||
// Throw an error if this IPFS node has not yet made a connection to a
|
||||
// wallet service provider.
|
||||
const selectedProvider =
|
||||
@@ -303,8 +313,8 @@ class BchAdapter {
|
||||
}
|
||||
|
||||
const rpcData = {
|
||||
endpoint: 'transaction',
|
||||
txid
|
||||
endpoint: 'txData',
|
||||
txids
|
||||
}
|
||||
|
||||
// Generate a UUID for the call.
|
||||
@@ -313,7 +323,7 @@ class BchAdapter {
|
||||
// Generate a JSON RPC command.
|
||||
const cmd = this.jsonrpc.request(rpcId, 'bch', rpcData)
|
||||
const cmdStr = JSON.stringify(cmd)
|
||||
// console.log('cmdStr: ', cmdStr)
|
||||
console.log('cmdStr: ', cmdStr)
|
||||
|
||||
// Send the RPC command to selected wallet service.
|
||||
const thisNode = this.ipfs.ipfsCoordAdapter.ipfsCoord.thisNode
|
||||
@@ -325,11 +335,12 @@ class BchAdapter {
|
||||
|
||||
// Wait for data to come back from the wallet service.
|
||||
const data = await this.waitForRPCResponse(rpcId)
|
||||
console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
return data
|
||||
} catch (err) {
|
||||
// console.log('createUser() error: ', err)
|
||||
wlogger.error('Error in adapters/bch.js/transaction()')
|
||||
wlogger.error('Error in adapters/bch.js/getTransaction()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ class IpfsCoordAdapter {
|
||||
attachRPCRouter (router) {
|
||||
try {
|
||||
_this.ipfsCoord.privateLog = router
|
||||
_this.ipfsCoord.adapters.orbit.privateLog = router
|
||||
_this.ipfsCoord.adapters.pubsub.privateLog = router
|
||||
} catch (err) {
|
||||
console.error('Error in attachRPCRouter()')
|
||||
throw err
|
||||
|
||||
@@ -76,7 +76,7 @@ class IpfsAdapter {
|
||||
const ipfsOptionsExternal = {
|
||||
host: this.config.ipfsHost,
|
||||
port: this.config.ipfsApiPort,
|
||||
agent: http.Agent({ keepAlive: true, maxSockets: 2000 })
|
||||
agent: http.Agent({ keepAlive: true, maxSockets: 200 })
|
||||
}
|
||||
|
||||
let ipfsOptions = ipfsOptionsEmbedded
|
||||
|
||||
@@ -49,12 +49,12 @@ class P2wdbAdapter {
|
||||
// Convert string input into an object.
|
||||
// const jsonData = JSON.parse(data)
|
||||
|
||||
console.log(`JSON RPC response for ID ${data.payload.id} received.`)
|
||||
// console.log(`JSON RPC response for ID ${data.payload.id} received.`)
|
||||
|
||||
_this.rpcDataQueue.push(data)
|
||||
} catch (err) {
|
||||
console.error('Error in p2wdb/rpcHandler(): ', err)
|
||||
// Do not throw error. This is a top-level function.
|
||||
// Do not throw error. This is a top-level function.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class P2wdbAdapter {
|
||||
|
||||
// Add names to the IPFS IDs for each provider.
|
||||
const initialServiceProviders =
|
||||
this.ipfs.ipfsCoordAdapter.state.p2wdbProviders
|
||||
this.ipfs.ipfsCoordAdapter.state.p2wdbProviders
|
||||
const serviceProviders = []
|
||||
for (let i = 0; i < initialServiceProviders.length; i++) {
|
||||
const thisProvider = initialServiceProviders[i]
|
||||
@@ -94,8 +94,7 @@ class P2wdbAdapter {
|
||||
|
||||
const outObj = {
|
||||
serviceProviders,
|
||||
selectedProvider:
|
||||
this.ipfs.ipfsCoordAdapter.state.selectedP2wdbProvider
|
||||
selectedProvider: this.ipfs.ipfsCoordAdapter.state.selectedP2wdbProvider
|
||||
}
|
||||
// console.log('outObj: ', outObj)
|
||||
|
||||
@@ -131,7 +130,7 @@ class P2wdbAdapter {
|
||||
// Throw an error if this IPFS node has not yet made a connection to a
|
||||
// wallet service provider.
|
||||
const selectedProvider =
|
||||
this.ipfs.ipfsCoordAdapter.state.selectedP2wdbProvider
|
||||
this.ipfs.ipfsCoordAdapter.state.selectedP2wdbProvider
|
||||
if (!selectedProvider) {
|
||||
throw new Error('No P2WDB Service provider available yet.')
|
||||
}
|
||||
@@ -174,7 +173,7 @@ class P2wdbAdapter {
|
||||
// Throw an error if this IPFS node has not yet made a connection to a
|
||||
// wallet service provider.
|
||||
const selectedProvider =
|
||||
this.ipfs.ipfsCoordAdapter.state.selectedP2wdbProvider
|
||||
this.ipfs.ipfsCoordAdapter.state.selectedP2wdbProvider
|
||||
if (!selectedProvider) {
|
||||
throw new Error('No P2WDB Service provider available yet.')
|
||||
}
|
||||
@@ -253,7 +252,7 @@ class P2wdbAdapter {
|
||||
|
||||
cnt++
|
||||
|
||||
// Exit if data was returned, or the window for a response expires.
|
||||
// Exit if data was returned, or the window for a response expires.
|
||||
} while (!dataFound && cnt < 10)
|
||||
// console.log(`dataFound: ${dataFound}, cnt: ${cnt}`)
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
/*
|
||||
This is the JSON RPC router for the users API
|
||||
|
||||
CT 3/5/22: This library can probably be deleted. Handling of the /about endpoint
|
||||
is now directly controlled by the ipfs-coord library.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
@@ -33,6 +36,8 @@ class AboutRPC {
|
||||
// This is a bit different than other router libraries, because there is
|
||||
// only one response, which is a string about this node.
|
||||
async aboutRouter (rpcData) {
|
||||
console.log('debugging: aboutRouter from ipfs-service-provider triggered')
|
||||
|
||||
return {
|
||||
success: true,
|
||||
status: 200,
|
||||
|
||||
@@ -271,10 +271,17 @@ class BchRESTControllerLib {
|
||||
|
||||
/**
|
||||
*
|
||||
* @api {post} /bch/transactions Transactions
|
||||
* @apiName Transactions
|
||||
* @api {post} /bch/txHistory TX History
|
||||
* @apiName TX History
|
||||
* @apiGroup REST BCH
|
||||
* @apiDescription This endpoint wraps the bchjs.Electrumx.transactions([]) function.
|
||||
* It returns the transaction history for an address. This list of TXIDs is
|
||||
* sorted and paginated.
|
||||
*
|
||||
* There are three possible inputs:
|
||||
* - address: (required) the address to query for a transaction history
|
||||
* - sortOrder: (optional) will sort results in 'DECENDING' (default) or 'ASCENDING' order.
|
||||
* - page: (optional) will return a 'page' of 100 results. Default is 0
|
||||
*
|
||||
* Given the 'addresses' property returns an array of objects
|
||||
* with the following properties
|
||||
@@ -289,7 +296,7 @@ class BchRESTControllerLib {
|
||||
* Note: For a single address pass the 'addresses' of string type
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "addresses": ["bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"] }' localhost:5001/bch/transactions
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "address": "bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj" }' localhost:5001/bch/txHistory
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
@@ -317,11 +324,20 @@ class BchRESTControllerLib {
|
||||
* "error": "Unprocessable Entity"
|
||||
* }
|
||||
*/
|
||||
async transactions (ctx) {
|
||||
async txHistory (ctx) {
|
||||
try {
|
||||
const addr = ctx.request.body.address
|
||||
// console.log('transactions REST API handler called.')
|
||||
// console.log(`body: ${JSON.stringify(ctx.request.body, null, 2)}`)
|
||||
|
||||
const data = await this.adapters.bch.getTransactions(addr)
|
||||
const addr = ctx.request.body.address
|
||||
const sortOrder = ctx.request.body.sortOrder
|
||||
const page = ctx.request.body.page
|
||||
|
||||
const data = await this.adapters.bch.getTransactions(
|
||||
addr,
|
||||
sortOrder,
|
||||
page
|
||||
)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
ctx.body = data
|
||||
@@ -331,11 +347,14 @@ class BchRESTControllerLib {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /bch/transaction Transaction
|
||||
* @apiName Transaction
|
||||
* @api {post} /bch/txData TX Data
|
||||
* @apiName txData
|
||||
* @apiGroup REST BCH
|
||||
* @apiDescription Get data about a specific transaction.
|
||||
* Given a transaction id this endpoint will return an object
|
||||
* @apiDescription Get expanded transaction data for an array of transaction
|
||||
* IDs. Each call is limited to 20 TXIDs or less.
|
||||
*
|
||||
* Get data about specific transactions.
|
||||
* Given an array of transaction IDs this endpoint will return an array of objects
|
||||
* with the following properties
|
||||
*
|
||||
* - txid: "" - Transaction ID
|
||||
@@ -353,11 +372,11 @@ class BchRESTControllerLib {
|
||||
* - isValidSLPTx: - Determines if the transaction was under SLP
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "txid": "01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b" }' localhost:5001/bch/transaction
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "txids": ["01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b"] }' localhost:5001/bch/transaction
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* [{
|
||||
* "txid":"01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b",
|
||||
* "hash":"01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b",
|
||||
* "version":1,
|
||||
@@ -406,7 +425,7 @@ class BchRESTControllerLib {
|
||||
* "time":1568338904,
|
||||
* "blocktime":1568338904,
|
||||
* "isValidSLPTx":false
|
||||
* }
|
||||
* }]
|
||||
*
|
||||
* @apiError UnprocessableEntity Missing required parameters
|
||||
*
|
||||
@@ -417,11 +436,19 @@ class BchRESTControllerLib {
|
||||
* "error": "Unprocessable Entity"
|
||||
* }
|
||||
*/
|
||||
async transaction (ctx) {
|
||||
async txData (ctx) {
|
||||
try {
|
||||
const txid = ctx.request.body.txid
|
||||
console.log(
|
||||
`txData called with this body data: ${JSON.stringify(
|
||||
ctx.request.body,
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
)
|
||||
|
||||
const data = await this.adapters.bch.getTransaction(txid)
|
||||
const txids = ctx.request.body.txids
|
||||
|
||||
const data = await this.adapters.bch.getTransaction(txids)
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
ctx.body = data
|
||||
|
||||
@@ -56,8 +56,8 @@ class BchRouter {
|
||||
this.router.post('/balance', this.postBalance)
|
||||
this.router.post('/utxos', this.postUtxos)
|
||||
this.router.post('/broadcast', this.postBroadcast)
|
||||
this.router.post('/transactions', this.postTransactions)
|
||||
this.router.post('/transaction', this.postTransaction)
|
||||
this.router.post('/txHistory', this.postTxHistory)
|
||||
this.router.post('/txData', this.postTxData)
|
||||
this.router.post('/pubkey', this.postPubKey)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
@@ -85,12 +85,12 @@ class BchRouter {
|
||||
await _this.bchRESTController.broadcast(ctx, next)
|
||||
}
|
||||
|
||||
async postTransactions (ctx, next) {
|
||||
await _this.bchRESTController.transactions(ctx, next)
|
||||
async postTxHistory (ctx, next) {
|
||||
await _this.bchRESTController.txHistory(ctx, next)
|
||||
}
|
||||
|
||||
async postTransaction (ctx, next) {
|
||||
await _this.bchRESTController.transaction(ctx, next)
|
||||
async postTxData (ctx, next) {
|
||||
await _this.bchRESTController.txData(ctx, next)
|
||||
}
|
||||
|
||||
async postPubKey (ctx, next) {
|
||||
|
||||
@@ -14,6 +14,7 @@ const LogsRESTController = require('./logs')
|
||||
const BchRESTController = require('./bch')
|
||||
const IpfsRESTController = require('./ipfs')
|
||||
const P2wdbRESTController = require('./p2wdb')
|
||||
const PriceRESTController = require('./price')
|
||||
|
||||
class RESTControllers {
|
||||
constructor (localConfig = {}) {
|
||||
@@ -67,6 +68,10 @@ class RESTControllers {
|
||||
// Attach the REST API Controllers associated with the /p2wdb route
|
||||
const p2wdbRESTController = new P2wdbRESTController(dependencies)
|
||||
p2wdbRESTController.attach(app)
|
||||
|
||||
// Attach the REST API Controllers associated with the /price route
|
||||
const priceRESTController = new PriceRESTController(dependencies)
|
||||
priceRESTController.attach(app)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
REST API Controller library for the /bch route
|
||||
*/
|
||||
|
||||
const axios = require('axios')
|
||||
const { wlogger } = require('../../../adapters/wlogger')
|
||||
|
||||
// let _this
|
||||
|
||||
class PriceRESTControllerLib {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating /price REST Controller.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantiating /price REST Controller.'
|
||||
)
|
||||
}
|
||||
|
||||
// Encapsulate dependencies
|
||||
this.axios = axios
|
||||
// this.UserModel = this.adapters.localdb.Users
|
||||
// this.userUseCases = this.useCases.user
|
||||
|
||||
// _this = this
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} /price/usd Get the USD price of BCH
|
||||
* @apiName Get the USD price of BCH
|
||||
* @apiGroup Price
|
||||
* @apiDescription Get the USD price of BCH from Coinbase.
|
||||
*
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -X GET "http://localhost:5005/price/usd" -H "accept: application/json"
|
||||
*
|
||||
*/
|
||||
async getUSD (ctx) {
|
||||
try {
|
||||
// Request options
|
||||
const opt = {
|
||||
method: 'get',
|
||||
baseURL: 'https://api.coinbase.com/v2/',
|
||||
url: '/exchange-rates?currency=BCH',
|
||||
timeout: 15000
|
||||
}
|
||||
|
||||
const response = await this.axios.request(opt)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
ctx.body = { usd: Number(response.data.data.rates.USD) }
|
||||
} catch (err) {
|
||||
// Write out error to error log.
|
||||
wlogger.error('Error in GET /price/usd.', err)
|
||||
|
||||
this.handleError(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
// DRY error handler
|
||||
handleError (ctx, err) {
|
||||
// If an HTTP status is specified by the buisiness logic, use that.
|
||||
if (err.status) {
|
||||
if (err.message) {
|
||||
ctx.throw(err.status, err.message)
|
||||
} else {
|
||||
ctx.throw(err.status)
|
||||
}
|
||||
} else {
|
||||
// By default use a 422 error if the HTTP status is not specified.
|
||||
ctx.throw(422, err.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PriceRESTControllerLib
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
REST API library for /bch route.
|
||||
*/
|
||||
|
||||
// Public npm libraries.
|
||||
const Router = require('koa-router')
|
||||
|
||||
// Local libraries.
|
||||
const PriceRESTControllerLib = require('./controller')
|
||||
const Validators = require('../middleware/validators')
|
||||
|
||||
let _this
|
||||
|
||||
class PriceRouter {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating Price REST Controller.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantiating Price REST Controller.'
|
||||
)
|
||||
}
|
||||
|
||||
const dependencies = {
|
||||
adapters: this.adapters,
|
||||
useCases: this.useCases
|
||||
}
|
||||
|
||||
// Encapsulate dependencies.
|
||||
this.priceRESTController = new PriceRESTControllerLib(dependencies)
|
||||
this.validators = new Validators()
|
||||
|
||||
// Instantiate the router and set the base route.
|
||||
const baseUrl = '/price'
|
||||
this.router = new Router({ prefix: baseUrl })
|
||||
|
||||
_this = this
|
||||
}
|
||||
|
||||
attach (app) {
|
||||
if (!app) {
|
||||
throw new Error(
|
||||
'Must pass app object when attaching REST API controllers.'
|
||||
)
|
||||
}
|
||||
|
||||
// Define the routes and attach the controller.
|
||||
this.router.get('/usd', this.getPrice)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(this.router.routes())
|
||||
app.use(this.router.allowedMethods())
|
||||
}
|
||||
|
||||
async getPrice (ctx, next) {
|
||||
await _this.priceRESTController.getUSD(ctx, next)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PriceRouter
|
||||
+97
-38
@@ -7,7 +7,7 @@
|
||||
This test will query each REST API endpoint and ensure they are working correctly.
|
||||
*/
|
||||
|
||||
const SERVER = 'http://localhost:5001'
|
||||
const SERVER = 'http://localhost:5005'
|
||||
|
||||
const axios = require('axios')
|
||||
const assert = require('chai').assert
|
||||
@@ -23,8 +23,8 @@ describe('#BCH E2E Tests', () => {
|
||||
const result = await axios.get(url)
|
||||
// console.log(`data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
assert.isAbove(result.data.status.state.serviceProviders.length, 0)
|
||||
assert.isOk(result.data.status.state.selectedServiceProvider)
|
||||
assert.isAbove(result.data.status.serviceProviders.length, 0)
|
||||
assert.isOk(result.data.status.selectedProvider)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -56,9 +56,9 @@ describe('#BCH E2E Tests', () => {
|
||||
const result = await axios.post(url, body)
|
||||
// console.log(`result.data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
assert.equal(result.data.address, body.address)
|
||||
assert.property(result.data, 'bchUtxos')
|
||||
assert.property(result.data, 'slpUtxos')
|
||||
assert.equal(result.data[0].address, body.address)
|
||||
assert.property(result.data[0], 'bchUtxos')
|
||||
assert.property(result.data[0], 'slpUtxos')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -74,42 +74,11 @@ describe('#BCH E2E Tests', () => {
|
||||
|
||||
assert.equal(result.data.status, 422)
|
||||
assert.equal(result.data.success, false)
|
||||
assert.equal(result.data.message, 'TX decode failed')
|
||||
assert.equal(result.data.message, 'Missing inputs')
|
||||
assert.equal(result.data.endpoint, 'broadcast')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#transactions', () => {
|
||||
it('should get transaction history for an address', async () => {
|
||||
const body = {
|
||||
address: 'bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj'
|
||||
}
|
||||
|
||||
const url = `${SERVER}/bch/transactions`
|
||||
const result = await axios.post(url, body)
|
||||
// console.log(`result.data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
assert.equal(result.data.status, 200)
|
||||
assert.equal(result.data.success, true)
|
||||
assert.property(result.data, 'transactions')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#transaction', () => {
|
||||
it('should get transaction details for a txid', async () => {
|
||||
const body = {
|
||||
txid: '01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b'
|
||||
}
|
||||
|
||||
const url = `${SERVER}/bch/transaction`
|
||||
const result = await axios.post(url, body)
|
||||
// console.log(`result.data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
assert.property(result.data, 'txid')
|
||||
assert.property(result.data, 'vin')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#pubkey', () => {
|
||||
it('should return "not found" if pubkey is not on chain', async () => {
|
||||
const body = {
|
||||
@@ -146,4 +115,94 @@ describe('#BCH E2E Tests', () => {
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#txHistory', () => {
|
||||
it('should get transaction history for an address, and sort by default in descending order.', async () => {
|
||||
const address = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
const body = {
|
||||
address
|
||||
}
|
||||
|
||||
const url = `${SERVER}/bch/txHistory`
|
||||
const result = await axios.post(url, body)
|
||||
// console.log(`result.data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
// Assert expected values and properties.
|
||||
assert.equal(result.data.status, 200)
|
||||
assert.equal(result.data.success, true)
|
||||
assert.equal(result.data.address, address)
|
||||
assert.isArray(result.data.txs)
|
||||
|
||||
// Assert expected sorting
|
||||
assert.isAbove(result.data.txs[0].height, result.data.txs[1].height)
|
||||
})
|
||||
|
||||
it('should sort in ascending order.', async () => {
|
||||
const address = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
|
||||
const body = {
|
||||
address,
|
||||
sortOrder: 'ASCENDING'
|
||||
}
|
||||
|
||||
const url = `${SERVER}/bch/txHistory`
|
||||
const result = await axios.post(url, body)
|
||||
// console.log(`result.data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
// Assert expected values and properties.
|
||||
assert.equal(result.data.status, 200)
|
||||
assert.equal(result.data.success, true)
|
||||
assert.equal(result.data.address, address)
|
||||
assert.isArray(result.data.txs)
|
||||
|
||||
// Assert expected sorting
|
||||
assert.isAbove(result.data.txs[1].height, result.data.txs[0].height)
|
||||
})
|
||||
|
||||
it('should paginate an address with deep tx history', async () => {
|
||||
const body = {
|
||||
address: 'bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d'
|
||||
}
|
||||
|
||||
const url = `${SERVER}/bch/txHistory`
|
||||
const result = await axios.post(url, body)
|
||||
// console.log(`result.data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
// Assert there is no more than 100 entries
|
||||
assert.isBelow(result.data.txs.length, 101)
|
||||
})
|
||||
|
||||
it('should get the second page of results', async () => {
|
||||
const body = {
|
||||
address: 'bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d',
|
||||
page: 1
|
||||
}
|
||||
|
||||
const url = `${SERVER}/bch/txHistory`
|
||||
const result = await axios.post(url, body)
|
||||
// console.log(`result.data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
// Assert there is no more than 100 entries
|
||||
assert.isBelow(result.data.txs.length, 101)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#txData', () => {
|
||||
it('should get transaction details for a txid', async () => {
|
||||
const body = {
|
||||
txids: [
|
||||
'01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b'
|
||||
]
|
||||
}
|
||||
|
||||
const url = `${SERVER}/bch/txData`
|
||||
const result = await axios.post(url, body)
|
||||
// console.log(`result.data: ${JSON.stringify(result.data, null, 2)}`)
|
||||
|
||||
assert.equal(result.data.status, 200)
|
||||
assert.isArray(result.data.txData)
|
||||
assert.property(result.data.txData[0], 'txid')
|
||||
assert.property(result.data.txData[0], 'vin')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -99,8 +99,9 @@ describe('#IPFS', () => {
|
||||
}
|
||||
},
|
||||
adapters: {
|
||||
orbit: {
|
||||
privateLog: () => {}
|
||||
pubsub: {
|
||||
privateLog: () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +122,7 @@ describe('#IPFS', () => {
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, 'Cannot read')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -52,7 +52,8 @@ describe('#IPFS-adapter', () => {
|
||||
it('should stop the IPFS node', async () => {
|
||||
// Mock dependencies
|
||||
uut.ipfs = {
|
||||
stop: () => {}
|
||||
stop: () => {
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.stop()
|
||||
@@ -61,24 +62,24 @@ describe('#IPFS-adapter', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#rmBlocksDir', () => {
|
||||
it('should delete the /blocks directory', () => {
|
||||
const result = uut.rmBlocksDir()
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should catch and throw an error', () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox.stub(uut.fs, 'rmdirSync').throws(new Error('test error'))
|
||||
|
||||
uut.rmBlocksDir()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.equal(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
// describe('#rmBlocksDir', () => {
|
||||
// it('should delete the /blocks directory', () => {
|
||||
// const result = uut.rmBlocksDir()
|
||||
//
|
||||
// assert.equal(result, true)
|
||||
// })
|
||||
//
|
||||
// it('should catch and throw an error', () => {
|
||||
// try {
|
||||
// // Force an error
|
||||
// sandbox.stub(uut.fs, 'rmdirSync').throws(new Error('test error'))
|
||||
//
|
||||
// uut.rmBlocksDir()
|
||||
//
|
||||
// assert.fail('Unexpected code path')
|
||||
// } catch (err) {
|
||||
// assert.equal(err.message, 'test error')
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
})
|
||||
|
||||
@@ -333,7 +333,7 @@ describe('#UserRPC', () => {
|
||||
assert.equal(result.endpoint, 'updateUser')
|
||||
assert.equal(result.success, false)
|
||||
assert.equal(result.status, 422)
|
||||
assert.include(result.message, 'Cannot read property')
|
||||
assert.include(result.message, 'Cannot read')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -375,7 +375,7 @@ describe('#UserRPC', () => {
|
||||
assert.equal(result.endpoint, 'getUser')
|
||||
assert.equal(result.success, false)
|
||||
assert.equal(result.status, 422)
|
||||
assert.include(result.message, 'Cannot read property')
|
||||
assert.include(result.message, 'Cannot read')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ describe('#BCH-REST-Controller', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#transactions', () => {
|
||||
describe('#txHistory', () => {
|
||||
it('should return 422 status on arbitrary error', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
@@ -225,7 +225,7 @@ describe('#BCH-REST-Controller', () => {
|
||||
address: 'blah'
|
||||
}
|
||||
|
||||
await uut.transactions(ctx)
|
||||
await uut.txHistory(ctx)
|
||||
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
@@ -242,14 +242,14 @@ describe('#BCH-REST-Controller', () => {
|
||||
address: 'blah'
|
||||
}
|
||||
|
||||
await uut.transactions(ctx)
|
||||
await uut.txHistory(ctx)
|
||||
|
||||
// Assert the expected HTTP response
|
||||
assert.equal(ctx.status, 200)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#transaction', () => {
|
||||
describe('#txData', () => {
|
||||
it('should return 422 status on arbitrary error', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
@@ -261,7 +261,7 @@ describe('#BCH-REST-Controller', () => {
|
||||
txid: 'blah'
|
||||
}
|
||||
|
||||
await uut.transaction(ctx)
|
||||
await uut.txData(ctx)
|
||||
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
@@ -280,7 +280,7 @@ describe('#BCH-REST-Controller', () => {
|
||||
txid: 'blah'
|
||||
}
|
||||
|
||||
await uut.transaction(ctx)
|
||||
await uut.txData(ctx)
|
||||
|
||||
// Assert the expected HTTP response
|
||||
assert.equal(ctx.status, 200)
|
||||
|
||||
@@ -14,7 +14,8 @@ let ctx
|
||||
const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
||||
|
||||
describe('Contact', () => {
|
||||
before(async () => {})
|
||||
before(async () => {
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
uut = new ContactController()
|
||||
@@ -36,7 +37,7 @@ describe('Contact', () => {
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.equal(err.status, 422)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, 'Cannot read')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ let ctx
|
||||
const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
||||
|
||||
describe('Logapi', () => {
|
||||
before(async () => {})
|
||||
before(async () => {
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
uut = new LogsApiController()
|
||||
@@ -35,7 +36,7 @@ describe('Logapi', () => {
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
assert.equal(err.status, 422)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, 'Cannot read')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ describe('#Users-REST-Controller', () => {
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.equal(err.status, 422)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, 'Cannot read')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -91,9 +91,9 @@ describe('#Users-REST-Controller', () => {
|
||||
assert.property(ctx.response.body, 'user')
|
||||
assert.property(ctx.response.body, 'token')
|
||||
|
||||
// Used by downstream tests.
|
||||
// testUser = ctx.response.body.user
|
||||
// console.log('testUser: ', testUser)
|
||||
// Used by downstream tests.
|
||||
// testUser = ctx.response.body.user
|
||||
// console.log('testUser: ', testUser)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -181,7 +181,7 @@ describe('#Users-REST-Controller', () => {
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.equal(err.status, 422)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, 'Cannot read')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -223,7 +223,7 @@ describe('#Users-REST-Controller', () => {
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.equal(err.status, 422)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, 'Cannot read')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ describe('#users-use-case', () => {
|
||||
await uut.getAllUsers()
|
||||
// console.log(`users: ${JSON.stringify(users, null, 2)}`)
|
||||
|
||||
// assert.isArray(users)
|
||||
// assert.isArray(users)
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
@@ -228,8 +228,8 @@ describe('#users-use-case', () => {
|
||||
// Assert that the expected properties for the user model exist.
|
||||
// assert.property(result, 'type')
|
||||
assert.property(result, '_id')
|
||||
// assert.property(result, 'email')
|
||||
// assert.property(result, 'name')
|
||||
// assert.property(result, 'email')
|
||||
// assert.property(result, 'name')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -241,7 +241,7 @@ describe('#users-use-case', () => {
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, 'Cannot read')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -346,7 +346,7 @@ describe('#users-use-case', () => {
|
||||
// assert.equal(result.name, 'testy tester')
|
||||
// })
|
||||
|
||||
// TODO: verify that an admin can change the type of a user
|
||||
// TODO: verify that an admin can change the type of a user
|
||||
})
|
||||
|
||||
describe('#authUser', () => {
|
||||
@@ -356,9 +356,9 @@ describe('#users-use-case', () => {
|
||||
await uut.authUser('test@test.com', 'password')
|
||||
// console.log('user: ', user)
|
||||
|
||||
// assert.property(user, '_id')
|
||||
// assert.property(user, 'email')
|
||||
// assert.property(user, 'name')
|
||||
// assert.property(user, '_id')
|
||||
// assert.property(user, 'email')
|
||||
// assert.property(user, 'name')
|
||||
})
|
||||
|
||||
it('should throw an error if no user matches the login', async () => {
|
||||
@@ -399,7 +399,7 @@ describe('#users-use-case', () => {
|
||||
assert.fail('Unexpected code path.')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, 'Cannot read property')
|
||||
assert.include(err.message, 'Cannot read')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user