mirror of
https://github.com/fullstack-cash/bch-api.git
synced 2026-09-21 16:52:04 -07:00
Merge pull request #189 from Permissionless-Software-Foundation/feat-getTokenData
fix(getTokenData): Updated to reflect changes in PS002 spec
This commit is contained in:
Generated
+219
-2767
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -31,8 +31,8 @@
|
|||||||
"node": ">=10.15.1"
|
"node": ">=10.15.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@psf/bch-js": "^4.20.7",
|
"@psf/bch-js": "6.2.9",
|
||||||
"apidoc": "0.50.5",
|
"apidoc": "^0.26.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"bitcore-lib-cash": "^8.23.1",
|
"bitcore-lib-cash": "^8.23.1",
|
||||||
"body-parser": "^1.18.3",
|
"body-parser": "^1.18.3",
|
||||||
|
|||||||
@@ -225,11 +225,23 @@ class PsfSlpIndexer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {post} /psf/slp/token/data Get token data
|
||||||
|
* @apiName Get token data
|
||||||
|
* @apiGroup PSF SLP
|
||||||
|
* @apiDescription Get mutable and immutable data if the token contains them.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
* curl -H "Content-Type: application/json" -X POST -d '{ "tokenId": "f055256b938f1ecfa270459d6f12c7c8c82b66d3263c03d5074445a2b1a498a3" }' localhost:3000/v5/psf/slp/token/data
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
// Get mutable and immutable data for a token, if the token was created with
|
// Get mutable and immutable data for a token, if the token was created with
|
||||||
// such data.
|
// such data.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// curl -H "Content-Type: application/json" -X POST -d '{ "tokenId": "afca62f07560b4c72c2ed6c9c3995315f964ccdfc37dded316d182640b42d88a" }' localhost:3000/v5/psf/slp/token/data
|
// curl -H "Content-Type: application/json" -X POST -d '{ "tokenId": "f055256b938f1ecfa270459d6f12c7c8c82b66d3263c03d5074445a2b1a498a3" }' localhost:3000/v5/psf/slp/token/data
|
||||||
async getTokenData (req, res, next) {
|
async getTokenData (req, res, next) {
|
||||||
try {
|
try {
|
||||||
// Verify env var is set for interacting with the indexer.
|
// Verify env var is set for interacting with the indexer.
|
||||||
@@ -276,6 +288,7 @@ class PsfSlpIndexer {
|
|||||||
res.status(200)
|
res.status(200)
|
||||||
return res.json(tokenData)
|
return res.json(tokenData)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.log('Error in getTokenData(): ', err)
|
||||||
return _this.errorHandler(err, res)
|
return _this.errorHandler(err, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -292,22 +305,23 @@ class PsfSlpIndexer {
|
|||||||
// Get the OP_RETURN data and decode it.
|
// Get the OP_RETURN data and decode it.
|
||||||
const mutableData = await _this.decodeOpReturn(documentHash)
|
const mutableData = await _this.decodeOpReturn(documentHash)
|
||||||
const jsonData = JSON.parse(mutableData)
|
const jsonData = JSON.parse(mutableData)
|
||||||
|
// console.log(`jsonData: ${JSON.stringify(jsonData, null, 2)}`)
|
||||||
|
|
||||||
const mspAddress = jsonData.mspAddress
|
const mutableDataAddr = jsonData.mda
|
||||||
|
|
||||||
// Gets the mutable data address (MDA) transaction history.
|
// Gets the mutable data address (MDA) transaction history.
|
||||||
const transactions = await _this.bchjs.Electrumx.transactions(mspAddress)
|
const transactions = await _this.bchjs.Electrumx.transactions(mutableDataAddr)
|
||||||
|
|
||||||
const mspTxs = transactions.transactions
|
const mdaTxs = transactions.transactions
|
||||||
// console.log(`mspTxs: ${JSON.stringify(mspTxs, null, 2)}`)
|
// console.log(`mdaTxs: ${JSON.stringify(mdaTxs, null, 2)}`)
|
||||||
|
|
||||||
let data = false
|
let data = false
|
||||||
// Maps each transaction of the mspAddress
|
// Maps each transaction of the mutableDataAddr
|
||||||
// if finds an OP_RETURN decode is and closes the loop
|
// if finds an OP_RETURN decode is and closes the loop
|
||||||
// Start with the newest TXID entry and scan the history to find the first
|
// Start with the newest TXID entry and scan the history to find the first
|
||||||
// entry with an IPFS CID.
|
// entry with an IPFS CID.
|
||||||
for (let i = mspTxs.length - 1; i > -1; i--) {
|
for (let i = mdaTxs.length - 1; i > -1; i--) {
|
||||||
const tx = mspTxs[i]
|
const tx = mdaTxs[i]
|
||||||
const txid = tx.tx_hash
|
const txid = tx.tx_hash
|
||||||
console.log(`Retrieving and decoding txid ${txid}`)
|
console.log(`Retrieving and decoding txid ${txid}`)
|
||||||
|
|
||||||
@@ -326,8 +340,16 @@ class PsfSlpIndexer {
|
|||||||
// Keep searching if this TX does not have a cid value.
|
// Keep searching if this TX does not have a cid value.
|
||||||
if (!obj.cid) continue
|
if (!obj.cid) continue
|
||||||
|
|
||||||
// TODO: Ensure data was generated by the MSP address and not an
|
// Ensure data was generated by the MDA
|
||||||
// update from a different address.
|
const txData = await this.bchjs.Transaction.get(txid)
|
||||||
|
const vinAddress = txData.txData.vin[0].address
|
||||||
|
|
||||||
|
// Skip entry if it was not made by the MDA private key.
|
||||||
|
if (mutableDataAddr !== vinAddress) {
|
||||||
|
console.log('Data is not generated by MDA')
|
||||||
|
data = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -352,6 +374,7 @@ class PsfSlpIndexer {
|
|||||||
return result
|
return result
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('Error in getMutableData().')
|
console.log('Error in getMutableData().')
|
||||||
|
// console.log('Error in getMutableData(): ', err)
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,7 +418,12 @@ class PsfSlpIndexer {
|
|||||||
if (!cid || typeof cid !== 'string') {
|
if (!cid || typeof cid !== 'string') {
|
||||||
throw new Error('cid must be a string.')
|
throw new Error('cid must be a string.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assuming that CID starts with ipfs://. Cutting out that prefix.
|
||||||
|
cid = cid.substring(7)
|
||||||
|
|
||||||
const dataUrl = `https://${cid}.ipfs.dweb.link/data.json`
|
const dataUrl = `https://${cid}.ipfs.dweb.link/data.json`
|
||||||
|
console.log(`dataUrl: ${dataUrl}`)
|
||||||
|
|
||||||
const response = await _this.axios.get(dataUrl)
|
const response = await _this.axios.get(dataUrl)
|
||||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||||
|
|||||||
@@ -29,6 +29,61 @@ const tokenStats = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// txData generated by MDA
|
||||||
|
const txDataByMDA = {
|
||||||
|
txData: {
|
||||||
|
txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||||
|
hash: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||||
|
version: 2,
|
||||||
|
size: 339,
|
||||||
|
locktime: 0,
|
||||||
|
vin: [
|
||||||
|
{
|
||||||
|
txid: '8370db30d94761ab9a11b71ecd22541151bf6125c8c613f0f6fab8ab794565a7',
|
||||||
|
vout: 0,
|
||||||
|
scriptSig: {
|
||||||
|
asm: '304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4[ALL|FORKID] 02791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851',
|
||||||
|
hex: '47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851'
|
||||||
|
},
|
||||||
|
sequence: 4294967295,
|
||||||
|
address: 'bitcoincash:qrg77j4jf2pl7azgvzrz2z567ls464gkuuhplt30dp',
|
||||||
|
value: 0.00051303,
|
||||||
|
tokenQty: 0,
|
||||||
|
tokenQtyStr: '0',
|
||||||
|
tokenId: null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
vout: [
|
||||||
|
{
|
||||||
|
value: 0,
|
||||||
|
n: 0,
|
||||||
|
scriptPubKey: {
|
||||||
|
asm: 'OP_RETURN 5262419 1 47454e45534953 54524f5554 54726f75742773207465737420746f6b656e 74726f757473626c6f672e636f6d 0 2 2 000000174876e800',
|
||||||
|
hex: '6a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e800',
|
||||||
|
type: 'nulldata'
|
||||||
|
},
|
||||||
|
tokenQtyStr: '0',
|
||||||
|
tokenQty: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
hex: '0200000001a7654579abb8faf6f013c6c82561bf51115422cd1eb7119aab6147d930db7083000000006a47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851ffffffff040000000000000000476a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e80022020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088ac22020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088accec20000000000001976a9145904159f2f69bfa63eefa712633a0d96dc2e7e8888ac00000000',
|
||||||
|
blockhash: '0000000000000000009f65225a3e12e23a7ea057c869047e0f36563a1f410267',
|
||||||
|
confirmations: 97398,
|
||||||
|
time: 1581773131,
|
||||||
|
blocktime: 1581773131,
|
||||||
|
blockheight: 622414,
|
||||||
|
isSlpTx: true,
|
||||||
|
tokenTxType: 'GENESIS',
|
||||||
|
tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||||
|
tokenType: 1,
|
||||||
|
tokenTicker: 'TROUT',
|
||||||
|
tokenName: "Trout's test token",
|
||||||
|
tokenDecimals: 2,
|
||||||
|
tokenUri: 'troutsblog.com',
|
||||||
|
tokenDocHash: '',
|
||||||
|
isValidSlp: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const txData = {
|
const txData = {
|
||||||
txData: {
|
txData: {
|
||||||
@@ -46,7 +101,7 @@ const txData = {
|
|||||||
hex: '47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851'
|
hex: '47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851'
|
||||||
},
|
},
|
||||||
sequence: 4294967295,
|
sequence: 4294967295,
|
||||||
address: 'bitcoincash:qpvsg9vl9a5mlf37a7n3yce6pktdctn73qwgaqm3wq',
|
address: 'bitcoincash:qrqy3kj7r822ps6628vwqq5k8hyjl6ey3y4eea2m4s',
|
||||||
value: 0.00051303,
|
value: 0.00051303,
|
||||||
tokenQty: 0,
|
tokenQty: 0,
|
||||||
tokenQtyStr: '0',
|
tokenQtyStr: '0',
|
||||||
@@ -156,11 +211,12 @@ const mutableData = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decodedOpReturn = JSON.stringify({
|
const decodedOpReturn = JSON.stringify({
|
||||||
mspAdddress: 'bitcoincash:qrg77j4jf2pl7azgvzrz2z567ls464gkuuhplt30dp',
|
mda: 'bitcoincash:qrg77j4jf2pl7azgvzrz2z567ls464gkuuhplt30dp',
|
||||||
cid: 'bafybeie6t5uyupddc7azms737xg4hxrj7i5t5ov3lb5g2qeehaujj6ak64'
|
cid: 'bafybeie6t5uyupddc7azms737xg4hxrj7i5t5ov3lb5g2qeehaujj6ak64'
|
||||||
})
|
})
|
||||||
module.exports = {
|
module.exports = {
|
||||||
tokenStats,
|
tokenStats,
|
||||||
|
txDataByMDA,
|
||||||
txData,
|
txData,
|
||||||
balance,
|
balance,
|
||||||
status,
|
status,
|
||||||
|
|||||||
@@ -151,6 +151,34 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
return this.skip()
|
return this.skip()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const result = await uut.getTokenStats(req, res)
|
||||||
|
const tokenData = result.tokenData
|
||||||
|
assert.property(tokenData, 'type')
|
||||||
|
assert.property(tokenData, 'ticker')
|
||||||
|
assert.property(tokenData, 'name')
|
||||||
|
assert.property(tokenData, 'tokenId')
|
||||||
|
assert.property(tokenData, 'documentUri')
|
||||||
|
assert.property(tokenData, 'documentHash')
|
||||||
|
assert.property(tokenData, 'decimals')
|
||||||
|
assert.property(tokenData, 'mintBatonIsActive')
|
||||||
|
assert.property(tokenData, 'tokensInCirculationBN')
|
||||||
|
assert.property(tokenData, 'tokensInCirculationStr')
|
||||||
|
assert.property(tokenData, 'blockCreated')
|
||||||
|
assert.property(tokenData, 'totalBurned')
|
||||||
|
assert.property(tokenData, 'totalMinted')
|
||||||
|
assert.property(tokenData, 'txs')
|
||||||
|
})
|
||||||
|
it('should GET tokens stats with tx hisroty', async function () {
|
||||||
|
req.body.tokenId =
|
||||||
|
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
|
||||||
|
req.body.withTxHistory = true
|
||||||
|
// Mock the RPC call for unit tests.
|
||||||
|
if (process.env.TEST === 'unit') {
|
||||||
|
sandbox.stub(uut.axios, 'post').resolves({ data: mockData.tokenStats })
|
||||||
|
} else {
|
||||||
|
return this.skip()
|
||||||
|
}
|
||||||
|
|
||||||
const result = await uut.getTokenStats(req, res)
|
const result = await uut.getTokenStats(req, res)
|
||||||
const tokenData = result.tokenData
|
const tokenData = result.tokenData
|
||||||
assert.property(tokenData, 'type')
|
assert.property(tokenData, 'type')
|
||||||
@@ -470,6 +498,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
assert.property(status, 'chainBlockHeight')
|
assert.property(status, 'chainBlockHeight')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#errorHandler', () => {
|
describe('#errorHandler', () => {
|
||||||
it('should handle unexpected errors', () => {
|
it('should handle unexpected errors', () => {
|
||||||
sandbox.stub(uut.routeUtils, 'decodeError').returns({ msg: false })
|
sandbox.stub(uut.routeUtils, 'decodeError').returns({ msg: false })
|
||||||
@@ -479,6 +508,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
|
assert.equal(res.statusCode, 400, 'HTTP status code 400 expected.')
|
||||||
assert.property(result, 'error')
|
assert.property(result, 'error')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle unknow errors', () => {
|
it('should handle unknow errors', () => {
|
||||||
sandbox.stub(uut.routeUtils, 'decodeError').returns({ msg: false })
|
sandbox.stub(uut.routeUtils, 'decodeError').returns({ msg: false })
|
||||||
|
|
||||||
@@ -488,6 +518,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
assert.property(result, 'error')
|
assert.property(result, 'error')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#checkEnvVar', () => {
|
describe('#checkEnvVar', () => {
|
||||||
it('should throw errors if SLP_INDEXER_API env var is not provided', () => {
|
it('should throw errors if SLP_INDEXER_API env var is not provided', () => {
|
||||||
const savedSlpIndexerUrl = process.env.SLP_INDEXER_API
|
const savedSlpIndexerUrl = process.env.SLP_INDEXER_API
|
||||||
@@ -505,6 +536,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
process.env.SLP_INDEXER_API = savedSlpIndexerUrl
|
process.env.SLP_INDEXER_API = savedSlpIndexerUrl
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#getCIDData', () => {
|
describe('#getCIDData', () => {
|
||||||
it('should throw errors if cid is not provided', async () => {
|
it('should throw errors if cid is not provided', async () => {
|
||||||
try {
|
try {
|
||||||
@@ -518,6 +550,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle axios error', async () => {
|
it('should handle axios error', async () => {
|
||||||
try {
|
try {
|
||||||
sandbox.stub(uut.axios, 'get').throws(new Error('test error'))
|
sandbox.stub(uut.axios, 'get').throws(new Error('test error'))
|
||||||
@@ -532,6 +565,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return cid object data', async () => {
|
it('should return cid object data', async () => {
|
||||||
sandbox.stub(uut.axios, 'get').resolves({ data: mockData.immutableData })
|
sandbox.stub(uut.axios, 'get').resolves({ data: mockData.immutableData })
|
||||||
const cid = 'bafybeigp3bfmj6woms7pywb7s7r6npcdudvsabvzne2chyspxtdendrwmy'
|
const cid = 'bafybeigp3bfmj6woms7pywb7s7r6npcdudvsabvzne2chyspxtdendrwmy'
|
||||||
@@ -553,6 +587,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle bchjs error', async () => {
|
it('should handle bchjs error', async () => {
|
||||||
try {
|
try {
|
||||||
sandbox.stub(uut.bchjs.Electrumx, 'txData').throws(new Error('test error'))
|
sandbox.stub(uut.bchjs.Electrumx, 'txData').throws(new Error('test error'))
|
||||||
@@ -567,12 +602,14 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return data', async () => {
|
it('should return data', async () => {
|
||||||
sandbox.stub(uut.bchjs.Electrumx, 'txData').resolves({ details: mockData.txData.txData })
|
sandbox.stub(uut.bchjs.Electrumx, 'txData').resolves({ details: mockData.txData.txData })
|
||||||
const txid = 'c37ba29f40ecc61662ea56324fdb72a5f1e66add2078854c2144765b9030358a'
|
const txid = 'c37ba29f40ecc61662ea56324fdb72a5f1e66add2078854c2144765b9030358a'
|
||||||
const result = await uut.decodeOpReturn(txid)
|
const result = await uut.decodeOpReturn(txid)
|
||||||
assert.isString(result)
|
assert.isString(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return false if data is not found', async () => {
|
it('should return false if data is not found', async () => {
|
||||||
sandbox.stub(uut.bchjs.Electrumx, 'txData').resolves({ details: { vout: [] } })
|
sandbox.stub(uut.bchjs.Electrumx, 'txData').resolves({ details: { vout: [] } })
|
||||||
const txid = 'c37ba29f40ecc61662ea56324fdb72a5f1e66add2078854c2144765b9030358a'
|
const txid = 'c37ba29f40ecc61662ea56324fdb72a5f1e66add2078854c2144765b9030358a'
|
||||||
@@ -580,6 +617,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
assert.isFalse(result)
|
assert.isFalse(result)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#getTokenData', async () => {
|
describe('#getTokenData', async () => {
|
||||||
it('should throw 400 error if tokenId is missing', async () => {
|
it('should throw 400 error if tokenId is missing', async () => {
|
||||||
const result = await uut.getTokenData(req, res)
|
const result = await uut.getTokenData(req, res)
|
||||||
@@ -687,6 +725,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
assert.property(genesisData, 'totalMinted')
|
assert.property(genesisData, 'totalMinted')
|
||||||
assert.property(genesisData, 'txs')
|
assert.property(genesisData, 'txs')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should GET tokens data if immutableData data not found', async function () {
|
it('should GET tokens data if immutableData data not found', async function () {
|
||||||
req.body.tokenId =
|
req.body.tokenId =
|
||||||
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
|
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
|
||||||
@@ -724,6 +763,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
assert.property(genesisData, 'totalMinted')
|
assert.property(genesisData, 'totalMinted')
|
||||||
assert.property(genesisData, 'txs')
|
assert.property(genesisData, 'txs')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should GET tokens data if mutable data not found', async function () {
|
it('should GET tokens data if mutable data not found', async function () {
|
||||||
req.body.tokenId =
|
req.body.tokenId =
|
||||||
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
|
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
|
||||||
@@ -762,6 +802,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
assert.property(genesisData, 'txs')
|
assert.property(genesisData, 'txs')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#getMutableData', () => {
|
describe('#getMutableData', () => {
|
||||||
it('should throw errors if documentHash is not provided', async () => {
|
it('should throw errors if documentHash is not provided', async () => {
|
||||||
try {
|
try {
|
||||||
@@ -775,6 +816,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw errors if cid is not provided in OP Return', async () => {
|
it('should throw errors if cid is not provided in OP Return', async () => {
|
||||||
try {
|
try {
|
||||||
sandbox.stub(uut, 'decodeOpReturn').resolves('{}')
|
sandbox.stub(uut, 'decodeOpReturn').resolves('{}')
|
||||||
@@ -810,6 +852,7 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle bchjs error', async () => {
|
it('should handle bchjs error', async () => {
|
||||||
try {
|
try {
|
||||||
sandbox.stub(uut, 'decodeOpReturn').resolves(mockData.decodedOpReturn)
|
sandbox.stub(uut, 'decodeOpReturn').resolves(mockData.decodedOpReturn)
|
||||||
@@ -826,6 +869,27 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should skip mutable data if was not generated by the MDA private key', async () => {
|
||||||
|
try {
|
||||||
|
sandbox.stub(uut, 'decodeOpReturn').resolves(mockData.decodedOpReturn)
|
||||||
|
|
||||||
|
sandbox.stub(uut.bchjs.Electrumx, 'transactions').resolves(mockData.transactions)
|
||||||
|
sandbox.stub(uut.bchjs.Transaction, 'get').resolves(mockData.txData)
|
||||||
|
|
||||||
|
const documentHash = 'c37ba29f40ecc61662ea56324fdb72a5f1e66add2078854c2144765b9030358a'
|
||||||
|
|
||||||
|
await uut.getMutableData(documentHash)
|
||||||
|
assert.fail('unexpected code path')
|
||||||
|
} catch (error) {
|
||||||
|
assert.include(
|
||||||
|
error.message,
|
||||||
|
'CID could not be found in OP_RETURN data',
|
||||||
|
'Error message expected'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('should return mutable data', async () => {
|
it('should return mutable data', async () => {
|
||||||
sandbox.stub(uut, 'decodeOpReturn')
|
sandbox.stub(uut, 'decodeOpReturn')
|
||||||
.onFirstCall().resolves(mockData.decodedOpReturn)
|
.onFirstCall().resolves(mockData.decodedOpReturn)
|
||||||
@@ -833,6 +897,8 @@ describe('#PsfSlpIndexer', () => {
|
|||||||
.onThirdCall().resolves(mockData.decodedOpReturn)
|
.onThirdCall().resolves(mockData.decodedOpReturn)
|
||||||
|
|
||||||
sandbox.stub(uut.bchjs.Electrumx, 'transactions').resolves(mockData.transactions)
|
sandbox.stub(uut.bchjs.Electrumx, 'transactions').resolves(mockData.transactions)
|
||||||
|
sandbox.stub(uut.bchjs.Transaction, 'get').resolves(mockData.txDataByMDA)
|
||||||
|
|
||||||
sandbox.stub(uut, 'getCIDData').resolves(mockData.mutableData)
|
sandbox.stub(uut, 'getCIDData').resolves(mockData.mutableData)
|
||||||
|
|
||||||
const documentHash = 'c37ba29f40ecc61662ea56324fdb72a5f1e66add2078854c2144765b9030358a'
|
const documentHash = 'c37ba29f40ecc61662ea56324fdb72a5f1e66add2078854c2144765b9030358a'
|
||||||
|
|||||||
Reference in New Issue
Block a user