@bsv/sdk 2.0.0 → 2.0.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -355,11 +355,74 @@ export default class Script {
355
355
  */
356
356
  findAndDelete (script: Script): Script {
357
357
  this.invalidateSerializationCaches()
358
- const buf = script.toHex()
358
+ const targetBytes = script.toUint8Array()
359
+ const targetLen = targetBytes.length
360
+ if (targetLen === 0) return this
361
+
362
+ const targetOp = targetBytes[0] ?? 0
363
+
364
+ const matchesChunk = (chunk: ScriptChunk): boolean => {
365
+ if (chunk.op !== targetOp) return false
366
+ const dataArr = chunk.data ?? []
367
+ const dataLen = dataArr.length
368
+
369
+ if (dataLen === 0) {
370
+ return targetLen === 1
371
+ }
372
+
373
+ if (chunk.op === OP.OP_RETURN) {
374
+ if (targetLen !== 1 + dataLen) return false
375
+ for (let j = 0; j < dataLen; j++) {
376
+ if (targetBytes[1 + j] !== dataArr[j]) return false
377
+ }
378
+ return true
379
+ }
380
+
381
+ if (chunk.op < OP.OP_PUSHDATA1) {
382
+ if (targetLen !== 1 + dataLen) return false
383
+ for (let j = 0; j < dataLen; j++) {
384
+ if (targetBytes[1 + j] !== dataArr[j]) return false
385
+ }
386
+ return true
387
+ }
388
+
389
+ if (chunk.op === OP.OP_PUSHDATA1) {
390
+ if (targetLen !== 2 + dataLen) return false
391
+ if (targetBytes[1] !== (dataLen & 0xff)) return false
392
+ for (let j = 0; j < dataLen; j++) {
393
+ if (targetBytes[2 + j] !== dataArr[j]) return false
394
+ }
395
+ return true
396
+ }
397
+
398
+ if (chunk.op === OP.OP_PUSHDATA2) {
399
+ if (targetLen !== 3 + dataLen) return false
400
+ if (targetBytes[1] !== (dataLen & 0xff)) return false
401
+ if (targetBytes[2] !== ((dataLen >> 8) & 0xff)) return false
402
+ for (let j = 0; j < dataLen; j++) {
403
+ if (targetBytes[3 + j] !== dataArr[j]) return false
404
+ }
405
+ return true
406
+ }
407
+
408
+ if (chunk.op === OP.OP_PUSHDATA4) {
409
+ if (targetLen !== 5 + dataLen) return false
410
+ const size = dataLen >>> 0
411
+ if (targetBytes[1] !== (size & 0xff)) return false
412
+ if (targetBytes[2] !== ((size >> 8) & 0xff)) return false
413
+ if (targetBytes[3] !== ((size >> 16) & 0xff)) return false
414
+ if (targetBytes[4] !== ((size >> 24) & 0xff)) return false
415
+ for (let j = 0; j < dataLen; j++) {
416
+ if (targetBytes[5 + j] !== dataArr[j]) return false
417
+ }
418
+ return true
419
+ }
420
+
421
+ return false
422
+ }
423
+
359
424
  for (let i = 0; i < this.chunks.length;) {
360
- const script2 = new Script([this.chunks[i]])
361
- const buf2 = script2.toHex()
362
- if (buf === buf2) {
425
+ if (matchesChunk(this.chunks[i])) {
363
426
  this.chunks.splice(i, 1)
364
427
  } else {
365
428
  i++
@@ -354,12 +354,45 @@ describe('Script', () => {
354
354
  })
355
355
 
356
356
  describe('#findAndDelete', () => {
357
- it('should find and delete this buffer', () => {
358
- expect(
359
- Script.fromASM('OP_RETURN f0f0')
360
- .findAndDelete(Script.fromASM('f0f0'))
361
- .toASM()
362
- ).toEqual('OP_RETURN')
357
+ it('should delete all matching single-chunk scripts', () => {
358
+ const target = new Script().writeBin([0xf0, 0xf0])
359
+ const script = new Script()
360
+ .writeOpCode(OP.OP_RETURN)
361
+ .writeBin([0xf0, 0xf0])
362
+ .writeOpCode(OP.OP_1)
363
+ .writeBin([0xf0, 0xf0])
364
+
365
+ expect(script.findAndDelete(target).toASM()).toEqual('OP_RETURN OP_1')
366
+ })
367
+
368
+ it('should match OP_RETURN chunks with data', () => {
369
+ const target = new Script([{ op: OP.OP_RETURN, data: [0x01, 0x02, 0x03] }])
370
+ const script = new Script([
371
+ { op: OP.OP_RETURN, data: [0x01, 0x02, 0x03] },
372
+ { op: OP.OP_1 }
373
+ ])
374
+
375
+ expect(script.findAndDelete(target).toASM()).toEqual('OP_1')
376
+ })
377
+
378
+ it('should handle PUSHDATA2 payloads', () => {
379
+ const data = Array.from({ length: 300 }, (_, i) => i & 0xff)
380
+ const other = data.slice()
381
+ other[0] = (other[0] + 1) & 0xff
382
+
383
+ const target = new Script().writeBin(data)
384
+ const script = new Script().writeBin(other).writeBin(data).writeOpCode(OP.OP_1)
385
+
386
+ script.findAndDelete(target)
387
+ expect(script.chunks).toHaveLength(2)
388
+ expect(script.chunks[0].data).toEqual(other)
389
+ expect(script.chunks[1].op).toEqual(OP.OP_1)
390
+ })
391
+
392
+ it('should not delete when the target has multiple chunks', () => {
393
+ const script = Script.fromASM('OP_1')
394
+ const target = Script.fromASM('OP_1 OP_2')
395
+ expect(script.findAndDelete(target).toASM()).toEqual('OP_1')
363
396
  })
364
397
  })
365
398
 
@@ -119,13 +119,13 @@ export default class WalletClient implements WalletInterface {
119
119
  }
120
120
  }
121
121
 
122
- // Try fast substrates first
122
+ // Try all substrates concurrently, select first available by priority order
123
123
  const fastAttempts = [
124
124
  attemptSubstrate(() => new WindowCWISubstrate()),
125
+ attemptSubstrate(() => new WalletWireTransceiver(new HTTPWalletWire(this.originator))),
125
126
  attemptSubstrate(() => new HTTPWalletJSON(this.originator, 'https://localhost:2121')),
126
127
  attemptSubstrate(() => new HTTPWalletJSON(this.originator)),
127
- attemptSubstrate(() => new ReactNativeWebView(this.originator)),
128
- attemptSubstrate(() => new WalletWireTransceiver(new HTTPWalletWire(this.originator)))
128
+ attemptSubstrate(() => new ReactNativeWebView(this.originator))
129
129
  ]
130
130
 
131
131
  const fastResults = await Promise.allSettled(fastAttempts)
@@ -1686,7 +1686,7 @@ export default class WalletWireTransceiver implements WalletInterface {
1686
1686
  const fieldKey = Utils.toUTF8(resultReader.read(fieldKeyLength))
1687
1687
  const fieldValueLength = resultReader.readVarIntNum()
1688
1688
  keyringForVerifier[fieldKey] = Utils.toBase64(
1689
- resultReader.read(fieldValueLength)
1689
+ resultReader.read(fieldValueLength)
1690
1690
  )
1691
1691
  }
1692
1692
  }