Compare commits

...
12 Commits
Author SHA1 Message Date
Chris Troutner 277c9ce0fd Merge pull request #217 from Permissionless-Software-Foundation/ct-unstable
feat(ipfs): Removing the ipfs pinning libraries and dependencies
2022-03-10 16:47:43 -08:00
Chris Troutner e0c07d1542 feat(ipfs): Removing the ipfs pinning libraries and dependencies 2022-03-10 16:45:27 -08:00
Chris Troutner 56bc942e87 fix(tests): Fixing broken integration test 2022-03-10 16:38:41 -08:00
Chris Troutner 34b9cefb65 fix(psf-slp-indexer): Switching URL back 2022-03-10 16:37:11 -08:00
Chris Troutner 6a35091eec fix(psf-slp-indexer): Fixing issue with url 2022-03-10 16:24:12 -08:00
Chris Troutner 02e3ff4dcd Merge pull request #216 from Permissionless-Software-Foundation/ct-unstable
fix(psf-slp-indexer): Adding flag for tx history of tokens
2022-02-06 13:26:05 -08:00
Chris Troutner 64f8adea25 fix(psf-slp-indexer): Adding flag for tx history of tokens 2022-02-06 13:23:25 -08:00
Chris Troutner bcf817f5c7 Merge pull request #215 from Permissionless-Software-Foundation/ct-unstable
Fixing integration test
2022-01-31 21:22:25 -08:00
Chris Troutner 541377e548 Fixing integration test 2022-01-31 21:18:08 -08:00
Chris Troutner 84b44b299a Merge pull request #214 from Permissionless-Software-Foundation/ct-unstable
fix(UTXO.get()): Added detection of null-tagged UTXOs
2022-01-31 21:13:50 -08:00
Chris Troutner b6456df1f4 Fixing unit tests 2022-01-31 21:11:11 -08:00
Chris Troutner b1826c04cb fix(UTXO.get()): Added detection of null-tagged UTXOs 2022-01-31 20:57:36 -08:00
10 changed files with 4805 additions and 3412 deletions
+4738 -2476
View File
File diff suppressed because it is too large Load Diff
+4 -6
View File
@@ -37,13 +37,11 @@
"url": "git+https://github.com/Permissionless-Software-Foundation/bch-js.git"
},
"dependencies": {
"@psf/bip21": "2.0.1",
"@chris.troutner/bip32-utils": "1.0.5",
"@psf/bip21": "2.0.1",
"@psf/bitcoincash-ops": "2.0.0",
"@psf/bitcoincashjs-lib": "4.0.2",
"@psf/coininfo": "4.0.0",
"@uppy/core": "1.10.4",
"@uppy/tus": "1.5.12",
"axios": "^0.21.4",
"bc-bip68": "1.0.5",
"bchaddrjs-slp": "0.2.5",
@@ -65,7 +63,7 @@
"wif": "2.0.6"
},
"devDependencies": {
"apidoc": "0.17.7",
"apidoc": "^0.50.5",
"assert": "2.0.0",
"chai": "4.1.2",
"coveralls": "3.0.2",
@@ -77,10 +75,10 @@
"eslint-plugin-standard": "4.0.0",
"husky": "^4.3.8",
"lodash.clonedeep": "4.5.0",
"mocha": "9.1.3",
"mocha": "^9.2.1",
"node-mocks-http": "1.7.0",
"nyc": "15.1.0",
"semantic-release": "18.0.0",
"semantic-release": "^19.0.2",
"sinon": "9.2.2",
"standard": "^16.0.4"
},
-2
View File
@@ -28,7 +28,6 @@ const Script = require('./script')
const Price = require('./price')
const Schnorr = require('./schnorr')
const SLP = require('./slp/slp')
const IPFS = require('./ipfs')
const Encryption = require('./encryption')
const Utxo = require('./utxo')
const Transaction = require('./transaction')
@@ -111,7 +110,6 @@ class BCHJS {
this.SLP = new SLP(libConfig)
this.SLP.HDNode = this.HDNode
this.IPFS = new IPFS()
this.Utxo = new Utxo(libConfig)
this.Transaction = new Transaction(libConfig)
-454
View File
@@ -1,454 +0,0 @@
/*
This library interacts with the IPFS REST API at FullStack.cash for uploading
and downloading data from the IPFS network.
*/
const axios = require('axios')
const Uppy = require('@uppy/core')
const Tus = require('@uppy/tus')
const fs = require('fs')
let _this
class IPFS {
constructor (config) {
this.IPFS_API = process.env.IPFS_API
? process.env.IPFS_API
: 'https://ipfs-file-upload.fullstackcash.nl'
// : `http://localhost:5001`
// Default options when calling axios.
this.axiosOptions = {
headers: {
// authorization: `Token ${this.apiToken}`,
timeout: 15000 // Timeout if the server does not respond in time.
}
}
_this = this
_this.axios = axios
_this.fs = fs
// Initialize Uppy
_this.uppy = _this.initUppy()
}
// Initializes Uppy, which is used for file uploads.
initUppy () {
const uppy = Uppy({
allowMultipleUploads: false,
meta: { test: 'avatar' },
debug: false,
restrictions: {
maxFileSize: null,
maxNumberOfFiles: 1,
minNumberOfFiles: 1,
allowedFileTypes: null // type of files allowed to load
}
})
uppy.use(Tus, { endpoint: `${_this.IPFS_API}/uppy-files` })
return uppy
}
/**
* @api IPFS.createFileModelServer() createFileModelServer()
* @apiName createFileModelServer()
* @apiGroup IPFS
* @apiDescription Creates a new model on the server. If successful, will
* return an object with file data. That object contains a BCH address,
* payment amount, and _id required to be able to upload a file.
*
* @apiExample Example usage:
* (async () => {
* try {
* const path = `${__dirname}/ipfs.js`
* let fileData = await bchjs.IPFS.createFileModelServer(path);
* console.log(fileData);
* } catch(error) {
* console.error(error)
* }
* })()
*
* {
* "success": true,
* "hostingCostBCH": 0.00004197,
* "hostingCostUSD": 0.01,
* "file": {
* "payloadLink": "",
* "hasBeenPaid": false,
* "_id": "5ec562319bfacc745e8d8a52",
* "schemaVersion": 1,
* "size": 4458,
* "fileName": "ipfs.js",
* "fileExtension": "js",
* "createdTimestamp": "1589994033.655",
* "hostingCost": 4196,
* "walletIndex": 49,
* "bchAddr": "bchtest:qzrpkevu7h2ayfa4rjx08r5elvpfu72dg567x3mh3c",
* "__v": 0
* }
*/
async createFileModelServer (path) {
try {
// Ensure the file exists.
if (!_this.fs.existsSync(path)) {
throw new Error(`Could not find this file: ${path}`)
}
// Read in the file.
const fileBuf = _this.fs.readFileSync(path)
// console.log(`fileBuf: `, fileBuf)
// console.log(`Buffer length: ${fileBuf.length}`)
// Get the file name from the path.
const splitPath = path.split('/')
const fileName = splitPath[splitPath.length - 1]
// Get the file extension.
const splitExt = fileName.split('.')
const fileExt = splitExt[splitExt.length - 1]
const fileObj = {
schemaVersion: 1,
size: fileBuf.length,
fileName: fileName,
fileExtension: fileExt
}
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
const fileData = await _this.axios.post(`${this.IPFS_API}/files`, {
file: fileObj
})
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
return fileData.data
} catch (err) {
console.error('Error in createFileModel()')
throw err
}
}
/**
* @api IPFS.uploadFileServer() uploadFileServer()
* @apiName uploadFile()
* @apiGroup IPFS
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
* successful, it will return an object with an ID, a BCH address, and an
* amount of BCH to pay.
*
* @apiExample Example usage:
* (async () => {
* try {
* const path = `${__dirname}/ipfs.js`
* let fileData = await bchjs.IPFS.uploadFileServer(path, "5ec562319bfacc745e8d8a52");
* console.log(fileData);
* } catch(error) {
* console.error(error)
* }
* })()
*
* {
* "schemaVersion": 1,
* "size": 2374,
* "fileId": "5ec562319bfacc745e8d8a52",
* "fileName": "ipfs.js",
* "fileExtension": "js"
* }
*/
async uploadFileServer (path, modelId) {
try {
// Ensure the file exists.
if (!_this.fs.existsSync(path)) {
throw new Error(`Could not find this file: ${path}`)
}
if (!modelId) {
throw new Error(
'Must include a file model ID in order to upload a file.'
)
}
// Read in the file.
const fileBuf = _this.fs.readFileSync(path)
// Get the file name from the path.
const splitPath = path.split('/')
const fileName = splitPath[splitPath.length - 1]
// Prepare the upload object. Get a file ID from Uppy.
const id = _this.uppy.addFile({
name: fileName,
data: fileBuf,
source: 'Local',
isRemote: false
})
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
// Add the model ID, required to be allowed to upload the file.
_this.uppy.setFileMeta(id, { fileModelId: modelId })
// Upload the file to the server.
const upData = await _this.uppy.upload()
if (upData.failed.length) {
throw new Error('The file could not be uploaded')
}
if (upData.successful.length) {
delete upData.successful[0].data
// console.log(`upData: ${JSON.stringify(upData, null, 2)}`)
const fileObj = {
schemaVersion: 1,
size: upData.successful[0].progress.bytesTotal,
fileId: upData.successful[0].meta.fileModelId,
fileName: upData.successful[0].name,
fileExtension: upData.successful[0].extension
}
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
return fileObj
// return true
}
return false
} catch (err) {
console.error('Error in bch-js/src/ipfs.js/upload(): ')
throw err
}
}
/**
* @api IPFS.getStatus() getStatus()
* @apiName getStatus()
* @apiGroup IPFS
* @apiDescription Gets the status of the uploaded file. Will return an object
* that indicates the payment status. If the file is paid, it should contain
* an IPFS hash.
*
* @apiExample Example usage:
* (async () => {
* try {
* const modelId = "5ec7392c2acfe57aa62e945a"
* let fileData = await bchjs.IPFS.getStatus(modelId)
* console.log(fileData)
* } catch(error) {
* console.error(error)
* }
* })()
*
* {
* "hasBeenPaid": true,
* "satCost": 4403,
* "bchAddr": "bchtest:qz5z82u0suqh80x5tfx4ht8kdrkkw664vcy44uz0wk",
* "ipfsHash": "QmRDHPhY5hCNVRMVQvS2H9uty8P1skdwgLaHpUAkEvsjcE",
* "fileId": "5ec7392c2acfe57aa62e945a",
* "fileName": "ipfs-e2e.js"
* }
*/
async getStatus (modelId) {
try {
if (!modelId) throw new Error('Must include a file model ID.')
const fileData = await _this.axios.get(
`${this.IPFS_API}/files/${modelId}`
)
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
const fileObj = {
hasBeenPaid: fileData.data.file.hasBeenPaid,
satCost: fileData.data.file.hostingCost,
bchAddr: fileData.data.file.bchAddr,
ipfsHash: fileData.data.file.payloadLink,
fileId: fileData.data.file._id,
fileName: fileData.data.file.fileName
}
return fileObj
} catch (err) {
console.error('Error in getStatus()')
throw err
}
}
/**
* @api IPFS.createFileModelWeb() createFileModelWeb()
* @apiName createFileModelWeb()
* @apiGroup IPFS
* @apiDescription Creates a new model on the server. If successful, will
* return an object with file data. That object contains a BCH address,
* payment amount, and _id required to be able to upload a file.
*
* @apiExample Example usage:
* (async () => {
* try {
* const content = ['PSF']
* const name = 'psf.txt' // Content can be Array , ArrayBuffer , Blob
* const options = { type: "text/plain" }
* const file = new File(content,name,options)
* let fileData = await bchjs.IPFS.createFileModelWeb(file);
* console.log(fileData);
* } catch(error) {
* console.error(error)
* }
* })()
*
* {
* "success": true,
* "hostingCostBCH": 0.00004197,
* "hostingCostUSD": 0.01,
* "file": {
* "payloadLink": "",
* "hasBeenPaid": false,
* "_id": "5ec562319bfacc745e8d8a52",
* "schemaVersion": 1,
* "size": 4458,
* "fileName": "ipfs.js",
* "fileExtension": "js",
* "createdTimestamp": "1589994033.655",
* "hostingCost": 4196,
* "walletIndex": 49,
* "bchAddr": "bchtest:qzrpkevu7h2ayfa4rjx08r5elvpfu72dg567x3mh3c",
* "__v": 0
* }
*/
async createFileModelWeb (file) {
try {
if (!file) throw new Error('File is required')
const { name, size } = file
if (!name || typeof name !== 'string') {
throw new Error("File should have the property 'name' of string type")
}
if (!size || typeof size !== 'number') {
throw new Error("File should have the property 'size' of number type")
}
// Get the file extension.
const splitExt = name.split('.')
const fileExt = splitExt[splitExt.length - 1]
const fileObj = {
schemaVersion: 1,
size: size,
fileName: name,
fileExtension: fileExt
}
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
const fileData = await _this.axios.post(`${this.IPFS_API}/files`, {
file: fileObj
})
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
return fileData.data
} catch (err) {
console.error('Error in createFileModelWeb()')
throw err
}
}
/**
* @api IPFS.uploadFileWeb() uploadFileWeb()
* @apiName uploadFileWeb()
* @apiGroup IPFS
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
* successful, it will return an object with an ID, a BCH address, and an
* amount of BCH to pay.
*
* @apiExample Example usage:
* (async () => {
* try {
* * const content = ['PSF']
* const name = 'psf.txt' // Content can be Array , ArrayBuffer , Blob
* const options = { type: "text/plain" }
* const file = new File(content,name,options)
* let fileData = await bchjs.IPFS.uploadFile(file, "5ec562319bfacc745e8d8a52");
* console.log(fileData);
* } catch(error) {
* console.error(error)
* }
* })()
*
* {
* "schemaVersion": 1,
* "size": 2374,
* "fileId": "5ec562319bfacc745e8d8a52",
* "fileName": "ipfs.js",
* "fileExtension": "js"
* }
*/
async uploadFileWeb (file, modelId) {
try {
if (!file) throw new Error('File is required')
const { name, type, size } = file
if (!name || typeof name !== 'string') {
throw new Error("File should have the property 'name' of string type")
}
if (!type || typeof type !== 'string') {
throw new Error("File should have the property 'type' of string type")
}
if (!size || typeof size !== 'number') {
throw new Error("File should have the property 'size' of number type")
}
if (!modelId) {
throw new Error(
'Must include a file model ID in order to upload a file.'
)
}
// Prepare the upload object. Get a file ID from Uppy.
const id = _this.uppy.addFile({
name: name,
data: file,
source: 'Local',
isRemote: false
})
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
// Add the model ID, required to be allowed to upload the file.
_this.uppy.setFileMeta(id, { fileModelId: modelId })
// Upload the file to the server.
const upData = await _this.uppy.upload()
if (upData.failed.length) {
throw new Error('The file could not be uploaded')
}
if (upData.successful.length) {
delete upData.successful[0].data
// console.log(`upData: ${JSON.stringify(upData, null, 2)}`)
const fileObj = {
schemaVersion: 1,
size: upData.successful[0].progress.bytesTotal,
fileId: upData.successful[0].meta.fileModelId,
fileName: upData.successful[0].name,
fileExtension: upData.successful[0].extension
}
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
return fileObj
// return true
}
return false
} catch (err) {
console.error('Error in bch-js/src/ipfs.js/uploadFileWeb(): ')
throw err
}
}
}
module.exports = IPFS
+13 -11
View File
@@ -41,7 +41,7 @@ class PsfSlpIndexer {
this.rawTransaction = new RawTransaction(config)
this.slpUtils = new SlpUtils(config)
// _this = this
// _this = this
}
/**
@@ -53,8 +53,8 @@ class PsfSlpIndexer {
* @apiExample Example usage:
* (async () => {
* try {
* let status = await bchjs.PsfSlpIndexer.status();
* console.log(status);
* let status = await bchjs.PsfSlpIndexer.status()
* console.log(status)
* } catch(error) {
* console.error(error)
* }
@@ -91,8 +91,8 @@ class PsfSlpIndexer {
* @apiExample Example usage:
* (async () => {
* try {
* let balance = await bchjs.PsfSlpIndexer.balance('bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n');
* console.log(balance);
* let balance = await bchjs.PsfSlpIndexer.balance('bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n')
* console.log(balance)
* } catch(error) {
* console.error(error)
* }
@@ -155,12 +155,14 @@ class PsfSlpIndexer {
* @apiName Token Stats
* @apiGroup PSF SLP
* @apiDescription Return list stats for a single slp token.
* The second input is a Boolean, which determins the the transaction history
* of the token is included in the returned data. The default is false.
*
* @apiExample Example usage:
* (async () => {
* try {
* let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2');
* console.log(tokenStats);
* let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', true)
* console.log(tokenStats)
* } catch(error) {
* console.error(error)
* }
@@ -194,13 +196,13 @@ class PsfSlpIndexer {
*
*/
async tokenStats (tokenId) {
async tokenStats (tokenId, withTxHistory = false) {
try {
// Handle single address.
if (typeof tokenId === 'string') {
const response = await axios.post(
`${this.restURL}psf/slp/token`,
{ tokenId },
{ tokenId, withTxHistory },
this.axiosOptions
)
return response.data
@@ -221,8 +223,8 @@ class PsfSlpIndexer {
* @apiExample Example usage:
* (async () => {
* try {
* let txData = await bchjs.PsfSlpIndexer.tx('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2');
* console.log(txData);
* let txData = await bchjs.PsfSlpIndexer.tx('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2')
* console.log(txData)
* } catch(error) {
* console.error(error)
* }
+12 -2
View File
@@ -404,8 +404,18 @@ class UTXO {
if (!thisUtxo.isSlp) {
thisUtxo.txid = thisUtxo.tx_hash
thisUtxo.vout = thisUtxo.tx_pos
thisUtxo.isSlp = false
thisUtxo.address = addr
// Check the transaction to see if its a 'null' token, ignored by
// the indexer.
const txData = await this.psfSlpIndexer.tx(thisUtxo.tx_hash)
// console.log(`txData: ${JSON.stringify(txData, null, 2)}`)
if (txData.txData.isValidSlp === null) {
thisUtxo.isSlp = null
} else {
thisUtxo.isSlp = false
}
// console.log(`thisUtxo.isSlp: ${thisUtxo.isSlp}`)
}
}
@@ -438,7 +448,7 @@ class UTXO {
return outObj
} catch (err) {
// console.error('Error in bchjs.utxo.get2(): ', err)
console.error('Error in bchjs.Utxo.get(): ', err)
if (err.error) throw new Error(err.error)
throw err
@@ -40,13 +40,24 @@ describe('#psf-slp-indexer', () => {
})
describe('#tokenStats', () => {
it('should get stats on a token', async () => {
it('should get stats on a token, without tx history', async () => {
const tokenId =
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId)
// console.log('result: ', result)
assert.property(result.tokenData, 'documentUri')
assert.property(result.tokenData, 'totalBurned')
})
it('should get stats on a token, with tx history', async () => {
const tokenId =
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId, true)
// console.log('result: ', result)
assert.property(result.tokenData, 'documentUri')
assert.property(result.tokenData, 'txs')
assert.property(result.tokenData, 'totalBurned')
@@ -6,6 +6,7 @@ const assert = require('chai').assert
const BCHJS = require('../../../../src/bch-js')
const bchjs = new BCHJS()
// const bchjs = new BCHJS({ restURL: 'http://192.168.2.129:3000/v5/' })
describe('#UTXO', () => {
beforeEach(async () => {
@@ -125,43 +126,35 @@ describe('#UTXO', () => {
it('should hydrate token UTXOs', async () => {
const utxos = [
{
txid:
'384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
txid: '384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
vout: 1,
type: 'token',
qty: '10000000',
tokenId:
'a436c8e1b6bee3d701c6044d190f76f774be83c36de8d34a988af4489e86dd37',
tokenId: 'a436c8e1b6bee3d701c6044d190f76f774be83c36de8d34a988af4489e86dd37',
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
},
{
txid:
'4fc789405d58ec612c69eba29aa56cf0c7f228349801114138424eb68df4479d',
txid: '4fc789405d58ec612c69eba29aa56cf0c7f228349801114138424eb68df4479d',
vout: 1,
type: 'token',
qty: '100000000',
tokenId:
'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
tokenId: 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
},
{
txid:
'42054bba4d69bfe7801ece0cffc754194b04239034fdfe9dbe321ef76c9a2d93',
txid: '42054bba4d69bfe7801ece0cffc754194b04239034fdfe9dbe321ef76c9a2d93',
vout: 5,
type: 'token',
qty: '4764',
tokenId:
'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
tokenId: 'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
},
{
txid:
'06938d0a0d15aa76524ffe61fe111d6d2b2ea9dd8dcd4c7c7744614ced370861',
txid: '06938d0a0d15aa76524ffe61fe111d6d2b2ea9dd8dcd4c7c7744614ced370861',
vout: 5,
type: 'token',
qty: '238',
tokenId:
'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
tokenId: 'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
}
]
@@ -199,7 +192,7 @@ describe('#UTXO', () => {
// TODO: NFTs are currently not identified as different than normal BCH UTXOs.
// The psf-slp-indexer needs to be updated to fix this issue.
it('should handle NFTs and minting batons', async () => {
it('should handle minting batons', async () => {
const addr = 'simpleledger:qrm0c67wwqh0w7wjxua2gdt2xggnm90xwsr5k22euj'
const result = await bchjs.Utxo.get(addr)
@@ -218,6 +211,15 @@ describe('#UTXO', () => {
assert.isAbove(result.bchUtxos.length, 0)
assert.equal(result.slpUtxos.type1.tokens.length, 0)
})
it('should handle Group NFTs', async () => {
const addr = 'bitcoincash:qrnghwrfgccf3s5e9wnglzxegcnhje9rkcwv2eka33'
const result = await bchjs.Utxo.get(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.nullUtxos.length, 0)
})
})
})
-443
View File
@@ -1,443 +0,0 @@
/*
Unit tests for the IPFS Class.
*/
const assert = require('chai').assert
const sinon = require('sinon')
const BCHJS = require('../../src/bch-js')
let bchjs
const mockData = require('./fixtures/ipfs-mock')
describe('#IPFS', () => {
let sandbox
beforeEach(() => {
sandbox = sinon.createSandbox()
bchjs = new BCHJS()
})
afterEach(() => sandbox.restore())
describe('#initUppy', () => {
it('should initialize uppy', () => {
bchjs.IPFS.initUppy()
})
})
describe('#createFileModelServer', () => {
it('should throw an error if file does not exist', async () => {
try {
const path = '/non-existant-file'
await bchjs.IPFS.createFileModelServer(path)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'Could not find this file')
}
})
it('should create a new file model', async () => {
const path = `${__dirname.toString()}/ipfs.js`
sandbox
.stub(bchjs.IPFS.axios, 'post')
.resolves({ data: mockData.mockNewFileModel })
const result = await bchjs.IPFS.createFileModelServer(path)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'hostingCostBCH')
assert.property(result, 'hostingCostUSD')
assert.property(result, 'file')
assert.property(result.file, 'payloadLink')
assert.property(result.file, 'hasBeenPaid')
assert.property(result.file, '_id')
assert.property(result.file, 'schemaVersion')
assert.property(result.file, 'size')
assert.property(result.file, 'fileName')
assert.property(result.file, 'fileExtension')
assert.property(result.file, 'createdTimestamp')
assert.property(result.file, 'hostingCost')
assert.property(result.file, 'walletIndex')
assert.property(result.file, 'bchAddr')
})
})
describe('#uploadFileServer', () => {
it('should throw an error if file does not exist', async () => {
try {
const path = '/non-existant-file'
await bchjs.IPFS.uploadFileServer(path)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'Could not find this file')
}
})
it('should throw an error if modelId is not included', async () => {
try {
const path = `${__dirname.toString()}/ipfs.js`
await bchjs.IPFS.uploadFileServer(path)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'Must include a file model ID')
}
})
it('Should throw error if the file was not uploaded', async () => {
try {
const mock = {
successful: [],
failed: [
{
id: 'file id'
}
]
}
sandbox.stub(bchjs.IPFS.uppy, 'upload').resolves(mock)
const path = `${__dirname.toString()}/ipfs.js`
await bchjs.IPFS.uploadFileServer(path, '5ec562319bfacc745e8d8a52')
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(err)
assert.include(err.message, 'The file could not be uploaded')
}
})
it('should return file object if the file is uploaded', async () => {
try {
sandbox.stub(bchjs.IPFS.uppy, 'upload').resolves(mockData.uploadData)
const path = `${__dirname.toString()}/ipfs.js`
const result = await bchjs.IPFS.uploadFileServer(
path,
'5ec562319bfacc745e8d8a52'
)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'schemaVersion')
assert.property(result, 'size')
assert.property(result, 'fileId')
assert.property(result, 'fileName')
assert.property(result, 'fileExtension')
} catch (err) {
// console.log(err)
assert.equal(true, false, 'Unexpected result')
}
})
})
describe('#getStatus', () => {
it('should throw an error if modelId is not included', async () => {
try {
await bchjs.IPFS.getStatus()
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'Must include a file model ID')
}
})
it('should get data on an unpaid file', async () => {
const modelId = '5ec7392c2acfe57aa62e945a'
sandbox
.stub(bchjs.IPFS.axios, 'get')
.resolves({ data: mockData.unpaidFileData })
const result = await bchjs.IPFS.getStatus(modelId)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'hasBeenPaid')
assert.property(result, 'satCost')
assert.property(result, 'bchAddr')
assert.property(result, 'ipfsHash')
assert.property(result, 'fileId')
assert.property(result, 'fileName')
})
it('should get data on an unpaid file', async () => {
const modelId = '5ec7392c2acfe57aa62e945a'
sandbox
.stub(bchjs.IPFS.axios, 'get')
.resolves({ data: mockData.paidFileData })
const result = await bchjs.IPFS.getStatus(modelId)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'hasBeenPaid')
assert.property(result, 'satCost')
assert.property(result, 'bchAddr')
assert.property(result, 'ipfsHash')
assert.property(result, 'fileId')
assert.property(result, 'fileName')
})
})
describe('#createFileModelWeb', () => {
it('should throw an error if file is undefined', async () => {
try {
let file
await bchjs.IPFS.createFileModelWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'File is required')
}
})
it('should throw an error if file is empty', async () => {
try {
const file = {}
await bchjs.IPFS.createFileModelWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(
err.message,
'File should have the property \'name\' of string type'
)
}
})
it("should throw an error if 'name' property is not included", async () => {
try {
const file = {
size: 5000
}
await bchjs.IPFS.createFileModelWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(
err.message,
'File should have the property \'name\' of string type'
)
}
})
it("should throw an error if 'size' property is not included", async () => {
try {
const file = {
name: 'ipfs.js'
}
await bchjs.IPFS.createFileModelWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(
err.message,
'File should have the property \'size\' of number type'
)
}
})
it('should create a new file model', async () => {
const file = {
name: 'ipfs.js',
size: 5000,
type: 'text/plain'
}
sandbox
.stub(bchjs.IPFS.axios, 'post')
.resolves({ data: mockData.mockNewFileModel })
const result = await bchjs.IPFS.createFileModelWeb(file)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'hostingCostBCH')
assert.property(result, 'hostingCostUSD')
assert.property(result, 'file')
assert.property(result.file, 'payloadLink')
assert.property(result.file, 'hasBeenPaid')
assert.property(result.file, '_id')
assert.property(result.file, 'schemaVersion')
assert.property(result.file, 'size')
assert.property(result.file, 'fileName')
assert.property(result.file, 'fileExtension')
assert.property(result.file, 'createdTimestamp')
assert.property(result.file, 'hostingCost')
assert.property(result.file, 'walletIndex')
assert.property(result.file, 'bchAddr')
})
})
describe('#uploadFileWeb', () => {
it('should throw an error if file is undefined', async () => {
try {
let file
await bchjs.IPFS.uploadFileWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'File is required')
}
})
it('should throw an error if file is empty', async () => {
try {
const file = {}
await bchjs.IPFS.uploadFileWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(
err.message,
'File should have the property \'name\' of string type'
)
}
})
it("should throw an error if 'name' property is not included", async () => {
try {
const file = {
size: 5000,
type: 'text/plain'
}
await bchjs.IPFS.uploadFileWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(
err.message,
'File should have the property \'name\' of string type'
)
}
})
it("should throw an error if 'size' property is not included", async () => {
try {
const file = {
name: 'ipfs.js',
type: 'text/plain'
}
await bchjs.IPFS.uploadFileWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(
err.message,
'File should have the property \'size\' of number type'
)
}
})
it("should throw an error if 'type' property is not included", async () => {
try {
const file = {
name: 'ipfs.js',
size: 5000
}
await bchjs.IPFS.uploadFileWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(
err.message,
'File should have the property \'type\' of string type'
)
}
})
it('should throw an error if modelId is not included', async () => {
try {
const file = {
name: 'ipfs.js',
size: 5000,
type: 'text/plain'
}
await bchjs.IPFS.uploadFileWeb(file)
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'Must include a file model ID')
}
})
it('Should throw error if the file was not uploaded', async () => {
try {
const mock = {
successful: [],
failed: [
{
id: 'file id'
}
]
}
sandbox.stub(bchjs.IPFS.uppy, 'upload').resolves(mock)
const file = {
name: 'ipfs.js',
size: 5000,
type: 'text/plain'
}
await bchjs.IPFS.uploadFileWeb(file, '5ec562319bfacc745e8d8a52')
assert.equal(true, false, 'Unexpected result')
} catch (err) {
// console.log(err)
assert.include(err.message, 'The file could not be uploaded')
}
})
it('should return file object if the file is uploaded', async () => {
try {
sandbox.stub(bchjs.IPFS.uppy, 'upload').resolves(mockData.uploadData)
const file = {
name: 'ipfs.js',
size: 5000,
type: 'text/plain'
}
const result = await bchjs.IPFS.uploadFileWeb(
file,
'5ec562319bfacc745e8d8a52'
)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'schemaVersion')
assert.property(result, 'size')
assert.property(result, 'fileId')
assert.property(result, 'fileName')
assert.property(result, 'fileExtension')
} catch (err) {
// console.log(err)
assert.equal(true, false, 'Unexpected result')
}
})
})
})
+7
View File
@@ -249,6 +249,10 @@ describe('#utxo', () => {
sandbox
.stub(bchjs.Utxo.psfSlpIndexer, 'balance')
.resolves(mockData.psfSlpIndexerUtxos01)
sandbox
.stub(bchjs.Utxo.psfSlpIndexer, 'tx')
.resolves({ txData: { isValidSlp: false } })
// Mock function to return the same input. Good enough for this test.
sandbox.stub(bchjs.Utxo, 'hydrateTokenData').resolves(x => x)
@@ -278,6 +282,9 @@ describe('#utxo', () => {
sandbox
.stub(bchjs.Utxo.electrumx, 'utxo')
.resolves(mockData.fulcrumUtxos02)
sandbox
.stub(bchjs.Utxo.psfSlpIndexer, 'tx')
.resolves({ txData: { isValidSlp: false } })
// Force psf-slp-indexer to return no UTXOs
sandbox