mirror of
https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-consumer.git
synced 2026-09-22 09:12:03 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ef0130559 | ||
|
|
610ca4ec8b | ||
|
|
1a32b941df | ||
|
|
433931111c | ||
|
|
3edc945487 | ||
|
|
c66194ceeb | ||
|
|
e35e130816 | ||
|
|
bba4bd5931 | ||
|
|
48d13ed6bc | ||
|
|
d6f9b1b754 | ||
|
|
25edd5fe71 | ||
|
|
cc84636e54 | ||
|
|
d73211191c | ||
|
|
b23acd3cdc | ||
|
|
c71fda38ff | ||
|
|
f99f49d840 | ||
|
|
2edd924c57 | ||
|
|
689c8fd8d9 | ||
|
|
ffd6c452c9 | ||
|
|
fc8e160874 | ||
|
|
d2f83307e6 | ||
|
|
1a09fcd26f |
+1
-1
@@ -1,5 +1,5 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2021 Permissionless Software Foundation
|
||||
Copyright (c) 2022 Permissionless Software Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
Generated
+21
-23
@@ -9,12 +9,12 @@
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@psf/bch-js": "6.4.5",
|
||||
"@psf/bch-js": "6.5.1",
|
||||
"axios": "0.27.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"glob": "7.1.6",
|
||||
"ipfs": "0.62.3",
|
||||
"ipfs-coord": "8.0.2",
|
||||
"ipfs-coord": "8.0.5",
|
||||
"ipfs-http-client": "55.0.0",
|
||||
"jsonrpc-lite": "2.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
@@ -36,7 +36,7 @@
|
||||
"nodemailer": "6.7.5",
|
||||
"passport-local": "1.0.0",
|
||||
"public-ip": "4.0.4",
|
||||
"semver": "^7.3.5",
|
||||
"semver": "7.3.5",
|
||||
"winston": "3.3.3",
|
||||
"winston-daily-rotate-file": "4.5.0"
|
||||
},
|
||||
@@ -1481,9 +1481,9 @@
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@psf/bch-js": {
|
||||
"version": "6.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@psf/bch-js/-/bch-js-6.4.5.tgz",
|
||||
"integrity": "sha512-sH72zbJJI5oe9EUMczFQb0jCaNQb8rc3/86E6xXKl3325HCwBqE80BX7JFvZ97Qv1gGxwp/3WROp59v6Dz2NKA==",
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@psf/bch-js/-/bch-js-6.5.1.tgz",
|
||||
"integrity": "sha512-W52V6NCte/LJZ2TMJwXorq2FdwMMzjS94sh4slebrcUp6oHiAG+/NouQ4ID/I1DEJQlQnQpf2j3zxveCimDERQ==",
|
||||
"dependencies": {
|
||||
"@chris.troutner/bip32-utils": "1.0.5",
|
||||
"@psf/bip21": "2.0.1",
|
||||
@@ -8839,10 +8839,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ipfs-coord": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "http://94.130.170.209:4873/ipfs-coord/-/ipfs-coord-8.0.2.tgz",
|
||||
"integrity": "sha512-CdUH4GLLFArUDb8LIRAXxPlhbRQ44A5PEWB4J9zzDB3by93O7DLEgjqPqLDolalzrtiQBVzoARO/exZvdxBF+w==",
|
||||
"license": "MIT",
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ipfs-coord/-/ipfs-coord-8.0.5.tgz",
|
||||
"integrity": "sha512-V4pqR+MU290ZxFRE+Rx/7JuxR7LsOFBLuL0av3eVU5ZQWqeF/Zi9vh52zCqpp1IBCXi4QXNZGlysvm16xFDXww==",
|
||||
"dependencies": {
|
||||
"axios": "0.21.4",
|
||||
"bch-encrypt-lib": "2.0.0",
|
||||
@@ -18621,10 +18620,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "http://94.130.170.209:4873/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"license": "ISC",
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
@@ -23177,9 +23175,9 @@
|
||||
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
|
||||
},
|
||||
"@psf/bch-js": {
|
||||
"version": "6.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@psf/bch-js/-/bch-js-6.4.5.tgz",
|
||||
"integrity": "sha512-sH72zbJJI5oe9EUMczFQb0jCaNQb8rc3/86E6xXKl3325HCwBqE80BX7JFvZ97Qv1gGxwp/3WROp59v6Dz2NKA==",
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@psf/bch-js/-/bch-js-6.5.1.tgz",
|
||||
"integrity": "sha512-W52V6NCte/LJZ2TMJwXorq2FdwMMzjS94sh4slebrcUp6oHiAG+/NouQ4ID/I1DEJQlQnQpf2j3zxveCimDERQ==",
|
||||
"requires": {
|
||||
"@chris.troutner/bip32-utils": "1.0.5",
|
||||
"@psf/bip21": "2.0.1",
|
||||
@@ -28417,9 +28415,9 @@
|
||||
}
|
||||
},
|
||||
"ipfs-coord": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "http://94.130.170.209:4873/ipfs-coord/-/ipfs-coord-8.0.2.tgz",
|
||||
"integrity": "sha512-CdUH4GLLFArUDb8LIRAXxPlhbRQ44A5PEWB4J9zzDB3by93O7DLEgjqPqLDolalzrtiQBVzoARO/exZvdxBF+w==",
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ipfs-coord/-/ipfs-coord-8.0.5.tgz",
|
||||
"integrity": "sha512-V4pqR+MU290ZxFRE+Rx/7JuxR7LsOFBLuL0av3eVU5ZQWqeF/Zi9vh52zCqpp1IBCXi4QXNZGlysvm16xFDXww==",
|
||||
"requires": {
|
||||
"axios": "0.21.4",
|
||||
"bch-encrypt-lib": "2.0.0",
|
||||
@@ -35493,9 +35491,9 @@
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "http://94.130.170.209:4873/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
|
||||
+3
-3
@@ -23,12 +23,12 @@
|
||||
},
|
||||
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-consumer",
|
||||
"dependencies": {
|
||||
"@psf/bch-js": "6.4.5",
|
||||
"@psf/bch-js": "6.5.1",
|
||||
"axios": "0.27.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
"glob": "7.1.6",
|
||||
"ipfs": "0.62.3",
|
||||
"ipfs-coord": "8.0.2",
|
||||
"ipfs-coord": "8.0.5",
|
||||
"ipfs-http-client": "55.0.0",
|
||||
"jsonrpc-lite": "2.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
@@ -50,7 +50,7 @@
|
||||
"nodemailer": "6.7.5",
|
||||
"passport-local": "1.0.0",
|
||||
"public-ip": "4.0.4",
|
||||
"semver": "^7.3.5",
|
||||
"semver": "7.3.5",
|
||||
"winston": "3.3.3",
|
||||
"winston-daily-rotate-file": "4.5.0"
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ version: '3.9'
|
||||
|
||||
services:
|
||||
mongo-bch-consumer:
|
||||
image: mongo
|
||||
image: mongo:4.2.0
|
||||
container_name: mongo-bch-consumer
|
||||
ports:
|
||||
- '5555:27017' # <host port>:<container port>
|
||||
@@ -14,7 +14,7 @@ services:
|
||||
restart: always
|
||||
|
||||
ipfs-bch-consumer:
|
||||
image: ipfs/go-ipfs:v0.13.0
|
||||
image: ipfs/go-ipfs:v0.14.0
|
||||
container_name: ipfs-bch-consumer
|
||||
environment:
|
||||
MY_ENV_VAR: 'placeholder'
|
||||
@@ -26,11 +26,12 @@ services:
|
||||
mem_limit: 2000mb
|
||||
ports:
|
||||
- 4001:4001
|
||||
- 4003:4003
|
||||
- 172.17.0.1:5001:5001
|
||||
- 172.17.0.1:8080:8080
|
||||
volumes:
|
||||
- ../data/go-ipfs/data:/data/ipfs
|
||||
- ../../swarm.key:/data/ipfs/swarm.key
|
||||
# - ../../swarm.key:/data/ipfs/swarm.key
|
||||
# https://docs.docker.com/compose/compose-file/compose-file-v3/#command
|
||||
# https://github.com/ipfs/go-ipfs/blob/91c52657166bcf86f2476926e4fe56694dc26562/Dockerfile#L115
|
||||
command:
|
||||
|
||||
@@ -33,6 +33,6 @@ export CONSUMER_ENV=production
|
||||
export IPFS_HOST=172.17.0.1
|
||||
export IPFS_API_PORT=5001
|
||||
export IPFS_TCP_PORT=4001
|
||||
#export IPFS_WS_PORT=5269
|
||||
export IPFS_WS_PORT=4003
|
||||
|
||||
npm start
|
||||
|
||||
@@ -30,4 +30,7 @@ export DBURL=mongodb://localhost:27017/ipfs-service-dev
|
||||
|
||||
export CONSUMER_ENV=production
|
||||
|
||||
# Lock the consumer into a preferred service provider.
|
||||
#export PREFERRED_PROVIDER=12D3KooWEzE3HNH86WCb2Xocu6PgBCnSGUD7myJmuTHvoedMwp7K
|
||||
|
||||
npm start
|
||||
|
||||
@@ -472,6 +472,49 @@ class BchAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
// Get token icon and other media associated with the token.
|
||||
async getTokenData2 (tokenId) {
|
||||
try {
|
||||
// Throw an error if this IPFS node has not yet made a connection to a
|
||||
// wallet service provider.
|
||||
const selectedProvider =
|
||||
this.ipfs.ipfsCoordAdapter.state.selectedServiceProvider
|
||||
if (!selectedProvider) {
|
||||
throw new Error('No BCH Wallet Service provider available yet.')
|
||||
}
|
||||
|
||||
const rpcData = {
|
||||
endpoint: 'getTokenData2',
|
||||
tokenId
|
||||
}
|
||||
|
||||
// Generate a UUID for the call.
|
||||
const rpcId = this.uid()
|
||||
|
||||
// Generate a JSON RPC command.
|
||||
const cmd = this.jsonrpc.request(rpcId, 'bch', rpcData)
|
||||
const cmdStr = JSON.stringify(cmd)
|
||||
console.log('cmdStr: ', cmdStr)
|
||||
|
||||
// Send the RPC command to selected wallet service.
|
||||
const thisNode = this.ipfs.ipfsCoordAdapter.ipfsCoord.thisNode
|
||||
await this.ipfs.ipfsCoordAdapter.ipfsCoord.useCases.peer.sendPrivateMessage(
|
||||
selectedProvider,
|
||||
cmdStr,
|
||||
thisNode
|
||||
)
|
||||
|
||||
// Wait for data to come back from the wallet service.
|
||||
const data = await this.waitForRPCResponse(rpcId)
|
||||
|
||||
return data
|
||||
} catch (err) {
|
||||
console.log('getTokenData2() error: ', err)
|
||||
wlogger.error('Error in adapters/bch.js/getTokenData2()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a promise that resolves to data when the RPC response is recieved.
|
||||
async waitForRPCResponse (rpcId) {
|
||||
try {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// Local libraries
|
||||
const IpfsAdapter = require('./ipfs')
|
||||
const IpfsCoordAdapter = require('./ipfs-coord')
|
||||
const config = require('../../../config')
|
||||
|
||||
class IPFS {
|
||||
constructor (localConfig = {}) {
|
||||
@@ -20,6 +21,7 @@ class IPFS {
|
||||
this.ipfsAdapter = new IpfsAdapter()
|
||||
this.IpfsCoordAdapter = IpfsCoordAdapter
|
||||
this.process = process
|
||||
this.config = config
|
||||
|
||||
this.ipfsCoordAdapter = {} // placeholder
|
||||
|
||||
@@ -40,8 +42,9 @@ class IPFS {
|
||||
|
||||
// Start ipfs-coord
|
||||
this.ipfsCoordAdapter = new this.IpfsCoordAdapter({
|
||||
ipfs: this.ipfs
|
||||
// eventEmitter: this.eventEmitter
|
||||
ipfs: this.ipfs,
|
||||
tcpPort: this.config.ipfsTcpPort,
|
||||
wsPort: this.config.ipfsWsPort
|
||||
})
|
||||
await this.ipfsCoordAdapter.start()
|
||||
console.log('ipfs-coord is ready.')
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
const { wlogger } = require('../../../adapters/wlogger')
|
||||
const config = require('../../../../config')
|
||||
|
||||
// let _this
|
||||
|
||||
@@ -23,10 +24,7 @@ class BchRESTControllerLib {
|
||||
}
|
||||
|
||||
// Encapsulate dependencies
|
||||
// this.UserModel = this.adapters.localdb.Users
|
||||
// this.userUseCases = this.useCases.user
|
||||
|
||||
// _this = this
|
||||
this.config = config
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,6 +64,11 @@ class BchRESTControllerLib {
|
||||
try {
|
||||
const providerId = ctx.request.body.provider
|
||||
|
||||
// Throw an error, if the provider has been set by an environment variable.
|
||||
if (this.config.preferredProvider) {
|
||||
throw new Error('Consumer has preferredProvider set in environment variable. Refusing to switch providers.')
|
||||
}
|
||||
|
||||
await this.adapters.bch.selectProvider(providerId)
|
||||
|
||||
const body = {
|
||||
@@ -556,59 +559,21 @@ class BchRESTControllerLib {
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {REST} /bch getTokenData
|
||||
* @apiPermission public
|
||||
* @apiName getTokenData
|
||||
* @apiGroup REST BCH
|
||||
* @apiDescription Get data associated with a token
|
||||
* Given a token ID, this endpoint will retrieve the IPFS CIDs associated with
|
||||
* the tokens mutable and immutable data. This is extension of the PS002
|
||||
* specification for mutable data for tokens:
|
||||
* https://github.com/Permissionless-Software-Foundation/specifications/blob/master/ps002-slp-mutable-data.md
|
||||
*
|
||||
* - jsonrpc: "" - jsonrpc version
|
||||
* - id: "" - jsonrpc id
|
||||
* - result: {} - Result of the petition with the RPC information
|
||||
* - success: - Request status
|
||||
* - getTokenData: - Address public key
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "getTokenData", "tokenId": "c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d" }}
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* {
|
||||
* "jsonrpc":"2.0",
|
||||
* "id":"555",
|
||||
* "result":{
|
||||
* "method":"bch",
|
||||
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
|
||||
* "value":{
|
||||
* "success": true,
|
||||
* "status": 200,
|
||||
* "endpoint": "getTokenData",
|
||||
* "tokenData": {
|
||||
* "genesisData": {
|
||||
* "type": 1,
|
||||
* "ticker": 'MT2',
|
||||
* "name": 'Mutable Token',
|
||||
* "tokenId": 'c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d',
|
||||
* "documentUri": 'ipfs://bafybeie7oxpsr7evcnlptecxfdhaqlot4732phukd2ekgvuzoir2frost4',
|
||||
* "documentHash": '56ed1a5768076a318d02b5db64e125544dca57ab6b2cc7ca61dfa4645d244463',
|
||||
* "decimals": 0,
|
||||
* "mintBatonIsActive": true,
|
||||
* "tokensInCirculationBN": '1000',
|
||||
* "tokensInCirculationStr": '1000',
|
||||
* "blockCreated": 739412,
|
||||
* "totalBurned": '0',
|
||||
* "totalMinted": '1000'
|
||||
* },
|
||||
* "immutableData": 'ipfs://bafybeie7oxpsr7evcnlptecxfdhaqlot4732phukd2ekgvuzoir2frost4',
|
||||
* "mutableData": 'ipfs://bafybeigotuony53ley3n63hqwyxiqruqn5uamskmci6f645putnc46jju4'
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
* @api {REST} /bch getTokenData
|
||||
* @apiPermission public
|
||||
* @apiName getTokenData
|
||||
* @apiGroup REST BCH
|
||||
* @apiDescription Get data associated with a token
|
||||
*
|
||||
* Given a token ID, this endpoint will retrieve the IPFS CIDs associated with
|
||||
* the tokens mutable and immutable data. This is extension of the PS002
|
||||
* specification for mutable data for tokens:
|
||||
* https://github.com/Permissionless-Software-Foundation/specifications/blob/master/ps002-slp-mutable-data.md
|
||||
*
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "tokenId": "43eddfb11c9941edffb8c8815574bb0a43969a7b1de39ad14cd043eaa24fd38d", "withTxHistory": true }' https://bc01-ca-bch-consumer.fullstackcash.nl/bch/getTokenData
|
||||
*/
|
||||
async getTokenData (ctx) {
|
||||
try {
|
||||
const tokenId = ctx.request.body.tokenId
|
||||
@@ -623,6 +588,41 @@ class BchRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {REST} /bch getTokenData2
|
||||
* @apiPermission public
|
||||
* @apiName getTokenData2
|
||||
* @apiGroup REST BCH
|
||||
* @apiDescription Get token icon and other media
|
||||
*
|
||||
* Get the icon for a token, given it's token ID.
|
||||
* This function expects a string input of a token ID property.
|
||||
* This function returns an object with a tokenIcon property that contains
|
||||
* the URL to the icon.
|
||||
*
|
||||
* The output object always have these properties:
|
||||
* - tokenIcon: A url to the token icon, if it exists.
|
||||
* - tokenStats: Data about the token from psf-slp-indexer.
|
||||
* - optimizedTokenIcon: An alternative, potentially more optimal, url to the token icon, if it exists.
|
||||
* - iconRepoCompatible: true if the token icon is available via token.bch.sx
|
||||
* - ps002Compatible: true if the token icon is compatible with PS007 specification.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "tokenId": "43eddfb11c9941edffb8c8815574bb0a43969a7b1de39ad14cd043eaa24fd38d" }' https://bc01-ca-bch-consumer.fullstackcash.nl/bch/getTokenData2
|
||||
*/
|
||||
async getTokenData2 (ctx) {
|
||||
try {
|
||||
const tokenId = ctx.request.body.tokenId
|
||||
|
||||
const data = await this.adapters.bch.getTokenData2(tokenId)
|
||||
console.log(`getTokenData2 data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
ctx.body = data
|
||||
} catch (err) {
|
||||
this.handleError(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
// DRY error handler
|
||||
handleError (ctx, err) {
|
||||
// If an HTTP status is specified by the buisiness logic, use that.
|
||||
|
||||
@@ -61,6 +61,7 @@ class BchRouter {
|
||||
this.router.post('/pubkey', this.postPubKey)
|
||||
this.router.post('/utxoIsValid', this.utxoIsValid)
|
||||
this.router.post('/getTokenData', this.getTokenData)
|
||||
this.router.post('/getTokenData2', this.getTokenData2)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(this.router.routes())
|
||||
@@ -106,6 +107,10 @@ class BchRouter {
|
||||
async getTokenData (ctx, next) {
|
||||
await _this.bchRESTController.getTokenData(ctx, next)
|
||||
}
|
||||
|
||||
async getTokenData2 (ctx, next) {
|
||||
await _this.bchRESTController.getTokenData2(ctx, next)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BchRouter
|
||||
|
||||
@@ -64,6 +64,31 @@ class PriceRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
// Get the XEC price.
|
||||
// TODO: Add API docs.
|
||||
async getXecPrice (ctx) {
|
||||
try {
|
||||
// Request options
|
||||
const opt = {
|
||||
method: 'get',
|
||||
baseURL: 'https://api.coinex.com',
|
||||
url: '/v1/market/ticker?market=xecusdt',
|
||||
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.ticker.last) }
|
||||
} catch (err) {
|
||||
// Write out error to error log.
|
||||
wlogger.error('Error in GET /price/xecusd.', err)
|
||||
|
||||
this.handleError(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
// DRY error handler
|
||||
handleError (ctx, err) {
|
||||
// If an HTTP status is specified by the buisiness logic, use that.
|
||||
|
||||
@@ -52,6 +52,7 @@ class PriceRouter {
|
||||
|
||||
// Define the routes and attach the controller.
|
||||
this.router.get('/usd', this.getPrice)
|
||||
this.router.get('/xecusd', this.getXecPrice)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(this.router.routes())
|
||||
@@ -61,6 +62,10 @@ class PriceRouter {
|
||||
async getPrice (ctx, next) {
|
||||
await _this.priceRESTController.getUSD(ctx, next)
|
||||
}
|
||||
|
||||
async getXecPrice (ctx, next) {
|
||||
await _this.priceRESTController.getXecPrice(ctx, next)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PriceRouter
|
||||
|
||||
@@ -344,4 +344,34 @@ describe('#bch-use-case', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getTokenData2', () => {
|
||||
it('should validate a utxo', async () => {
|
||||
// Force connection to a wallet service
|
||||
uut.ipfs.ipfsCoordAdapter.state = {
|
||||
selectedServiceProvider: 'abc123'
|
||||
}
|
||||
|
||||
// Mock depenencies
|
||||
sandbox.stub(uut, 'waitForRPCResponse').resolves({ key: 'value' })
|
||||
|
||||
const tokenId = 'blah'
|
||||
|
||||
const result = await uut.getTokenData2(tokenId)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.key, 'value')
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
await uut.getTokenData2()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.equal(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -394,4 +394,40 @@ describe('#BCH-REST-Controller', () => {
|
||||
assert.equal(ctx.status, 200)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getTokenData2', () => {
|
||||
it('should return 422 status on arbitrary error', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(uut.adapters.bch, 'getTokenData2')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
ctx.request.body = {
|
||||
tokenId: 'blah'
|
||||
}
|
||||
|
||||
await uut.getTokenData2(ctx)
|
||||
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
console.log('err: ', err)
|
||||
assert.equal(err.status, 422)
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
it('should return 200 status on success', async () => {
|
||||
sandbox.stub(uut.adapters.bch, 'getTokenData2').resolves({ status: 200 })
|
||||
|
||||
ctx.request.body = {
|
||||
tokenId: 'blah'
|
||||
}
|
||||
|
||||
await uut.getTokenData2(ctx)
|
||||
|
||||
// Assert the expected HTTP response
|
||||
assert.equal(ctx.status, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
Mocks for the Adapter library.
|
||||
*/
|
||||
|
||||
const ipfs = {
|
||||
ipfsAdapter: {
|
||||
ipfs: {}
|
||||
},
|
||||
ipfsCoordAdapter: {
|
||||
ipfsCoord: {
|
||||
class IpfsAdapter {
|
||||
constructor () {
|
||||
this.ipfs = {
|
||||
files: {
|
||||
stat: () => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IpfsCoordAdapter {
|
||||
constructor () {
|
||||
|
||||
this.ipfsCoord = {
|
||||
useCases: {
|
||||
peer: {
|
||||
sendPrivateMessage: () => {}
|
||||
@@ -17,13 +25,21 @@ const ipfs = {
|
||||
peerData: []
|
||||
}
|
||||
},
|
||||
peerInputHandler: () => {},
|
||||
state: {
|
||||
|
||||
this.peerInputHandler = () => {}
|
||||
|
||||
this.state = {
|
||||
serviceProviders: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ipfs = {
|
||||
ipfsAdapter: new IpfsAdapter(),
|
||||
ipfsCoordAdapter: new IpfsCoordAdapter()
|
||||
}
|
||||
ipfs.ipfs = ipfs.ipfsAdapter.ipfs
|
||||
|
||||
const localdb = {
|
||||
Users: class Users {
|
||||
static findById () {}
|
||||
@@ -101,6 +117,10 @@ class BchUseCaseMock {
|
||||
return {}
|
||||
}
|
||||
|
||||
async getTokenData2() {
|
||||
return {}
|
||||
}
|
||||
|
||||
async waitForRPCResponse () {
|
||||
return {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user