mirror of
https://github.com/Permissionless-Software-Foundation/ipfs-bch-wallet-service.git
synced 2026-09-22 09:12:02 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79918f6376 | ||
|
|
da5942b28f | ||
|
|
d54cd3889b | ||
|
|
5df54feb5e | ||
|
|
fb841df43e | ||
|
|
a763ec640f | ||
|
|
e74e063b0d | ||
|
|
142cdb17a6 | ||
|
|
a129988538 | ||
|
|
6bf85b4639 | ||
|
|
733e8fd405 | ||
|
|
baee72c1c6 | ||
|
|
5d12749043 | ||
|
|
2ebd8b998f | ||
|
|
11618a796f | ||
|
|
025ae20704 |
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"srcDir": "",
|
||||
"destDir": "",
|
||||
"files": "**/*.js",
|
||||
"command": "npm run lint"
|
||||
}
|
||||
]
|
||||
Generated
+437
-698
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -24,12 +24,12 @@
|
||||
},
|
||||
"repository": "Permissionless-Software-Foundation/ipfs-bch-wallet-service",
|
||||
"dependencies": {
|
||||
"@psf/bch-js": "5.3.2",
|
||||
"@psf/bch-js": "6.4.0",
|
||||
"axios": "0.25.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"glob": "7.1.6",
|
||||
"ipfs": "0.60.0",
|
||||
"ipfs-coord": "7.1.4",
|
||||
"ipfs-coord": "7.1.6",
|
||||
"ipfs-http-client": "55.0.0",
|
||||
"jsonrpc-lite": "2.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
|
||||
@@ -14,7 +14,7 @@ services:
|
||||
restart: always
|
||||
|
||||
ipfs-bch-wallet:
|
||||
image: ipfs/go-ipfs:v0.11.0
|
||||
image: ipfs/go-ipfs:v0.12.0
|
||||
container_name: ipfs-bch-wallet
|
||||
environment:
|
||||
MY_ENV_VAR: 'placeholder'
|
||||
|
||||
@@ -71,6 +71,14 @@ class BCHRPC {
|
||||
case 'pubkey':
|
||||
await this.rateLimit.limiter(rpcData.from)
|
||||
return await this.pubKey(rpcData)
|
||||
|
||||
case 'utxoIsValid':
|
||||
await this.rateLimit.limiter(rpcData.from)
|
||||
return await this.utxoIsValid(rpcData)
|
||||
|
||||
case 'getTokenData':
|
||||
await this.rateLimit.limiter(rpcData.from)
|
||||
return await this.getTokenData(rpcData)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error in BCHRPC/rpcRouter()')
|
||||
@@ -529,7 +537,6 @@ class BCHRPC {
|
||||
return retObj
|
||||
} catch (err) {
|
||||
console.error('Error in JSON RPC BCH txData()): ', err)
|
||||
// throw err
|
||||
|
||||
// Return an error response
|
||||
return {
|
||||
@@ -577,7 +584,6 @@ class BCHRPC {
|
||||
*
|
||||
* }
|
||||
*/
|
||||
|
||||
async pubKey (rpcData) {
|
||||
try {
|
||||
// console.log('createUser rpcData: ', rpcData)
|
||||
@@ -598,11 +604,13 @@ class BCHRPC {
|
||||
return retObj
|
||||
} catch (err) {
|
||||
console.error('Error in JSON RPC BCH pubKey()')
|
||||
// throw err
|
||||
|
||||
// Handle different error formats.
|
||||
let error = err
|
||||
if (err.error && typeof err.error === 'string') {
|
||||
error = new Error(err.error)
|
||||
}
|
||||
|
||||
// Return an error response
|
||||
return {
|
||||
success: false,
|
||||
@@ -612,6 +620,169 @@ class BCHRPC {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {JSON} /bch UtxoIsValid
|
||||
* @apiPermission public
|
||||
* @apiName UtxoIsValid
|
||||
* @apiGroup JSON BCH
|
||||
* @apiDescription Verify if UTXO is valid
|
||||
* Given a UTXO object (txid and vout), a full node is queried to verify that
|
||||
* the UTXO still exists in the mempool (true), or if it has been spent (false).
|
||||
*
|
||||
* - jsonrpc: "" - jsonrpc version
|
||||
* - id: "" - jsonrpc id
|
||||
* - result: {} - Result of the petition with the RPC information
|
||||
* - success: - Request status
|
||||
* - isValid: - Boolean: true or false
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* {"jsonrpc":"2.0","id":"555","method":"bch","params":{ "endpoint": "utxoIsValid", "utxo": {"tx_hash": "17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a", "tx_pos": 0}}}
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* {
|
||||
* "jsonrpc":"2.0",
|
||||
* "id":"555",
|
||||
* "result":{
|
||||
* "method":"bch",
|
||||
* "reciever":"QmU86vLVbUY1UhziKB6rak7GPKRA2QHWvzNm2AjEvXNsT6",
|
||||
* "value":{
|
||||
* "success": true,
|
||||
* "status": 200,
|
||||
* "endpoint": "utxoIsValid",
|
||||
* "isValid": true
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* }
|
||||
*/
|
||||
async utxoIsValid (rpcData) {
|
||||
try {
|
||||
// console.log('createUser rpcData: ', rpcData)
|
||||
|
||||
const utxo = rpcData.payload.params.utxo
|
||||
// console.log('utxo: ', utxo)
|
||||
|
||||
const isValid = await this.bchjs.Utxo.isValid(utxo)
|
||||
|
||||
const retObj = {
|
||||
success: true,
|
||||
status: 200,
|
||||
endpoint: 'utxoIsValid',
|
||||
isValid
|
||||
}
|
||||
// retObj.status = 200
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
console.error('Error in JSON RPC BCH utxoIsValid()')
|
||||
|
||||
// Handle different error formats.
|
||||
let error = err
|
||||
if (err.error && typeof err.error === 'string') {
|
||||
error = new Error(err.error)
|
||||
}
|
||||
|
||||
// Return an error response
|
||||
return {
|
||||
success: false,
|
||||
status: 422,
|
||||
message: error.message,
|
||||
endpoint: 'utxoIsValid'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {JSON} /bch getTokenData
|
||||
* @apiPermission public
|
||||
* @apiName getTokenData
|
||||
* @apiGroup JSON 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
|
||||
* - publickey: - 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'
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
async getTokenData (rpcData) {
|
||||
try {
|
||||
// console.log('createUser rpcData: ', rpcData)
|
||||
|
||||
const tokenId = rpcData.payload.params.tokenId
|
||||
// console.log('tokenId: ', tokenId)
|
||||
|
||||
const tokenData = await this.bchjs.PsfSlpIndexer.getTokenData(tokenId)
|
||||
|
||||
const retObj = {
|
||||
success: true,
|
||||
status: 200,
|
||||
endpoint: 'getTokenData',
|
||||
tokenData
|
||||
}
|
||||
// retObj.status = 200
|
||||
|
||||
return retObj
|
||||
} catch (err) {
|
||||
console.error('Error in JSON RPC BCH utxoIsValid()')
|
||||
|
||||
// Handle different error formats.
|
||||
let error = err
|
||||
if (err.error && typeof err.error === 'string') {
|
||||
error = new Error(err.error)
|
||||
}
|
||||
|
||||
// Return an error response
|
||||
return {
|
||||
success: false,
|
||||
status: 422,
|
||||
message: error.message,
|
||||
endpoint: 'getTokenData'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BCHRPC
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Integration tests for the endpoints in controllers/json-rpc/bch
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
const assert = require('chai').assert
|
||||
|
||||
// Local libraries
|
||||
const BCHController = require('../../../../src/controllers/json-rpc/bch')
|
||||
const Adapters = require('../../../../src/adapters')
|
||||
const UseCases = require('../../../../src/use-cases')
|
||||
|
||||
describe('#BCH', () => {
|
||||
let uut
|
||||
|
||||
before(async () => {
|
||||
const adapters = new Adapters()
|
||||
const useCases = new UseCases({ adapters })
|
||||
// await adapters.start()
|
||||
|
||||
uut = new BCHController({ adapters, useCases })
|
||||
})
|
||||
|
||||
describe('#utxoIsValid', () => {
|
||||
it('should return true for valid UTXO with fullnode properties', async () => {
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
utxo: {
|
||||
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
|
||||
vout: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.utxoIsValid(rpcData)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.isValid, true)
|
||||
})
|
||||
|
||||
it('should return true for valid UTXO with fulcrum properties', async () => {
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
utxo: {
|
||||
tx_hash: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
|
||||
tx_pos: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.utxoIsValid(rpcData)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.isValid, true)
|
||||
})
|
||||
|
||||
it('should return false for valid UTXO with fullnode properties', async () => {
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
utxo: {
|
||||
txid: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
|
||||
vout: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.utxoIsValid(rpcData)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.isValid, false)
|
||||
})
|
||||
|
||||
it('should return false for valid UTXO with fulcrum properties', async () => {
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
utxo: {
|
||||
tx_hash: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
|
||||
tx_pos: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.utxoIsValid(rpcData)
|
||||
// console.log('result: ', result
|
||||
|
||||
assert.equal(result.isValid, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getTokenData', () => {
|
||||
it('should return data for a token', async () => {
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
tokenId: 'c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.getTokenData(rpcData)
|
||||
console.log('result: ', result)
|
||||
|
||||
// assert.equal(result.isValid, true)
|
||||
assert.property(result.tokenData, 'immutableData')
|
||||
assert.property(result.tokenData, 'mutableData')
|
||||
assert.equal(result.success, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -14,7 +14,7 @@ describe('#BCH', () => {
|
||||
|
||||
before(async () => {
|
||||
const adapters = new Adapters()
|
||||
await adapters.start()
|
||||
// await adapters.start()
|
||||
|
||||
uut = new BCHUseCases({ adapters })
|
||||
})
|
||||
|
||||
@@ -488,6 +488,7 @@ describe('#BCHRPC', () => {
|
||||
assert.equal(response.message, 'No transaction history.')
|
||||
assert.equal(response.endpoint, 'pubkey')
|
||||
})
|
||||
|
||||
it('should return an error for invalid input', async () => {
|
||||
// Force an error
|
||||
sandbox
|
||||
@@ -513,4 +514,128 @@ describe('#BCHRPC', () => {
|
||||
assert.equal(response.endpoint, 'pubkey')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#utxoIsValid', () => {
|
||||
it('should return false if UTXO.isValid() returns false', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(uut.bchjs.Utxo, 'isValid')
|
||||
.resolves(false)
|
||||
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
utxo: {
|
||||
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
|
||||
vout: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.utxoIsValid(rpcData)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.isValid, false)
|
||||
assert.equal(result.success, true)
|
||||
})
|
||||
|
||||
it('should return true if UTXO.isValid() returns true', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(uut.bchjs.Utxo, 'isValid')
|
||||
.resolves(true)
|
||||
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
utxo: {
|
||||
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
|
||||
vout: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.utxoIsValid(rpcData)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.isValid, true)
|
||||
assert.equal(result.success, true)
|
||||
})
|
||||
|
||||
it('should catch and return errors', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(uut.bchjs.Utxo, 'isValid')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
utxo: {
|
||||
txid: 'b94e1ff82eb5781f98296f0af2488ff06202f12ee92b0175963b8dba688d1b40',
|
||||
vout: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.utxoIsValid(rpcData)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.success, false)
|
||||
assert.equal(result.status, 422)
|
||||
assert.equal(result.message, 'test error')
|
||||
assert.equal(result.endpoint, 'utxoIsValid')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getTokenData', () => {
|
||||
it('should return data from PsfSlpIndexer.getTokenData()', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(uut.bchjs.PsfSlpIndexer, 'getTokenData')
|
||||
.resolves({ a: 'b' })
|
||||
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
tokenId: 'c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.getTokenData(rpcData)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.success, true)
|
||||
assert.equal(result.status, 200)
|
||||
assert.equal(result.endpoint, 'getTokenData')
|
||||
assert.property(result, 'tokenData')
|
||||
})
|
||||
|
||||
it('should catch and return errors', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(uut.bchjs.PsfSlpIndexer, 'getTokenData')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
const rpcData = {
|
||||
payload: {
|
||||
params: {
|
||||
tokenId: 'c85042ab08a2099f27de880a30f9a42874202751d834c42717a20801a00aab0d'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = await uut.getTokenData(rpcData)
|
||||
// console.log('result: ', result)
|
||||
|
||||
assert.equal(result.success, false)
|
||||
assert.equal(result.status, 422)
|
||||
assert.equal(result.message, 'test error')
|
||||
assert.equal(result.endpoint, 'getTokenData')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -60,7 +60,8 @@ const bchjs = {
|
||||
sortAllTxs: () => {}
|
||||
},
|
||||
Utxo: {
|
||||
get: () => {}
|
||||
get: () => {},
|
||||
isValid: () => true
|
||||
},
|
||||
Transaction: {
|
||||
get: () => {}
|
||||
@@ -73,6 +74,9 @@ const bchjs = {
|
||||
},
|
||||
Util: {
|
||||
chunk100: () => {}
|
||||
},
|
||||
PsfSlpIndexer: {
|
||||
getTokenData: () => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user