Compare commits

...
4 Commits
7 changed files with 130 additions and 32 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@psf/bch-js",
"version": "4.0.0",
"version": "5.0.0",
"description": "The FullStack.cash JavaScript library for Bitcoin Cash and SLP Tokens",
"author": "Chris Troutner <chris.troutner@gmail.com>",
"contributors": [
@@ -18,7 +18,7 @@
"test:integration:local:abc": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:local:bchn": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v5/ mocha --timeout 30000 test/integration/chains/testnet",
"test:integration:decatur:bchn": "export RESTURL=http://192.168.2.129:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:decatur:bchn": "export RESTURL=http://192.168.2.139:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:decatur:abc": "export RESTURL=http://192.168.2.141:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v5/ && mocha --timeout 30000 test/integration/",
"test:temp": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 -g '#Encryption' test/integration/",
+42 -2
View File
@@ -1,10 +1,17 @@
/*
This library interacts with the PSF slp indexer REST API endpoints operated
by FullStack.cash
TODO:
- detect TXs from tokens in the blacklist.
*/
// Public npm libraries
const axios = require('axios')
// Local libraries
const RawTransaction = require('./raw-transactions')
// let _this
class PsfSlpIndexer {
@@ -29,6 +36,9 @@ class PsfSlpIndexer {
}
}
// Encapsulate dependencies
this.rawTransaction = new RawTransaction(config)
// _this = this
}
@@ -283,8 +293,38 @@ class PsfSlpIndexer {
}
throw new Error('Input txid must be a string.')
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
// console.log('error: ', error)
// Case: txid is not stored in the psf-slp-indexer tx database.
// Response: If it's not in the database, then it can be assumed the TX
// is not a token TX?
if (
error.response &&
error.response.data &&
error.response.data.error &&
error.response.data.error.includes('Key not found in database')
) {
// console.log(
// 'TX not found in psf-slp-indexer. Retrieving from full node.'
// )
// Get the TX Details from the full node.
const txDetails = await this.rawTransaction.getTxData(txid)
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
// TODO: Run the TX through decodeOpReturn() to see if it has a tokenID
// that is in the blacklist. If it is, then set isValidSlp = null to
// signal that it's state can not be determined.
// Assumption: transaction is not a valid SLP UTXO.
txDetails.isValidSlp = false
const outObj = {
txData: txDetails
}
return outObj
} else throw error
}
}
}
+11 -2
View File
@@ -2,18 +2,27 @@
High-level functions for working with Transactions
*/
// Global npm libraries
const BigNumber = require('bignumber.js')
// Local libraries
const RawTransaction = require('./raw-transactions')
const SlpUtils = require('./slp/utils')
const Blockchain = require('./blockchain')
const PsfSlpIndexer = require('./psf-slp-indexer')
class Transaction {
constructor (config) {
constructor (config = {}) {
// Encapsulate dependencies
this.slpUtils = new SlpUtils(config)
this.rawTransaction = new RawTransaction(config)
this.blockchain = new Blockchain(config)
this.psfSlpIndexer = new PsfSlpIndexer(config)
}
// Proxy the call to the psf-slp-indexer.
async get (txid) {
return await this.psfSlpIndexer.tx(txid)
}
/**
@@ -42,7 +51,7 @@ class Transaction {
// CT 10/31/21: TODO: this function should be refactored to use get2(), but
// add waterfall validation of the TX and its inputs.
async get (txid) {
async getOld (txid) {
try {
if (typeof txid !== 'string') {
throw new Error(
@@ -54,7 +54,7 @@ describe('#psf-slp-indexer', () => {
})
describe('#tx', () => {
it('should get hydrated tx data', async () => {
it('should get hydrated tx data for an SLP transaction', async () => {
const txid =
'83361c34cac2ea7f9ca287fca57a96cc0763719f0cdf4850f9696c1e68eb635c'
@@ -64,6 +64,37 @@ describe('#psf-slp-indexer', () => {
assert.property(result.txData, 'vin')
assert.property(result.txData, 'vout')
assert.property(result.txData, 'isValidSlp')
assert.equal(result.txData.isValidSlp, true)
})
it('should handle non-SLP transaction', async () => {
const txid =
'03d6e6b63647ce7b02ecc73dc6d41b485be14a3e20eed4474b8a840358ddf14e'
const result = await bchjs.PsfSlpIndexer.tx(txid)
// console.log('result: ', result)
assert.property(result.txData, 'vin')
assert.property(result.txData, 'vout')
assert.property(result.txData, 'isValidSlp')
assert.equal(result.txData.isValidSlp, false)
})
// FlexUSD transactions
// Currently FlexUSD UTXOs are reported as invalid SLP UTXOs, which means
// the wallet will burn them. There is a TODO in the code. This test will
// need to be changed when it is done.
it('should handle a blacklisted token', async () => {
const txid =
'302113c11b90edc5f36c073d2f8a75e1e0eaf59b56235491a843d3819cd6a85f'
const result = await bchjs.PsfSlpIndexer.tx(txid)
// console.log('result: ', result)
assert.property(result.txData, 'vin')
assert.property(result.txData, 'vout')
assert.property(result.txData, 'isValidSlp')
assert.equal(result.txData.isValidSlp, false)
})
})
})
+6 -5
View File
@@ -11,12 +11,12 @@ describe('#Transaction', () => {
if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
})
describe('#get', () => {
describe('#getOld', () => {
it('should get details about a non-SLP transaction', async () => {
const txid =
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
const result = await bchjs.Transaction.get(txid)
const result = await bchjs.Transaction.getOld(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
@@ -37,7 +37,7 @@ describe('#Transaction', () => {
const txid =
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
const result = await bchjs.Transaction.get(txid)
const result = await bchjs.Transaction.getOld(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
@@ -69,9 +69,10 @@ describe('#Transaction', () => {
// that is also a valid SLP tx, but is unrelated. Both TXs pass DAG validation,
// but for separate tokens.
it('should get problematic transaction', async () => {
const txid = 'a19f2f395a8b0e15b6202944c56834367d128f1e3630486a4756de53424a46fe'
const txid =
'a19f2f395a8b0e15b6202944c56834367d128f1e3630486a4756de53424a46fe'
const result = await bchjs.Transaction.get(txid)
const result = await bchjs.Transaction.getOld(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// The token ID should equal the txid for this Vin.
+18 -12
View File
@@ -38,6 +38,7 @@ describe('#PsfSlpIndexer', () => {
assert.include(err.message, 'test error')
}
})
it('should handle request error', async () => {
try {
// Stub the network call.
@@ -239,20 +240,25 @@ describe('#PsfSlpIndexer', () => {
assert.include(err.message, 'test error')
}
})
it('should handle request error', async () => {
try {
// Stub the network call.
const testErr = new Error()
testErr.response = { data: { status: 422 } }
sandbox.stub(axios, 'post').throws(testErr)
const txid =
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
await bchjs.PsfSlpIndexer.tx(txid)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
assert.equal(err.status, 422)
it('should get tx from full node if not available from slp indexer', async () => {
// Stub the call to the SLP indexer.
const testErr = {
response: { data: { error: 'Key not found in database' } }
}
sandbox.stub(axios, 'post').rejects(testErr)
// Stub the call to the full node
sandbox
.stub(bchjs.PsfSlpIndexer.rawTransaction, 'getTxData')
.resolves({ txid: 'fakeTxid' })
const txid =
'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
const result = await bchjs.PsfSlpIndexer.tx(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result.txData.txid, 'fakeTxid')
})
})
})
+19 -8
View File
@@ -22,10 +22,10 @@ describe('#TransactionLib', () => {
})
afterEach(() => sandbox.restore())
describe('#get', () => {
describe('#getOld', () => {
it('should throw an error if txid is not specified', async () => {
try {
await bchjs.Transaction.get()
await bchjs.Transaction.getOld()
assert.fail('Unexpected code path!')
} catch (err) {
@@ -45,7 +45,7 @@ describe('#TransactionLib', () => {
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
.resolves(mockData.nonSlpTxDetails)
const result = await bchjs.Transaction.get(txid)
const result = await bchjs.Transaction.getOld(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
@@ -84,7 +84,7 @@ describe('#TransactionLib', () => {
const txid =
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
const result = await bchjs.Transaction.get(txid)
const result = await bchjs.Transaction.getOld(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
@@ -114,7 +114,7 @@ describe('#TransactionLib', () => {
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
.rejects(new Error('test error'))
await bchjs.Transaction.get(txid)
await bchjs.Transaction.getOld(txid)
assert.fail('Unexpected code path')
} catch (err) {
@@ -147,7 +147,7 @@ describe('#TransactionLib', () => {
const txid =
'874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e'
const result = await bchjs.Transaction.get(txid)
const result = await bchjs.Transaction.getOld(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
@@ -195,7 +195,7 @@ describe('#TransactionLib', () => {
const txid =
'4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa'
const result = await bchjs.Transaction.get(txid)
const result = await bchjs.Transaction.getOld(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
@@ -246,7 +246,7 @@ describe('#TransactionLib', () => {
const txid =
'6bc111fbf5b118021d68355ca19a0e77fa358dd931f284b2550f79a51ab4792a'
const result = await bchjs.Transaction.get(txid)
const result = await bchjs.Transaction.getOld(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Assert that there are stanardized properties.
@@ -705,4 +705,15 @@ describe('#TransactionLib', () => {
assert.equal(result.isSlpTx, true)
})
})
describe('#get', () => {
it('should proxy psf-slp-indexer', async () => {
// console.log('bchjs.Transaction: ', bchjs.Transaction)
sandbox.stub(bchjs.Transaction.psfSlpIndexer, 'tx').resolves('test data')
const result = await bchjs.Transaction.get()
assert.equal(result, 'test data')
})
})
})