@bsv/sdk 1.6.8 → 1.6.10

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 (92) hide show
  1. package/README.md +9 -4
  2. package/dist/cjs/package.json +7 -5
  3. package/dist/cjs/src/wallet/substrates/HTTPWalletJSON.js +11 -3
  4. package/dist/cjs/src/wallet/substrates/HTTPWalletJSON.js.map +1 -1
  5. package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js +1 -1
  6. package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
  7. package/dist/cjs/src/wallet/substrates/utils/toOriginHeader.js +21 -0
  8. package/dist/cjs/src/wallet/substrates/utils/toOriginHeader.js.map +1 -0
  9. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  10. package/dist/esm/src/wallet/substrates/HTTPWalletJSON.js +9 -1
  11. package/dist/esm/src/wallet/substrates/HTTPWalletJSON.js.map +1 -1
  12. package/dist/esm/src/wallet/substrates/WalletWireProcessor.js +1 -1
  13. package/dist/esm/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
  14. package/dist/esm/src/wallet/substrates/utils/toOriginHeader.js +17 -0
  15. package/dist/esm/src/wallet/substrates/utils/toOriginHeader.js.map +1 -0
  16. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  17. package/dist/types/src/wallet/substrates/HTTPWalletJSON.d.ts.map +1 -1
  18. package/dist/types/src/wallet/substrates/utils/toOriginHeader.d.ts +2 -0
  19. package/dist/types/src/wallet/substrates/utils/toOriginHeader.d.ts.map +1 -0
  20. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  21. package/dist/umd/bundle.js +1 -1
  22. package/docs/concepts/beef.md +84 -0
  23. package/docs/concepts/chain-tracking.md +122 -0
  24. package/docs/concepts/decentralized-identity.md +184 -0
  25. package/docs/concepts/fees.md +217 -0
  26. package/docs/concepts/identity-certificates.md +255 -0
  27. package/docs/concepts/index.md +62 -0
  28. package/docs/concepts/key-management.md +176 -0
  29. package/docs/concepts/script-templates.md +163 -0
  30. package/docs/concepts/sdk-philosophy.md +72 -0
  31. package/docs/concepts/signatures.md +179 -0
  32. package/docs/concepts/spv-verification.md +106 -0
  33. package/docs/concepts/transaction-encoding.md +148 -0
  34. package/docs/concepts/transaction-structure.md +63 -0
  35. package/docs/concepts/trust-model.md +123 -0
  36. package/docs/concepts/verification.md +219 -0
  37. package/docs/concepts/wallet-integration.md +95 -0
  38. package/docs/guides/direct-transaction-creation.md +137 -0
  39. package/docs/guides/http-client-configuration.md +414 -0
  40. package/docs/guides/index.md +30 -0
  41. package/docs/guides/transaction-signing-methods.md +268 -0
  42. package/docs/index.md +74 -0
  43. package/docs/reference/arc-config.md +698 -0
  44. package/docs/reference/brc-100.md +33 -0
  45. package/docs/reference/configuration.md +829 -0
  46. package/docs/reference/debugging.md +700 -0
  47. package/docs/reference/errors.md +547 -0
  48. package/docs/reference/index.md +98 -0
  49. package/docs/reference/network-config.md +914 -0
  50. package/docs/reference/op-codes.md +306 -0
  51. package/docs/reference/transaction-signatures.md +94 -0
  52. package/docs/{wallet.md → reference/wallet.md} +9 -0
  53. package/docs/requirements.txt +3 -0
  54. package/docs/tutorials/advanced-transaction.md +575 -0
  55. package/docs/tutorials/aes-encryption.md +947 -0
  56. package/docs/tutorials/authfetch-tutorial.md +957 -0
  57. package/docs/tutorials/ecdh-key-exchange.md +547 -0
  58. package/docs/tutorials/elliptic-curve-fundamentals.md +603 -0
  59. package/docs/tutorials/error-handling.md +1215 -0
  60. package/docs/tutorials/first-transaction-low-level.md +204 -0
  61. package/docs/tutorials/first-transaction.md +278 -0
  62. package/docs/tutorials/hashes-and-hmacs.md +814 -0
  63. package/docs/tutorials/identity-management.md +702 -0
  64. package/docs/tutorials/index.md +182 -0
  65. package/docs/tutorials/key-management.md +536 -0
  66. package/docs/tutorials/protowallet-development.md +716 -0
  67. package/docs/tutorials/script-construction.md +690 -0
  68. package/docs/tutorials/spv-merkle-proofs.md +682 -0
  69. package/docs/tutorials/testnet-transactions-low-level.md +352 -0
  70. package/docs/tutorials/transaction-broadcasting.md +535 -0
  71. package/docs/tutorials/transaction-types.md +419 -0
  72. package/docs/tutorials/type-42.md +582 -0
  73. package/docs/tutorials/uhrp-storage.md +579 -0
  74. package/package.json +7 -5
  75. package/src/transaction/__tests/Transaction.test.ts +1 -1
  76. package/src/wallet/substrates/HTTPWalletJSON.ts +11 -1
  77. package/src/wallet/substrates/WalletWireProcessor.ts +1 -1
  78. package/src/wallet/substrates/__tests/toOriginHeader.test.ts +34 -0
  79. package/src/wallet/substrates/utils/toOriginHeader.ts +15 -0
  80. package/docs/README.md +0 -21
  81. /package/docs/{auth.md → reference/auth.md} +0 -0
  82. /package/docs/{compat.md → reference/compat.md} +0 -0
  83. /package/docs/{identity.md → reference/identity.md} +0 -0
  84. /package/docs/{kvstore.md → reference/kvstore.md} +0 -0
  85. /package/docs/{messages.md → reference/messages.md} +0 -0
  86. /package/docs/{overlay-tools.md → reference/overlay-tools.md} +0 -0
  87. /package/docs/{primitives.md → reference/primitives.md} +0 -0
  88. /package/docs/{registry.md → reference/registry.md} +0 -0
  89. /package/docs/{script.md → reference/script.md} +0 -0
  90. /package/docs/{storage.md → reference/storage.md} +0 -0
  91. /package/docs/{totp.md → reference/totp.md} +0 -0
  92. /package/docs/{transaction.md → reference/transaction.md} +0 -0
@@ -0,0 +1,690 @@
1
+ # Script Construction and Custom Logic
2
+
3
+ Learn how to create, manipulate, and implement custom Bitcoin scripts using the BSV TypeScript SDK. This tutorial covers both basic script operations and advanced script template creation.
4
+
5
+ ## Prerequisites
6
+
7
+ - Completed "Your First BSV Transaction" tutorial
8
+ - Basic understanding of Bitcoin script operations
9
+ - Node.js and TypeScript knowledge
10
+
11
+ > **📚 Related Concepts**: Review [Script Templates](../concepts/script-templates.md) and [Transaction Structure](../concepts/transaction-structure.md) for foundational understanding. See [OP Codes Reference](../reference/op-codes.md) for complete opcode documentation.
12
+
13
+ ## Learning Goals
14
+
15
+ - Understand Bitcoin script fundamentals
16
+ - Create and serialize scripts in different formats
17
+ - Build custom script templates
18
+ - Implement locking and unlocking logic
19
+ - Work with opcodes and script chunks
20
+
21
+ > **💡 Try It Interactive**: Test script construction and custom templates in our [Interactive BSV Coding Environment](https://fast.brc.dev/) - experiment with opcodes and script logic in real-time!
22
+
23
+ ## Duration
24
+
25
+ 60 minutes
26
+
27
+ ---
28
+
29
+ ## Part 1: Script Fundamentals
30
+
31
+ ### Understanding Bitcoin Scripts
32
+
33
+ Bitcoin scripts are small programs that define the conditions under which bitcoins can be spent. They consist of:
34
+
35
+ - **Locking Scripts**: Define spending conditions (found in transaction outputs)
36
+ - **Unlocking Scripts**: Provide evidence to satisfy conditions (found in transaction inputs)
37
+
38
+ ### Setting Up
39
+
40
+ First, install the SDK and import the necessary modules:
41
+
42
+ ```bash
43
+ npm install @bsv/sdk
44
+ ```
45
+
46
+ ```typescript
47
+ import {
48
+ Script,
49
+ LockingScript,
50
+ UnlockingScript,
51
+ OP,
52
+ PrivateKey,
53
+ P2PKH,
54
+ ScriptTemplate,
55
+ Transaction,
56
+ Hash
57
+ } from '@bsv/sdk'
58
+ ```
59
+
60
+ ### Creating Scripts from Different Formats
61
+
62
+ The SDK supports creating scripts from various formats:
63
+
64
+ #### From ASM (Assembly)
65
+
66
+ ```typescript
67
+ // Create a P2PKH script from ASM
68
+ const scriptFromASM = Script.fromASM(
69
+ 'OP_DUP OP_HASH160 1451baa3aad777144a0759998a03538018dd7b4b OP_EQUALVERIFY OP_CHECKSIG'
70
+ )
71
+
72
+ console.log('Script from ASM:', scriptFromASM.toHex())
73
+ ```
74
+
75
+ #### From Hexadecimal
76
+
77
+ ```typescript
78
+ // Create script from hex
79
+ const scriptFromHex = Script.fromHex('76a9141451baa3aad777144a0759998a03538018dd7b4b88ac')
80
+
81
+ console.log('Script from hex:', scriptFromHex.toASM())
82
+ ```
83
+
84
+ #### From Binary Array
85
+
86
+ ```typescript
87
+ // Create script from binary data
88
+ const binaryData = [OP.OP_TRUE, OP.OP_RETURN, 4, 0x74, 0x65, 0x73, 0x74]
89
+ const scriptFromBinary = Script.fromBinary(binaryData)
90
+
91
+ console.log('Script from binary:', scriptFromBinary.toASM())
92
+ ```
93
+
94
+ ### Script Serialization
95
+
96
+ Convert scripts between different formats for storage or transmission:
97
+
98
+ ```typescript
99
+ const script = Script.fromASM('OP_DUP OP_HASH160 1451baa3aad777144a0759998a03538018dd7b4b OP_EQUALVERIFY OP_CHECKSIG')
100
+
101
+ // Serialize to different formats
102
+ const scriptAsHex = script.toHex()
103
+ const scriptAsASM = script.toASM()
104
+ const scriptAsBinary = script.toBinary()
105
+
106
+ console.log('Hex:', scriptAsHex)
107
+ console.log('ASM:', scriptAsASM)
108
+ console.log('Binary length:', scriptAsBinary.length)
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Part 2: Working with Script Chunks
114
+
115
+ ### Understanding Script Chunks
116
+
117
+ Scripts are composed of chunks, each containing either an opcode or data:
118
+
119
+ ```typescript
120
+ // Create a script with mixed opcodes and data
121
+ const script = new Script([
122
+ { op: OP.OP_DUP },
123
+ { op: OP.OP_HASH160 },
124
+ { op: 20, data: [0x14, 0x51, 0xba, 0xa3, 0xaa, 0xd7, 0x77, 0x14, 0x4a, 0x07, 0x59, 0x99, 0x8a, 0x03, 0x53, 0x80, 0x18, 0xdd, 0x7b, 0x4b] },
125
+ { op: OP.OP_EQUALVERIFY },
126
+ { op: OP.OP_CHECKSIG }
127
+ ])
128
+
129
+ console.log('Script chunks:', script.chunks.length)
130
+ console.log('Script ASM:', script.toASM())
131
+ ```
132
+
133
+ ### Building Scripts Programmatically
134
+
135
+ ```typescript
136
+ // Build a script step by step
137
+ const script = new Script()
138
+
139
+ // Add opcodes
140
+ script.writeOpCode(OP.OP_DUP)
141
+ script.writeOpCode(OP.OP_HASH160)
142
+
143
+ // Add data
144
+ const pubkeyHash = [0x14, 0x51, 0xba, 0xa3, 0xaa, 0xd7, 0x77, 0x14, 0x4a, 0x07, 0x59, 0x99, 0x8a, 0x03, 0x53, 0x80, 0x18, 0xdd, 0x7b, 0x4b]
145
+ script.writeBin(pubkeyHash)
146
+
147
+ // Add more opcodes
148
+ script.writeOpCode(OP.OP_EQUALVERIFY)
149
+ script.writeOpCode(OP.OP_CHECKSIG)
150
+
151
+ console.log('Built script:', script.toASM())
152
+ ```
153
+
154
+ ### Adding Numbers and Data
155
+
156
+ ```typescript
157
+ const script = new Script()
158
+
159
+ // Add numbers (automatically encoded)
160
+ script.writeNumber(42)
161
+ script.writeNumber(1000)
162
+
163
+ // Add binary data
164
+ script.writeBin([0x48, 0x65, 0x6c, 0x6c, 0x6f]) // "Hello"
165
+
166
+ // Add another script
167
+ const dataScript = Script.fromASM('OP_TRUE OP_FALSE')
168
+ script.writeScript(dataScript)
169
+
170
+ console.log('Data script:', script.toASM())
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Part 3: Standard Script Templates
176
+
177
+ ### Using P2PKH Template
178
+
179
+ The P2PKH (Pay to Public Key Hash) template is the most common script type:
180
+
181
+ ```typescript
182
+ async function runP2PKHExample() {
183
+ // Generate a key pair
184
+ const privateKey = PrivateKey.fromRandom()
185
+ const publicKey = privateKey.toPublicKey()
186
+ const pubkeyHash = publicKey.toHash()
187
+
188
+ // Create P2PKH template
189
+ const p2pkh = new P2PKH()
190
+
191
+ // Create locking script
192
+ const lockingScript = p2pkh.lock(pubkeyHash)
193
+ console.log('P2PKH locking script:', lockingScript.toASM())
194
+
195
+ // Create unlocking script
196
+ const unlockingTemplate = p2pkh.unlock(privateKey)
197
+ console.log('Unlocking script estimate:', await unlockingTemplate.estimateLength())
198
+ }
199
+
200
+ // Run the example
201
+ runP2PKHExample().catch(console.error)
202
+ ```
203
+
204
+ ### Data Storage Scripts
205
+
206
+ Create scripts that store arbitrary data:
207
+
208
+ ```typescript
209
+ // Create a simple data storage script
210
+ const dataScript = new Script()
211
+ dataScript.writeOpCode(OP.OP_FALSE)
212
+ dataScript.writeOpCode(OP.OP_RETURN)
213
+ dataScript.writeBin([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64]) // "Hello World"
214
+
215
+ console.log('Data script:', dataScript.toASM())
216
+ console.log('Data script hex:', dataScript.toHex())
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Part 4: Custom Script Templates
222
+
223
+ ### Creating a Simple Custom Template
224
+
225
+ Let's create a custom script template for a simple puzzle:
226
+
227
+ ```typescript
228
+ import { ScriptTemplate, LockingScript, UnlockingScript, OP, Transaction } from '@bsv/sdk'
229
+
230
+ class SimplePuzzle implements ScriptTemplate {
231
+ /**
232
+ * Creates a locking script that requires a specific number to unlock
233
+ */
234
+ lock(secretNumber: number): LockingScript {
235
+ const script = new LockingScript()
236
+ script.writeNumber(secretNumber)
237
+ script.writeOpCode(OP.OP_EQUAL)
238
+ return script
239
+ }
240
+
241
+ /**
242
+ * Creates an unlocking script with the secret number
243
+ */
244
+ unlock(secretNumber: number) {
245
+ return {
246
+ sign: async (tx: Transaction, inputIndex: number): Promise<UnlockingScript> => {
247
+ const script = new UnlockingScript()
248
+ script.writeNumber(secretNumber)
249
+ return script
250
+ },
251
+ estimateLength: async (): Promise<number> => {
252
+ // Estimate: number encoding (1-5 bytes) + push opcode (1 byte)
253
+ return 6
254
+ }
255
+ }
256
+ }
257
+ }
258
+
259
+ async function runSimplePuzzleExample() {
260
+ // Usage example
261
+ const puzzle = new SimplePuzzle()
262
+ const secretNumber = 42
263
+
264
+ const lockingScript = puzzle.lock(secretNumber)
265
+ console.log('Puzzle locking script:', lockingScript.toASM())
266
+
267
+ const unlockingTemplate = puzzle.unlock(secretNumber)
268
+ console.log('Estimated unlock length:', await unlockingTemplate.estimateLength())
269
+ }
270
+
271
+ // Run the example
272
+ runSimplePuzzleExample().catch(console.error)
273
+ ```
274
+
275
+ ### Advanced Custom Template: Hash Puzzle
276
+
277
+ Create a more sophisticated template that uses hash functions:
278
+
279
+ ```typescript
280
+ class HashPuzzle implements ScriptTemplate {
281
+ /**
282
+ * Creates a locking script that requires the preimage of a hash
283
+ */
284
+ lock(hash: number[]): LockingScript {
285
+ const script = new LockingScript()
286
+ script.writeOpCode(OP.OP_SHA256)
287
+ script.writeBin(hash)
288
+ script.writeOpCode(OP.OP_EQUAL)
289
+ return script
290
+ }
291
+
292
+ /**
293
+ * Creates an unlocking script with the preimage
294
+ */
295
+ unlock(preimage: number[]) {
296
+ return {
297
+ sign: async (tx: Transaction, inputIndex: number): Promise<UnlockingScript> => {
298
+ const script = new UnlockingScript()
299
+ script.writeBin(preimage)
300
+ return script
301
+ },
302
+ estimateLength: async (): Promise<number> => {
303
+ // Estimate: preimage length + push opcodes
304
+ return preimage.length + 5
305
+ }
306
+ }
307
+ }
308
+ }
309
+
310
+ async function runHashPuzzleExample() {
311
+ // Usage example
312
+ const hashPuzzle = new HashPuzzle()
313
+ const preimage = [0x48, 0x65, 0x6c, 0x6c, 0x6f] // "Hello"
314
+ const hash = Hash.sha256(preimage)
315
+
316
+ const lockingScript = hashPuzzle.lock(hash)
317
+ console.log('Hash puzzle locking script:', lockingScript.toASM())
318
+
319
+ const unlockingTemplate = hashPuzzle.unlock(preimage)
320
+ console.log('Hash puzzle unlock estimate:', await unlockingTemplate.estimateLength())
321
+ }
322
+
323
+ // Run the example
324
+ runHashPuzzleExample().catch(console.error)
325
+ ```
326
+
327
+ ---
328
+
329
+ ## Part 5: Multi-Signature Scripts
330
+
331
+ ### Creating Multi-Sig Templates
332
+
333
+ ```typescript
334
+ class MultiSig implements ScriptTemplate {
335
+ /**
336
+ * Creates a multi-signature locking script
337
+ */
338
+ lock(requiredSigs: number, publicKeys: number[][]): LockingScript {
339
+ const script = new LockingScript()
340
+
341
+ // Required signatures count
342
+ script.writeNumber(requiredSigs)
343
+
344
+ // Add public keys
345
+ for (const pubkey of publicKeys) {
346
+ script.writeBin(pubkey)
347
+ }
348
+
349
+ // Total public keys count
350
+ script.writeNumber(publicKeys.length)
351
+ script.writeOpCode(OP.OP_CHECKMULTISIG)
352
+
353
+ return script
354
+ }
355
+
356
+ /**
357
+ * Creates an unlocking script for multi-sig
358
+ */
359
+ unlock(signatures: number[][]) {
360
+ return {
361
+ sign: async (tx: Transaction, inputIndex: number): Promise<UnlockingScript> => {
362
+ const script = new UnlockingScript()
363
+
364
+ // OP_0 due to CHECKMULTISIG bug
365
+ script.writeOpCode(OP.OP_0)
366
+
367
+ // Add signatures
368
+ for (const sig of signatures) {
369
+ script.writeBin(sig)
370
+ }
371
+
372
+ return script
373
+ },
374
+ estimateLength: async (): Promise<number> => {
375
+ // Estimate: OP_0 + signatures with push opcodes
376
+ return 1 + signatures.reduce((total, sig) => total + sig.length + 1, 0)
377
+ }
378
+ }
379
+ }
380
+ }
381
+
382
+ async function runMultiSigExample() {
383
+ // Usage example
384
+ const multiSig = new MultiSig()
385
+ const requiredSigs = 2
386
+ const publicKeys = [
387
+ [0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31, 0x32, 0x33],
388
+ [0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65]
389
+ ]
390
+
391
+ const lockingScript = multiSig.lock(requiredSigs, publicKeys)
392
+ console.log('Multi-sig locking script:', lockingScript.toASM())
393
+
394
+ const unlockingTemplate = multiSig.unlock([
395
+ [0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97],
396
+ [0x98, 0x99, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, 0x120, 0x121, 0x122, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129]
397
+ ])
398
+ console.log('Multi-sig unlock estimate:', await unlockingTemplate.estimateLength())
399
+ }
400
+
401
+ // Run the example
402
+ runMultiSigExample().catch(console.error)
403
+ ```
404
+
405
+ ---
406
+
407
+ ## Part 6: Script Validation and Testing
408
+
409
+ ### Testing Script Templates
410
+
411
+ ```typescript
412
+ // Test the simple puzzle template
413
+ async function testSimplePuzzle() {
414
+ const puzzle = new SimplePuzzle()
415
+ const secretNumber = 123
416
+
417
+ // Create locking script
418
+ const lockingScript = puzzle.lock(secretNumber)
419
+
420
+ // Create unlocking script
421
+ const unlockingTemplate = puzzle.unlock(secretNumber)
422
+
423
+ // In a real scenario, you would use this with a transaction
424
+ console.log('Puzzle test:')
425
+ console.log('Locking script:', lockingScript.toASM())
426
+ console.log('Estimated unlock length:', await unlockingTemplate.estimateLength())
427
+
428
+ // Test with wrong number
429
+ const wrongUnlock = puzzle.unlock(456)
430
+ console.log('Wrong unlock estimate:', await wrongUnlock.estimateLength())
431
+ }
432
+
433
+ testSimplePuzzle()
434
+ ```
435
+
436
+ ### Script Analysis
437
+
438
+ ```typescript
439
+ // Analyze script properties
440
+ function analyzeScript(script: Script) {
441
+ console.log('Script Analysis:')
442
+ console.log('- Chunks:', script.chunks.length)
443
+ console.log('- ASM:', script.toASM())
444
+ console.log('- Hex:', script.toHex())
445
+ console.log('- Binary length:', script.toBinary().length)
446
+ console.log('- Is push-only:', script.isPushOnly())
447
+ }
448
+
449
+ const testScript = Script.fromASM('OP_DUP OP_HASH160 1451baa3aad777144a0759998a03538018dd7b4b OP_EQUALVERIFY OP_CHECKSIG')
450
+ analyzeScript(testScript)
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Part 7: Advanced Script Operations
456
+
457
+ ### Script Manipulation
458
+
459
+ ```typescript
460
+ // Modify existing scripts
461
+ const script = Script.fromASM('OP_DUP OP_HASH160 1451baa3aad777144a0759998a03538018dd7b4b OP_EQUALVERIFY OP_CHECKSIG')
462
+
463
+ // Remove code separators (if any)
464
+ script.removeCodeseparators()
465
+
466
+ // Modify specific chunks
467
+ script.setChunkOpCode(0, OP.OP_2DUP) // Change first OP_DUP to OP_2DUP
468
+
469
+ console.log('Modified script:', script.toASM())
470
+ ```
471
+
472
+ ### Combining Scripts
473
+
474
+ ```typescript
475
+ // Combine multiple scripts
476
+ const script1 = Script.fromASM('OP_TRUE')
477
+ const script2 = Script.fromASM('OP_FALSE')
478
+ const script3 = Script.fromASM('OP_ADD')
479
+
480
+ const combinedScript = new Script()
481
+ combinedScript.writeScript(script1)
482
+ combinedScript.writeScript(script2)
483
+ combinedScript.writeScript(script3)
484
+
485
+ console.log('Combined script:', combinedScript.toASM())
486
+ ```
487
+
488
+ ---
489
+
490
+ ## Part 8: Real-World Example
491
+
492
+ ### Creating a Time-Locked Script Template
493
+
494
+ ```typescript
495
+ class TimeLock implements ScriptTemplate {
496
+ /**
497
+ * Creates a time-locked script that can only be spent after a certain time
498
+ */
499
+ lock(lockTime: number, pubkeyHash: number[]): LockingScript {
500
+ const script = new LockingScript()
501
+
502
+ // Push the lock time
503
+ script.writeNumber(lockTime)
504
+ script.writeOpCode(OP.OP_CHECKLOCKTIMEVERIFY)
505
+ script.writeOpCode(OP.OP_DROP)
506
+
507
+ // Standard P2PKH after time check
508
+ script.writeOpCode(OP.OP_DUP)
509
+ script.writeOpCode(OP.OP_HASH160)
510
+ script.writeBin(pubkeyHash)
511
+ script.writeOpCode(OP.OP_EQUALVERIFY)
512
+ script.writeOpCode(OP.OP_CHECKSIG)
513
+
514
+ return script
515
+ }
516
+
517
+ /**
518
+ * Creates an unlocking script for time-locked output
519
+ */
520
+ unlock(privateKey: PrivateKey) {
521
+ return {
522
+ sign: async (tx: Transaction, inputIndex: number): Promise<UnlockingScript> => {
523
+ // This would need proper signature creation in a real implementation
524
+ const script = new UnlockingScript()
525
+
526
+ // Add signature (simplified - would need proper SIGHASH implementation)
527
+ const dummySig = [0x30, 0x44, 0x02, 0x20] // Placeholder signature
528
+ script.writeBin(dummySig)
529
+
530
+ // Add public key
531
+ const pubkey = privateKey.toPublicKey().encode(true) as number[]
532
+ script.writeBin(pubkey)
533
+
534
+ return script
535
+ },
536
+ estimateLength: async (): Promise<number> => {
537
+ // Signature (~71 bytes) + public key (33 bytes) + push opcodes
538
+ return 106
539
+ }
540
+ }
541
+ }
542
+ }
543
+
544
+ // Usage
545
+ const timeLock = new TimeLock()
546
+ const lockTime = Math.floor(Date.now() / 1000) + 3600 // 1 hour from now
547
+ const privateKey = PrivateKey.fromRandom()
548
+ const pubkeyHash = privateKey.toPublicKey().toHash()
549
+
550
+ const lockingScript = timeLock.lock(lockTime, pubkeyHash)
551
+ console.log('Time-locked script:', lockingScript.toASM())
552
+ ```
553
+
554
+ ---
555
+
556
+ ## Best Practices
557
+
558
+ ### 1. Script Efficiency
559
+
560
+ - Keep scripts as small as possible to minimize fees
561
+ - Use standard templates when possible
562
+ - Avoid unnecessary operations
563
+
564
+ ### 2. Security Considerations
565
+
566
+ - Validate all inputs in custom templates
567
+ - Test scripts thoroughly before mainnet use
568
+
569
+ ### 3. Testing
570
+
571
+ ```typescript
572
+ // Always test your custom templates
573
+ async function testTemplate(template: ScriptTemplate, ...lockParams: any[]) {
574
+ try {
575
+ const lockingScript = template.lock(...lockParams)
576
+ console.log('✓ Locking script created:', lockingScript.toASM())
577
+
578
+ // Test unlocking if parameters are available
579
+ // const unlockingTemplate = template.unlock(...unlockParams)
580
+ // const estimate = await unlockingTemplate.estimateLength()
581
+ // console.log('✓ Unlock estimate:', estimate)
582
+
583
+ } catch (error) {
584
+ console.error('✗ Template test failed:', error.message)
585
+ }
586
+ }
587
+ ```
588
+
589
+ ---
590
+
591
+ ## Common Patterns
592
+
593
+ ### 1. Data Storage Pattern
594
+
595
+ ```typescript
596
+ // Store data with OP_RETURN
597
+ const dataScript = new Script()
598
+ dataScript.writeOpCode(OP.OP_FALSE)
599
+ dataScript.writeOpCode(OP.OP_RETURN)
600
+ dataScript.writeBin([/* your data */])
601
+ ```
602
+
603
+ ### 2. Conditional Spending Pattern
604
+
605
+ ```typescript
606
+ // IF-ELSE conditional spending
607
+ const conditionalScript = new Script()
608
+ conditionalScript.writeOpCode(OP.OP_IF)
609
+ // ... condition true path
610
+ conditionalScript.writeOpCode(OP.OP_ELSE)
611
+ // ... condition false path
612
+ conditionalScript.writeOpCode(OP.OP_ENDIF)
613
+ ```
614
+
615
+ ### 3. Hash Verification Pattern
616
+
617
+ ```typescript
618
+ // Verify hash preimage
619
+ const hashScript = new Script()
620
+ hashScript.writeOpCode(OP.OP_SHA256)
621
+ hashScript.writeBin([/* expected hash */])
622
+ hashScript.writeOpCode(OP.OP_EQUAL)
623
+ ```
624
+
625
+ ---
626
+
627
+ ## Integration with `WalletClient`
628
+
629
+ Your custom script templates can be used with the `WalletClient` for production applications:
630
+
631
+ ```typescript
632
+ // Create a wallet client instance
633
+ const walletClient = new WalletClient({
634
+ // ... wallet client options
635
+ })
636
+
637
+ // Create a custom script template
638
+ const customTemplate = new SimplePuzzle()
639
+
640
+ // Create a locking script
641
+ const lockingScript = customTemplate.lock(42)
642
+
643
+ // Create a transaction with the custom script
644
+ const tx = walletClient.createTransaction({
645
+ // ... transaction options
646
+ lockingScript,
647
+ })
648
+
649
+ // Send the transaction
650
+ walletClient.sendTransaction(tx)
651
+ ```
652
+
653
+ ---
654
+
655
+ ## Summary
656
+
657
+ In this tutorial, you learned:
658
+
659
+ - ✅ Bitcoin script fundamentals and structure
660
+ - ✅ Creating scripts from different formats (ASM, hex, binary)
661
+ - ✅ Working with script chunks and opcodes
662
+ - ✅ Using standard script templates like P2PKH
663
+ - ✅ Building custom script templates
664
+ - ✅ Implementing locking and unlocking logic
665
+ - ✅ Advanced script operations and combinations
666
+ - ✅ Best practices for script development
667
+
668
+ You now have the knowledge to create sophisticated Bitcoin scripts and custom templates for your applications. Remember to test thoroughly and consider security implications when deploying custom scripts.
669
+
670
+ ## Next Steps
671
+
672
+ - Explore the [Advanced Transaction Construction](./advanced-transaction.md) tutorial
673
+ - Learn about [Transaction Broadcasting](./transaction-broadcasting.md)
674
+ - Study the SDK's built-in script templates for more examples
675
+ - Practice with testnet before deploying to mainnet
676
+
677
+ ## Troubleshooting
678
+
679
+ ### Common Issues
680
+
681
+ 1. **Script too large**: Minimize operations and data size
682
+ 2. **Invalid opcodes**: Check opcode values against the OP enum
683
+ 3. **Serialization errors**: Ensure proper data encoding
684
+ 4. **Template errors**: Verify unlock function returns correct structure
685
+
686
+ ### Getting Help
687
+
688
+ - Check the [BSV TypeScript SDK documentation](https://docs.bsvblockchain.org/)
689
+ - Review existing script templates in the SDK source
690
+ - Test scripts on testnet before mainnet deployment