mirror of
https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service.git
synced 2026-09-21 16:52:03 -07:00
feat(Fulcrum): Added transactions endpoint for REST and JSON RPC
This commit is contained in:
Vendored
+13
-6
@@ -13,9 +13,15 @@ module.exports = {
|
||||
logPass: 'test',
|
||||
|
||||
// Email server settings if nodemailer email notifications are used.
|
||||
emailServer: process.env.EMAILSERVER ? process.env.EMAILSERVER : 'mail.someserver.com',
|
||||
emailUser: process.env.EMAILUSER ? process.env.EMAILUSER : 'noreply@someserver.com',
|
||||
emailPassword: process.env.EMAILPASS ? process.env.EMAILPASS : 'emailpassword',
|
||||
emailServer: process.env.EMAILSERVER
|
||||
? process.env.EMAILSERVER
|
||||
: 'mail.someserver.com',
|
||||
emailUser: process.env.EMAILUSER
|
||||
? process.env.EMAILUSER
|
||||
: 'noreply@someserver.com',
|
||||
emailPassword: process.env.EMAILPASS
|
||||
? process.env.EMAILPASS
|
||||
: 'emailpassword',
|
||||
|
||||
// IPFS settings.
|
||||
isCircuitRelay: process.env.ENABLE_CIRCUIT_RELAY ? true : false,
|
||||
@@ -27,9 +33,10 @@ module.exports = {
|
||||
announceJsonLd: {
|
||||
'@context': 'https://schema.org/',
|
||||
'@type': 'WebAPI',
|
||||
name: 'ipfs-service-provider',
|
||||
description: 'This is a generic IPFS Serivice Provider that uses JSON RPC over IPFS to communicate with it. This instance has not been customized. Source code: https://github.com/Permissionless-Software-Foundation/ipfs-service-provider',
|
||||
documentation: 'https://ipfs-service-provider.fullstack.cash/',
|
||||
name: 'ipfs-bch-wallet-service',
|
||||
description:
|
||||
'IPFS service providing BCH blockchain access needed by a wallet.',
|
||||
documentation: 'https://ipfs-bch-wallet-service.fullstack.cash/',
|
||||
provider: {
|
||||
'@type': 'Organization',
|
||||
name: 'Permissionless Software Foundation',
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
This is the JSON RPC router for the Fulcrum API
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
const jsonrpc = require('jsonrpc-lite')
|
||||
const BCHJS = require('@psf/bch-js')
|
||||
|
||||
// Local libraries
|
||||
// const UserLib = require('../../../use-cases/user')
|
||||
const Validators = require('../validators')
|
||||
const RateLimit = require('../rate-limit')
|
||||
|
||||
class FulcrumRPC {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating User JSON RPC Controller.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantiating User JSON RPC Controller.'
|
||||
)
|
||||
}
|
||||
|
||||
// Encapsulate dependencies
|
||||
this.userLib = this.useCases.user
|
||||
this.jsonrpc = jsonrpc
|
||||
this.validators = new Validators(localConfig)
|
||||
this.rateLimit = new RateLimit()
|
||||
this.bchjs = new BCHJS()
|
||||
}
|
||||
|
||||
// Top-level router for this library. All other methods in this class are for
|
||||
// a specific endpoint. This method routes incoming calls to one of those
|
||||
// methods.
|
||||
async fulcrumRouter (rpcData) {
|
||||
let endpoint = 'unknown'
|
||||
try {
|
||||
console.log('fulcrumRouter rpcData: ', rpcData)
|
||||
|
||||
endpoint = rpcData.payload.params.endpoint
|
||||
let user
|
||||
|
||||
// Route the call based on the value of the method property.
|
||||
switch (endpoint) {
|
||||
case 'transactions':
|
||||
await this.rateLimit.limiter(rpcData.from)
|
||||
return await this.transactions(rpcData)
|
||||
|
||||
// case 'getAllUsers':
|
||||
// await this.validators.ensureUser(rpcData)
|
||||
// await this.rateLimit.limiter(rpcData.from)
|
||||
// return await this.getAll(rpcData)
|
||||
//
|
||||
// case 'getUser':
|
||||
// user = await this.validators.ensureUser(rpcData)
|
||||
// await this.rateLimit.limiter(rpcData.from)
|
||||
// return await this.getUser(rpcData, user)
|
||||
//
|
||||
// case 'updateUser':
|
||||
// user = await this.validators.ensureTargetUserOrAdmin(rpcData)
|
||||
// await this.rateLimit.limiter(rpcData.from)
|
||||
// return await this.updateUser(rpcData, user)
|
||||
//
|
||||
// case 'deleteUser':
|
||||
// user = await this.validators.ensureTargetUserOrAdmin(rpcData)
|
||||
// await this.rateLimit.limiter(rpcData.from)
|
||||
// return await this.deleteUser(rpcData, user)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error in FulcrumRPC/rpcRouter()')
|
||||
// throw err
|
||||
|
||||
return {
|
||||
success: false,
|
||||
status: err.status || 500,
|
||||
message: err.message,
|
||||
endpoint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {JSON} /fulcrum Transactions
|
||||
* @apiPermission public
|
||||
* @apiName Transactions
|
||||
* @apiGroup JSON Fulcrum
|
||||
* @apiDescription This endpoint wraps the bchjs.Electrumx.transactions([]) function.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* {"jsonrpc":"2.0","id":"555","method":"fulcrum","params":{ "endpoint": "transactions", "addresses": ["bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"]}}
|
||||
*
|
||||
*/
|
||||
async transactions (rpcData) {
|
||||
try {
|
||||
// console.log('createUser rpcData: ', rpcData)
|
||||
|
||||
const addrs = rpcData.payload.params.addresses
|
||||
|
||||
const data = await this.bchjs.Electrumx.transactions(addrs)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
const retObj = data
|
||||
retObj.status = 200
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
// console.error('Error in createUser()')
|
||||
// throw err
|
||||
|
||||
// Return an error response
|
||||
return {
|
||||
success: false,
|
||||
status: 422,
|
||||
message: err.message,
|
||||
endpoint: 'transactions'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO create deleteUser()
|
||||
}
|
||||
|
||||
module.exports = FulcrumRPC
|
||||
@@ -10,6 +10,7 @@ const { wlogger } = require('../../adapters/wlogger')
|
||||
const UserController = require('./users')
|
||||
const AuthController = require('./auth')
|
||||
const AboutController = require('./about')
|
||||
const FulcrumController = require('./fulcrum')
|
||||
|
||||
let _this
|
||||
|
||||
@@ -35,6 +36,7 @@ class JSONRPC {
|
||||
this.userController = new UserController(localConfig)
|
||||
this.authController = new AuthController(localConfig)
|
||||
this.aboutController = new AboutController()
|
||||
this.fulcrumController = new FulcrumController(localConfig)
|
||||
|
||||
_this = this
|
||||
}
|
||||
@@ -80,6 +82,9 @@ class JSONRPC {
|
||||
break
|
||||
case 'about':
|
||||
retObj = await _this.aboutController.aboutRouter(parsedData)
|
||||
break
|
||||
case 'fulcrum':
|
||||
retObj = await _this.fulcrumController.fulcrumRouter(parsedData)
|
||||
}
|
||||
|
||||
// console.log('retObj: ', retObj)
|
||||
|
||||
@@ -14,7 +14,7 @@ class RateLimit {
|
||||
// Set default rate limit options.
|
||||
this.defaultOptions = {
|
||||
interval: { min: 1 },
|
||||
max: 60,
|
||||
max: 1000, // 1000 RPM while prototyping.
|
||||
onLimitReached: this.onLimitReached
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Controller for the /fulcrum REST API endpoints.
|
||||
*/
|
||||
|
||||
const BCHJS = require('@psf/bch-js')
|
||||
|
||||
let _this
|
||||
|
||||
class FulcrumController {
|
||||
constructor () {
|
||||
_this = this
|
||||
_this.bchjs = new BCHJS()
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /fulcrum/transactions Transactions
|
||||
* @apiName Transactions
|
||||
* @apiGroup REST Fulcrum
|
||||
* @apiDescription This endpoint wraps the bchjs.Electrumx.transactions([]) function.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "addresses": ["bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj"] }' localhost:5001/fulcrum/transactions
|
||||
*
|
||||
* @apiParam {Object} obj object (required)
|
||||
* @apiParam {String} obj.email Sender Email.
|
||||
* @apiParam {String} obj.formMessage Message.
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
*
|
||||
* success:true,
|
||||
* data: <data>
|
||||
* }
|
||||
*
|
||||
* @apiError UnprocessableEntity Missing required parameters
|
||||
*
|
||||
* @apiErrorExample {json} Error-Response:
|
||||
* HTTP/1.1 422 Unprocessable Entity
|
||||
* {
|
||||
* "status": 422,
|
||||
* "error": "Unprocessable Entity"
|
||||
* }
|
||||
*/
|
||||
async transactions (ctx) {
|
||||
try {
|
||||
const addrs = ctx.request.body.addresses
|
||||
|
||||
const data = await _this.bchjs.Electrumx.transactions(addrs)
|
||||
// console.log(`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.
|
||||
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 = FulcrumController
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
REST API library for /fulcrum route.
|
||||
*/
|
||||
|
||||
// Public npm libraries.
|
||||
const Router = require('koa-router')
|
||||
|
||||
// Local libraries.
|
||||
const FulcrumRESTControllerLib = require('./controller')
|
||||
|
||||
class FulcrumRouter {
|
||||
constructor (localConfig = {}) {
|
||||
// Dependency Injection.
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating Fulcrum REST Controller.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantiating Fulcrum REST Controller.'
|
||||
)
|
||||
}
|
||||
|
||||
const dependencies = {
|
||||
adapters: this.adapters,
|
||||
useCases: this.useCases
|
||||
}
|
||||
|
||||
// Encapsulate dependencies.
|
||||
this.fulcrumRESTController = new FulcrumRESTControllerLib(dependencies)
|
||||
|
||||
// Instantiate the router and set the base route.
|
||||
const baseUrl = '/fulcrum'
|
||||
this.router = new Router({ prefix: baseUrl })
|
||||
}
|
||||
|
||||
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.post('/transactions', this.fulcrumRESTController.transactions)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(this.router.routes())
|
||||
app.use(this.router.allowedMethods())
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FulcrumRouter
|
||||
@@ -11,6 +11,7 @@ const AuthRESTController = require('./auth')
|
||||
const UserRouter = require('./users')
|
||||
const ContactRESTController = require('./contact')
|
||||
const LogsRESTController = require('./logs')
|
||||
const FulcrumRESTController = require('./fulcrum')
|
||||
|
||||
class RESTControllers {
|
||||
constructor (localConfig = {}) {
|
||||
@@ -52,6 +53,10 @@ class RESTControllers {
|
||||
// Attach the REST API Controllers associated with the /logs route
|
||||
const logsRESTController = new LogsRESTController(dependencies)
|
||||
logsRESTController.attach(app)
|
||||
|
||||
// Attach the REST API Controllers associated with the /fulcrum route
|
||||
const fulcrumRESTController = new FulcrumRESTController(dependencies)
|
||||
fulcrumRESTController.attach(app)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user