@psf/bch-js 4.22.0 → 4.22.1
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 +2 -2
- package/test/integration/chains/bchn/slp.js +229 -225
- package/test/integration/slp.js +907 -901
package/test/integration/slp.js
CHANGED
|
@@ -30,965 +30,971 @@ describe('#SLP', () => {
|
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
describe('#util', () => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const result = await bchjs.SLP.Utils.list(tokenId)
|
|
39
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
40
|
-
|
|
41
|
-
assert.hasAnyKeys(result, [
|
|
42
|
-
'decimals',
|
|
43
|
-
'timestamp',
|
|
44
|
-
'timestamp_unix',
|
|
45
|
-
'versionType',
|
|
46
|
-
'documentUri',
|
|
47
|
-
'symbol',
|
|
48
|
-
'name',
|
|
49
|
-
'containsBaton',
|
|
50
|
-
'id',
|
|
51
|
-
'documentHash',
|
|
52
|
-
'initialTokenQty',
|
|
53
|
-
'blockCreated',
|
|
54
|
-
'blockLastActiveSend',
|
|
55
|
-
'blockLastActiveMint',
|
|
56
|
-
'txnsSinceGenesis',
|
|
57
|
-
'validAddress',
|
|
58
|
-
'totalMinted',
|
|
59
|
-
'totalBurned',
|
|
60
|
-
'circulatingSupply',
|
|
61
|
-
'mintingBatonStatus'
|
|
62
|
-
])
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// describe("#decodeOpReturn", () => {
|
|
67
|
-
// it("should decode the OP_RETURN for a SEND txid", async () => {
|
|
68
|
-
// const txid =
|
|
69
|
-
// "266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
|
|
70
|
-
//
|
|
71
|
-
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
72
|
-
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
73
|
-
//
|
|
74
|
-
// assert.hasAllKeys(result, [
|
|
75
|
-
// "tokenType",
|
|
76
|
-
// "transactionType",
|
|
77
|
-
// "tokenId",
|
|
78
|
-
// "spendData"
|
|
79
|
-
// ])
|
|
80
|
-
// })
|
|
81
|
-
//
|
|
82
|
-
// it("should decode the OP_RETURN for a GENESIS txid", async () => {
|
|
83
|
-
// const txid =
|
|
84
|
-
// "497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
|
85
|
-
//
|
|
86
|
-
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
87
|
-
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
88
|
-
//
|
|
89
|
-
// assert.hasAllKeys(result, [
|
|
90
|
-
// "tokenType",
|
|
91
|
-
// "transactionType",
|
|
92
|
-
// "ticker",
|
|
93
|
-
// "name",
|
|
94
|
-
// "documentUrl",
|
|
95
|
-
// "documentHash",
|
|
96
|
-
// "decimals",
|
|
97
|
-
// "mintBatonVout",
|
|
98
|
-
// "initialQty",
|
|
99
|
-
// "tokensSentTo",
|
|
100
|
-
// "batonHolder"
|
|
101
|
-
// ])
|
|
102
|
-
// })
|
|
103
|
-
//
|
|
104
|
-
// it("should decode the OP_RETURN for a MINT txid", async () => {
|
|
105
|
-
// const txid =
|
|
106
|
-
// "65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
|
|
107
|
-
//
|
|
108
|
-
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
109
|
-
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
110
|
-
//
|
|
111
|
-
// assert.hasAllKeys(result, [
|
|
112
|
-
// "tokenType",
|
|
113
|
-
// "transactionType",
|
|
114
|
-
// "tokenId",
|
|
115
|
-
// "mintBatonVout",
|
|
116
|
-
// "batonStillExists",
|
|
117
|
-
// "quantity",
|
|
118
|
-
// "tokensSentTo",
|
|
119
|
-
// "batonHolder"
|
|
120
|
-
// ])
|
|
121
|
-
// })
|
|
122
|
-
//
|
|
123
|
-
// it("should throw an error for a non-SLP transaction", async () => {
|
|
124
|
-
// try {
|
|
125
|
-
// const txid =
|
|
126
|
-
// "3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
|
|
127
|
-
//
|
|
128
|
-
// await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
129
|
-
//
|
|
130
|
-
// assert.equal(true, false, "Unexpected result")
|
|
131
|
-
// } catch (err) {
|
|
132
|
-
// // console.log(`err: `, err)
|
|
133
|
-
// assert.include(err.message, "Not an OP_RETURN")
|
|
134
|
-
// }
|
|
135
|
-
// })
|
|
136
|
-
// })
|
|
137
|
-
|
|
138
|
-
describe('#decodeOpReturn', () => {
|
|
139
|
-
it('should decode the OP_RETURN for a SEND txid', async () => {
|
|
140
|
-
const txid =
|
|
141
|
-
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
|
|
142
|
-
|
|
143
|
-
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
144
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
145
|
-
|
|
146
|
-
assert.hasAllKeys(result, ['tokenType', 'txType', 'tokenId', 'amounts'])
|
|
147
|
-
assert.equal(
|
|
148
|
-
result.tokenId,
|
|
149
|
-
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
// Verify outputs
|
|
153
|
-
assert.equal(result.amounts.length, 2)
|
|
154
|
-
assert.equal(result.amounts[0], '100000000')
|
|
155
|
-
assert.equal(result.amounts[1], '99883300000000')
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('should decode the OP_RETURN for a GENESIS txid', async () => {
|
|
159
|
-
const txid =
|
|
160
|
-
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
|
161
|
-
|
|
162
|
-
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
163
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
164
|
-
|
|
165
|
-
assert.hasAllKeys(result, [
|
|
166
|
-
'tokenType',
|
|
167
|
-
'txType',
|
|
168
|
-
'tokenId',
|
|
169
|
-
'ticker',
|
|
170
|
-
'name',
|
|
171
|
-
'documentUri',
|
|
172
|
-
'documentHash',
|
|
173
|
-
'decimals',
|
|
174
|
-
'mintBatonVout',
|
|
175
|
-
'qty'
|
|
176
|
-
])
|
|
177
|
-
assert.equal(
|
|
178
|
-
result.tokenId,
|
|
179
|
-
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
|
180
|
-
)
|
|
181
|
-
assert.equal(result.txType, 'GENESIS')
|
|
182
|
-
assert.equal(result.ticker, 'TOK-CH')
|
|
183
|
-
assert.equal(result.name, 'TokyoCash')
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
it('should decode the OP_RETURN for a MINT txid', async () => {
|
|
187
|
-
const txid =
|
|
188
|
-
'65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4'
|
|
189
|
-
|
|
190
|
-
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
191
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
192
|
-
|
|
193
|
-
assert.hasAllKeys(result, [
|
|
194
|
-
'tokenType',
|
|
195
|
-
'txType',
|
|
196
|
-
'tokenId',
|
|
197
|
-
'mintBatonVout',
|
|
198
|
-
'qty'
|
|
199
|
-
])
|
|
200
|
-
})
|
|
33
|
+
if (process.env.TESTSLP) {
|
|
34
|
+
describe('#list', () => {
|
|
35
|
+
it('should get information on the Spice token', async () => {
|
|
36
|
+
const tokenId =
|
|
37
|
+
'4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf'
|
|
201
38
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const txid =
|
|
205
|
-
'3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec'
|
|
206
|
-
|
|
207
|
-
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
208
|
-
|
|
209
|
-
assert.equal(true, false, 'Unexpected result')
|
|
210
|
-
} catch (err) {
|
|
211
|
-
// console.log(`err: `, err)
|
|
212
|
-
assert.include(err.message, 'scriptpubkey not op_return')
|
|
213
|
-
}
|
|
214
|
-
})
|
|
39
|
+
const result = await bchjs.SLP.Utils.list(tokenId)
|
|
40
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
215
41
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
42
|
+
assert.hasAnyKeys(result, [
|
|
43
|
+
'decimals',
|
|
44
|
+
'timestamp',
|
|
45
|
+
'timestamp_unix',
|
|
46
|
+
'versionType',
|
|
47
|
+
'documentUri',
|
|
48
|
+
'symbol',
|
|
49
|
+
'name',
|
|
50
|
+
'containsBaton',
|
|
51
|
+
'id',
|
|
52
|
+
'documentHash',
|
|
53
|
+
'initialTokenQty',
|
|
54
|
+
'blockCreated',
|
|
55
|
+
'blockLastActiveSend',
|
|
56
|
+
'blockLastActiveMint',
|
|
57
|
+
'txnsSinceGenesis',
|
|
58
|
+
'validAddress',
|
|
59
|
+
'totalMinted',
|
|
60
|
+
'totalBurned',
|
|
61
|
+
'circulatingSupply',
|
|
62
|
+
'mintingBatonStatus'
|
|
63
|
+
])
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// describe("#decodeOpReturn", () => {
|
|
68
|
+
// it("should decode the OP_RETURN for a SEND txid", async () => {
|
|
69
|
+
// const txid =
|
|
70
|
+
// "266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
|
|
71
|
+
//
|
|
72
|
+
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
73
|
+
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
74
|
+
//
|
|
75
|
+
// assert.hasAllKeys(result, [
|
|
76
|
+
// "tokenType",
|
|
77
|
+
// "transactionType",
|
|
78
|
+
// "tokenId",
|
|
79
|
+
// "spendData"
|
|
80
|
+
// ])
|
|
81
|
+
// })
|
|
82
|
+
//
|
|
83
|
+
// it("should decode the OP_RETURN for a GENESIS txid", async () => {
|
|
84
|
+
// const txid =
|
|
85
|
+
// "497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
|
86
|
+
//
|
|
87
|
+
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
88
|
+
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
89
|
+
//
|
|
90
|
+
// assert.hasAllKeys(result, [
|
|
91
|
+
// "tokenType",
|
|
92
|
+
// "transactionType",
|
|
93
|
+
// "ticker",
|
|
94
|
+
// "name",
|
|
95
|
+
// "documentUrl",
|
|
96
|
+
// "documentHash",
|
|
97
|
+
// "decimals",
|
|
98
|
+
// "mintBatonVout",
|
|
99
|
+
// "initialQty",
|
|
100
|
+
// "tokensSentTo",
|
|
101
|
+
// "batonHolder"
|
|
102
|
+
// ])
|
|
103
|
+
// })
|
|
104
|
+
//
|
|
105
|
+
// it("should decode the OP_RETURN for a MINT txid", async () => {
|
|
106
|
+
// const txid =
|
|
107
|
+
// "65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
|
|
108
|
+
//
|
|
109
|
+
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
110
|
+
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
111
|
+
//
|
|
112
|
+
// assert.hasAllKeys(result, [
|
|
113
|
+
// "tokenType",
|
|
114
|
+
// "transactionType",
|
|
115
|
+
// "tokenId",
|
|
116
|
+
// "mintBatonVout",
|
|
117
|
+
// "batonStillExists",
|
|
118
|
+
// "quantity",
|
|
119
|
+
// "tokensSentTo",
|
|
120
|
+
// "batonHolder"
|
|
121
|
+
// ])
|
|
122
|
+
// })
|
|
123
|
+
//
|
|
124
|
+
// it("should throw an error for a non-SLP transaction", async () => {
|
|
125
|
+
// try {
|
|
126
|
+
// const txid =
|
|
127
|
+
// "3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
|
|
128
|
+
//
|
|
129
|
+
// await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
130
|
+
//
|
|
131
|
+
// assert.equal(true, false, "Unexpected result")
|
|
132
|
+
// } catch (err) {
|
|
133
|
+
// // console.log(`err: `, err)
|
|
134
|
+
// assert.include(err.message, "Not an OP_RETURN")
|
|
135
|
+
// }
|
|
136
|
+
// })
|
|
137
|
+
// })
|
|
138
|
+
|
|
139
|
+
describe('#decodeOpReturn', () => {
|
|
140
|
+
it('should decode the OP_RETURN for a SEND txid', async () => {
|
|
221
141
|
const txid =
|
|
222
|
-
'
|
|
142
|
+
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
|
|
223
143
|
|
|
224
|
-
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
144
|
+
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
225
145
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
226
|
-
} catch (err) {
|
|
227
|
-
// console.log(`err: `, err)
|
|
228
|
-
assert.include(err.message, 'amount string size not 8 bytes')
|
|
229
|
-
}
|
|
230
|
-
})
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
describe('#tokenUtxoDetails', () => {
|
|
234
|
-
// // This captures an important corner-case. When an SLP token is created, the
|
|
235
|
-
// // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
|
|
236
|
-
it('should return details on minting baton from genesis transaction', async () => {
|
|
237
|
-
const utxos = [
|
|
238
|
-
{
|
|
239
|
-
txid:
|
|
240
|
-
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
|
|
241
|
-
vout: 3,
|
|
242
|
-
amount: 0.00002015,
|
|
243
|
-
satoshis: 2015,
|
|
244
|
-
height: 594892,
|
|
245
|
-
confirmations: 5
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
txid:
|
|
249
|
-
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
|
|
250
|
-
vout: 2,
|
|
251
|
-
amount: 0.00000546,
|
|
252
|
-
satoshis: 546,
|
|
253
|
-
height: 594892,
|
|
254
|
-
confirmations: 5
|
|
255
|
-
}
|
|
256
|
-
]
|
|
257
|
-
|
|
258
|
-
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
259
|
-
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
260
|
-
|
|
261
|
-
assert.equal(data[0].isValid, false, 'Change UTXO marked as false.')
|
|
262
|
-
|
|
263
|
-
assert.property(data[1], 'txid')
|
|
264
|
-
assert.property(data[1], 'vout')
|
|
265
|
-
assert.property(data[1], 'amount')
|
|
266
|
-
assert.property(data[1], 'satoshis')
|
|
267
|
-
assert.property(data[1], 'height')
|
|
268
|
-
assert.property(data[1], 'confirmations')
|
|
269
|
-
assert.property(data[1], 'utxoType')
|
|
270
|
-
assert.property(data[1], 'tokenId')
|
|
271
|
-
assert.property(data[1], 'tokenTicker')
|
|
272
|
-
assert.property(data[1], 'tokenName')
|
|
273
|
-
assert.property(data[1], 'tokenDocumentUrl')
|
|
274
|
-
assert.property(data[1], 'tokenDocumentHash')
|
|
275
|
-
assert.property(data[1], 'decimals')
|
|
276
|
-
assert.property(data[1], 'isValid')
|
|
277
|
-
assert.equal(data[1].isValid, true)
|
|
278
|
-
})
|
|
279
146
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
height: 600297,
|
|
291
|
-
confirmations: 76
|
|
292
|
-
}
|
|
293
|
-
]
|
|
294
|
-
|
|
295
|
-
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
296
|
-
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
297
|
-
|
|
298
|
-
assert.property(data[0], 'txid')
|
|
299
|
-
assert.property(data[0], 'vout')
|
|
300
|
-
assert.property(data[0], 'amount')
|
|
301
|
-
assert.property(data[0], 'satoshis')
|
|
302
|
-
assert.property(data[0], 'height')
|
|
303
|
-
assert.property(data[0], 'confirmations')
|
|
304
|
-
assert.property(data[0], 'utxoType')
|
|
305
|
-
assert.property(data[0], 'transactionType')
|
|
306
|
-
assert.property(data[0], 'tokenId')
|
|
307
|
-
assert.property(data[0], 'tokenTicker')
|
|
308
|
-
assert.property(data[0], 'tokenName')
|
|
309
|
-
assert.property(data[0], 'tokenDocumentUrl')
|
|
310
|
-
assert.property(data[0], 'tokenDocumentHash')
|
|
311
|
-
assert.property(data[0], 'decimals')
|
|
312
|
-
assert.property(data[0], 'mintBatonVout')
|
|
313
|
-
assert.property(data[0], 'tokenQty')
|
|
314
|
-
assert.property(data[0], 'isValid')
|
|
315
|
-
assert.equal(data[0].isValid, true)
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
it('should return details for a simple SEND SLP token utxo', async () => {
|
|
319
|
-
const utxos = [
|
|
320
|
-
{
|
|
321
|
-
txid:
|
|
322
|
-
'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
|
|
323
|
-
vout: 1,
|
|
324
|
-
amount: 0.00000546,
|
|
325
|
-
satoshis: 546,
|
|
326
|
-
height: 596089,
|
|
327
|
-
confirmations: 748
|
|
328
|
-
}
|
|
329
|
-
]
|
|
330
|
-
|
|
331
|
-
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
332
|
-
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
333
|
-
|
|
334
|
-
assert.property(data[0], 'txid')
|
|
335
|
-
assert.property(data[0], 'vout')
|
|
336
|
-
assert.property(data[0], 'amount')
|
|
337
|
-
assert.property(data[0], 'satoshis')
|
|
338
|
-
assert.property(data[0], 'height')
|
|
339
|
-
assert.property(data[0], 'confirmations')
|
|
340
|
-
assert.property(data[0], 'utxoType')
|
|
341
|
-
assert.property(data[0], 'tokenId')
|
|
342
|
-
assert.property(data[0], 'tokenTicker')
|
|
343
|
-
assert.property(data[0], 'tokenName')
|
|
344
|
-
assert.property(data[0], 'tokenDocumentUrl')
|
|
345
|
-
assert.property(data[0], 'tokenDocumentHash')
|
|
346
|
-
assert.property(data[0], 'decimals')
|
|
347
|
-
assert.property(data[0], 'tokenQty')
|
|
348
|
-
assert.property(data[0], 'isValid')
|
|
349
|
-
assert.equal(data[0].isValid, true)
|
|
350
|
-
})
|
|
351
|
-
|
|
352
|
-
it('should handle BCH and SLP utxos in the same TX', async () => {
|
|
353
|
-
const utxos = [
|
|
354
|
-
{
|
|
355
|
-
txid:
|
|
356
|
-
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
|
357
|
-
vout: 3,
|
|
358
|
-
value: '6816',
|
|
359
|
-
height: 606848,
|
|
360
|
-
confirmations: 13,
|
|
361
|
-
satoshis: 6816
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
txid:
|
|
365
|
-
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
|
366
|
-
vout: 2,
|
|
367
|
-
value: '546',
|
|
368
|
-
height: 606848,
|
|
369
|
-
confirmations: 13,
|
|
370
|
-
satoshis: 546
|
|
371
|
-
}
|
|
372
|
-
]
|
|
373
|
-
|
|
374
|
-
const result = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
375
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
376
|
-
|
|
377
|
-
assert.isArray(result)
|
|
378
|
-
assert.equal(result.length, 2)
|
|
379
|
-
assert.equal(result[0].isValid, false)
|
|
380
|
-
assert.equal(result[1].isValid, true)
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
it('should handle problematic utxos', async () => {
|
|
384
|
-
const utxos = [
|
|
385
|
-
{
|
|
386
|
-
txid:
|
|
387
|
-
'0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959',
|
|
388
|
-
vout: 0,
|
|
389
|
-
amount: 0.00018362,
|
|
390
|
-
satoshis: 18362,
|
|
391
|
-
height: 613483,
|
|
392
|
-
confirmations: 124
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
txid:
|
|
396
|
-
'67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19',
|
|
397
|
-
vout: 1,
|
|
398
|
-
amount: 0.00000546,
|
|
399
|
-
satoshis: 546,
|
|
400
|
-
height: 612075,
|
|
401
|
-
confirmations: 1532
|
|
402
|
-
}
|
|
403
|
-
]
|
|
404
|
-
|
|
405
|
-
const result = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
406
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
407
|
-
|
|
408
|
-
assert.isArray(result)
|
|
409
|
-
assert.equal(result.length, 2)
|
|
410
|
-
assert.equal(result[0].isValid, false)
|
|
411
|
-
assert.equal(result[1].isValid, true)
|
|
412
|
-
})
|
|
413
|
-
|
|
414
|
-
it('should return false for BCH-only UTXOs', async () => {
|
|
415
|
-
const utxos = [
|
|
416
|
-
{
|
|
417
|
-
txid:
|
|
418
|
-
'a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b',
|
|
419
|
-
vout: 0,
|
|
420
|
-
amount: 0.00001,
|
|
421
|
-
satoshis: 1000,
|
|
422
|
-
confirmations: 0,
|
|
423
|
-
ts: 1578424704
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
txid:
|
|
427
|
-
'53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44',
|
|
428
|
-
vout: 0,
|
|
429
|
-
amount: 0.00001,
|
|
430
|
-
satoshis: 1000,
|
|
431
|
-
confirmations: 0,
|
|
432
|
-
ts: 1578424634
|
|
433
|
-
}
|
|
434
|
-
]
|
|
435
|
-
|
|
436
|
-
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
437
|
-
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
438
|
-
|
|
439
|
-
assert.isArray(data)
|
|
440
|
-
assert.equal(data[0].isValid, false)
|
|
441
|
-
assert.equal(data[1].isValid, false)
|
|
442
|
-
})
|
|
443
|
-
|
|
444
|
-
it('should handle a dust attack', async () => {
|
|
445
|
-
// it("#dustattack", async () => {
|
|
446
|
-
const utxos = [
|
|
447
|
-
{
|
|
448
|
-
height: 655965,
|
|
449
|
-
tx_hash:
|
|
450
|
-
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
|
|
451
|
-
tx_pos: 151,
|
|
452
|
-
value: 547,
|
|
453
|
-
satoshis: 547,
|
|
454
|
-
txid:
|
|
455
|
-
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
|
|
456
|
-
vout: 151,
|
|
457
|
-
address: 'bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww',
|
|
458
|
-
hdIndex: 11
|
|
459
|
-
}
|
|
460
|
-
]
|
|
461
|
-
|
|
462
|
-
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
463
|
-
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
464
|
-
|
|
465
|
-
assert.equal(data[0].isValid, false)
|
|
466
|
-
})
|
|
467
|
-
|
|
468
|
-
it('should handle null SLPDB validations', async () => {
|
|
469
|
-
const utxos = [
|
|
470
|
-
{
|
|
471
|
-
height: 665577,
|
|
472
|
-
tx_hash:
|
|
473
|
-
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
|
474
|
-
tx_pos: 1,
|
|
475
|
-
value: 546
|
|
476
|
-
},
|
|
477
|
-
{
|
|
478
|
-
height: 665577,
|
|
479
|
-
tx_hash:
|
|
480
|
-
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
481
|
-
tx_pos: 1,
|
|
482
|
-
value: 546
|
|
483
|
-
}
|
|
484
|
-
]
|
|
485
|
-
|
|
486
|
-
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
487
|
-
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
488
|
-
|
|
489
|
-
assert.isArray(data)
|
|
490
|
-
// assert.equal(data[0].isValid, null)
|
|
491
|
-
})
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
describe('#tokenUtxoDetailsWL', () => {
|
|
495
|
-
it('should return details for a simple SEND SLP token utxo', async () => {
|
|
496
|
-
const utxos = [
|
|
497
|
-
{
|
|
498
|
-
height: 660554,
|
|
499
|
-
tx_hash:
|
|
500
|
-
'89b3f0c84efe8b01b24e2d7ac08636de5781f31dbb84478e3de868ca0a7ed93a',
|
|
501
|
-
tx_pos: 1,
|
|
502
|
-
value: 546
|
|
503
|
-
}
|
|
504
|
-
]
|
|
505
|
-
|
|
506
|
-
const data = await bchjs.SLP.Utils.tokenUtxoDetailsWL(utxos)
|
|
507
|
-
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
508
|
-
|
|
509
|
-
assert.property(data[0], 'txid')
|
|
510
|
-
assert.property(data[0], 'vout')
|
|
511
|
-
assert.property(data[0], 'height')
|
|
512
|
-
assert.property(data[0], 'utxoType')
|
|
513
|
-
assert.property(data[0], 'tokenId')
|
|
514
|
-
assert.property(data[0], 'tokenTicker')
|
|
515
|
-
assert.property(data[0], 'tokenName')
|
|
516
|
-
assert.property(data[0], 'tokenDocumentUrl')
|
|
517
|
-
assert.property(data[0], 'tokenDocumentHash')
|
|
518
|
-
assert.property(data[0], 'decimals')
|
|
519
|
-
assert.property(data[0], 'tokenQty')
|
|
520
|
-
assert.property(data[0], 'isValid')
|
|
521
|
-
assert.equal(data[0].isValid, true)
|
|
522
|
-
})
|
|
147
|
+
assert.hasAllKeys(result, [
|
|
148
|
+
'tokenType',
|
|
149
|
+
'txType',
|
|
150
|
+
'tokenId',
|
|
151
|
+
'amounts'
|
|
152
|
+
])
|
|
153
|
+
assert.equal(
|
|
154
|
+
result.tokenId,
|
|
155
|
+
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
|
156
|
+
)
|
|
523
157
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
vout: 0,
|
|
530
|
-
amount: 0.00001,
|
|
531
|
-
satoshis: 1000,
|
|
532
|
-
confirmations: 0,
|
|
533
|
-
ts: 1578424704
|
|
534
|
-
},
|
|
535
|
-
{
|
|
536
|
-
txid:
|
|
537
|
-
'53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44',
|
|
538
|
-
vout: 0,
|
|
539
|
-
amount: 0.00001,
|
|
540
|
-
satoshis: 1000,
|
|
541
|
-
confirmations: 0,
|
|
542
|
-
ts: 1578424634
|
|
543
|
-
}
|
|
544
|
-
]
|
|
158
|
+
// Verify outputs
|
|
159
|
+
assert.equal(result.amounts.length, 2)
|
|
160
|
+
assert.equal(result.amounts[0], '100000000')
|
|
161
|
+
assert.equal(result.amounts[1], '99883300000000')
|
|
162
|
+
})
|
|
545
163
|
|
|
546
|
-
|
|
547
|
-
|
|
164
|
+
it('should decode the OP_RETURN for a GENESIS txid', async () => {
|
|
165
|
+
const txid =
|
|
166
|
+
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
|
548
167
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
assert.equal(data[1].isValid, false)
|
|
552
|
-
})
|
|
168
|
+
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
169
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
553
170
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
171
|
+
assert.hasAllKeys(result, [
|
|
172
|
+
'tokenType',
|
|
173
|
+
'txType',
|
|
174
|
+
'tokenId',
|
|
175
|
+
'ticker',
|
|
176
|
+
'name',
|
|
177
|
+
'documentUri',
|
|
178
|
+
'documentHash',
|
|
179
|
+
'decimals',
|
|
180
|
+
'mintBatonVout',
|
|
181
|
+
'qty'
|
|
182
|
+
])
|
|
183
|
+
assert.equal(
|
|
184
|
+
result.tokenId,
|
|
185
|
+
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
|
186
|
+
)
|
|
187
|
+
assert.equal(result.txType, 'GENESIS')
|
|
188
|
+
assert.equal(result.ticker, 'TOK-CH')
|
|
189
|
+
assert.equal(result.name, 'TokyoCash')
|
|
190
|
+
})
|
|
571
191
|
|
|
572
|
-
|
|
573
|
-
|
|
192
|
+
it('should decode the OP_RETURN for a MINT txid', async () => {
|
|
193
|
+
const txid =
|
|
194
|
+
'65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4'
|
|
574
195
|
|
|
575
|
-
|
|
576
|
-
|
|
196
|
+
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
197
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
577
198
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
'
|
|
591
|
-
|
|
592
|
-
|
|
199
|
+
assert.hasAllKeys(result, [
|
|
200
|
+
'tokenType',
|
|
201
|
+
'txType',
|
|
202
|
+
'tokenId',
|
|
203
|
+
'mintBatonVout',
|
|
204
|
+
'qty'
|
|
205
|
+
])
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('should throw an error for a non-SLP transaction', async () => {
|
|
209
|
+
try {
|
|
210
|
+
const txid =
|
|
211
|
+
'3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec'
|
|
212
|
+
|
|
213
|
+
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
214
|
+
|
|
215
|
+
assert.equal(true, false, 'Unexpected result')
|
|
216
|
+
} catch (err) {
|
|
217
|
+
// console.log(`err: `, err)
|
|
218
|
+
assert.include(err.message, 'scriptpubkey not op_return')
|
|
593
219
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
//
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
|
|
610
|
-
|
|
611
|
-
assert.isArray(balances)
|
|
612
|
-
assert.hasAllKeys(balances[0], [
|
|
613
|
-
'tokenId',
|
|
614
|
-
'balanceString',
|
|
615
|
-
'balance',
|
|
616
|
-
'decimalCount',
|
|
617
|
-
'slpAddress'
|
|
618
|
-
])
|
|
619
|
-
})
|
|
620
|
-
|
|
621
|
-
it('should fetch balances for multiple addresses', async () => {
|
|
622
|
-
const addresses = [
|
|
623
|
-
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9',
|
|
624
|
-
'simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57'
|
|
625
|
-
]
|
|
626
|
-
|
|
627
|
-
const balances = await bchjs.SLP.Utils.balancesForAddress(addresses)
|
|
628
|
-
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
|
|
629
|
-
|
|
630
|
-
assert.isArray(balances)
|
|
631
|
-
assert.isArray(balances[0])
|
|
632
|
-
assert.hasAllKeys(balances[0][0], [
|
|
633
|
-
'tokenId',
|
|
634
|
-
'balanceString',
|
|
635
|
-
'balance',
|
|
636
|
-
'decimalCount',
|
|
637
|
-
'slpAddress'
|
|
638
|
-
])
|
|
639
|
-
})
|
|
640
|
-
})
|
|
641
|
-
|
|
642
|
-
describe('#hydrateUtxos-', () => {
|
|
643
|
-
it('should hydrate UTXOs', async () => {
|
|
644
|
-
const utxos = [
|
|
645
|
-
{
|
|
646
|
-
utxos: [
|
|
647
|
-
{
|
|
648
|
-
txid:
|
|
649
|
-
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
|
650
|
-
vout: 3,
|
|
651
|
-
value: '6816',
|
|
652
|
-
height: 606848,
|
|
653
|
-
confirmations: 13,
|
|
654
|
-
satoshis: 6816
|
|
655
|
-
},
|
|
656
|
-
{
|
|
657
|
-
txid:
|
|
658
|
-
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
|
659
|
-
vout: 2,
|
|
660
|
-
value: '546',
|
|
661
|
-
height: 606848,
|
|
662
|
-
confirmations: 13,
|
|
663
|
-
satoshis: 546
|
|
664
|
-
}
|
|
665
|
-
]
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
// Note: This TX is interpreted as valid by the original decodeOpReturn().
|
|
223
|
+
// Fixing this issue and related issues was the reason for creating the
|
|
224
|
+
// decodeOpReturn2() method using the slp-parser library.
|
|
225
|
+
it('should throw error for invalid SLP transaction', async () => {
|
|
226
|
+
try {
|
|
227
|
+
const txid =
|
|
228
|
+
'a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415'
|
|
229
|
+
|
|
230
|
+
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
231
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
232
|
+
} catch (err) {
|
|
233
|
+
// console.log(`err: `, err)
|
|
234
|
+
assert.include(err.message, 'amount string size not 8 bytes')
|
|
666
235
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
//
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
'
|
|
710
|
-
'
|
|
711
|
-
'
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
236
|
+
})
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
describe('#tokenUtxoDetails', () => {
|
|
240
|
+
// // This captures an important corner-case. When an SLP token is created, the
|
|
241
|
+
// // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
|
|
242
|
+
it('should return details on minting baton from genesis transaction', async () => {
|
|
243
|
+
const utxos = [
|
|
244
|
+
{
|
|
245
|
+
txid:
|
|
246
|
+
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
|
|
247
|
+
vout: 3,
|
|
248
|
+
amount: 0.00002015,
|
|
249
|
+
satoshis: 2015,
|
|
250
|
+
height: 594892,
|
|
251
|
+
confirmations: 5
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
txid:
|
|
255
|
+
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
|
|
256
|
+
vout: 2,
|
|
257
|
+
amount: 0.00000546,
|
|
258
|
+
satoshis: 546,
|
|
259
|
+
height: 594892,
|
|
260
|
+
confirmations: 5
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
265
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
266
|
+
|
|
267
|
+
assert.equal(data[0].isValid, false, 'Change UTXO marked as false.')
|
|
268
|
+
|
|
269
|
+
assert.property(data[1], 'txid')
|
|
270
|
+
assert.property(data[1], 'vout')
|
|
271
|
+
assert.property(data[1], 'amount')
|
|
272
|
+
assert.property(data[1], 'satoshis')
|
|
273
|
+
assert.property(data[1], 'height')
|
|
274
|
+
assert.property(data[1], 'confirmations')
|
|
275
|
+
assert.property(data[1], 'utxoType')
|
|
276
|
+
assert.property(data[1], 'tokenId')
|
|
277
|
+
assert.property(data[1], 'tokenTicker')
|
|
278
|
+
assert.property(data[1], 'tokenName')
|
|
279
|
+
assert.property(data[1], 'tokenDocumentUrl')
|
|
280
|
+
assert.property(data[1], 'tokenDocumentHash')
|
|
281
|
+
assert.property(data[1], 'decimals')
|
|
282
|
+
assert.property(data[1], 'isValid')
|
|
283
|
+
assert.equal(data[1].isValid, true)
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
it('should return details for a MINT token utxo', async () => {
|
|
287
|
+
// Mock the call to REST API
|
|
288
|
+
|
|
289
|
+
const utxos = [
|
|
290
|
+
{
|
|
291
|
+
txid:
|
|
292
|
+
'cf4b922d1e1aa56b52d752d4206e1448ea76c3ebe69b3b97d8f8f65413bd5c76',
|
|
293
|
+
vout: 1,
|
|
294
|
+
amount: 0.00000546,
|
|
295
|
+
satoshis: 546,
|
|
296
|
+
height: 600297,
|
|
297
|
+
confirmations: 76
|
|
298
|
+
}
|
|
299
|
+
]
|
|
300
|
+
|
|
301
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
302
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
303
|
+
|
|
304
|
+
assert.property(data[0], 'txid')
|
|
305
|
+
assert.property(data[0], 'vout')
|
|
306
|
+
assert.property(data[0], 'amount')
|
|
307
|
+
assert.property(data[0], 'satoshis')
|
|
308
|
+
assert.property(data[0], 'height')
|
|
309
|
+
assert.property(data[0], 'confirmations')
|
|
310
|
+
assert.property(data[0], 'utxoType')
|
|
311
|
+
assert.property(data[0], 'transactionType')
|
|
312
|
+
assert.property(data[0], 'tokenId')
|
|
313
|
+
assert.property(data[0], 'tokenTicker')
|
|
314
|
+
assert.property(data[0], 'tokenName')
|
|
315
|
+
assert.property(data[0], 'tokenDocumentUrl')
|
|
316
|
+
assert.property(data[0], 'tokenDocumentHash')
|
|
317
|
+
assert.property(data[0], 'decimals')
|
|
318
|
+
assert.property(data[0], 'mintBatonVout')
|
|
319
|
+
assert.property(data[0], 'tokenQty')
|
|
320
|
+
assert.property(data[0], 'isValid')
|
|
321
|
+
assert.equal(data[0].isValid, true)
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
it('should return details for a simple SEND SLP token utxo', async () => {
|
|
325
|
+
const utxos = [
|
|
326
|
+
{
|
|
327
|
+
txid:
|
|
328
|
+
'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
|
|
329
|
+
vout: 1,
|
|
330
|
+
amount: 0.00000546,
|
|
331
|
+
satoshis: 546,
|
|
332
|
+
height: 596089,
|
|
333
|
+
confirmations: 748
|
|
334
|
+
}
|
|
335
|
+
]
|
|
336
|
+
|
|
337
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
338
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
339
|
+
|
|
340
|
+
assert.property(data[0], 'txid')
|
|
341
|
+
assert.property(data[0], 'vout')
|
|
342
|
+
assert.property(data[0], 'amount')
|
|
343
|
+
assert.property(data[0], 'satoshis')
|
|
344
|
+
assert.property(data[0], 'height')
|
|
345
|
+
assert.property(data[0], 'confirmations')
|
|
346
|
+
assert.property(data[0], 'utxoType')
|
|
347
|
+
assert.property(data[0], 'tokenId')
|
|
348
|
+
assert.property(data[0], 'tokenTicker')
|
|
349
|
+
assert.property(data[0], 'tokenName')
|
|
350
|
+
assert.property(data[0], 'tokenDocumentUrl')
|
|
351
|
+
assert.property(data[0], 'tokenDocumentHash')
|
|
352
|
+
assert.property(data[0], 'decimals')
|
|
353
|
+
assert.property(data[0], 'tokenQty')
|
|
354
|
+
assert.property(data[0], 'isValid')
|
|
355
|
+
assert.equal(data[0].isValid, true)
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
it('should handle BCH and SLP utxos in the same TX', async () => {
|
|
359
|
+
const utxos = [
|
|
360
|
+
{
|
|
361
|
+
txid:
|
|
362
|
+
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
|
363
|
+
vout: 3,
|
|
364
|
+
value: '6816',
|
|
365
|
+
height: 606848,
|
|
366
|
+
confirmations: 13,
|
|
367
|
+
satoshis: 6816
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
txid:
|
|
371
|
+
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
|
372
|
+
vout: 2,
|
|
373
|
+
value: '546',
|
|
374
|
+
height: 606848,
|
|
375
|
+
confirmations: 13,
|
|
376
|
+
satoshis: 546
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
|
|
380
|
+
const result = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
381
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
719
382
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
383
|
+
assert.isArray(result)
|
|
384
|
+
assert.equal(result.length, 2)
|
|
385
|
+
assert.equal(result[0].isValid, false)
|
|
386
|
+
assert.equal(result[1].isValid, true)
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
it('should handle problematic utxos', async () => {
|
|
390
|
+
const utxos = [
|
|
391
|
+
{
|
|
392
|
+
txid:
|
|
393
|
+
'0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959',
|
|
394
|
+
vout: 0,
|
|
395
|
+
amount: 0.00018362,
|
|
396
|
+
satoshis: 18362,
|
|
397
|
+
height: 613483,
|
|
398
|
+
confirmations: 124
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
txid:
|
|
402
|
+
'67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19',
|
|
403
|
+
vout: 1,
|
|
404
|
+
amount: 0.00000546,
|
|
405
|
+
satoshis: 546,
|
|
406
|
+
height: 612075,
|
|
407
|
+
confirmations: 1532
|
|
408
|
+
}
|
|
409
|
+
]
|
|
410
|
+
|
|
411
|
+
const result = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
412
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
726
413
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
assert.equal(result
|
|
730
|
-
assert.equal(result
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
414
|
+
assert.isArray(result)
|
|
415
|
+
assert.equal(result.length, 2)
|
|
416
|
+
assert.equal(result[0].isValid, false)
|
|
417
|
+
assert.equal(result[1].isValid, true)
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
it('should return false for BCH-only UTXOs', async () => {
|
|
421
|
+
const utxos = [
|
|
422
|
+
{
|
|
423
|
+
txid:
|
|
424
|
+
'a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b',
|
|
425
|
+
vout: 0,
|
|
426
|
+
amount: 0.00001,
|
|
427
|
+
satoshis: 1000,
|
|
428
|
+
confirmations: 0,
|
|
429
|
+
ts: 1578424704
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
txid:
|
|
433
|
+
'53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44',
|
|
434
|
+
vout: 0,
|
|
435
|
+
amount: 0.00001,
|
|
436
|
+
satoshis: 1000,
|
|
437
|
+
confirmations: 0,
|
|
438
|
+
ts: 1578424634
|
|
439
|
+
}
|
|
440
|
+
]
|
|
441
|
+
|
|
442
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
443
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
444
|
+
|
|
445
|
+
assert.isArray(data)
|
|
446
|
+
assert.equal(data[0].isValid, false)
|
|
447
|
+
assert.equal(data[1].isValid, false)
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
it('should handle a dust attack', async () => {
|
|
451
|
+
// it("#dustattack", async () => {
|
|
452
|
+
const utxos = [
|
|
453
|
+
{
|
|
454
|
+
height: 655965,
|
|
455
|
+
tx_hash:
|
|
456
|
+
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
|
|
457
|
+
tx_pos: 151,
|
|
458
|
+
value: 547,
|
|
459
|
+
satoshis: 547,
|
|
460
|
+
txid:
|
|
461
|
+
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
|
|
462
|
+
vout: 151,
|
|
463
|
+
address: 'bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww',
|
|
464
|
+
hdIndex: 11
|
|
465
|
+
}
|
|
466
|
+
]
|
|
467
|
+
|
|
468
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
469
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
470
|
+
|
|
471
|
+
assert.equal(data[0].isValid, false)
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
it('should handle null SLPDB validations', async () => {
|
|
475
|
+
const utxos = [
|
|
476
|
+
{
|
|
477
|
+
height: 665577,
|
|
478
|
+
tx_hash:
|
|
479
|
+
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
|
480
|
+
tx_pos: 1,
|
|
481
|
+
value: 546
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
height: 665577,
|
|
485
|
+
tx_hash:
|
|
486
|
+
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
487
|
+
tx_pos: 1,
|
|
488
|
+
value: 546
|
|
489
|
+
}
|
|
490
|
+
]
|
|
491
|
+
|
|
492
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
493
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
494
|
+
|
|
495
|
+
assert.isArray(data)
|
|
496
|
+
// assert.equal(data[0].isValid, null)
|
|
497
|
+
})
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
describe('#tokenUtxoDetailsWL', () => {
|
|
501
|
+
it('should return details for a simple SEND SLP token utxo', async () => {
|
|
502
|
+
const utxos = [
|
|
503
|
+
{
|
|
504
|
+
height: 660554,
|
|
505
|
+
tx_hash:
|
|
506
|
+
'89b3f0c84efe8b01b24e2d7ac08636de5781f31dbb84478e3de868ca0a7ed93a',
|
|
507
|
+
tx_pos: 1,
|
|
508
|
+
value: 546
|
|
509
|
+
}
|
|
510
|
+
]
|
|
511
|
+
|
|
512
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetailsWL(utxos)
|
|
513
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
514
|
+
|
|
515
|
+
assert.property(data[0], 'txid')
|
|
516
|
+
assert.property(data[0], 'vout')
|
|
517
|
+
assert.property(data[0], 'height')
|
|
518
|
+
assert.property(data[0], 'utxoType')
|
|
519
|
+
assert.property(data[0], 'tokenId')
|
|
520
|
+
assert.property(data[0], 'tokenTicker')
|
|
521
|
+
assert.property(data[0], 'tokenName')
|
|
522
|
+
assert.property(data[0], 'tokenDocumentUrl')
|
|
523
|
+
assert.property(data[0], 'tokenDocumentHash')
|
|
524
|
+
assert.property(data[0], 'decimals')
|
|
525
|
+
assert.property(data[0], 'tokenQty')
|
|
526
|
+
assert.property(data[0], 'isValid')
|
|
527
|
+
assert.equal(data[0].isValid, true)
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
it('should return false for BCH-only UTXOs', async () => {
|
|
531
|
+
const utxos = [
|
|
532
|
+
{
|
|
533
|
+
txid:
|
|
534
|
+
'a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b',
|
|
535
|
+
vout: 0,
|
|
536
|
+
amount: 0.00001,
|
|
537
|
+
satoshis: 1000,
|
|
538
|
+
confirmations: 0,
|
|
539
|
+
ts: 1578424704
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
txid:
|
|
543
|
+
'53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44',
|
|
544
|
+
vout: 0,
|
|
545
|
+
amount: 0.00001,
|
|
546
|
+
satoshis: 1000,
|
|
547
|
+
confirmations: 0,
|
|
548
|
+
ts: 1578424634
|
|
549
|
+
}
|
|
550
|
+
]
|
|
551
|
+
|
|
552
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetailsWL(utxos)
|
|
553
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
554
|
+
|
|
555
|
+
assert.isArray(data)
|
|
556
|
+
assert.equal(data[0].isValid, false)
|
|
557
|
+
assert.equal(data[1].isValid, false)
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
it('should handle a dust attack', async () => {
|
|
561
|
+
// it("#dustattack", async () => {
|
|
562
|
+
const utxos = [
|
|
563
|
+
{
|
|
564
|
+
height: 655965,
|
|
565
|
+
tx_hash:
|
|
566
|
+
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
|
|
567
|
+
tx_pos: 151,
|
|
568
|
+
value: 547,
|
|
569
|
+
satoshis: 547,
|
|
570
|
+
txid:
|
|
571
|
+
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
|
|
572
|
+
vout: 151,
|
|
573
|
+
address: 'bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww',
|
|
574
|
+
hdIndex: 11
|
|
575
|
+
}
|
|
576
|
+
]
|
|
577
|
+
|
|
578
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetailsWL(utxos)
|
|
579
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
580
|
+
|
|
581
|
+
assert.equal(data[0].isValid, false)
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
it('should handle null SLPDB validations', async () => {
|
|
585
|
+
const utxos = [
|
|
586
|
+
{
|
|
587
|
+
height: 665577,
|
|
588
|
+
tx_hash:
|
|
589
|
+
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
|
590
|
+
tx_pos: 1,
|
|
591
|
+
value: 546
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
height: 665577,
|
|
595
|
+
tx_hash:
|
|
596
|
+
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
597
|
+
tx_pos: 1,
|
|
598
|
+
value: 546
|
|
599
|
+
}
|
|
600
|
+
]
|
|
601
|
+
|
|
602
|
+
const data = await bchjs.SLP.Utils.tokenUtxoDetailsWL(utxos)
|
|
603
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
604
|
+
|
|
605
|
+
assert.isArray(data)
|
|
606
|
+
// assert.equal(data[0].isValid, null)
|
|
607
|
+
})
|
|
608
|
+
})
|
|
609
|
+
|
|
610
|
+
describe('#balancesForAddress', () => {
|
|
611
|
+
it('should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9', async () => {
|
|
612
|
+
const balances = await bchjs.SLP.Utils.balancesForAddress(
|
|
613
|
+
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
|
738
614
|
)
|
|
739
|
-
console.log(
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}
|
|
759
|
-
|
|
615
|
+
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
|
|
616
|
+
|
|
617
|
+
assert.isArray(balances)
|
|
618
|
+
assert.hasAllKeys(balances[0], [
|
|
619
|
+
'tokenId',
|
|
620
|
+
'balanceString',
|
|
621
|
+
'balance',
|
|
622
|
+
'decimalCount',
|
|
623
|
+
'slpAddress'
|
|
624
|
+
])
|
|
625
|
+
})
|
|
626
|
+
|
|
627
|
+
it('should fetch balances for multiple addresses', async () => {
|
|
628
|
+
const addresses = [
|
|
629
|
+
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9',
|
|
630
|
+
'simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57'
|
|
631
|
+
]
|
|
632
|
+
|
|
633
|
+
const balances = await bchjs.SLP.Utils.balancesForAddress(addresses)
|
|
634
|
+
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
|
|
635
|
+
|
|
636
|
+
assert.isArray(balances)
|
|
637
|
+
assert.isArray(balances[0])
|
|
638
|
+
assert.hasAllKeys(balances[0][0], [
|
|
639
|
+
'tokenId',
|
|
640
|
+
'balanceString',
|
|
641
|
+
'balance',
|
|
642
|
+
'decimalCount',
|
|
643
|
+
'slpAddress'
|
|
644
|
+
])
|
|
645
|
+
})
|
|
646
|
+
})
|
|
647
|
+
|
|
648
|
+
describe('#hydrateUtxos-', () => {
|
|
649
|
+
it('should hydrate UTXOs', async () => {
|
|
650
|
+
const utxos = [
|
|
651
|
+
{
|
|
652
|
+
utxos: [
|
|
653
|
+
{
|
|
654
|
+
txid:
|
|
655
|
+
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
|
656
|
+
vout: 3,
|
|
657
|
+
value: '6816',
|
|
658
|
+
height: 606848,
|
|
659
|
+
confirmations: 13,
|
|
660
|
+
satoshis: 6816
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
txid:
|
|
664
|
+
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
|
665
|
+
vout: 2,
|
|
666
|
+
value: '546',
|
|
667
|
+
height: 606848,
|
|
668
|
+
confirmations: 13,
|
|
669
|
+
satoshis: 546
|
|
670
|
+
}
|
|
671
|
+
]
|
|
672
|
+
}
|
|
673
|
+
]
|
|
674
|
+
|
|
675
|
+
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos)
|
|
676
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
760
677
|
|
|
761
|
-
|
|
762
|
-
|
|
678
|
+
// Test the general structure of the output.
|
|
679
|
+
assert.isArray(result.slpUtxos)
|
|
680
|
+
assert.equal(result.slpUtxos.length, 1)
|
|
681
|
+
assert.equal(result.slpUtxos[0].utxos.length, 2)
|
|
682
|
+
|
|
683
|
+
// Test the non-slp UTXO.
|
|
684
|
+
assert.property(result.slpUtxos[0].utxos[0], 'txid')
|
|
685
|
+
assert.property(result.slpUtxos[0].utxos[0], 'vout')
|
|
686
|
+
assert.property(result.slpUtxos[0].utxos[0], 'value')
|
|
687
|
+
assert.property(result.slpUtxos[0].utxos[0], 'height')
|
|
688
|
+
assert.property(result.slpUtxos[0].utxos[0], 'confirmations')
|
|
689
|
+
assert.property(result.slpUtxos[0].utxos[0], 'satoshis')
|
|
690
|
+
assert.property(result.slpUtxos[0].utxos[0], 'isValid')
|
|
691
|
+
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
|
763
692
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
693
|
+
// Test the slp UTXO.
|
|
694
|
+
assert.property(result.slpUtxos[0].utxos[1], 'txid')
|
|
695
|
+
assert.property(result.slpUtxos[0].utxos[1], 'vout')
|
|
696
|
+
assert.property(result.slpUtxos[0].utxos[1], 'value')
|
|
697
|
+
assert.property(result.slpUtxos[0].utxos[1], 'height')
|
|
698
|
+
assert.property(result.slpUtxos[0].utxos[1], 'confirmations')
|
|
699
|
+
assert.property(result.slpUtxos[0].utxos[1], 'satoshis')
|
|
700
|
+
assert.property(result.slpUtxos[0].utxos[1], 'isValid')
|
|
701
|
+
assert.equal(result.slpUtxos[0].utxos[1].isValid, true)
|
|
702
|
+
assert.property(result.slpUtxos[0].utxos[1], 'transactionType')
|
|
703
|
+
assert.property(result.slpUtxos[0].utxos[1], 'tokenId')
|
|
704
|
+
assert.property(result.slpUtxos[0].utxos[1], 'tokenTicker')
|
|
705
|
+
assert.property(result.slpUtxos[0].utxos[1], 'tokenName')
|
|
706
|
+
assert.property(result.slpUtxos[0].utxos[1], 'tokenDocumentUrl')
|
|
707
|
+
assert.property(result.slpUtxos[0].utxos[1], 'tokenDocumentHash')
|
|
708
|
+
assert.property(result.slpUtxos[0].utxos[1], 'decimals')
|
|
709
|
+
assert.property(result.slpUtxos[0].utxos[1], 'tokenType')
|
|
710
|
+
assert.property(result.slpUtxos[0].utxos[1], 'tokenQty')
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
it('should process data directly from Electrumx', async () => {
|
|
714
|
+
const addrs = [
|
|
715
|
+
'bitcoincash:qqnt53cfw990u6y38xgezm0lfa8hknw0wueezcpagp',
|
|
716
|
+
'bitcoincash:qrh3qgtax6adegzc7zxm6m4sgrv9wq28yqnfn33ce5',
|
|
717
|
+
'bitcoincash:qqcaee5w4ws77n8s2gzy6fwtma6uxd7ctq8553e495'
|
|
718
|
+
]
|
|
719
|
+
|
|
720
|
+
const utxos = await bchjs.Electrumx.utxo(addrs)
|
|
721
|
+
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
|
722
|
+
|
|
723
|
+
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
|
|
724
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
768
725
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
]
|
|
726
|
+
// Test the general structure of the output.
|
|
727
|
+
assert.isArray(result.slpUtxos)
|
|
728
|
+
assert.equal(result.slpUtxos.length, 3)
|
|
729
|
+
assert.equal(result.slpUtxos[0].utxos.length, 1)
|
|
730
|
+
assert.equal(result.slpUtxos[1].utxos.length, 1)
|
|
731
|
+
assert.equal(result.slpUtxos[2].utxos.length, 2)
|
|
732
|
+
|
|
733
|
+
try {
|
|
734
|
+
// Test the expected values.
|
|
735
|
+
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
|
736
|
+
assert.equal(result.slpUtxos[1].utxos[0].isValid, true)
|
|
737
|
+
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, 'TROUT')
|
|
738
|
+
assert.equal(result.slpUtxos[2].utxos[0].isValid, false)
|
|
739
|
+
assert.equal(result.slpUtxos[2].utxos[1].isValid, true)
|
|
740
|
+
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, 'VALENTINE')
|
|
741
|
+
} catch (err) {
|
|
742
|
+
console.error(
|
|
743
|
+
'The hydrateUtxos call may hitting rate limits, or SLPDB may be having issues if "isValid" results are "null"'
|
|
744
|
+
)
|
|
745
|
+
console.log('Error: ', err)
|
|
781
746
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
747
|
+
})
|
|
748
|
+
|
|
749
|
+
it('should handle null SLPDB validations', async () => {
|
|
750
|
+
const utxos = [
|
|
751
|
+
{
|
|
752
|
+
height: 665577,
|
|
753
|
+
tx_hash:
|
|
754
|
+
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
|
755
|
+
tx_pos: 1,
|
|
756
|
+
value: 546
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
height: 665577,
|
|
760
|
+
tx_hash:
|
|
761
|
+
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
|
762
|
+
tx_pos: 1,
|
|
763
|
+
value: 546
|
|
764
|
+
}
|
|
765
|
+
]
|
|
766
|
+
|
|
767
|
+
const data = await bchjs.SLP.Utils.hydrateUtxos([{ utxos: utxos }])
|
|
768
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
769
|
+
|
|
770
|
+
assert.isArray(data.slpUtxos)
|
|
771
|
+
assert.equal(data.slpUtxos[0].isValid, null)
|
|
772
|
+
})
|
|
773
|
+
})
|
|
774
|
+
|
|
775
|
+
describe('#hydrateUtxosWL', () => {
|
|
776
|
+
it('should hydrate UTXOs', async () => {
|
|
777
|
+
const utxos = [
|
|
778
|
+
{
|
|
779
|
+
utxos: [
|
|
780
|
+
{
|
|
781
|
+
txid:
|
|
782
|
+
'89b3f0c84efe8b01b24e2d7ac08636de5781f31dbb84478e3de868ca0a7ed93a',
|
|
783
|
+
vout: 1,
|
|
784
|
+
value: 546
|
|
785
|
+
}
|
|
786
|
+
]
|
|
787
|
+
}
|
|
788
|
+
]
|
|
789
|
+
|
|
790
|
+
const result = await bchjs.SLP.Utils.hydrateUtxosWL(utxos)
|
|
791
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
819
792
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
assert.equal(result.slpUtxos
|
|
823
|
-
assert.equal(result.slpUtxos[
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
assert.
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
793
|
+
// Test the general structure of the output.
|
|
794
|
+
assert.isArray(result.slpUtxos)
|
|
795
|
+
assert.equal(result.slpUtxos.length, 1)
|
|
796
|
+
assert.equal(result.slpUtxos[0].utxos.length, 1)
|
|
797
|
+
|
|
798
|
+
// Test the non-slp UTXO.
|
|
799
|
+
assert.property(result.slpUtxos[0].utxos[0], 'txid')
|
|
800
|
+
assert.property(result.slpUtxos[0].utxos[0], 'vout')
|
|
801
|
+
assert.property(result.slpUtxos[0].utxos[0], 'value')
|
|
802
|
+
assert.property(result.slpUtxos[0].utxos[0], 'isValid')
|
|
803
|
+
assert.equal(result.slpUtxos[0].utxos[0].isValid, true)
|
|
804
|
+
})
|
|
805
|
+
|
|
806
|
+
it('should process data directly from Electrumx', async () => {
|
|
807
|
+
const addrs = [
|
|
808
|
+
'bitcoincash:qqnt53cfw990u6y38xgezm0lfa8hknw0wueezcpagp',
|
|
809
|
+
'bitcoincash:qrh3qgtax6adegzc7zxm6m4sgrv9wq28yqnfn33ce5',
|
|
810
|
+
'bitcoincash:qqcaee5w4ws77n8s2gzy6fwtma6uxd7ctq8553e495'
|
|
811
|
+
]
|
|
812
|
+
|
|
813
|
+
const utxos = await bchjs.Electrumx.utxo(addrs)
|
|
814
|
+
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
|
815
|
+
|
|
816
|
+
const result = await bchjs.SLP.Utils.hydrateUtxosWL(utxos.utxos)
|
|
817
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
835
818
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
819
|
+
// Test the general structure of the output.
|
|
820
|
+
assert.isArray(result.slpUtxos)
|
|
821
|
+
assert.equal(result.slpUtxos.length, 3)
|
|
822
|
+
assert.equal(result.slpUtxos[0].utxos.length, 1)
|
|
823
|
+
assert.equal(result.slpUtxos[1].utxos.length, 1)
|
|
824
|
+
assert.equal(result.slpUtxos[2].utxos.length, 2)
|
|
825
|
+
|
|
826
|
+
try {
|
|
827
|
+
// Test the expected values.
|
|
828
|
+
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
|
829
|
+
assert.equal(result.slpUtxos[1].utxos[0].isValid, true)
|
|
830
|
+
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, 'TROUT')
|
|
831
|
+
assert.equal(result.slpUtxos[2].utxos[0].isValid, false)
|
|
832
|
+
// assert.equal(result.slpUtxos[2].utxos[1].isValid, null)
|
|
833
|
+
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, 'VALENTINE')
|
|
834
|
+
} catch (err) {
|
|
835
|
+
console.error(
|
|
836
|
+
'The hydrateUtxos call may hitting rate limits, or SLPDB may be having issues if "isValid" results are "null"'
|
|
837
|
+
)
|
|
838
|
+
console.log('Error: ', err)
|
|
851
839
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
840
|
+
})
|
|
841
|
+
|
|
842
|
+
it('should handle null SLPDB validations', async () => {
|
|
843
|
+
const utxos = [
|
|
844
|
+
{
|
|
845
|
+
height: 665577,
|
|
846
|
+
tx_hash:
|
|
847
|
+
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
|
848
|
+
tx_pos: 1,
|
|
849
|
+
value: 546
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
height: 665577,
|
|
853
|
+
tx_hash:
|
|
854
|
+
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
|
855
|
+
tx_pos: 1,
|
|
856
|
+
value: 546
|
|
857
|
+
}
|
|
858
|
+
]
|
|
859
|
+
|
|
860
|
+
const data = await bchjs.SLP.Utils.hydrateUtxosWL([{ utxos: utxos }])
|
|
861
|
+
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
862
|
+
|
|
863
|
+
assert.isArray(data.slpUtxos)
|
|
864
|
+
assert.equal(data.slpUtxos[0].isValid, null)
|
|
865
|
+
})
|
|
866
|
+
})
|
|
867
|
+
|
|
868
|
+
describe('#validateTxid', () => {
|
|
869
|
+
// This test is not necessary.
|
|
870
|
+
it('should handle a null response from SLPDB', async () => {
|
|
871
|
+
const txid =
|
|
872
|
+
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419'
|
|
867
873
|
|
|
868
|
-
|
|
869
|
-
|
|
874
|
+
const result = await bchjs.SLP.Utils.validateTxid(txid)
|
|
875
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
870
876
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
877
|
+
assert.isArray(result)
|
|
878
|
+
assert.equal(result[0].txid, txid)
|
|
879
|
+
// assert.equal(result[0].valid, null)
|
|
880
|
+
})
|
|
875
881
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
882
|
+
it('should handle a null response from SLPDB', async () => {
|
|
883
|
+
const txid = [
|
|
884
|
+
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
|
885
|
+
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
|
|
886
|
+
]
|
|
881
887
|
|
|
882
|
-
|
|
883
|
-
|
|
888
|
+
const result = await bchjs.SLP.Utils.validateTxid(txid)
|
|
889
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
884
890
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
891
|
+
assert.isArray(result)
|
|
892
|
+
assert.equal(result[0].txid, txid[0])
|
|
893
|
+
// assert.equal(result[0].valid, null)
|
|
894
|
+
})
|
|
888
895
|
})
|
|
889
|
-
})
|
|
890
896
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
897
|
+
describe('#validateTxid2', () => {
|
|
898
|
+
it('should invalidate a known invalid TXID', async () => {
|
|
899
|
+
const txid =
|
|
900
|
+
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
|
895
901
|
|
|
896
|
-
|
|
897
|
-
|
|
902
|
+
const result = await bchjs.SLP.Utils.validateTxid2(txid)
|
|
903
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
898
904
|
|
|
899
|
-
|
|
900
|
-
|
|
905
|
+
assert.property(result, 'txid')
|
|
906
|
+
assert.equal(result.txid, txid)
|
|
901
907
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
908
|
+
assert.property(result, 'isValid')
|
|
909
|
+
assert.equal(result.isValid, false)
|
|
910
|
+
})
|
|
905
911
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
912
|
+
it('should validate a known valid TXID', async () => {
|
|
913
|
+
const txid =
|
|
914
|
+
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
|
|
909
915
|
|
|
910
|
-
|
|
911
|
-
|
|
916
|
+
const result = await bchjs.SLP.Utils.validateTxid2(txid)
|
|
917
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
912
918
|
|
|
913
|
-
|
|
914
|
-
|
|
919
|
+
assert.property(result, 'txid')
|
|
920
|
+
assert.equal(result.txid, txid)
|
|
915
921
|
|
|
916
|
-
|
|
917
|
-
|
|
922
|
+
assert.property(result, 'isValid')
|
|
923
|
+
assert.equal(result.isValid, true)
|
|
924
|
+
})
|
|
918
925
|
})
|
|
919
|
-
})
|
|
920
926
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
927
|
+
describe('#getWhitelist', () => {
|
|
928
|
+
it('should get the whitelist', async () => {
|
|
929
|
+
const result = await bchjs.SLP.Utils.getWhitelist()
|
|
930
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
925
931
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
932
|
+
assert.isArray(result)
|
|
933
|
+
assert.property(result[0], 'name')
|
|
934
|
+
assert.property(result[1], 'tokenId')
|
|
935
|
+
})
|
|
929
936
|
})
|
|
930
|
-
})
|
|
931
937
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
938
|
+
describe('#getStatus', () => {
|
|
939
|
+
it('should return the current block height of the SLPDB indexer', async () => {
|
|
940
|
+
const result = await bchjs.SLP.Utils.getStatus()
|
|
935
941
|
|
|
936
|
-
|
|
942
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
937
943
|
|
|
938
|
-
|
|
939
|
-
|
|
944
|
+
assert.property(result, 'bchBlockHeight')
|
|
945
|
+
assert.property(result, 'slpProcessedBlockHeight')
|
|
946
|
+
})
|
|
940
947
|
})
|
|
941
|
-
})
|
|
942
948
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
949
|
+
describe('#waterfallValidateTxid', () => {
|
|
950
|
+
it('should validate known good txid not in whitelist', async () => {
|
|
951
|
+
const txid =
|
|
952
|
+
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
|
|
947
953
|
|
|
948
|
-
|
|
949
|
-
|
|
954
|
+
const result = await bchjs.SLP.Utils.waterfallValidateTxid(txid)
|
|
955
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
950
956
|
|
|
951
|
-
|
|
952
|
-
|
|
957
|
+
assert.equal(result, true)
|
|
958
|
+
})
|
|
953
959
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
960
|
+
it('should invalidate a known invalid TXID', async () => {
|
|
961
|
+
const txid =
|
|
962
|
+
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
|
957
963
|
|
|
958
|
-
|
|
959
|
-
|
|
964
|
+
const result = await bchjs.SLP.Utils.waterfallValidateTxid(txid)
|
|
965
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
960
966
|
|
|
961
|
-
|
|
967
|
+
assert.equal(result, false)
|
|
968
|
+
})
|
|
962
969
|
})
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
}
|
|
976
|
-
]
|
|
977
|
-
const sendQty = 1.5
|
|
970
|
+
describe('#tokentype1', () => {
|
|
971
|
+
describe('#getHexOpReturn', () => {
|
|
972
|
+
it('should return OP_RETURN object ', async () => {
|
|
973
|
+
const tokenUtxos = [
|
|
974
|
+
{
|
|
975
|
+
tokenId:
|
|
976
|
+
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
|
|
977
|
+
decimals: 8,
|
|
978
|
+
tokenQty: 2
|
|
979
|
+
}
|
|
980
|
+
]
|
|
981
|
+
const sendQty = 1.5
|
|
978
982
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
983
|
+
const result = await bchjs.SLP.TokenType1.getHexOpReturn(
|
|
984
|
+
tokenUtxos,
|
|
985
|
+
sendQty
|
|
986
|
+
)
|
|
987
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
984
988
|
|
|
985
|
-
|
|
986
|
-
|
|
989
|
+
assert.property(result, 'script')
|
|
990
|
+
assert.isString(result.script)
|
|
987
991
|
|
|
988
|
-
|
|
989
|
-
|
|
992
|
+
assert.property(result, 'outputs')
|
|
993
|
+
assert.isNumber(result.outputs)
|
|
994
|
+
})
|
|
995
|
+
})
|
|
990
996
|
})
|
|
991
|
-
}
|
|
997
|
+
}
|
|
992
998
|
})
|
|
993
999
|
})
|
|
994
1000
|
|