@bsv/sdk 1.6.12 → 1.6.15
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/README.md +4 -4
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/transaction/broadcasters/DefaultBroadcaster.js +1 -1
- package/dist/cjs/src/transaction/broadcasters/DefaultBroadcaster.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/transaction/broadcasters/DefaultBroadcaster.js +1 -1
- package/dist/esm/src/transaction/broadcasters/DefaultBroadcaster.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/transaction/http/HttpClient.d.ts +2 -0
- package/dist/types/src/transaction/http/HttpClient.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/MARKDOWN_VALIDATION_GUIDE.md +175 -0
- package/docs/concepts/beef.md +8 -0
- package/docs/concepts/chain-tracking.md +12 -0
- package/docs/concepts/decentralized-identity.md +37 -0
- package/docs/concepts/fees.md +32 -0
- package/docs/concepts/identity-certificates.md +53 -1
- package/docs/concepts/index.md +15 -0
- package/docs/concepts/key-management.md +9 -0
- package/docs/concepts/script-templates.md +13 -0
- package/docs/concepts/sdk-philosophy.md +8 -0
- package/docs/concepts/signatures.md +15 -0
- package/docs/concepts/spv-verification.md +12 -0
- package/docs/concepts/transaction-encoding.md +19 -0
- package/docs/concepts/transaction-structure.md +4 -0
- package/docs/concepts/trust-model.md +16 -0
- package/docs/concepts/verification.md +31 -0
- package/docs/concepts/wallet-integration.md +6 -0
- package/docs/guides/development-wallet-setup.md +374 -0
- package/docs/guides/direct-transaction-creation.md +12 -2
- package/docs/guides/http-client-configuration.md +122 -48
- package/docs/guides/index.md +117 -9
- package/docs/guides/large-transactions.md +448 -0
- package/docs/guides/multisig-transactions.md +792 -0
- package/docs/guides/security-best-practices.md +494 -0
- package/docs/guides/transaction-batching.md +132 -0
- package/docs/guides/transaction-signing-methods.md +230 -79
- package/docs/index.md +0 -2
- package/docs/reference/configuration.md +6 -0
- package/docs/reference/debugging.md +5 -0
- package/docs/reference/errors.md +50 -0
- package/docs/reference/index.md +14 -1
- package/docs/reference/op-codes.md +20 -1
- package/docs/reference/transaction-signatures.md +2 -1
- package/docs/reference/transaction.md +9 -0
- package/docs/tutorials/advanced-transaction.md +1 -4
- package/docs/tutorials/aes-encryption.md +3 -1
- package/docs/tutorials/authfetch-tutorial.md +29 -0
- package/docs/tutorials/ecdh-key-exchange.md +2 -0
- package/docs/tutorials/elliptic-curve-fundamentals.md +3 -0
- package/docs/tutorials/error-handling.md +1 -0
- package/docs/tutorials/first-transaction-low-level.md +1 -0
- package/docs/tutorials/first-transaction.md +5 -8
- package/docs/tutorials/hashes-and-hmacs.md +5 -31
- package/docs/tutorials/identity-management.md +27 -0
- package/docs/tutorials/index.md +114 -77
- package/docs/tutorials/key-management.md +5 -3
- package/docs/tutorials/protowallet-development.md +27 -0
- package/docs/tutorials/spv-merkle-proofs.md +9 -6
- package/docs/tutorials/testnet-transactions-low-level.md +25 -18
- package/docs/tutorials/transaction-broadcasting.md +10 -7
- package/docs/tutorials/transaction-types.md +5 -4
- package/docs/tutorials/type-42.md +0 -14
- package/docs/tutorials/uhrp-storage.md +23 -3
- package/package.json +1 -1
- package/src/identity/README.md +0 -1
- package/src/primitives/__tests/SymmetricKey.test.ts +45 -0
- package/src/primitives/__tests/SymmetricKeyCompatibility.test.ts +150 -0
- package/src/transaction/__tests/Transaction.test.ts +1 -1
- package/src/transaction/broadcasters/DefaultBroadcaster.ts +1 -1
- package/src/transaction/broadcasters/__tests/ARC.test.ts +1 -1
- package/src/transaction/http/HttpClient.ts +2 -0
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
This guide demonstrates two different approaches to signing Bitcoin transactions with the BSV TypeScript SDK:
|
|
8
8
|
|
|
9
|
-
1. **Using WalletClient
|
|
9
|
+
1. **Using `WalletClient`** - A high-level approach that abstracts key management and signing details
|
|
10
10
|
2. **Using Low-level APIs** - A direct approach with more control over the transaction signing process
|
|
11
11
|
|
|
12
|
-
Each method has its advantages depending on your use case. The WalletClient approach is recommended for production applications where security is paramount, while the low-level approach gives you more control and is useful for educational purposes or specialized applications.
|
|
12
|
+
Each method has its advantages depending on your use case. The `WalletClient` approach is recommended for production applications where security is paramount, while the low-level approach gives you more control and is useful for educational purposes or specialized applications.
|
|
13
13
|
|
|
14
14
|
## Prerequisites
|
|
15
15
|
|
|
@@ -17,9 +17,11 @@ Each method has its advantages depending on your use case. The WalletClient appr
|
|
|
17
17
|
- Familiarity with Bitcoin transaction structure
|
|
18
18
|
- Understanding of basic cryptographic principles
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
> **📚 Related Concepts**: This guide builds on [Digital Signatures](../concepts/signatures.md), [Key Management](../concepts/key-management.md), [Transaction Structure](../concepts/transaction-structure.md), and [Wallet Integration](../concepts/wallet-integration.md).
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
## Method 1: `WalletClient` Signing (Recommended)
|
|
23
|
+
|
|
24
|
+
The `WalletClient` provides a secure, high-level interface for managing keys and signing transactions. This approach is recommended for production applications as it:
|
|
23
25
|
|
|
24
26
|
- Abstracts away complex key management
|
|
25
27
|
- Provides better security by isolating private keys
|
|
@@ -56,21 +58,27 @@ async function walletTransactionDemo() {
|
|
|
56
58
|
// 2. Creating a transaction with WalletClient
|
|
57
59
|
console.log('\n2. Creating a transaction with WalletClient')
|
|
58
60
|
|
|
59
|
-
//
|
|
60
|
-
const
|
|
61
|
+
// Get our own address to send payment to self (realistic example)
|
|
62
|
+
const ourAddress = await wallet.getAddress()
|
|
61
63
|
const amountSatoshis = 100
|
|
62
64
|
|
|
65
|
+
console.log(`Our wallet address: ${ourAddress}`)
|
|
66
|
+
|
|
67
|
+
// Create a proper P2PKH locking script for our address
|
|
68
|
+
const lockingScript = new P2PKH().lock(ourAddress)
|
|
69
|
+
|
|
63
70
|
// Create a payment action using WalletClient
|
|
64
71
|
// This builds a complete transaction structure internally
|
|
65
72
|
const actionResult = await wallet.createAction({
|
|
66
|
-
description: `
|
|
73
|
+
description: `Self-payment demonstration`,
|
|
67
74
|
// Define outputs for the transaction
|
|
68
75
|
outputs: [
|
|
69
76
|
{
|
|
70
|
-
//
|
|
71
|
-
lockingScript:
|
|
77
|
+
// Use proper P2PKH script construction
|
|
78
|
+
lockingScript: lockingScript.toHex(),
|
|
72
79
|
satoshis: amountSatoshis,
|
|
73
|
-
|
|
80
|
+
basket: 'tutorial',
|
|
81
|
+
outputDescription: `Payment to our own address`
|
|
74
82
|
}
|
|
75
83
|
],
|
|
76
84
|
// Set options to ensure we get a signable transaction
|
|
@@ -86,8 +94,9 @@ async function walletTransactionDemo() {
|
|
|
86
94
|
console.log('No signable transaction returned - check wallet configuration')
|
|
87
95
|
return
|
|
88
96
|
}
|
|
89
|
-
console.log(`- Description: Payment
|
|
97
|
+
console.log(`- Description: Payment demonstration`)
|
|
90
98
|
console.log(`- Amount: ${amountSatoshis} satoshis`)
|
|
99
|
+
console.log(`- Recipient: ${ourAddress} (our own address)`)
|
|
91
100
|
|
|
92
101
|
// 3. Sign the transaction with WalletClient
|
|
93
102
|
console.log('\n3. Signing transaction with WalletClient')
|
|
@@ -106,7 +115,7 @@ async function walletTransactionDemo() {
|
|
|
106
115
|
console.log(`Transaction ID: ${signResult.txid}`)
|
|
107
116
|
}
|
|
108
117
|
|
|
109
|
-
// 4. Examine the transaction
|
|
118
|
+
// 4. Examine the transaction (retrieve it from the network and inspect it)
|
|
110
119
|
console.log('\n4. Examining the transaction')
|
|
111
120
|
|
|
112
121
|
// Check if we have a transaction ID from the sign result
|
|
@@ -114,20 +123,92 @@ async function walletTransactionDemo() {
|
|
|
114
123
|
console.log(`Transaction ID: ${signResult.txid}`)
|
|
115
124
|
console.log('Transaction was successfully signed and broadcast!')
|
|
116
125
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
// Actually retrieve and inspect the transaction using the wallet
|
|
127
|
+
try {
|
|
128
|
+
// Wait a moment for the transaction to propagate
|
|
129
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
130
|
+
|
|
131
|
+
// Retry logic to find the transaction outputs
|
|
132
|
+
const maxRetries = 5 // 30 seconds with 5-second intervals
|
|
133
|
+
const retryInterval = 5000 // 5 seconds
|
|
134
|
+
let relatedOutputs: any[] = []
|
|
135
|
+
let retryCount = 0
|
|
136
|
+
|
|
137
|
+
console.log('\nSearching for transaction outputs...')
|
|
138
|
+
|
|
139
|
+
while (retryCount < maxRetries && relatedOutputs.length === 0) {
|
|
140
|
+
try {
|
|
141
|
+
// List our outputs to see the transaction result
|
|
142
|
+
const { outputs } = await wallet.listOutputs({ basket: 'tutorial' })
|
|
143
|
+
|
|
144
|
+
// Find outputs related to our transaction
|
|
145
|
+
// Extract txid from outpoint (format: "txid.outputIndex")
|
|
146
|
+
relatedOutputs = outputs.filter(output => {
|
|
147
|
+
const [outputTxid] = output.outpoint.split('.')
|
|
148
|
+
return outputTxid === signResult.txid
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
if (relatedOutputs.length > 0) {
|
|
152
|
+
console.log('\nTransaction inspection results:')
|
|
153
|
+
console.log(`- Found ${relatedOutputs.length} output(s) from this transaction`)
|
|
154
|
+
|
|
155
|
+
relatedOutputs.forEach((output, index) => {
|
|
156
|
+
console.log(`\nOutput ${index + 1}:`)
|
|
157
|
+
console.log(` - Value: ${output.satoshis} satoshis`)
|
|
158
|
+
console.log(` - Outpoint: ${output.outpoint}`)
|
|
159
|
+
console.log(` - Locking Script: ${output.lockingScript}`)
|
|
160
|
+
console.log(` - Spendable: ${output.spendable ? 'Yes' : 'No'}`)
|
|
161
|
+
if (output.tags && output.tags.length > 0) {
|
|
162
|
+
console.log(` - Tags: ${output.tags.join(', ')}`)
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
// Analyze the locking script
|
|
167
|
+
const firstOutput = relatedOutputs[0]
|
|
168
|
+
console.log('\nScript Analysis:')
|
|
169
|
+
console.log(`- Script Type: P2PKH (Pay-to-Public-Key-Hash)`)
|
|
170
|
+
console.log(`- Script validates payment to: ${ourAddress}`)
|
|
171
|
+
console.log(`- This output can be spent by providing a valid signature`)
|
|
172
|
+
|
|
173
|
+
break // Found the outputs, exit the retry loop
|
|
174
|
+
} else {
|
|
175
|
+
retryCount++
|
|
176
|
+
if (retryCount < maxRetries) {
|
|
177
|
+
console.log(`Attempt ${retryCount}/${maxRetries}: Transaction not propagated yet, retrying in ${retryInterval/1000} seconds...`)
|
|
178
|
+
await new Promise(resolve => setTimeout(resolve, retryInterval))
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} catch (listError: any) {
|
|
182
|
+
retryCount++
|
|
183
|
+
if (retryCount < maxRetries) {
|
|
184
|
+
console.log(`Attempt ${retryCount}/${maxRetries}: Error listing outputs, retrying in ${retryInterval/1000} seconds...`)
|
|
185
|
+
console.log(`Error: ${listError.message}`)
|
|
186
|
+
await new Promise(resolve => setTimeout(resolve, retryInterval))
|
|
187
|
+
} else {
|
|
188
|
+
throw listError // Re-throw on final attempt
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (relatedOutputs.length === 0) {
|
|
194
|
+
console.log('\nTransaction outputs not found after 30 seconds.')
|
|
195
|
+
console.log('This might be because:')
|
|
196
|
+
console.log('- The outputs went to a different basket')
|
|
197
|
+
console.log('- The transaction is taking longer to sync')
|
|
198
|
+
console.log('- Network connectivity issues')
|
|
199
|
+
console.log('\nYou can check the transaction on WhatsOnChain:')
|
|
200
|
+
console.log(`https://whatsonchain.com/tx/${signResult.txid}`)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
} catch (inspectionError) {
|
|
204
|
+
console.log('\nCould not inspect transaction details:')
|
|
205
|
+
console.log('This is normal and can happen because:')
|
|
206
|
+
console.log('- Transaction is still propagating through the network')
|
|
207
|
+
console.log('- Wallet needs time to sync with the blockchain')
|
|
208
|
+
console.log('- Network connectivity issues')
|
|
209
|
+
console.log(`\nError details: ${inspectionError.message}`)
|
|
210
|
+
}
|
|
125
211
|
|
|
126
|
-
console.log('\nExample output information you would see:')
|
|
127
|
-
console.log('- Input count: typically 1 or more inputs from your wallet')
|
|
128
|
-
console.log('- Output count: at least 2 (payment + change)')
|
|
129
|
-
console.log('- Input scripts: Contains signatures and public keys')
|
|
130
|
-
console.log('- Output scripts: Contains P2PKH or other locking scripts')
|
|
131
212
|
} else {
|
|
132
213
|
console.log('No transaction ID available - transaction may not have been broadcast')
|
|
133
214
|
}
|
|
@@ -140,7 +221,7 @@ async function walletTransactionDemo() {
|
|
|
140
221
|
walletTransactionDemo().catch(console.error)
|
|
141
222
|
```
|
|
142
223
|
|
|
143
|
-
### Key Benefits of the WalletClient Approach
|
|
224
|
+
### Key Benefits of the `WalletClient` Approach
|
|
144
225
|
|
|
145
226
|
1. **Security**: Private keys are managed by the wallet service, reducing exposure
|
|
146
227
|
2. **Abstraction**: Complex transaction construction details are handled internally
|
|
@@ -153,81 +234,162 @@ The low-level approach gives you direct control over the transaction signing pro
|
|
|
153
234
|
|
|
154
235
|
- Educational purposes to understand the underlying mechanics
|
|
155
236
|
- Specialized applications requiring custom transaction structures
|
|
156
|
-
-
|
|
157
|
-
|
|
158
|
-
### Example Code
|
|
237
|
+
- Custom fee calculation and UTXO management
|
|
238
|
+
- Advanced transaction types and complex scripts
|
|
159
239
|
|
|
160
240
|
```typescript
|
|
161
|
-
import { PrivateKey,
|
|
241
|
+
import { PrivateKey, Transaction, P2PKH, Script } from '@bsv/sdk'
|
|
162
242
|
|
|
163
|
-
async function
|
|
164
|
-
|
|
243
|
+
async function lowLevelTransactionDemo() {
|
|
244
|
+
console.log('\n=== Low-Level Transaction Signing Demo ===')
|
|
245
|
+
|
|
246
|
+
// 1. Generate keys for our demonstration
|
|
165
247
|
const privateKey = PrivateKey.fromRandom()
|
|
248
|
+
const publicKey = privateKey.toPublicKey()
|
|
166
249
|
const address = privateKey.toAddress()
|
|
167
250
|
|
|
168
|
-
console.log('\
|
|
251
|
+
console.log('\n1. Key Generation:')
|
|
169
252
|
console.log(`Private Key (WIF): ${privateKey.toWif()}`)
|
|
170
|
-
console.log(`
|
|
253
|
+
console.log(`Public Key: ${publicKey.toString()}`)
|
|
254
|
+
console.log(`Address: ${address}`)
|
|
171
255
|
|
|
172
|
-
// Create a
|
|
256
|
+
// 2. Create a realistic transaction with proper structure
|
|
257
|
+
console.log('\n2. Creating Transaction Structure:')
|
|
258
|
+
|
|
259
|
+
// Create a transaction that demonstrates real Bitcoin transaction patterns
|
|
173
260
|
const tx = new Transaction()
|
|
174
261
|
|
|
175
|
-
// For
|
|
176
|
-
//
|
|
177
|
-
// For our example, we'll create a simple transaction structure
|
|
178
|
-
// In a real scenario, you would use actual UTXOs
|
|
262
|
+
// For this demo, we'll create a transaction that spends from a P2PKH output
|
|
263
|
+
// and creates a new P2PKH output (self-payment) plus an OP_RETURN data output
|
|
179
264
|
|
|
180
|
-
// First, create a
|
|
181
|
-
const
|
|
182
|
-
|
|
265
|
+
// First, create a source transaction that contains funds we can spend
|
|
266
|
+
const sourceTransaction = new Transaction()
|
|
267
|
+
sourceTransaction.addOutput({
|
|
183
268
|
lockingScript: new P2PKH().lock(address),
|
|
184
|
-
satoshis:
|
|
269
|
+
satoshis: 1000 // Source has 1000 satoshis
|
|
185
270
|
})
|
|
186
271
|
|
|
187
|
-
//
|
|
272
|
+
// Add input that spends from our source transaction
|
|
188
273
|
tx.addInput({
|
|
189
|
-
sourceTransaction
|
|
274
|
+
sourceTransaction,
|
|
190
275
|
sourceOutputIndex: 0,
|
|
191
276
|
unlockingScriptTemplate: new P2PKH().unlock(privateKey)
|
|
192
277
|
})
|
|
193
278
|
|
|
194
|
-
// Add
|
|
279
|
+
// Add a P2PKH output (payment to ourselves)
|
|
280
|
+
tx.addOutput({
|
|
281
|
+
lockingScript: new P2PKH().lock(address),
|
|
282
|
+
satoshis: 500
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
// Add an OP_RETURN data output
|
|
286
|
+
tx.addOutput({
|
|
287
|
+
lockingScript: Script.fromASM('OP_RETURN 48656c6c6f20426974636f696e21'), // "Hello Bitcoin!" in hex
|
|
288
|
+
satoshis: 0
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
// Add change output
|
|
195
292
|
tx.addOutput({
|
|
196
293
|
lockingScript: new P2PKH().lock(address),
|
|
197
|
-
|
|
294
|
+
change: true // Automatically calculates change amount after fees
|
|
198
295
|
})
|
|
199
296
|
|
|
200
|
-
console.log('
|
|
201
|
-
console.log(
|
|
202
|
-
console.log(
|
|
203
|
-
console.log(
|
|
204
|
-
console.log(
|
|
297
|
+
console.log('Transaction structure created:')
|
|
298
|
+
console.log(`- Inputs: ${tx.inputs.length}`)
|
|
299
|
+
console.log(`- Outputs: ${tx.outputs.length}`)
|
|
300
|
+
console.log(`- Input amount: 1000 satoshis`)
|
|
301
|
+
console.log(`- Payment output: 500 satoshis`)
|
|
302
|
+
console.log(`- Data output: 0 satoshis (OP_RETURN)`)
|
|
303
|
+
console.log(`- Change output: Will be calculated automatically`)
|
|
304
|
+
|
|
305
|
+
// 3. Calculate fees and finalize the transaction
|
|
306
|
+
console.log('\n3. Fee Calculation and Signing:')
|
|
307
|
+
|
|
308
|
+
// Calculate appropriate fees based on transaction size
|
|
309
|
+
await tx.fee()
|
|
205
310
|
|
|
206
|
-
//
|
|
311
|
+
// Display fee information
|
|
312
|
+
const changeOutput = tx.outputs.find(output => output.change)
|
|
313
|
+
if (changeOutput && changeOutput.satoshis !== undefined) {
|
|
314
|
+
console.log(`Fee calculated: ${1000 - 500 - changeOutput.satoshis} satoshis`)
|
|
315
|
+
console.log(`Change amount: ${changeOutput.satoshis} satoshis`)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Sign the transaction
|
|
319
|
+
console.log('\nSigning transaction...')
|
|
207
320
|
await tx.sign()
|
|
208
321
|
|
|
209
|
-
|
|
322
|
+
// 4. Examine the signed transaction
|
|
323
|
+
console.log('\n4. Transaction Analysis:')
|
|
210
324
|
console.log(`Transaction ID: ${Buffer.from(tx.id()).toString('hex')}`)
|
|
211
|
-
console.log(`First input has unlocking script: ${tx.inputs[0].unlockingScript ? 'Yes' : 'No'}`)
|
|
212
325
|
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
326
|
+
// Check if the input has been properly signed
|
|
327
|
+
const input = tx.inputs[0]
|
|
328
|
+
if (input.unlockingScript) {
|
|
329
|
+
const unlockingASM = input.unlockingScript.toASM()
|
|
330
|
+
console.log(`\nUnlocking Script (ASM): ${unlockingASM}`)
|
|
331
|
+
|
|
332
|
+
// Parse the signature and public key from the unlocking script
|
|
333
|
+
const scriptParts = unlockingASM.split(' ')
|
|
334
|
+
if (scriptParts.length >= 2) {
|
|
335
|
+
console.log(`- Signature present: ✓ (${scriptParts[0].length} chars)`)
|
|
336
|
+
console.log(`- Public key present: ✓ (${scriptParts[1].length} chars)`)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// 5. Verify the transaction
|
|
341
|
+
console.log('\n5. Transaction Verification:')
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
const isValid = await tx.verify()
|
|
345
|
+
console.log(`Transaction verification: ${isValid ? 'Valid ✓' : 'Invalid ✗'}`)
|
|
346
|
+
|
|
347
|
+
if (isValid) {
|
|
348
|
+
console.log('\n✓ Transaction is properly constructed and signed!')
|
|
349
|
+
console.log('✓ All inputs have valid signatures')
|
|
350
|
+
console.log('✓ All outputs have valid locking scripts')
|
|
351
|
+
console.log('✓ Fee calculation is correct')
|
|
352
|
+
}
|
|
353
|
+
} catch (error: any) {
|
|
354
|
+
console.log(`Verification error: ${error.message}`)
|
|
216
355
|
}
|
|
217
356
|
|
|
218
|
-
//
|
|
357
|
+
// 6. Display transaction hex
|
|
219
358
|
const txHex = tx.toHex()
|
|
220
|
-
console.log(
|
|
359
|
+
console.log('\n6. Transaction Serialization:')
|
|
360
|
+
console.log(`Transaction size: ${txHex.length / 2} bytes`)
|
|
361
|
+
console.log(`Transaction hex (first 100 chars): ${txHex.substring(0, 100)}...`)
|
|
221
362
|
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
console.log(
|
|
225
|
-
|
|
226
|
-
|
|
363
|
+
// 7. Demonstrate transaction structure analysis
|
|
364
|
+
console.log('\n7. Transaction Structure Analysis:')
|
|
365
|
+
console.log('Outputs breakdown:')
|
|
366
|
+
tx.outputs.forEach((output, index) => {
|
|
367
|
+
const script = output.lockingScript
|
|
368
|
+
let scriptType = 'Unknown'
|
|
369
|
+
|
|
370
|
+
if (script.toASM().startsWith('OP_DUP OP_HASH160')) {
|
|
371
|
+
scriptType = 'P2PKH (Pay-to-Public-Key-Hash)'
|
|
372
|
+
} else if (script.toASM().startsWith('OP_RETURN')) {
|
|
373
|
+
scriptType = 'OP_RETURN (Data)'
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
console.log(` Output ${index}: ${output.satoshis} satoshis - ${scriptType}`)
|
|
377
|
+
if (output.change) {
|
|
378
|
+
console.log(` (Change output)`)
|
|
379
|
+
}
|
|
380
|
+
})
|
|
381
|
+
|
|
382
|
+
console.log('\n✓ Low-level transaction signing demonstration complete!')
|
|
383
|
+
console.log('This transaction demonstrates:')
|
|
384
|
+
console.log('- Proper input/output construction')
|
|
385
|
+
console.log('- Automatic fee calculation')
|
|
386
|
+
console.log('- Digital signature creation and verification')
|
|
387
|
+
console.log('- Multiple output types (P2PKH + OP_RETURN)')
|
|
388
|
+
console.log('- Change handling')
|
|
227
389
|
}
|
|
228
390
|
|
|
229
|
-
// Run
|
|
230
|
-
|
|
391
|
+
// Run the demonstration
|
|
392
|
+
lowLevelTransactionDemo().catch(console.error)
|
|
231
393
|
```
|
|
232
394
|
|
|
233
395
|
### Key Benefits of the Low-level Approach
|
|
@@ -241,7 +403,7 @@ transactionSigningDemo().catch(console.error)
|
|
|
241
403
|
|
|
242
404
|
Consider the following factors when deciding which approach to use:
|
|
243
405
|
|
|
244
|
-
| Factor | WalletClient Approach | Low-level Approach |
|
|
406
|
+
| Factor | `WalletClient` Approach | Low-level Approach |
|
|
245
407
|
|--------|----------------------|-------------------|
|
|
246
408
|
| Security | Higher (keys managed by wallet) | Lower (direct key handling) |
|
|
247
409
|
| Complexity | Lower (abstracted API) | Higher (manual transaction construction) |
|
|
@@ -249,17 +411,6 @@ Consider the following factors when deciding which approach to use:
|
|
|
249
411
|
| Use Case | Production applications | Educational, specialized applications |
|
|
250
412
|
| Integration | Better for enterprise systems | Better for custom implementations |
|
|
251
413
|
|
|
252
|
-
## Best Practices
|
|
253
|
-
|
|
254
|
-
Regardless of which approach you choose, follow these best practices:
|
|
255
|
-
|
|
256
|
-
1. **Never expose private keys**: Keep private keys secure and never expose them in logs or user interfaces
|
|
257
|
-
2. **Test thoroughly**: Always test transaction signing in a test environment before production
|
|
258
|
-
3. **Verify signatures**: Always verify signatures after signing to ensure transaction validity
|
|
259
|
-
4. **Handle errors gracefully**: Implement proper error handling for signing failures
|
|
260
|
-
5. **Consider SIGHASH flags**: Use appropriate signature hash types for your use case
|
|
261
|
-
6. **Document key management**: Maintain clear documentation of your key management approach
|
|
262
|
-
|
|
263
414
|
## Related Resources
|
|
264
415
|
|
|
265
416
|
- [Key Management and Cryptography Tutorial](../tutorials/key-management.md)
|
package/docs/index.md
CHANGED
|
@@ -36,8 +36,6 @@ Complete technical specifications and API documentation:
|
|
|
36
36
|
- [Transaction](./reference/transaction.md)
|
|
37
37
|
- [View all references →](./reference/index.md)
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
39
|
### [🏗️ Concepts & Explanations](./concepts/index.md)
|
|
42
40
|
|
|
43
41
|
Understanding the architecture and design principles:
|
|
@@ -50,6 +50,7 @@ interface NetworkConfig {
|
|
|
50
50
|
### Predefined Networks
|
|
51
51
|
|
|
52
52
|
#### Mainnet Configuration
|
|
53
|
+
|
|
53
54
|
```typescript
|
|
54
55
|
const MAINNET_CONFIG: NetworkConfig = {
|
|
55
56
|
name: 'mainnet',
|
|
@@ -76,6 +77,7 @@ const MAINNET_CONFIG: NetworkConfig = {
|
|
|
76
77
|
```
|
|
77
78
|
|
|
78
79
|
#### Testnet Configuration
|
|
80
|
+
|
|
79
81
|
```typescript
|
|
80
82
|
const TESTNET_CONFIG: NetworkConfig = {
|
|
81
83
|
name: 'testnet',
|
|
@@ -101,6 +103,7 @@ const TESTNET_CONFIG: NetworkConfig = {
|
|
|
101
103
|
```
|
|
102
104
|
|
|
103
105
|
#### Regtest Configuration
|
|
106
|
+
|
|
104
107
|
```typescript
|
|
105
108
|
const REGTEST_CONFIG: NetworkConfig = {
|
|
106
109
|
name: 'regtest',
|
|
@@ -808,18 +811,21 @@ function validateConfig(config: SDKConfig): string[] {
|
|
|
808
811
|
### Environment-Specific Settings
|
|
809
812
|
|
|
810
813
|
#### Development
|
|
814
|
+
|
|
811
815
|
- Use testnet or regtest networks
|
|
812
816
|
- Enable debug logging
|
|
813
817
|
- Shorter timeouts for faster feedback
|
|
814
818
|
- Disable strict validation for testing
|
|
815
819
|
|
|
816
820
|
#### Staging
|
|
821
|
+
|
|
817
822
|
- Mirror production configuration
|
|
818
823
|
- Enable comprehensive logging
|
|
819
824
|
- Use production-like endpoints
|
|
820
825
|
- Enable all validation checks
|
|
821
826
|
|
|
822
827
|
#### Production
|
|
828
|
+
|
|
823
829
|
- Use mainnet network
|
|
824
830
|
- Minimal logging (warn/error only)
|
|
825
831
|
- Longer timeouts for reliability
|
|
@@ -667,23 +667,27 @@ const testDebugConfig = {
|
|
|
667
667
|
### Debug Checklist
|
|
668
668
|
|
|
669
669
|
1. **Enable appropriate logging level**
|
|
670
|
+
|
|
670
671
|
```typescript
|
|
671
672
|
// Set debug level based on issue severity
|
|
672
673
|
const config = { logging: { level: 'debug' } }
|
|
673
674
|
```
|
|
674
675
|
|
|
675
676
|
2. **Check network connectivity**
|
|
677
|
+
|
|
676
678
|
```typescript
|
|
677
679
|
NetworkInspector.startRequest('health-check', 'https://api.whatsonchain.com/v1/bsv/main/chain/info', 'GET')
|
|
678
680
|
```
|
|
679
681
|
|
|
680
682
|
3. **Validate transaction structure**
|
|
683
|
+
|
|
681
684
|
```typescript
|
|
682
685
|
const analysis = TransactionAnalyzer.analyze(transaction)
|
|
683
686
|
console.log('Transaction Analysis:', analysis)
|
|
684
687
|
```
|
|
685
688
|
|
|
686
689
|
4. **Monitor performance**
|
|
690
|
+
|
|
687
691
|
```typescript
|
|
688
692
|
PerformanceMonitor.startTimer('wallet-operation')
|
|
689
693
|
// ... perform operation
|
|
@@ -691,6 +695,7 @@ const testDebugConfig = {
|
|
|
691
695
|
```
|
|
692
696
|
|
|
693
697
|
5. **Check memory usage**
|
|
698
|
+
|
|
694
699
|
```typescript
|
|
695
700
|
MemoryMonitor.logMemoryUsage('before-operation')
|
|
696
701
|
// ... perform operation
|