@psf/bch-js 4.20.12 → 4.20.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/address.js +74 -1
- package/src/price.js +5 -5
- package/src/raw-transactions.js +3 -0
- package/src/slp/tokentype1.js +9 -3
- package/src/slp/utils.js +1 -1
- package/src/transaction.js +54 -12
- package/test/unit/fixtures/transaction-mock.js +252 -1
- package/test/unit/transaction-unit.js +96 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@psf/bch-js",
|
|
3
|
-
"version": "4.20.
|
|
3
|
+
"version": "4.20.16",
|
|
4
4
|
"description": "The FullStack.cash JavaScript library for Bitcoin Cash and SLP Tokens",
|
|
5
5
|
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
|
6
6
|
"contributors": [
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"bip66": "^1.1.5",
|
|
55
55
|
"bitcoinjs-message": "^2.0.0",
|
|
56
56
|
"bs58": "^4.0.1",
|
|
57
|
-
"
|
|
57
|
+
"ecashaddrjs": "^1.0.7",
|
|
58
58
|
"ini": "^1.3.8",
|
|
59
59
|
"randombytes": "^2.0.6",
|
|
60
60
|
"safe-buffer": "^5.1.2",
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
"eslint-plugin-standard": "^4.0.0",
|
|
77
77
|
"husky": "^4.3.6",
|
|
78
78
|
"lodash.clonedeep": "^4.5.0",
|
|
79
|
-
"mocha": "^
|
|
79
|
+
"mocha": "^9.1.3",
|
|
80
80
|
"node-mocks-http": "^1.7.0",
|
|
81
|
-
"nyc": "^
|
|
81
|
+
"nyc": "^15.1.0",
|
|
82
82
|
"prettier": "^1.18.2",
|
|
83
83
|
"semantic-release": "^17.3.9",
|
|
84
84
|
"sinon": "^7.3.2",
|
package/src/address.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// const axios = require("axios")
|
|
2
2
|
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
|
3
|
-
const cashaddr = require('
|
|
3
|
+
const cashaddr = require('ecashaddrjs')
|
|
4
4
|
const coininfo = require('@psf/coininfo')
|
|
5
5
|
|
|
6
6
|
class Address {
|
|
@@ -129,6 +129,63 @@ class Address {
|
|
|
129
129
|
return cashAddress.split(':')[1]
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
/**
|
|
133
|
+
* @api Address.toEcashAddress() toEcashAddress()
|
|
134
|
+
* @apiName toEcashAddress
|
|
135
|
+
* @apiGroup Address
|
|
136
|
+
* @apiDescription Convert legacy to cashAddress format
|
|
137
|
+
*
|
|
138
|
+
* @apiExample Example usage:
|
|
139
|
+
* // mainnet
|
|
140
|
+
* bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2')
|
|
141
|
+
* // ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
|
|
142
|
+
*
|
|
143
|
+
* // mainnet no prefix
|
|
144
|
+
* bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2', false)
|
|
145
|
+
* // qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
|
|
146
|
+
*
|
|
147
|
+
*/
|
|
148
|
+
toEcashAddress (address, prefix = true) {
|
|
149
|
+
const decoded = this._decode(address)
|
|
150
|
+
|
|
151
|
+
const ecashAddress = cashaddr.encode(
|
|
152
|
+
'ecash',
|
|
153
|
+
decoded.type,
|
|
154
|
+
decoded.hash
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if (prefix) return ecashAddress
|
|
158
|
+
return ecashAddress.split(':')[1]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @api Address.ecashtoCashAddress() ecashtoCashAddress()
|
|
163
|
+
* @apiName ecashtoCashAddress
|
|
164
|
+
* @apiGroup Address
|
|
165
|
+
* @apiDescription Convert legacy to cashAddress format
|
|
166
|
+
*
|
|
167
|
+
* @apiExample Example usage:
|
|
168
|
+
* // mainnet
|
|
169
|
+
* bchjs.Address.ecashtoCashAddress('ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da')
|
|
170
|
+
* // bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2
|
|
171
|
+
*
|
|
172
|
+
* // mainnet no prefix
|
|
173
|
+
* bchjs.Address.ecashtoCashAddress('ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da', false)
|
|
174
|
+
* // qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2
|
|
175
|
+
*/
|
|
176
|
+
ecashtoCashAddress (address, prefix = true) {
|
|
177
|
+
const decoded = this._decodeEcashAddress(address)
|
|
178
|
+
|
|
179
|
+
const cashAddress = cashaddr.encode(
|
|
180
|
+
'bitcoincash',
|
|
181
|
+
decoded.type,
|
|
182
|
+
decoded.hash
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
if (prefix) return cashAddress
|
|
186
|
+
return cashAddress.split(':')[1]
|
|
187
|
+
}
|
|
188
|
+
|
|
132
189
|
// Converts any address format to hash160
|
|
133
190
|
toHash160 (address) {
|
|
134
191
|
const legacyAddress = this.toLegacyAddress(address)
|
|
@@ -271,6 +328,22 @@ class Address {
|
|
|
271
328
|
throw new Error(`Invalid format : ${address}`)
|
|
272
329
|
}
|
|
273
330
|
|
|
331
|
+
_decodeEcashAddress (address) {
|
|
332
|
+
if (address.indexOf(':') !== -1) {
|
|
333
|
+
const decoded = cashaddr.decode(address)
|
|
334
|
+
decoded.format = 'cashaddr'
|
|
335
|
+
return decoded
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
try {
|
|
339
|
+
const decoded = cashaddr.decode(`ecash:${address}`)
|
|
340
|
+
decoded.format = 'cashaddr'
|
|
341
|
+
return decoded
|
|
342
|
+
} catch (error) {}
|
|
343
|
+
|
|
344
|
+
throw new Error(`Invalid format : ${address}`)
|
|
345
|
+
}
|
|
346
|
+
|
|
274
347
|
/**
|
|
275
348
|
* @api Address.isLegacyAddress() isLegacyAddress()
|
|
276
349
|
* @apiName isLegacyAddress
|
package/src/price.js
CHANGED
|
@@ -128,7 +128,7 @@ class Price {
|
|
|
128
128
|
* @apiGroup Price
|
|
129
129
|
* @apiDescription Return current price of BCHA in USD.
|
|
130
130
|
* This endpoint gets the USD price of XEC from the Coinex API. The price
|
|
131
|
-
* denominated in BCHA comes from bch-api, so it has a better chance of
|
|
131
|
+
* denominated in BCHA comes from bch-api, so it has a better chance of
|
|
132
132
|
* working in Tor.
|
|
133
133
|
*
|
|
134
134
|
* @apiExample Example usage:
|
|
@@ -150,7 +150,7 @@ class Price {
|
|
|
150
150
|
this.axiosOptions
|
|
151
151
|
)
|
|
152
152
|
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
const bchaPrice = response.data.usd * 1000000
|
|
155
155
|
// Convert XEC denomination to BCHA denomination
|
|
156
156
|
|
|
@@ -161,7 +161,7 @@ class Price {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
/**
|
|
165
165
|
* @api price.getXecUsd() getXecUsd()
|
|
166
166
|
* @apiName Price getXecUsd()
|
|
167
167
|
* @apiGroup Price
|
|
@@ -179,9 +179,9 @@ class Price {
|
|
|
179
179
|
* }
|
|
180
180
|
*})()
|
|
181
181
|
*
|
|
182
|
-
* // 0.00021234
|
|
182
|
+
* // 0.00021234
|
|
183
183
|
*/
|
|
184
|
-
|
|
184
|
+
async getXecUsd () {
|
|
185
185
|
try {
|
|
186
186
|
const response = await this.axios.get(
|
|
187
187
|
`${this.restURL}price/bchausd`,
|
package/src/raw-transactions.js
CHANGED
|
@@ -319,6 +319,9 @@ class RawTransactions {
|
|
|
319
319
|
const inputTxid = vin.txid
|
|
320
320
|
const inputVout = vin.vout
|
|
321
321
|
|
|
322
|
+
// TODO: Coinbase TXs have no input transaction. Figure out how to
|
|
323
|
+
// handle this corner case.
|
|
324
|
+
|
|
322
325
|
// Get the TX details for the input, in order to retrieve the address of
|
|
323
326
|
// the sender.
|
|
324
327
|
const txDetailsParent = await this.getRawTransaction(inputTxid, true)
|
package/src/slp/tokentype1.js
CHANGED
|
@@ -287,9 +287,15 @@ class TokenType1 {
|
|
|
287
287
|
try {
|
|
288
288
|
// TODO: Add input validation.
|
|
289
289
|
|
|
290
|
-
let baseQty
|
|
291
|
-
|
|
292
|
-
|
|
290
|
+
let baseQty
|
|
291
|
+
if (configObj.decimals !== 0) {
|
|
292
|
+
baseQty = new BigNumber(configObj.initialQty).times(
|
|
293
|
+
10 ** configObj.decimals
|
|
294
|
+
)
|
|
295
|
+
} else {
|
|
296
|
+
baseQty = new BigNumber(configObj.initialQty)
|
|
297
|
+
}
|
|
298
|
+
|
|
293
299
|
baseQty = baseQty.absoluteValue()
|
|
294
300
|
baseQty = Math.floor(baseQty)
|
|
295
301
|
baseQty = baseQty.toString()
|
package/src/slp/utils.js
CHANGED
|
@@ -921,7 +921,7 @@ class Utils {
|
|
|
921
921
|
* const txid =
|
|
922
922
|
* "266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
|
|
923
923
|
*
|
|
924
|
-
* const data = await
|
|
924
|
+
* const data = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
925
925
|
*
|
|
926
926
|
* console.log(`Decoded OP_RETURN data: ${JSON.stringify(data,null,2)}`)
|
|
927
927
|
* } catch (error) {
|
package/src/transaction.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const RawTransaction = require('./raw-transactions')
|
|
6
6
|
const SlpUtils = require('./slp/utils')
|
|
7
|
+
const BigNumber = require('bignumber.js')
|
|
7
8
|
|
|
8
9
|
class Transaction {
|
|
9
10
|
constructor (config) {
|
|
@@ -75,9 +76,18 @@ class Transaction {
|
|
|
75
76
|
// Add the token quantity to each output.
|
|
76
77
|
for (let i = 0; i < outTokenData.amounts.length; i++) {
|
|
77
78
|
const rawQty = outTokenData.amounts[i]
|
|
78
|
-
const realQty = Number(rawQty) / Math.pow(10, txDetails.tokenDecimals)
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
// const realQty = Number(rawQty) / Math.pow(10, txDetails.tokenDecimals)
|
|
80
|
+
|
|
81
|
+
// Calculate the real quantity using a BigNumber, then convert it to a
|
|
82
|
+
// floating point number.
|
|
83
|
+
let realQty = new BigNumber(rawQty).dividedBy(
|
|
84
|
+
10 ** parseInt(txDetails.tokenDecimals)
|
|
85
|
+
)
|
|
86
|
+
realQty = realQty.toString()
|
|
87
|
+
// realQty = parseFloat(realQty)
|
|
88
|
+
|
|
89
|
+
txDetails.vout[i + 1].tokenQtyStr = realQty
|
|
90
|
+
txDetails.vout[i + 1].tokenQty = parseFloat(realQty)
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
// Add tokenQty = null to any outputs that don't have a value.
|
|
@@ -101,17 +111,49 @@ class Transaction {
|
|
|
101
111
|
// `vin[${i}] tokenData: ${JSON.stringify(inTokenData, null, 2)}`
|
|
102
112
|
// )
|
|
103
113
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
let tokenQty = 0
|
|
115
|
+
if (inTokenData.txType === 'SEND') {
|
|
116
|
+
// Get the appropriate vout token amount. This may throw an error,
|
|
117
|
+
// which means this Vin is not actually a token UTXO, it was just
|
|
118
|
+
// associated with a previous token TX.
|
|
119
|
+
tokenQty = inTokenData.amounts[thisVin.vout - 1]
|
|
120
|
+
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
|
|
121
|
+
|
|
122
|
+
//
|
|
123
|
+
} else if (inTokenData.txType === 'GENESIS') {
|
|
124
|
+
// Only vout[1] of a Genesis transaction represents the tokens.
|
|
125
|
+
// Any other outputs in that transaction are normal BCH UTXOs.
|
|
126
|
+
if (thisVin.vout === 1) {
|
|
127
|
+
tokenQty = inTokenData.qty
|
|
128
|
+
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
|
|
129
|
+
}
|
|
130
|
+
} else if (inTokenData.txType === 'MINT') {
|
|
131
|
+
// vout=1 (second output) recieves the newly minted tokens.
|
|
132
|
+
tokenQty = inTokenData.qty
|
|
133
|
+
|
|
134
|
+
//
|
|
135
|
+
} else {
|
|
136
|
+
console.log(
|
|
137
|
+
'Unexpected code path in Transaction.get(). What is the txType?'
|
|
138
|
+
)
|
|
139
|
+
console.log(inTokenData)
|
|
140
|
+
throw new Error('Unexpected code path')
|
|
141
|
+
}
|
|
109
142
|
|
|
110
143
|
if (tokenQty) {
|
|
111
|
-
const realQty =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
144
|
+
// const realQty =
|
|
145
|
+
// Number(tokenQty) / Math.pow(10, txDetails.tokenDecimals)
|
|
146
|
+
|
|
147
|
+
// Calculate the real quantity using a BigNumber, then convert it to a
|
|
148
|
+
// floating point number.
|
|
149
|
+
let realQty = new BigNumber(tokenQty).dividedBy(
|
|
150
|
+
10 ** parseInt(txDetails.tokenDecimals)
|
|
151
|
+
)
|
|
152
|
+
realQty = realQty.toString()
|
|
153
|
+
// realQty = parseFloat(realQty)
|
|
154
|
+
|
|
155
|
+
thisVin.tokenQtyStr = realQty
|
|
156
|
+
thisVin.tokenQty = parseFloat(realQty)
|
|
115
157
|
// txDetails.vin[i].tokenQty = tokenQty
|
|
116
158
|
} else {
|
|
117
159
|
thisVin.tokenQty = null
|
|
@@ -175,10 +175,261 @@ const mockOpReturnData03 = {
|
|
|
175
175
|
amounts: ['1000000000', '99883400000000']
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
const genesisTestInputTx = {
|
|
179
|
+
txid: '874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e',
|
|
180
|
+
hash: '874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e',
|
|
181
|
+
version: 1,
|
|
182
|
+
size: 480,
|
|
183
|
+
locktime: 543408,
|
|
184
|
+
vin: [
|
|
185
|
+
{
|
|
186
|
+
txid: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
|
187
|
+
vout: 1,
|
|
188
|
+
scriptSig: {
|
|
189
|
+
asm:
|
|
190
|
+
'30440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f55[ALL|FORKID] 028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11',
|
|
191
|
+
hex:
|
|
192
|
+
'4730440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f554121028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11'
|
|
193
|
+
},
|
|
194
|
+
sequence: 4294967294,
|
|
195
|
+
address: 'bitcoincash:qp2jesd06k8ycj4wvkpl9lcwaemtr04f5yphjsa07v',
|
|
196
|
+
value: 0.00000546
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
txid: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
|
200
|
+
vout: 3,
|
|
201
|
+
scriptSig: {
|
|
202
|
+
asm:
|
|
203
|
+
'3045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519[ALL|FORKID] 02cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bc',
|
|
204
|
+
hex:
|
|
205
|
+
'483045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519412102cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bc'
|
|
206
|
+
},
|
|
207
|
+
sequence: 4294967294,
|
|
208
|
+
address: 'bitcoincash:qppj3euc36x5u6twr5cxrrea2rca53vsfu3dxwr86j',
|
|
209
|
+
value: 0.00172192
|
|
210
|
+
}
|
|
211
|
+
],
|
|
212
|
+
vout: [
|
|
213
|
+
{
|
|
214
|
+
value: 0,
|
|
215
|
+
n: 0,
|
|
216
|
+
scriptPubKey: {
|
|
217
|
+
asm:
|
|
218
|
+
'OP_RETURN 5262419 1 1145980243 323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35 00000000004c4b40 00000000004c4b40',
|
|
219
|
+
hex:
|
|
220
|
+
'6a04534c500001010453454e4420323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d350800000000004c4b400800000000004c4b40',
|
|
221
|
+
type: 'nulldata'
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
value: 0.00000546,
|
|
226
|
+
n: 1,
|
|
227
|
+
scriptPubKey: {
|
|
228
|
+
asm:
|
|
229
|
+
'OP_DUP OP_HASH160 0a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e0 OP_EQUALVERIFY OP_CHECKSIG',
|
|
230
|
+
hex: '76a9140a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e088ac',
|
|
231
|
+
reqSigs: 1,
|
|
232
|
+
type: 'pubkeyhash',
|
|
233
|
+
addresses: ['bitcoincash:qq98fnuup7eldhtzc067ang76mss29pguqh7qv9eac']
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
value: 0.00000546,
|
|
238
|
+
n: 2,
|
|
239
|
+
scriptPubKey: {
|
|
240
|
+
asm:
|
|
241
|
+
'OP_DUP OP_HASH160 d4548261e1be0de7e50b7511597799ec4af2b173 OP_EQUALVERIFY OP_CHECKSIG',
|
|
242
|
+
hex: '76a914d4548261e1be0de7e50b7511597799ec4af2b17388ac',
|
|
243
|
+
reqSigs: 1,
|
|
244
|
+
type: 'pubkeyhash',
|
|
245
|
+
addresses: ['bitcoincash:qr29fqnpuxlqmel9pd63zkthn8ky4u43wv0v7pg5mn']
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
value: 0.00171165,
|
|
250
|
+
n: 3,
|
|
251
|
+
scriptPubKey: {
|
|
252
|
+
asm:
|
|
253
|
+
'OP_DUP OP_HASH160 d4548261e1be0de7e50b7511597799ec4af2b173 OP_EQUALVERIFY OP_CHECKSIG',
|
|
254
|
+
hex: '76a914d4548261e1be0de7e50b7511597799ec4af2b17388ac',
|
|
255
|
+
reqSigs: 1,
|
|
256
|
+
type: 'pubkeyhash',
|
|
257
|
+
addresses: ['bitcoincash:qr29fqnpuxlqmel9pd63zkthn8ky4u43wv0v7pg5mn']
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
],
|
|
261
|
+
hex:
|
|
262
|
+
'0100000002359dab0d9c8ddc788b14c0b51493d195c9fbd9f2203d091663350bae351e3a32010000006a4730440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f554121028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11feffffff359dab0d9c8ddc788b14c0b51493d195c9fbd9f2203d091663350bae351e3a32030000006b483045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519412102cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bcfeffffff040000000000000000406a04534c500001010453454e4420323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d350800000000004c4b400800000000004c4b4022020000000000001976a9140a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e088ac22020000000000001976a914d4548261e1be0de7e50b7511597799ec4af2b17388ac9d9c0200000000001976a914d4548261e1be0de7e50b7511597799ec4af2b17388acb04a0800',
|
|
263
|
+
blockhash: '000000000000000000292a9c6150fce48e2edd8df346948494fe6249e6e7f63b',
|
|
264
|
+
confirmations: 163095,
|
|
265
|
+
time: 1534271330,
|
|
266
|
+
blocktime: 1534271330
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const mintTestInputTx = {
|
|
270
|
+
txid: '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa',
|
|
271
|
+
hash: '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa',
|
|
272
|
+
version: 1,
|
|
273
|
+
size: 585,
|
|
274
|
+
locktime: 543613,
|
|
275
|
+
vin: [
|
|
276
|
+
{
|
|
277
|
+
txid: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
|
278
|
+
vout: 1,
|
|
279
|
+
scriptSig: {
|
|
280
|
+
asm: '3045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2[ALL|FORKID] 02056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74',
|
|
281
|
+
hex: '483045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2412102056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74'
|
|
282
|
+
},
|
|
283
|
+
sequence: 4294967294,
|
|
284
|
+
address: 'bitcoincash:qpaf9wltgmpjlg2vxwwu7zdw5y4z7m277ckxn8cufl',
|
|
285
|
+
value: 0.00000546,
|
|
286
|
+
tokenQtyStr: '43545.34534',
|
|
287
|
+
tokenQty: 43545.34534
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
txid: 'ee9d3cf5153599c134147e3fac9844c68e216843f4452a1ce15a29452af6db34',
|
|
291
|
+
vout: 1,
|
|
292
|
+
scriptSig: {
|
|
293
|
+
asm: '3045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a[ALL|FORKID] 024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2',
|
|
294
|
+
hex: '483045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a4121024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2'
|
|
295
|
+
},
|
|
296
|
+
sequence: 4294967294,
|
|
297
|
+
address: 'bitcoincash:qqf89zzwd0fqc3npkks997r5l7dpfjf9kgx2rqu500',
|
|
298
|
+
value: 0.00000546,
|
|
299
|
+
tokenQtyStr: '2.34123',
|
|
300
|
+
tokenQty: 2.34123
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
txid: 'ee9d3cf5153599c134147e3fac9844c68e216843f4452a1ce15a29452af6db34',
|
|
304
|
+
vout: 3,
|
|
305
|
+
scriptSig: {
|
|
306
|
+
asm: '3044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae[ALL|FORKID] 02eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56',
|
|
307
|
+
hex: '473044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae412102eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56'
|
|
308
|
+
},
|
|
309
|
+
sequence: 4294967294,
|
|
310
|
+
address: 'bitcoincash:qqt30r33k0jx3sxe34tmupaujpaljnglmvqgrrfp2x',
|
|
311
|
+
value: 0.00054848,
|
|
312
|
+
tokenQtyStr: '2.34123',
|
|
313
|
+
tokenQty: 2.34123
|
|
314
|
+
}
|
|
315
|
+
],
|
|
316
|
+
vout: [
|
|
317
|
+
{
|
|
318
|
+
value: 0,
|
|
319
|
+
n: 0,
|
|
320
|
+
scriptPubKey: {
|
|
321
|
+
asm: 'OP_RETURN 5262419 1 1145980243 938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8 0000000103907f11',
|
|
322
|
+
hex: '6a04534c500001010453454e4420938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8080000000103907f11',
|
|
323
|
+
type: 'nulldata'
|
|
324
|
+
},
|
|
325
|
+
tokenQty: null
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
value: 0.00000546,
|
|
329
|
+
n: 1,
|
|
330
|
+
scriptPubKey: {
|
|
331
|
+
asm: 'OP_DUP OP_HASH160 059775ff94f65c04e8a6847e74eb9809d8cd779b OP_EQUALVERIFY OP_CHECKSIG',
|
|
332
|
+
hex: '76a914059775ff94f65c04e8a6847e74eb9809d8cd779b88ac',
|
|
333
|
+
reqSigs: 1,
|
|
334
|
+
type: 'pubkeyhash',
|
|
335
|
+
addresses: [
|
|
336
|
+
'bitcoincash:qqzewa0ljnm9cp8g56z8ua8tnqya3nthnvhv5hpu8y'
|
|
337
|
+
]
|
|
338
|
+
},
|
|
339
|
+
tokenQtyStr: '43547.68657',
|
|
340
|
+
tokenQty: 43547.68657
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
value: 0.00054808,
|
|
344
|
+
n: 2,
|
|
345
|
+
scriptPubKey: {
|
|
346
|
+
asm: 'OP_DUP OP_HASH160 0e330dc9009e1e07831f5a22d4ade8977ab674c8 OP_EQUALVERIFY OP_CHECKSIG',
|
|
347
|
+
hex: '76a9140e330dc9009e1e07831f5a22d4ade8977ab674c888ac',
|
|
348
|
+
reqSigs: 1,
|
|
349
|
+
type: 'pubkeyhash',
|
|
350
|
+
addresses: [
|
|
351
|
+
'bitcoincash:qq8rxrwfqz0pupurradz949dazth4dn5eqs3mhrucv'
|
|
352
|
+
]
|
|
353
|
+
},
|
|
354
|
+
tokenQty: null
|
|
355
|
+
}
|
|
356
|
+
],
|
|
357
|
+
hex: '0100000003f8cda53b43b0ea49991a9bc6c74eb901d2a8b964bc7b8987d76789618ec18c93010000006b483045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2412102056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74feffffff34dbf62a45295ae11c2a45f44368218ec64498ac3f7e1434c1993515f53c9dee010000006b483045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a4121024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2feffffff34dbf62a45295ae11c2a45f44368218ec64498ac3f7e1434c1993515f53c9dee030000006a473044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae412102eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56feffffff030000000000000000376a04534c500001010453454e4420938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8080000000103907f1122020000000000001976a914059775ff94f65c04e8a6847e74eb9809d8cd779b88ac18d60000000000001976a9140e330dc9009e1e07831f5a22d4ade8977ab674c888ac7d4b0800',
|
|
358
|
+
blockhash: '00000000000000000140f0d813052da59c811a936494a8d8b2d60b215d19e3dc',
|
|
359
|
+
confirmations: 167007,
|
|
360
|
+
time: 1534391953,
|
|
361
|
+
blocktime: 1534391953,
|
|
362
|
+
isValidSLPTx: true,
|
|
363
|
+
tokenTxType: 'SEND',
|
|
364
|
+
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
|
365
|
+
tokenTicker: 'Bubb2',
|
|
366
|
+
tokenName: 'the new bubbles!',
|
|
367
|
+
tokenDecimals: 5,
|
|
368
|
+
tokenUri: '',
|
|
369
|
+
tokenDocHash: ''
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const genesisTestOpReturnData01 = {
|
|
373
|
+
tokenType: 1,
|
|
374
|
+
txType: 'SEND',
|
|
375
|
+
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
|
376
|
+
amounts: ['5000000', '5000000']
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const genesisTestOpReturnData02 = {
|
|
380
|
+
tokenType: 1,
|
|
381
|
+
txType: 'GENESIS',
|
|
382
|
+
ticker: '',
|
|
383
|
+
name: '',
|
|
384
|
+
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
|
385
|
+
documentUri: '',
|
|
386
|
+
documentHash: '',
|
|
387
|
+
decimals: 0,
|
|
388
|
+
mintBatonVout: 2,
|
|
389
|
+
qty: '10000000'
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const mintTestOpReturnData01 = {
|
|
393
|
+
tokenType: 1,
|
|
394
|
+
txType: 'SEND',
|
|
395
|
+
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
|
396
|
+
amounts: [
|
|
397
|
+
'4354768657'
|
|
398
|
+
]
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const mintTestOpReturnData02 = {
|
|
402
|
+
tokenType: 1,
|
|
403
|
+
txType: 'GENESIS',
|
|
404
|
+
ticker: 'Bubb2',
|
|
405
|
+
name: 'the new bubbles!',
|
|
406
|
+
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
|
407
|
+
documentUri: '',
|
|
408
|
+
documentHash: '',
|
|
409
|
+
decimals: 5,
|
|
410
|
+
mintBatonVout: 2,
|
|
411
|
+
qty: '4354534534'
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const mintTestOpReturnData03 = {
|
|
415
|
+
tokenType: 1,
|
|
416
|
+
txType: 'MINT',
|
|
417
|
+
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
|
|
418
|
+
mintBatonVout: 2,
|
|
419
|
+
qty: '234123'
|
|
420
|
+
}
|
|
421
|
+
|
|
178
422
|
module.exports = {
|
|
179
423
|
nonSlpTxDetails,
|
|
180
424
|
slpTxDetails,
|
|
181
425
|
mockOpReturnData01,
|
|
182
426
|
mockOpReturnData02,
|
|
183
|
-
mockOpReturnData03
|
|
427
|
+
mockOpReturnData03,
|
|
428
|
+
genesisTestInputTx,
|
|
429
|
+
mintTestInputTx,
|
|
430
|
+
genesisTestOpReturnData01,
|
|
431
|
+
genesisTestOpReturnData02,
|
|
432
|
+
mintTestOpReturnData01,
|
|
433
|
+
mintTestOpReturnData02,
|
|
434
|
+
mintTestOpReturnData03
|
|
184
435
|
}
|
|
@@ -115,5 +115,101 @@ describe('#TransactionLib', () => {
|
|
|
115
115
|
assert.include(err.message, 'test error')
|
|
116
116
|
}
|
|
117
117
|
})
|
|
118
|
+
|
|
119
|
+
// This test case was created in response to a bug. When the input TX
|
|
120
|
+
// was a Genesis SLP transaction, the inputs of the transaction were not
|
|
121
|
+
// being hydrated properly.
|
|
122
|
+
it('should get input details when input is a genesis tx', async () => {
|
|
123
|
+
// Mock dependencies
|
|
124
|
+
sandbox
|
|
125
|
+
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
|
126
|
+
.resolves(mockData.genesisTestInputTx)
|
|
127
|
+
sandbox
|
|
128
|
+
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
|
129
|
+
.onCall(0)
|
|
130
|
+
.resolves(mockData.genesisTestOpReturnData01)
|
|
131
|
+
.onCall(1)
|
|
132
|
+
.resolves(mockData.genesisTestOpReturnData02)
|
|
133
|
+
.onCall(2)
|
|
134
|
+
.resolves(mockData.genesisTestOpReturnData02)
|
|
135
|
+
.onCall(3)
|
|
136
|
+
.resolves(mockData.genesisTestOpReturnData02)
|
|
137
|
+
sandbox
|
|
138
|
+
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
|
|
139
|
+
.resolves(true)
|
|
140
|
+
|
|
141
|
+
const txid =
|
|
142
|
+
'874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e'
|
|
143
|
+
|
|
144
|
+
const result = await bchjs.Transaction.get(txid)
|
|
145
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
146
|
+
|
|
147
|
+
// Assert that there are stanardized properties.
|
|
148
|
+
assert.property(result, 'txid')
|
|
149
|
+
assert.property(result, 'vin')
|
|
150
|
+
assert.property(result, 'vout')
|
|
151
|
+
assert.property(result.vout[0], 'value')
|
|
152
|
+
assert.property(result.vout[1].scriptPubKey, 'addresses')
|
|
153
|
+
|
|
154
|
+
// Assert that added properties exist.
|
|
155
|
+
assert.property(result.vout[0], 'tokenQty')
|
|
156
|
+
assert.equal(result.vout[0].tokenQty, null)
|
|
157
|
+
assert.property(result.vin[0], 'address')
|
|
158
|
+
assert.property(result.vin[0], 'value')
|
|
159
|
+
assert.property(result.vin[0], 'tokenQty')
|
|
160
|
+
assert.property(result, 'isValidSLPTx')
|
|
161
|
+
assert.equal(result.isValidSLPTx, true)
|
|
162
|
+
|
|
163
|
+
// Assert inputs values unique to a Genesis input have the proper values.
|
|
164
|
+
assert.equal(result.vin[0].tokenQty, 10000000)
|
|
165
|
+
assert.equal(result.vin[1].tokenQty, null)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('should get input details when input is a mint tx', async () => {
|
|
169
|
+
// Mock dependencies
|
|
170
|
+
sandbox
|
|
171
|
+
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
|
172
|
+
.resolves(mockData.mintTestInputTx)
|
|
173
|
+
sandbox
|
|
174
|
+
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
|
175
|
+
.onCall(0)
|
|
176
|
+
.resolves(mockData.mintTestOpReturnData01)
|
|
177
|
+
.onCall(1)
|
|
178
|
+
.resolves(mockData.mintTestOpReturnData02)
|
|
179
|
+
.onCall(2)
|
|
180
|
+
.resolves(mockData.mintTestOpReturnData02)
|
|
181
|
+
.onCall(3)
|
|
182
|
+
.resolves(mockData.mintTestOpReturnData03)
|
|
183
|
+
.onCall(4)
|
|
184
|
+
.resolves(mockData.mintTestOpReturnData03)
|
|
185
|
+
sandbox
|
|
186
|
+
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
|
|
187
|
+
.resolves(true)
|
|
188
|
+
|
|
189
|
+
const txid =
|
|
190
|
+
'4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa'
|
|
191
|
+
|
|
192
|
+
const result = await bchjs.Transaction.get(txid)
|
|
193
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
194
|
+
|
|
195
|
+
// Assert that there are stanardized properties.
|
|
196
|
+
assert.property(result, 'txid')
|
|
197
|
+
assert.property(result, 'vin')
|
|
198
|
+
assert.property(result, 'vout')
|
|
199
|
+
assert.property(result.vout[0], 'value')
|
|
200
|
+
assert.property(result.vout[1].scriptPubKey, 'addresses')
|
|
201
|
+
|
|
202
|
+
// Assert that added properties exist.
|
|
203
|
+
assert.property(result.vout[0], 'tokenQty')
|
|
204
|
+
assert.equal(result.vout[0].tokenQty, null)
|
|
205
|
+
assert.property(result.vin[0], 'address')
|
|
206
|
+
assert.property(result.vin[0], 'value')
|
|
207
|
+
assert.property(result.vin[0], 'tokenQty')
|
|
208
|
+
assert.property(result, 'isValidSLPTx')
|
|
209
|
+
assert.equal(result.isValidSLPTx, true)
|
|
210
|
+
|
|
211
|
+
// Assert inputs values unique to a Mint input have the proper values.
|
|
212
|
+
assert.equal(result.vin[2].tokenQty, 2.34123)
|
|
213
|
+
})
|
|
118
214
|
})
|
|
119
215
|
})
|