@bsv/sdk 1.8.10 → 1.8.11

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.
Files changed (41) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/primitives/utils.js +19 -1
  3. package/dist/cjs/src/primitives/utils.js.map +1 -1
  4. package/dist/cjs/src/script/templates/P2PKH.js +2 -7
  5. package/dist/cjs/src/script/templates/P2PKH.js.map +1 -1
  6. package/dist/cjs/src/script/templates/PushDrop.js +3 -8
  7. package/dist/cjs/src/script/templates/PushDrop.js.map +1 -1
  8. package/dist/cjs/src/transaction/Beef.js +2 -7
  9. package/dist/cjs/src/transaction/Beef.js.map +1 -1
  10. package/dist/cjs/src/transaction/Transaction.js +3 -3
  11. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  12. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  13. package/dist/esm/src/primitives/utils.js +17 -0
  14. package/dist/esm/src/primitives/utils.js.map +1 -1
  15. package/dist/esm/src/script/templates/P2PKH.js +3 -8
  16. package/dist/esm/src/script/templates/P2PKH.js.map +1 -1
  17. package/dist/esm/src/script/templates/PushDrop.js +3 -8
  18. package/dist/esm/src/script/templates/PushDrop.js.map +1 -1
  19. package/dist/esm/src/transaction/Beef.js +3 -8
  20. package/dist/esm/src/transaction/Beef.js.map +1 -1
  21. package/dist/esm/src/transaction/Transaction.js +3 -3
  22. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  23. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  24. package/dist/types/src/primitives/utils.d.ts +13 -0
  25. package/dist/types/src/primitives/utils.d.ts.map +1 -1
  26. package/dist/types/src/script/templates/P2PKH.d.ts.map +1 -1
  27. package/dist/types/src/script/templates/PushDrop.d.ts.map +1 -1
  28. package/dist/types/src/transaction/Beef.d.ts.map +1 -1
  29. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  30. package/dist/umd/bundle.js +3 -3
  31. package/dist/umd/bundle.js.map +1 -1
  32. package/docs/reference/wallet.md +38 -8
  33. package/package.json +1 -1
  34. package/src/primitives/__tests/utils.test.ts +27 -1
  35. package/src/primitives/utils.ts +17 -0
  36. package/src/script/__tests/Spend.test.ts +74 -1
  37. package/src/script/__tests/SpendComplex.test.ts +5 -9
  38. package/src/script/templates/P2PKH.ts +3 -8
  39. package/src/script/templates/PushDrop.ts +3 -7
  40. package/src/transaction/Beef.ts +3 -8
  41. package/src/transaction/Transaction.ts +3 -3
@@ -3426,7 +3426,7 @@ static unknownToJson(error: any): string
3426
3426
 
3427
3427
  Returns
3428
3428
 
3429
- stringified JSON representation of the error such that it can be desirialized to a WalletError.
3429
+ stringified JSON representation of the error such that it can be deserialized to a WalletError.
3430
3430
 
3431
3431
  Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
3432
3432
 
@@ -4562,17 +4562,17 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
4562
4562
 
4563
4563
  | | | |
4564
4564
  | --- | --- | --- |
4565
- | [isHexString](#function-ishexstring) | [validateDiscoverByAttributesArgs](#function-validatediscoverbyattributesargs) | [validateOutpointString](#function-validateoutpointstring) |
4566
- | [parseWalletOutpoint](#function-parsewalletoutpoint) | [validateDiscoverByIdentityKeyArgs](#function-validatediscoverbyidentitykeyargs) | [validatePositiveIntegerOrZero](#function-validatepositiveintegerorzero) |
4567
- | [toOriginHeader](#function-tooriginheader) | [validateInteger](#function-validateinteger) | [validateProveCertificateArgs](#function-validateprovecertificateargs) |
4568
- | [validateAbortActionArgs](#function-validateabortactionargs) | [validateInternalizeActionArgs](#function-validateinternalizeactionargs) | [validateRelinquishCertificateArgs](#function-validaterelinquishcertificateargs) |
4569
- | [validateAcquireDirectCertificateArgs](#function-validateacquiredirectcertificateargs) | [validateInternalizeOutput](#function-validateinternalizeoutput) | [validateRelinquishOutputArgs](#function-validaterelinquishoutputargs) |
4570
- | [validateAcquireIssuanceCertificateArgs](#function-validateacquireissuancecertificateargs) | [validateListActionsArgs](#function-validatelistactionsargs) | [validateSatoshis](#function-validatesatoshis) |
4565
+ | [isHexString](#function-ishexstring) | [validateCreateActionOutput](#function-validatecreateactionoutput) | [validateOriginator](#function-validateoriginator) |
4566
+ | [parseWalletOutpoint](#function-parsewalletoutpoint) | [validateDiscoverByAttributesArgs](#function-validatediscoverbyattributesargs) | [validateOutpointString](#function-validateoutpointstring) |
4567
+ | [toOriginHeader](#function-tooriginheader) | [validateDiscoverByIdentityKeyArgs](#function-validatediscoverbyidentitykeyargs) | [validatePositiveIntegerOrZero](#function-validatepositiveintegerorzero) |
4568
+ | [validateAbortActionArgs](#function-validateabortactionargs) | [validateInteger](#function-validateinteger) | [validateProveCertificateArgs](#function-validateprovecertificateargs) |
4569
+ | [validateAcquireDirectCertificateArgs](#function-validateacquiredirectcertificateargs) | [validateInternalizeActionArgs](#function-validateinternalizeactionargs) | [validateRelinquishCertificateArgs](#function-validaterelinquishcertificateargs) |
4570
+ | [validateAcquireIssuanceCertificateArgs](#function-validateacquireissuancecertificateargs) | [validateInternalizeOutput](#function-validateinternalizeoutput) | [validateRelinquishOutputArgs](#function-validaterelinquishoutputargs) |
4571
+ | [validateBase64String](#function-validatebase64string) | [validateListActionsArgs](#function-validatelistactionsargs) | [validateSatoshis](#function-validatesatoshis) |
4571
4572
  | [validateBasketInsertion](#function-validatebasketinsertion) | [validateListCertificatesArgs](#function-validatelistcertificatesargs) | [validateSignActionArgs](#function-validatesignactionargs) |
4572
4573
  | [validateCreateActionArgs](#function-validatecreateactionargs) | [validateListOutputsArgs](#function-validatelistoutputsargs) | [validateSignActionOptions](#function-validatesignactionoptions) |
4573
4574
  | [validateCreateActionInput](#function-validatecreateactioninput) | [validateOptionalInteger](#function-validateoptionalinteger) | [validateStringLength](#function-validatestringlength) |
4574
4575
  | [validateCreateActionOptions](#function-validatecreateactionoptions) | [validateOptionalOutpointString](#function-validateoptionaloutpointstring) | [validateWalletPayment](#function-validatewalletpayment) |
4575
- | [validateCreateActionOutput](#function-validatecreateactionoutput) | [validateOriginator](#function-validateoriginator) | |
4576
4576
 
4577
4577
  Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
4578
4578
 
@@ -4692,6 +4692,36 @@ when args contain fields invalid for issuance
4692
4692
 
4693
4693
  Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
4694
4694
 
4695
+ ---
4696
+ ### Function: validateBase64String
4697
+
4698
+ Validate a Base64 string (structure and decoded size).
4699
+
4700
+ ```ts
4701
+ export function validateBase64String(s: string, name: string, min?: number, max?: number): string
4702
+ ```
4703
+
4704
+ Returns
4705
+
4706
+ validated base64 string
4707
+
4708
+ Argument Details
4709
+
4710
+ + **s**
4711
+ + base64 string
4712
+ + **name**
4713
+ + parameter name used in error messages
4714
+ + **min**
4715
+ + optional minimum decoded byte length
4716
+ + **max**
4717
+ + optional maximum decoded byte length
4718
+
4719
+ Throws
4720
+
4721
+ WERR_INVALID_PARAMETER when invalid
4722
+
4723
+ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
4724
+
4695
4725
  ---
4696
4726
  ### Function: validateBasketInsertion
4697
4727
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "1.8.10",
3
+ "version": "1.8.11",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -7,7 +7,8 @@ import {
7
7
  fromBase58,
8
8
  toBase58,
9
9
  fromBase58Check,
10
- toBase58Check
10
+ toBase58Check,
11
+ verifyNotNull
11
12
  } from '../../primitives/utils'
12
13
 
13
14
  describe('utils', () => {
@@ -207,3 +208,28 @@ describe('utils', () => {
207
208
  expect(toArray(input)).toEqual(expected)
208
209
  })
209
210
  })
211
+
212
+ describe('verifyNotNull', () => {
213
+ it('should return the value if it is not null or undefined', () => {
214
+ expect(verifyNotNull(42)).toBe(42)
215
+ expect(verifyNotNull('hello')).toBe('hello')
216
+ expect(verifyNotNull({})).toEqual({})
217
+ expect(verifyNotNull([])).toEqual([])
218
+ })
219
+
220
+ it('should throw an error with default message if value is null', () => {
221
+ expect(() => verifyNotNull(null)).toThrow('Expected a valid value, but got undefined or null.')
222
+ })
223
+
224
+ it('should throw an error with default message if value is undefined', () => {
225
+ expect(() => verifyNotNull(undefined)).toThrow('Expected a valid value, but got undefined or null.')
226
+ })
227
+
228
+ it('should throw an error with custom message if value is null', () => {
229
+ expect(() => verifyNotNull(null, 'Custom error')).toThrow('Custom error')
230
+ })
231
+
232
+ it('should throw an error with custom message if value is undefined', () => {
233
+ expect(() => verifyNotNull(undefined, 'Another custom error')).toThrow('Another custom error')
234
+ })
235
+ })
@@ -819,3 +819,20 @@ export const minimallyEncode = (buf: number[]): number[] => {
819
819
 
820
820
  const OverflowInt64 = new BigNumber(2).pow(new BigNumber(63))
821
821
  const OverflowUint64 = new BigNumber(2).pow(new BigNumber(64))
822
+
823
+ /**
824
+ * Verifies that a value is not null or undefined, throwing an error if it is.
825
+ *
826
+ * @template T - The type of the value being verified
827
+ * @param {T | undefined | null} value - The value to verify
828
+ * @param {string} errorMessage - The error message to throw if the value is null or undefined
829
+ * @returns {T} - The verified value
830
+ * @throws {Error} - If the value is null or undefined
831
+ *
832
+ * @example
833
+ * const myValue = verifyNotNull(someValue, 'someValue must be defined')
834
+ */
835
+ export function verifyNotNull<T> (value: T | undefined | null, errorMessage: string = 'Expected a valid value, but got undefined or null.'): T {
836
+ if (value == null) throw new Error(errorMessage)
837
+ return value
838
+ }
@@ -7,8 +7,30 @@ import RPuzzle from '../../script/templates/RPuzzle'
7
7
  import Transaction from '../../transaction/Transaction'
8
8
  import LockingScript from '../../script/LockingScript'
9
9
  import UnlockingScript from '../../script/UnlockingScript'
10
-
10
+ import MerklePath from '../../transaction/MerklePath'
11
+ import ChainTracker from '../../transaction/ChainTracker'
11
12
  import spendValid from './spend.valid.vectors'
13
+ import Script from '../../script/Script'
14
+
15
+ export class MockChain implements ChainTracker {
16
+ mock: { blockheaders: string[] }
17
+
18
+ constructor(mock: { blockheaders: string[] }) {
19
+ this.mock = mock
20
+ }
21
+
22
+ addBlock(merkleRoot: string) {
23
+ this.mock.blockheaders.push(merkleRoot)
24
+ }
25
+
26
+ async isValidRootForHeight(root: string, height: number): Promise<boolean> {
27
+ return this.mock.blockheaders[height] === root
28
+ }
29
+
30
+ async currentHeight(): Promise<number> {
31
+ return this.mock.blockheaders.length
32
+ }
33
+ }
12
34
 
13
35
  describe('Spend', () => {
14
36
  it('Successfully validates a P2PKH spend', async () => {
@@ -368,4 +390,55 @@ describe('Spend', () => {
368
390
  expect(spend.validate()).toBe(true)
369
391
  })
370
392
  }
393
+
394
+ it('Successfully validates a spend where sequence is set to undefined', async () => {
395
+ const sourceTransaction = new Transaction(
396
+ 1,
397
+ [{
398
+ sourceTXID: '0000000000000000000000000000000000000000000000000000000000000000',
399
+ sourceOutputIndex: 0,
400
+ unlockingScript: Script.fromASM('OP_TRUE'),
401
+ sequence: 0xffffffff
402
+ }],
403
+ [
404
+ {
405
+ lockingScript: Script.fromASM('OP_NOP'),
406
+ satoshis: 2
407
+ }
408
+ ],
409
+ 0
410
+ )
411
+ const txid = sourceTransaction.id('hex')
412
+ sourceTransaction.merklePath = MerklePath.fromCoinbaseTxidAndHeight(txid, 0)
413
+ const chain = new MockChain({ blockheaders: [] })
414
+ chain.addBlock(txid)
415
+
416
+ const spendTx = new Transaction(
417
+ 1,
418
+ [
419
+ {
420
+ unlockingScript: Script.fromASM('OP_TRUE'),
421
+ sourceTransaction,
422
+ sourceOutputIndex: 0
423
+ }
424
+ ],
425
+ [{
426
+ lockingScript: Script.fromASM('OP_NOP'),
427
+ satoshis: 1
428
+ }],
429
+ 0
430
+ )
431
+
432
+ const valid = await spendTx.verify(chain)
433
+
434
+ expect(valid).toBe(true)
435
+
436
+ const b = spendTx.toBinary()
437
+ const t = Transaction.fromBinary(b)
438
+ expect(t.inputs[0].sequence).toBe(0xffffffff)
439
+
440
+ const b2 = spendTx.toEF()
441
+ const t2 = Transaction.fromEF(b2)
442
+ expect(t2.inputs[0].sequence).toBe(0xffffffff)
443
+ })
371
444
  })
@@ -1,6 +1,7 @@
1
1
  import Script from '../../script/Script'
2
2
  import Spend from '../../script/Spend'
3
3
  import Transaction from '../../transaction/Transaction'
4
+ import { verifyNotNull } from '../../primitives/utils'
4
5
 
5
6
  describe('SpendComplex', () => {
6
7
  it('complex unlock script validation', () => {
@@ -19,11 +20,6 @@ describe('SpendComplex', () => {
19
20
  })
20
21
  })
21
22
 
22
- function verifyTruthy<T> (v: T | undefined): T {
23
- if (v == null) throw new Error('must have value')
24
- return v
25
- }
26
-
27
23
  export function validateUnlockScript (
28
24
  spendingRawTx: string,
29
25
  vin: number,
@@ -34,16 +30,16 @@ export function validateUnlockScript (
34
30
  const ls = Script.fromHex(lockingScript)
35
31
 
36
32
  const spend = new Spend({
37
- sourceTXID: verifyTruthy(spendingTx.inputs[vin].sourceTXID),
38
- sourceOutputIndex: verifyTruthy(spendingTx.inputs[vin].sourceOutputIndex),
33
+ sourceTXID: verifyNotNull(spendingTx.inputs[vin].sourceTXID, 'sourceTXID must have value'),
34
+ sourceOutputIndex: verifyNotNull(spendingTx.inputs[vin].sourceOutputIndex, 'sourceOutputIndex must have value'),
39
35
  sourceSatoshis: amount,
40
36
  lockingScript: ls,
41
37
  transactionVersion: spendingTx.version,
42
38
  otherInputs: spendingTx.inputs.filter((v, i) => i !== vin),
43
39
  inputIndex: vin,
44
- unlockingScript: verifyTruthy(spendingTx.inputs[vin].unlockingScript),
40
+ unlockingScript: verifyNotNull(spendingTx.inputs[vin].unlockingScript, 'unlockingScript must have value'),
45
41
  outputs: spendingTx.outputs,
46
- inputSequence: verifyTruthy(spendingTx.inputs[vin].sequence),
42
+ inputSequence: verifyNotNull(spendingTx.inputs[vin].sequence, 'sequence must have value'),
47
43
  lockTime: spendingTx.lockTime
48
44
  })
49
45
 
@@ -1,6 +1,6 @@
1
1
  import OP from '../OP.js'
2
2
  import ScriptTemplate from '../ScriptTemplate.js'
3
- import { fromBase58Check } from '../../primitives/utils.js'
3
+ import { fromBase58Check, verifyNotNull } from '../../primitives/utils.js'
4
4
  import LockingScript from '../LockingScript.js'
5
5
  import UnlockingScript from '../UnlockingScript.js'
6
6
  import Transaction from '../../transaction/Transaction.js'
@@ -9,11 +9,6 @@ import TransactionSignature from '../../primitives/TransactionSignature.js'
9
9
  import { sha256 } from '../../primitives/Hash.js'
10
10
  import Script from '../Script.js'
11
11
 
12
- function verifyTruthy<T>(v: T | undefined): T {
13
- if (v == null) throw new Error('must have value')
14
- return v
15
- }
16
-
17
12
  /**
18
13
  * P2PKH (Pay To Public Key Hash) class implementing ScriptTemplate.
19
14
  *
@@ -125,13 +120,13 @@ export default class P2PKH implements ScriptTemplate {
125
120
 
126
121
  const preimage = TransactionSignature.format({
127
122
  sourceTXID,
128
- sourceOutputIndex: verifyTruthy(input.sourceOutputIndex),
123
+ sourceOutputIndex: verifyNotNull(input.sourceOutputIndex, 'input.sourceOutputIndex must have value'),
129
124
  sourceSatoshis,
130
125
  transactionVersion: tx.version,
131
126
  otherInputs,
132
127
  inputIndex,
133
128
  outputs: tx.outputs,
134
- inputSequence: verifyTruthy(input.sequence),
129
+ inputSequence: verifyNotNull(input.sequence, 'input.sequence must have value'),
135
130
  subscript: lockingScript,
136
131
  lockTime: tx.lockTime,
137
132
  scope: signatureScope
@@ -9,11 +9,7 @@ import {
9
9
  import { WalletInterface } from '../../wallet/Wallet.interfaces.js'
10
10
  import { Transaction } from '../../transaction/index.js'
11
11
  import { WalletProtocol } from '../../wallet/Wallet.interfaces.js'
12
-
13
- function verifyTruthy<T>(v: T | undefined): T {
14
- if (v == null) throw new Error('must have value')
15
- return v
16
- }
12
+ import { verifyNotNull } from '../../primitives/utils.js'
17
13
 
18
14
  /**
19
15
  * For a given piece of data to push onto the stack in script, creates the correct minimally-encoded script chunk,
@@ -71,7 +67,7 @@ export default class PushDrop implements ScriptTemplate {
71
67
  fields: number[][]
72
68
  } {
73
69
  const lockingPublicKey = PublicKey.fromString(
74
- Utils.toHex(verifyTruthy(script.chunks[0].data)) // Ensure not undefined
70
+ Utils.toHex(verifyNotNull(script.chunks[0].data, 'script.chunks[0].data must have value'))
75
71
  )
76
72
 
77
73
  const fields: number[][] = []
@@ -249,7 +245,7 @@ export default class PushDrop implements ScriptTemplate {
249
245
 
250
246
  const preimage = TransactionSignature.format({
251
247
  sourceTXID,
252
- sourceOutputIndex: verifyTruthy(input.sourceOutputIndex),
248
+ sourceOutputIndex: verifyNotNull(input.sourceOutputIndex, 'input.sourceOutputIndex must have value'),
253
249
  sourceSatoshis,
254
250
  transactionVersion: tx.version,
255
251
  otherInputs,
@@ -2,14 +2,9 @@ import MerklePath from './MerklePath.js'
2
2
  import Transaction from './Transaction.js'
3
3
  import ChainTracker from './ChainTracker.js'
4
4
  import BeefTx from './BeefTx.js'
5
- import { Reader, Writer, toHex, toArray } from '../primitives/utils.js'
5
+ import { Reader, Writer, toHex, toArray, verifyNotNull } from '../primitives/utils.js'
6
6
  import { hash256 } from '../primitives/Hash.js'
7
7
 
8
- function verifyTruthy<T> (v: T | undefined): T {
9
- if (v == null) throw new Error('Expected a valid value, but got undefined.')
10
- return v
11
- }
12
-
13
8
  export const BEEF_V1 = 4022206465 // 0100BEEF in LE order
14
9
  export const BEEF_V2 = 4022206466 // 0200BEEF in LE order
15
10
  export const ATOMIC_BEEF = 0x01010101 // 01010101
@@ -156,7 +151,7 @@ export class Beef {
156
151
 
157
152
  for (const i of beefTx.tx.inputs) {
158
153
  if (i.sourceTransaction == null) {
159
- const itx = this.findTxid(verifyTruthy(i.sourceTXID)) // Ensure sourceTXID is valid
154
+ const itx = this.findTxid(verifyNotNull(i.sourceTXID, 'sourceTXID must be valid'))
160
155
  if (itx != null) {
161
156
  i.sourceTransaction = itx.tx
162
157
  }
@@ -185,7 +180,7 @@ export class Beef {
185
180
  } else {
186
181
  for (const i of tx.inputs) {
187
182
  if (i.sourceTransaction == null) {
188
- const itx = beef.findTxid(verifyTruthy(i.sourceTXID)) // Ensure sourceTXID is valid
183
+ const itx = beef.findTxid(verifyNotNull(i.sourceTXID, 'sourceTXID must be valid'))
189
184
  if (itx != null) {
190
185
  i.sourceTransaction = itx.tx
191
186
  }
@@ -618,7 +618,7 @@ export default class Transaction {
618
618
  const scriptBin = i.unlockingScript.toBinary()
619
619
  writer.writeVarIntNum(scriptBin.length)
620
620
  writer.write(scriptBin)
621
- writer.writeUInt32LE(i.sequence ?? 0)
621
+ writer.writeUInt32LE(i.sequence ?? 0xffffffff) // default to max sequence
622
622
  }
623
623
  writer.writeVarIntNum(this.outputs.length)
624
624
  for (const o of this.outputs) {
@@ -659,7 +659,7 @@ export default class Transaction {
659
659
  const scriptBin = i.unlockingScript.toBinary()
660
660
  writer.writeVarIntNum(scriptBin.length)
661
661
  writer.write(scriptBin)
662
- writer.writeUInt32LE(i.sequence ?? 0)
662
+ writer.writeUInt32LE(i.sequence ?? 0xffffffff) // default to max sequence
663
663
  writer.writeUInt64LE(
664
664
  i.sourceTransaction.outputs[i.sourceOutputIndex].satoshis ?? 0
665
665
  )
@@ -866,7 +866,7 @@ export default class Transaction {
866
866
  transactionVersion: tx.version,
867
867
  otherInputs,
868
868
  unlockingScript: input.unlockingScript,
869
- inputSequence: input.sequence ?? 0,
869
+ inputSequence: input.sequence ?? 0xffffffff, // default to max sequence
870
870
  inputIndex: i,
871
871
  outputs: tx.outputs,
872
872
  lockTime: tx.lockTime,