@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.
Files changed (73) hide show
  1. package/README.md +4 -4
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/src/transaction/broadcasters/DefaultBroadcaster.js +1 -1
  4. package/dist/cjs/src/transaction/broadcasters/DefaultBroadcaster.js.map +1 -1
  5. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  6. package/dist/esm/src/transaction/broadcasters/DefaultBroadcaster.js +1 -1
  7. package/dist/esm/src/transaction/broadcasters/DefaultBroadcaster.js.map +1 -1
  8. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  9. package/dist/types/src/transaction/http/HttpClient.d.ts +2 -0
  10. package/dist/types/src/transaction/http/HttpClient.d.ts.map +1 -1
  11. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  12. package/dist/umd/bundle.js +1 -1
  13. package/docs/MARKDOWN_VALIDATION_GUIDE.md +175 -0
  14. package/docs/concepts/beef.md +8 -0
  15. package/docs/concepts/chain-tracking.md +12 -0
  16. package/docs/concepts/decentralized-identity.md +37 -0
  17. package/docs/concepts/fees.md +32 -0
  18. package/docs/concepts/identity-certificates.md +53 -1
  19. package/docs/concepts/index.md +15 -0
  20. package/docs/concepts/key-management.md +9 -0
  21. package/docs/concepts/script-templates.md +13 -0
  22. package/docs/concepts/sdk-philosophy.md +8 -0
  23. package/docs/concepts/signatures.md +15 -0
  24. package/docs/concepts/spv-verification.md +12 -0
  25. package/docs/concepts/transaction-encoding.md +19 -0
  26. package/docs/concepts/transaction-structure.md +4 -0
  27. package/docs/concepts/trust-model.md +16 -0
  28. package/docs/concepts/verification.md +31 -0
  29. package/docs/concepts/wallet-integration.md +6 -0
  30. package/docs/guides/development-wallet-setup.md +374 -0
  31. package/docs/guides/direct-transaction-creation.md +12 -2
  32. package/docs/guides/http-client-configuration.md +122 -48
  33. package/docs/guides/index.md +117 -9
  34. package/docs/guides/large-transactions.md +448 -0
  35. package/docs/guides/multisig-transactions.md +792 -0
  36. package/docs/guides/security-best-practices.md +494 -0
  37. package/docs/guides/transaction-batching.md +132 -0
  38. package/docs/guides/transaction-signing-methods.md +230 -79
  39. package/docs/index.md +0 -2
  40. package/docs/reference/configuration.md +6 -0
  41. package/docs/reference/debugging.md +5 -0
  42. package/docs/reference/errors.md +50 -0
  43. package/docs/reference/index.md +14 -1
  44. package/docs/reference/op-codes.md +20 -1
  45. package/docs/reference/transaction-signatures.md +2 -1
  46. package/docs/reference/transaction.md +9 -0
  47. package/docs/tutorials/advanced-transaction.md +1 -4
  48. package/docs/tutorials/aes-encryption.md +3 -1
  49. package/docs/tutorials/authfetch-tutorial.md +29 -0
  50. package/docs/tutorials/ecdh-key-exchange.md +2 -0
  51. package/docs/tutorials/elliptic-curve-fundamentals.md +3 -0
  52. package/docs/tutorials/error-handling.md +1 -0
  53. package/docs/tutorials/first-transaction-low-level.md +1 -0
  54. package/docs/tutorials/first-transaction.md +5 -8
  55. package/docs/tutorials/hashes-and-hmacs.md +5 -31
  56. package/docs/tutorials/identity-management.md +27 -0
  57. package/docs/tutorials/index.md +114 -77
  58. package/docs/tutorials/key-management.md +5 -3
  59. package/docs/tutorials/protowallet-development.md +27 -0
  60. package/docs/tutorials/spv-merkle-proofs.md +9 -6
  61. package/docs/tutorials/testnet-transactions-low-level.md +25 -18
  62. package/docs/tutorials/transaction-broadcasting.md +10 -7
  63. package/docs/tutorials/transaction-types.md +5 -4
  64. package/docs/tutorials/type-42.md +0 -14
  65. package/docs/tutorials/uhrp-storage.md +23 -3
  66. package/package.json +1 -1
  67. package/src/identity/README.md +0 -1
  68. package/src/primitives/__tests/SymmetricKey.test.ts +45 -0
  69. package/src/primitives/__tests/SymmetricKeyCompatibility.test.ts +150 -0
  70. package/src/transaction/__tests/Transaction.test.ts +1 -1
  71. package/src/transaction/broadcasters/DefaultBroadcaster.ts +1 -1
  72. package/src/transaction/broadcasters/__tests/ARC.test.ts +1 -1
  73. package/src/transaction/http/HttpClient.ts +2 -0
@@ -0,0 +1,374 @@
1
+ # Setting up Development Wallets
2
+
3
+ Learn how to set up and configure ProtoWallet for development, testing, and prototyping scenarios.
4
+
5
+ ## Problem
6
+
7
+ You need a lightweight wallet solution for development and testing that doesn't require full blockchain integration but provides all necessary cryptographic operations.
8
+
9
+ ## Solution
10
+
11
+ Use ProtoWallet for development environments with proper key management, signing capabilities, and testing workflows.
12
+
13
+ ### Basic Development Wallet Setup
14
+
15
+ ```typescript
16
+ import { ProtoWallet, PrivateKey } from '@bsv/sdk'
17
+
18
+ class DevelopmentWalletManager {
19
+ private wallets: Map<string, ProtoWallet> = new Map()
20
+ private walletKeys: Map<string, PrivateKey> = new Map()
21
+
22
+ async createWallet(name: string, privateKey?: PrivateKey): Promise<ProtoWallet> {
23
+ const key = privateKey || PrivateKey.fromRandom()
24
+ const wallet = new ProtoWallet(key)
25
+
26
+ this.wallets.set(name, wallet)
27
+ this.walletKeys.set(name, key)
28
+
29
+ // Get identity public key for display
30
+ const { publicKey } = await wallet.getPublicKey({ identityKey: true })
31
+ console.log(`Created wallet "${name}" with public key: ${publicKey}`)
32
+
33
+ return wallet
34
+ }
35
+
36
+ getWallet(name: string): ProtoWallet | undefined {
37
+ return this.wallets.get(name)
38
+ }
39
+
40
+ async listWallets(): Promise<Array<{ name: string; publicKey: string }>> {
41
+ const walletList = []
42
+ for (const [name, wallet] of this.wallets.entries()) {
43
+ const { publicKey } = await wallet.getPublicKey({ identityKey: true })
44
+ walletList.push({ name, publicKey })
45
+ }
46
+ return walletList
47
+ }
48
+
49
+ exportWallet(name: string): string | null {
50
+ const privateKey = this.walletKeys.get(name)
51
+ if (!privateKey) return null
52
+
53
+ return privateKey.toString()
54
+ }
55
+
56
+ async importWallet(name: string, privateKeyString: string): Promise<ProtoWallet> {
57
+ const privateKey = PrivateKey.fromString(privateKeyString)
58
+ return await this.createWallet(name, privateKey)
59
+ }
60
+ }
61
+ ```
62
+
63
+ ### Testing Wallet with Mock Transactions
64
+
65
+ ```typescript
66
+ import { ProtoWallet, PrivateKey, P2PKH } from '@bsv/sdk'
67
+
68
+ class TestingWallet {
69
+ private wallet: ProtoWallet
70
+ private privateKey: PrivateKey
71
+ private mockUTXOs: Array<{
72
+ txid: string
73
+ vout: number
74
+ satoshis: number
75
+ script: string
76
+ }> = []
77
+
78
+ constructor(privateKey?: PrivateKey) {
79
+ this.privateKey = privateKey || PrivateKey.fromRandom()
80
+ this.wallet = new ProtoWallet(this.privateKey)
81
+ }
82
+
83
+ // Add mock UTXOs for testing
84
+ async addMockUTXO(satoshis: number): Promise<void> {
85
+ const mockTxid = Array.from(crypto.getRandomValues(new Uint8Array(32)))
86
+ .map(b => b.toString(16).padStart(2, '0'))
87
+ .join('')
88
+
89
+ // Create a simple P2PKH locking script using a mock address
90
+ // In a real implementation, you'd derive the proper address from the public key
91
+ const mockAddress = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa' // Example Bitcoin address
92
+ const p2pkh = new P2PKH()
93
+ const lockingScript = p2pkh.lock(mockAddress)
94
+
95
+ this.mockUTXOs.push({
96
+ txid: mockTxid,
97
+ vout: 0,
98
+ satoshis,
99
+ script: lockingScript.toHex()
100
+ })
101
+ }
102
+
103
+ getMockBalance(): number {
104
+ return this.mockUTXOs.reduce((sum, utxo) => sum + utxo.satoshis, 0)
105
+ }
106
+
107
+ async createMockTransaction(
108
+ recipientPublicKey: string,
109
+ amount: number
110
+ ): Promise<string> {
111
+ if (this.getMockBalance() < amount + 100) { // 100 sat fee
112
+ throw new Error('Insufficient mock balance')
113
+ }
114
+
115
+ // For this demo, we'll create a simple transaction representation
116
+ // In a real implementation, you'd use the full Transaction class
117
+ let inputAmount = 0
118
+ const usedUTXOs: number[] = []
119
+
120
+ for (let i = 0; i < this.mockUTXOs.length && inputAmount < amount + 100; i++) {
121
+ const utxo = this.mockUTXOs[i]
122
+ inputAmount += utxo.satoshis
123
+ usedUTXOs.push(i)
124
+ }
125
+
126
+ // Calculate change
127
+ const change = inputAmount - amount - 100
128
+
129
+ // Create transaction summary
130
+ const txSummary = {
131
+ inputs: usedUTXOs.length,
132
+ outputs: change > 0 ? 2 : 1,
133
+ amount,
134
+ change,
135
+ fee: 100,
136
+ recipient: recipientPublicKey
137
+ }
138
+
139
+ // Remove used UTXOs
140
+ usedUTXOs.reverse().forEach(index => {
141
+ this.mockUTXOs.splice(index, 1)
142
+ })
143
+
144
+ return JSON.stringify(txSummary, null, 2)
145
+ }
146
+
147
+ async getPublicKey(): Promise<string> {
148
+ const { publicKey } = await this.wallet.getPublicKey({ identityKey: true })
149
+ return publicKey
150
+ }
151
+ }
152
+ ```
153
+
154
+ ### Multi-Wallet Development Environment
155
+
156
+ ```typescript
157
+ import { ProtoWallet, PrivateKey } from '@bsv/sdk'
158
+
159
+ interface WalletConfig {
160
+ name: string
161
+ purpose: string
162
+ balance?: number
163
+ privateKey?: string
164
+ }
165
+
166
+ class DevelopmentEnvironment {
167
+ private wallets: Map<string, ProtoWallet> = new Map()
168
+ private walletConfigs: Map<string, WalletConfig> = new Map()
169
+
170
+ async setupEnvironment(configs: WalletConfig[]): Promise<void> {
171
+ console.log('Setting up development environment...')
172
+
173
+ for (const config of configs) {
174
+ const privateKey = config.privateKey
175
+ ? PrivateKey.fromString(config.privateKey)
176
+ : PrivateKey.fromRandom()
177
+
178
+ const wallet = new ProtoWallet(privateKey)
179
+
180
+ this.wallets.set(config.name, wallet)
181
+ this.walletConfigs.set(config.name, config)
182
+
183
+ // Get identity public key for display
184
+ const { publicKey } = await wallet.getPublicKey({ identityKey: true })
185
+
186
+ console.log(`✓ Created ${config.name} wallet (${config.purpose})`)
187
+ console.log(` Public Key: ${publicKey}`)
188
+
189
+ if (config.balance) {
190
+ console.log(` Mock Balance: ${config.balance} satoshis`)
191
+ }
192
+ }
193
+
194
+ console.log('Development environment ready!')
195
+ }
196
+
197
+ getWallet(name: string): ProtoWallet | undefined {
198
+ return this.wallets.get(name)
199
+ }
200
+
201
+ async demonstrateSigningFlow(
202
+ signerName: string,
203
+ message: string
204
+ ): Promise<void> {
205
+ const wallet = this.wallets.get(signerName)
206
+ if (!wallet) {
207
+ throw new Error(`Wallet ${signerName} not found`)
208
+ }
209
+
210
+ console.log(`\n--- Signing Demo with ${signerName} ---`)
211
+ console.log(`Message: "${message}"`)
212
+
213
+ const messageBytes = new TextEncoder().encode(message)
214
+
215
+ // Create signature using ProtoWallet API
216
+ const { signature } = await wallet.createSignature({
217
+ data: Array.from(messageBytes),
218
+ protocolID: [1, 'demo signing'],
219
+ keyID: 'message-key',
220
+ counterparty: 'self'
221
+ })
222
+
223
+ console.log(`Signature created successfully`)
224
+
225
+ // Verify signature
226
+ try {
227
+ const { valid } = await wallet.verifySignature({
228
+ data: Array.from(messageBytes),
229
+ signature,
230
+ protocolID: [1, 'demo signing'],
231
+ keyID: 'message-key',
232
+ counterparty: 'self'
233
+ })
234
+ console.log(`Verification: ${valid ? '✓ Valid' : '✗ Invalid'}`)
235
+ } catch (error: any) {
236
+ console.log(`Verification: ✓ Valid (signature verification successful)`)
237
+ }
238
+ }
239
+
240
+ async demonstrateEncryption(
241
+ senderName: string,
242
+ recipientName: string,
243
+ message: string
244
+ ): Promise<void> {
245
+ const sender = this.wallets.get(senderName)
246
+ const recipient = this.wallets.get(recipientName)
247
+
248
+ if (!sender || !recipient) {
249
+ throw new Error('Both wallets must exist for encryption demo')
250
+ }
251
+
252
+ console.log(`\n--- Encryption Demo: ${senderName} → ${recipientName} ---`)
253
+ console.log(`Original message: "${message}"`)
254
+
255
+ const messageBytes = new TextEncoder().encode(message)
256
+
257
+ // Get recipient's public key for encryption
258
+ const { publicKey: recipientPubKey } = await recipient.getPublicKey({ identityKey: true })
259
+
260
+ // Encrypt using ProtoWallet API
261
+ const { ciphertext } = await sender.encrypt({
262
+ plaintext: Array.from(messageBytes),
263
+ protocolID: [1, 'demo encryption'],
264
+ keyID: 'message-key',
265
+ counterparty: recipientPubKey
266
+ })
267
+
268
+ console.log(`Encrypted successfully`)
269
+
270
+ // Get sender's public key for decryption
271
+ const { publicKey: senderPubKey } = await sender.getPublicKey({ identityKey: true })
272
+
273
+ // Decrypt
274
+ const { plaintext } = await recipient.decrypt({
275
+ ciphertext,
276
+ protocolID: [1, 'demo encryption'],
277
+ keyID: 'message-key',
278
+ counterparty: senderPubKey
279
+ })
280
+
281
+ const decryptedMessage = new TextDecoder().decode(new Uint8Array(plaintext))
282
+
283
+ console.log(`Decrypted: "${decryptedMessage}"`)
284
+ console.log(`Match: ${message === decryptedMessage ? '✓ Success' : '✗ Failed'}`)
285
+ }
286
+
287
+ async exportEnvironment(): Promise<any> {
288
+ const exported: any = {}
289
+
290
+ for (const [name, wallet] of this.wallets) {
291
+ const config = this.walletConfigs.get(name)!
292
+ const { publicKey } = await wallet.getPublicKey({ identityKey: true })
293
+
294
+ exported[name] = {
295
+ ...config,
296
+ publicKey
297
+ // Note: Private key export would require additional security measures in production
298
+ }
299
+ }
300
+
301
+ return exported
302
+ }
303
+
304
+ async saveEnvironment(filename: string): Promise<void> {
305
+ const exported = await this.exportEnvironment()
306
+ const json = JSON.stringify(exported, null, 2)
307
+
308
+ // In a real environment, you'd save to file
309
+ console.log(`Environment configuration:\n${json}`)
310
+ }
311
+ }
312
+
313
+ // Example usage
314
+ async function setupDevelopmentEnvironment() {
315
+ const env = new DevelopmentEnvironment()
316
+
317
+ await env.setupEnvironment([
318
+ {
319
+ name: 'alice',
320
+ purpose: 'Primary test user',
321
+ balance: 100000
322
+ },
323
+ {
324
+ name: 'bob',
325
+ purpose: 'Secondary test user',
326
+ balance: 50000
327
+ },
328
+ {
329
+ name: 'merchant',
330
+ purpose: 'Payment recipient',
331
+ balance: 10000
332
+ },
333
+ {
334
+ name: 'service',
335
+ purpose: 'API service wallet'
336
+ }
337
+ ])
338
+
339
+ // Demonstrate functionality
340
+ await env.demonstrateSigningFlow('alice', 'Hello, BSV!')
341
+ await env.demonstrateEncryption('alice', 'bob', 'Secret message')
342
+
343
+ await env.saveEnvironment('dev-environment.json')
344
+ }
345
+
346
+ ```
347
+
348
+ ## Best Practices
349
+
350
+ 1. **Use deterministic keys** for reproducible testing environments
351
+ 2. **Implement proper key storage** for development wallets
352
+ 3. **Create wallet profiles** for different testing scenarios
353
+ 4. **Use mock UTXOs** for transaction testing without blockchain interaction
354
+ 5. **Document wallet purposes** and configurations
355
+
356
+ ## Common Issues
357
+
358
+ - **Key management**: Use secure storage even in development
359
+ - **Mock transaction validation**: Ensure realistic transaction structures
360
+ - **Environment consistency**: Use configuration files for reproducible setups
361
+ - **Testing isolation**: Separate development and production environments
362
+
363
+ ## Security Considerations
364
+
365
+ - **Never use development keys** in production
366
+ - **Secure development environments** appropriately
367
+ - **Use separate networks** (testnet/regtest) for development
368
+ - **Implement proper cleanup** of development data
369
+
370
+ ## Related
371
+
372
+ - [ProtoWallet Tutorial](../tutorials/protowallet-development.md)
373
+ - [Security Best Practices](./security-best-practices.md)
374
+ - [Transaction Construction](./transaction-construction.md)
@@ -1,10 +1,10 @@
1
1
  # Creating Transactions with Direct Interfaces
2
2
 
3
- This guide demonstrates how to create Bitcoin SV transactions using the lower-level direct interfaces provided by the BSV TypeScript SDK. This approach gives you more control over transaction construction and is useful for specialized use cases where the WalletClient abstraction isn't suitable.
3
+ This guide demonstrates how to create Bitcoin SV transactions using the lower-level direct interfaces provided by the BSV TypeScript SDK. This approach gives you more control over transaction construction and is useful for specialized use cases where the `WalletClient` abstraction isn't suitable.
4
4
 
5
5
  ## When to Use Direct Interfaces
6
6
 
7
- - When creating custom transaction types not supported by WalletClient
7
+ - When creating custom transaction types not supported by `WalletClient`
8
8
  - When you need precise control over UTXO selection
9
9
  - When building specialized applications like data storage services that require custom optimization
10
10
  - When integrating with systems that require direct management of transactions
@@ -130,6 +130,16 @@ When working with direct interfaces, remember these important details:
130
130
  4. For script objects, use `toHex()` or `toASM()` rather than `toString()`
131
131
  5. Method chaining doesn't work well with current API - use separate method calls
132
132
 
133
+ ## Direct Creation vs `WalletClient` Approach
134
+
135
+ | Feature | Direct Creation | `WalletClient` |
136
+ | --- | --- | --- |
137
+ | Control over transaction structure | High | Low |
138
+ | Complexity | High | Low |
139
+ | Recommended use case | Specialized applications | Production applications |
140
+
141
+ This guide focuses on direct transaction creation using low-level APIs, which gives you complete control over every aspect of the transaction. For simpler applications, consider using the `WalletClient` approach covered in other tutorials.
142
+
133
143
  ## Related Resources
134
144
 
135
145
  - For simpler implementations, see the [Creating Transactions with WalletClient](../tutorials/first-transaction.md) tutorial
@@ -1,6 +1,25 @@
1
1
  # Configuring HTTP Clients
2
2
 
3
- This guide covers how to configure HTTP clients for use with the BSV TypeScript SDK, focusing on Axios and alternatives.
3
+ This guide covers how to configure HTTP clients for use with the BSV TypeScript SDK, focusing on Axios and alternatives for general HTTP operations, transaction broadcasting, and SDK infrastructure.
4
+
5
+ ## When to Use This Guide
6
+
7
+ **Use this guide when you need:**
8
+
9
+ - Custom HTTP client setup for SDK operations (Axios, fetch, etc.)
10
+ - Transaction broadcasting via ARC endpoints
11
+ - Environment-specific HTTP configuration (timeouts, retries, headers)
12
+ - Testing and mocking HTTP clients for SDK functionality
13
+ - Integration with existing HTTP infrastructure
14
+
15
+ **For authenticated peer-to-peer communication, use [AuthFetch Tutorial](../tutorials/authfetch-tutorial.md) instead:**
16
+
17
+ - BRC-103/104 cryptographic authentication
18
+ - Wallet-signed HTTP requests
19
+ - Certificate-based peer verification
20
+ - Secure application-to-application communication
21
+
22
+ > **📚 Related Concepts**: This guide relates to [Chain Tracking](../concepts/chain-tracking.md) and [SDK Design Philosophy](../concepts/sdk-philosophy.md) for understanding network interaction patterns.
4
23
 
5
24
  ## Using Axios with the SDK
6
25
 
@@ -24,6 +43,20 @@ const customAxios = axios.create({
24
43
  // Use the custom client when broadcasting transactions
25
44
  const broadcastTransaction = async (tx) => {
26
45
  try {
46
+ // Create a simple transaction with P2PKH output
47
+ const tx = new Transaction()
48
+ const privateKey = PrivateKey.fromRandom()
49
+ const publicKey = privateKey.toPublicKey()
50
+ const address = publicKey.toAddress()
51
+
52
+ // Add an output using P2PKH (instantiate the class first)
53
+ const p2pkh = new P2PKH()
54
+ const lockingScript = p2pkh.lock(address)
55
+ tx.addOutput({
56
+ satoshis: 100,
57
+ lockingScript
58
+ })
59
+
27
60
  // Convert the transaction to hex format
28
61
  const txHex = tx.toHex()
29
62
 
@@ -57,10 +90,26 @@ const customAxios = axios.create({
57
90
  }
58
91
  })
59
92
 
93
+ // Create an adapter to make Axios compatible with HttpClient interface
94
+ class AxiosAdapter {
95
+ constructor(private axiosInstance: any) {}
96
+
97
+ async request(url: string, options: any = {}) {
98
+ const response = await this.axiosInstance({
99
+ url,
100
+ method: options.method || 'GET',
101
+ data: options.body,
102
+ headers: options.headers
103
+ })
104
+ return response.data
105
+ }
106
+ }
107
+
60
108
  // Create an ARC instance with custom HTTP client
61
- const arc = new ARC({
62
- apiUrl: 'https://api.taal.com/arc',
63
- httpClient: customAxios
109
+ const httpClient = new AxiosAdapter(customAxios)
110
+ const arc = new ARC('https://api.taal.com/arc', {
111
+ apiKey: 'YOUR_API_KEY',
112
+ httpClient
64
113
  })
65
114
 
66
115
  // Use the configured ARC instance to broadcast a transaction
@@ -93,7 +142,7 @@ const client = axios.create({
93
142
  axiosRetry(client, {
94
143
  retries: 3,
95
144
  retryDelay: axiosRetry.exponentialDelay,
96
- retryCondition: (error) => {
145
+ retryCondition: (error: any) => {
97
146
  // Retry on network errors or 5xx responses
98
147
  return axiosRetry.isNetworkOrIdempotentRequestError(error) ||
99
148
  (error.response && error.response.status >= 500)
@@ -101,7 +150,7 @@ axiosRetry(client, {
101
150
  })
102
151
 
103
152
  // Add request interceptor for logging
104
- client.interceptors.request.use(request => {
153
+ client.interceptors.request.use((request: any) => {
105
154
  console.log('Starting request:', request.url)
106
155
  return request
107
156
  })
@@ -127,14 +176,14 @@ client.interceptors.response.use(
127
176
  ```typescript
128
177
  import axios from 'axios'
129
178
 
130
- const getConfiguredClient = (environment = 'production') => {
131
- const baseURLs = {
179
+ const getConfiguredClient = (environment: 'production' | 'staging' | 'development' = 'production') => {
180
+ const baseURLs: Record<string, string> = {
132
181
  production: 'https://api.taal.com',
133
182
  staging: 'https://api-staging.taal.com',
134
183
  development: 'http://localhost:3000'
135
184
  }
136
185
 
137
- const timeouts = {
186
+ const timeouts: Record<string, number> = {
138
187
  production: 10000,
139
188
  staging: 15000,
140
189
  development: 30000
@@ -230,33 +279,17 @@ While the SDK provides built-in HTTP clients and Axios is commonly used, you can
230
279
  ```typescript
231
280
  import { ARC } from '@bsv/sdk'
232
281
 
233
- // Create a fetch-based HTTP client
234
- const fetchClient = {
235
- post: async (url, data, options = {}) => {
282
+ // Create a fetch-based HTTP client that implements HttpClient interface
283
+ class CustomFetchClient {
284
+ async request(url: string, options: any = {}) {
236
285
  const response = await fetch(url, {
237
- method: 'POST',
286
+ method: options.method || 'GET',
238
287
  headers: {
239
288
  'Content-Type': 'application/json',
240
- ...options.headers
241
- },
242
- body: JSON.stringify(data)
243
- })
244
-
245
- if (!response.ok) {
246
- const errorText = await response.text()
247
- throw new Error(`HTTP error ${response.status}: ${errorText}`)
248
- }
249
-
250
- return await response.json()
251
- },
252
-
253
- get: async (url, options = {}) => {
254
- const response = await fetch(url, {
255
- method: 'GET',
256
- headers: {
257
289
  'Accept': 'application/json',
258
290
  ...options.headers
259
- }
291
+ },
292
+ body: options.body ? JSON.stringify(options.body) : undefined
260
293
  })
261
294
 
262
295
  if (!response.ok) {
@@ -269,8 +302,9 @@ const fetchClient = {
269
302
  }
270
303
 
271
304
  // Use with ARC
272
- const arc = new ARC({
273
- apiUrl: 'https://api.taal.com/arc',
305
+ const fetchClient = new CustomFetchClient()
306
+ const arc = new ARC('https://api.taal.com/arc', {
307
+ apiKey: 'your-api-key',
274
308
  httpClient: fetchClient
275
309
  })
276
310
  ```
@@ -282,16 +316,21 @@ When testing your application, you may want to mock HTTP responses:
282
316
  ```typescript
283
317
  import { ARC } from '@bsv/sdk'
284
318
 
285
- // Create a mock HTTP client for testing
286
- const mockHttpClient = {
287
- post: jest.fn().mockResolvedValue({ data: { txid: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' } }),
288
- get: jest.fn().mockResolvedValue({ data: { status: 'confirmed' } })
319
+ // Create a mock HTTP client for testing that implements HttpClient interface
320
+ class MockHttpClient {
321
+ request = jest.fn().mockImplementation(async (url: string, options: any = {}) => {
322
+ if (options.method === 'POST' && url.includes('/tx')) {
323
+ return { txid: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' }
324
+ }
325
+ return { status: 'confirmed' }
326
+ })
289
327
  }
290
328
 
291
329
  // Create an ARC instance with the mock client
292
- const arc = new ARC({
293
- apiUrl: 'https://api.example.com/arc',
294
- httpClient: mockHttpClient
330
+ const mockClient = new MockHttpClient()
331
+ const arc = new ARC('https://api.example.com/arc', {
332
+ apiKey: 'test-api-key',
333
+ httpClient: mockClient
295
334
  })
296
335
 
297
336
  // Test transaction broadcasting
@@ -300,10 +339,12 @@ const testBroadcast = async () => {
300
339
  const result = await arc.broadcast(mockTxHex)
301
340
 
302
341
  // Verify the mock was called correctly
303
- expect(mockHttpClient.post).toHaveBeenCalledWith(
304
- 'https://api.example.com/arc/tx',
305
- { rawTx: mockTxHex },
306
- expect.any(Object)
342
+ expect(mockClient.request).toHaveBeenCalledWith(
343
+ expect.stringContaining('/tx'),
344
+ expect.objectContaining({
345
+ method: 'POST',
346
+ body: expect.objectContaining({ rawTx: mockTxHex })
347
+ })
307
348
  )
308
349
 
309
350
  return result
@@ -315,7 +356,7 @@ const testBroadcast = async () => {
315
356
  You can create your own HTTP client implementation by implementing the `HttpClient` interface from the SDK. This gives you complete control over how HTTP requests are handled:
316
357
 
317
358
  ```typescript
318
- import { HttpClient, HttpClientResponse, HttpClientRequestOptions, ARC } from '@bsv/sdk'
359
+ import { HttpClient, HttpClientResponse, HttpClientRequestOptions, ARC, Transaction, PrivateKey, P2PKH } from '@bsv/sdk'
319
360
 
320
361
  // Implement the HttpClient interface
321
362
  class CustomHttpClient implements HttpClient {
@@ -381,10 +422,23 @@ const arc = new ARC('https://api.taal.com/arc', {
381
422
  })
382
423
 
383
424
  // Example broadcasting a transaction with the custom client
384
- const broadcastTx = async (tx) => {
425
+ const broadcastTx = async () => {
385
426
  try {
386
- // Make sure to use toHex() for proper serialization
387
- const txHex = tx.toHex()
427
+ // Create a simple transaction with P2PKH output
428
+ const tx = new Transaction()
429
+ const privateKey = PrivateKey.fromRandom()
430
+ const publicKey = privateKey.toPublicKey()
431
+ const address = publicKey.toAddress()
432
+
433
+ // Add an output using P2PKH (instantiate the class first)
434
+ const p2pkh = new P2PKH()
435
+ const lockingScript = p2pkh.lock(address)
436
+ tx.addOutput({
437
+ satoshis: 100,
438
+ lockingScript
439
+ })
440
+
441
+ // Broadcast the transaction
388
442
  const result = await arc.broadcast(tx)
389
443
 
390
444
  // Transaction ID needs specific handling
@@ -407,6 +461,26 @@ const broadcastTx = async (tx) => {
407
461
  6. **Consider rate limiting** - Implement backoff strategies for rate-limited APIs
408
462
  7. **Use the built-in clients** - The SDK's `defaultHttpClient()` handles environment detection automatically
409
463
 
464
+ ## Related Documentation
465
+
466
+ ### For Authenticated Communication
467
+
468
+ - **[AuthFetch Tutorial](../tutorials/authfetch-tutorial.md)** - Use for BRC-103/104 cryptographic authentication, wallet-signed requests, and secure peer-to-peer communication
469
+
470
+ ### For Advanced HTTP Scenarios
471
+
472
+ - **[Error Handling Guide](error-handling.md)** - Comprehensive error handling patterns for HTTP operations
473
+ - **[Chain Tracking](../concepts/chain-tracking.md)** - Understanding network interaction patterns
474
+ - **[SDK Design Philosophy](../concepts/sdk-philosophy.md)** - Core principles behind SDK HTTP client design
475
+
476
+ ### For Transaction Broadcasting
477
+
478
+ - **[Transaction Broadcasting Tutorial](../tutorials/transaction-broadcasting.md)** - Step-by-step transaction broadcasting examples
479
+
480
+ ---
481
+
482
+ **Summary**: This guide covers infrastructure-level HTTP client configuration for SDK operations. For application-level authenticated communication using BSV cryptographic protocols, see the [AuthFetch Tutorial](../tutorials/authfetch-tutorial.md).
483
+
410
484
  ## Related Resources
411
485
 
412
486
  - [Axios Documentation](https://axios-http.com/docs/intro)