@bsv/sdk 1.9.2 → 1.9.4
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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/kvstore/GlobalKVStore.js +116 -98
- package/dist/cjs/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/cjs/src/kvstore/types.js.map +1 -1
- package/dist/cjs/src/overlay-tools/index.js +1 -0
- package/dist/cjs/src/overlay-tools/index.js.map +1 -1
- package/dist/cjs/src/overlay-tools/withDoubleSpendRetry.js +55 -0
- package/dist/cjs/src/overlay-tools/withDoubleSpendRetry.js.map +1 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/kvstore/GlobalKVStore.js +117 -99
- package/dist/esm/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/esm/src/kvstore/types.js.map +1 -1
- package/dist/esm/src/overlay-tools/index.js +1 -0
- package/dist/esm/src/overlay-tools/index.js.map +1 -1
- package/dist/esm/src/overlay-tools/withDoubleSpendRetry.js +48 -0
- package/dist/esm/src/overlay-tools/withDoubleSpendRetry.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/kvstore/GlobalKVStore.d.ts.map +1 -1
- package/dist/types/src/kvstore/types.d.ts +2 -0
- package/dist/types/src/kvstore/types.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/index.d.ts +1 -0
- package/dist/types/src/overlay-tools/index.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/withDoubleSpendRetry.d.ts +14 -0
- package/dist/types/src/overlay-tools/withDoubleSpendRetry.d.ts.map +1 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +2 -2
- package/dist/umd/bundle.js.map +1 -1
- package/docs/fast-docs.png +0 -0
- package/docs/index.md +49 -44
- package/docs/reference/kvstore.md +9 -0
- package/docs/reference/overlay-tools.md +32 -0
- package/docs/swagger.png +0 -0
- package/package.json +1 -1
- package/src/kvstore/GlobalKVStore.ts +134 -114
- package/src/kvstore/__tests/GlobalKVStore.test.ts +11 -1
- package/src/kvstore/types.ts +2 -0
- package/src/overlay-tools/index.ts +1 -0
- package/src/overlay-tools/withDoubleSpendRetry.ts +71 -0
- package/docs/MARKDOWN_VALIDATION_GUIDE.md +0 -175
- package/docs/concepts/beef.md +0 -92
- package/docs/concepts/chain-tracking.md +0 -134
- package/docs/concepts/decentralized-identity.md +0 -221
- package/docs/concepts/fees.md +0 -249
- package/docs/concepts/identity-certificates.md +0 -307
- package/docs/concepts/index.md +0 -77
- package/docs/concepts/key-management.md +0 -185
- package/docs/concepts/script-templates.md +0 -176
- package/docs/concepts/sdk-philosophy.md +0 -80
- package/docs/concepts/signatures.md +0 -194
- package/docs/concepts/spv-verification.md +0 -118
- package/docs/concepts/transaction-encoding.md +0 -167
- package/docs/concepts/transaction-structure.md +0 -67
- package/docs/concepts/trust-model.md +0 -139
- package/docs/concepts/verification.md +0 -250
- package/docs/concepts/wallet-integration.md +0 -101
- package/docs/guides/development-wallet-setup.md +0 -374
- package/docs/guides/direct-transaction-creation.md +0 -147
- package/docs/guides/http-client-configuration.md +0 -488
- package/docs/guides/index.md +0 -138
- package/docs/guides/large-transactions.md +0 -448
- package/docs/guides/multisig-transactions.md +0 -792
- package/docs/guides/security-best-practices.md +0 -494
- package/docs/guides/transaction-batching.md +0 -132
- package/docs/guides/transaction-signing-methods.md +0 -419
- package/docs/reference/arc-config.md +0 -698
- package/docs/reference/brc-100.md +0 -33
- package/docs/reference/configuration.md +0 -835
- package/docs/reference/debugging.md +0 -705
- package/docs/reference/errors.md +0 -597
- package/docs/reference/index.md +0 -111
- package/docs/reference/network-config.md +0 -914
- package/docs/reference/op-codes.md +0 -325
- package/docs/reference/transaction-signatures.md +0 -95
- package/docs/tutorials/advanced-transaction.md +0 -572
- package/docs/tutorials/aes-encryption.md +0 -949
- package/docs/tutorials/authfetch-tutorial.md +0 -986
- package/docs/tutorials/ecdh-key-exchange.md +0 -549
- package/docs/tutorials/elliptic-curve-fundamentals.md +0 -606
- package/docs/tutorials/error-handling.md +0 -1216
- package/docs/tutorials/first-transaction-low-level.md +0 -205
- package/docs/tutorials/first-transaction.md +0 -275
- package/docs/tutorials/hashes-and-hmacs.md +0 -788
- package/docs/tutorials/identity-management.md +0 -729
- package/docs/tutorials/index.md +0 -219
- package/docs/tutorials/key-management.md +0 -538
- package/docs/tutorials/protowallet-development.md +0 -743
- package/docs/tutorials/script-construction.md +0 -690
- package/docs/tutorials/spv-merkle-proofs.md +0 -685
- package/docs/tutorials/testnet-transactions-low-level.md +0 -359
- package/docs/tutorials/transaction-broadcasting.md +0 -538
- package/docs/tutorials/transaction-types.md +0 -420
- package/docs/tutorials/type-42.md +0 -568
- package/docs/tutorials/uhrp-storage.md +0 -599
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
# Transaction Verification
|
|
2
|
-
|
|
3
|
-
Understanding how to verify Bitcoin transactions using the BSV TypeScript SDK.
|
|
4
|
-
|
|
5
|
-
## What is Transaction Verification?
|
|
6
|
-
|
|
7
|
-
Transaction verification ensures that Bitcoin transactions are valid and can be trusted:
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
import { Transaction } from '@bsv/sdk'
|
|
11
|
-
|
|
12
|
-
// Verify a transaction
|
|
13
|
-
const isValid = await transaction.verify(chainTracker, {
|
|
14
|
-
merkleProof: proof,
|
|
15
|
-
blockHeader: header
|
|
16
|
-
})
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Verification Levels
|
|
20
|
-
|
|
21
|
-
### Basic Validation
|
|
22
|
-
|
|
23
|
-
Check transaction structure and format:
|
|
24
|
-
|
|
25
|
-
- Valid input/output formats
|
|
26
|
-
- Correct serialization
|
|
27
|
-
- Proper script syntax
|
|
28
|
-
- Signature format validation
|
|
29
|
-
|
|
30
|
-
### Script Execution
|
|
31
|
-
|
|
32
|
-
Verify that unlocking scripts satisfy locking scripts:
|
|
33
|
-
|
|
34
|
-
- Execute Bitcoin script opcodes
|
|
35
|
-
- Validate signature operations
|
|
36
|
-
- Check script conditions
|
|
37
|
-
- Ensure proper stack state
|
|
38
|
-
|
|
39
|
-
### SPV Verification
|
|
40
|
-
|
|
41
|
-
Confirm transaction inclusion in the blockchain:
|
|
42
|
-
|
|
43
|
-
- Verify merkle proofs
|
|
44
|
-
- Validate block headers
|
|
45
|
-
- Check proof of work
|
|
46
|
-
- Confirm transaction position
|
|
47
|
-
|
|
48
|
-
## SDK Verification Methods
|
|
49
|
-
|
|
50
|
-
### Transaction.verify()
|
|
51
|
-
|
|
52
|
-
Complete transaction verification:
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
const result = await transaction.verify(chainTracker, {
|
|
56
|
-
merkleProof: merkleProof,
|
|
57
|
-
blockHeader: blockHeader,
|
|
58
|
-
maxMemoryLimit: 100000000
|
|
59
|
-
})
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Script Verification
|
|
63
|
-
|
|
64
|
-
Verify individual scripts:
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
const isValid = unlockingScript.verify(
|
|
68
|
-
lockingScript,
|
|
69
|
-
transaction,
|
|
70
|
-
inputIndex
|
|
71
|
-
)
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Signature Verification
|
|
75
|
-
|
|
76
|
-
Check digital signatures:
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
const publicKey = PrivateKey.fromWif(wif).toPublicKey()
|
|
80
|
-
const isValid = publicKey.verify(messageHash, signature)
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Verification Options
|
|
84
|
-
|
|
85
|
-
### Memory Limits
|
|
86
|
-
|
|
87
|
-
Control script execution memory usage:
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
const options = {
|
|
91
|
-
maxMemoryLimit: 50000000 // 50MB limit
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Scripts-Only Mode
|
|
96
|
-
|
|
97
|
-
Skip SPV verification for performance:
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
const options = {
|
|
101
|
-
scriptsOnly: true
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Custom Chain Tracker
|
|
106
|
-
|
|
107
|
-
Use specific data sources:
|
|
108
|
-
|
|
109
|
-
```typescript
|
|
110
|
-
const customTracker = new WhatsOnChain('testnet')
|
|
111
|
-
const isValid = await transaction.verify(customTracker)
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## BEEF Verification
|
|
115
|
-
|
|
116
|
-
BEEF format includes verification data:
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
// BEEF transactions include proofs
|
|
120
|
-
const beefTx = Transaction.fromHexBEEF(beefData)
|
|
121
|
-
|
|
122
|
-
// Verify using included proofs
|
|
123
|
-
const isValid = await beefTx.verify(chainTracker)
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## Error Handling
|
|
127
|
-
|
|
128
|
-
Common verification failures:
|
|
129
|
-
|
|
130
|
-
- Invalid signatures
|
|
131
|
-
- Script execution errors
|
|
132
|
-
- Missing merkle proofs
|
|
133
|
-
- Network connectivity issues
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
try {
|
|
137
|
-
const isValid = await transaction.verify(chainTracker)
|
|
138
|
-
if (!isValid) {
|
|
139
|
-
console.log('Transaction verification failed')
|
|
140
|
-
}
|
|
141
|
-
} catch (error) {
|
|
142
|
-
console.error('Verification error:', error.message)
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## Performance Considerations
|
|
147
|
-
|
|
148
|
-
### Batch Verification
|
|
149
|
-
|
|
150
|
-
Verify multiple transactions efficiently:
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
const results = await Promise.all(
|
|
154
|
-
transactions.map(tx => tx.verify(chainTracker))
|
|
155
|
-
)
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Caching
|
|
159
|
-
|
|
160
|
-
Cache verification results:
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
const verificationCache = new Map()
|
|
164
|
-
|
|
165
|
-
if (!verificationCache.has(txid)) {
|
|
166
|
-
const result = await transaction.verify(chainTracker)
|
|
167
|
-
verificationCache.set(txid, result)
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
## Security Best Practices
|
|
172
|
-
|
|
173
|
-
### Always Verify
|
|
174
|
-
|
|
175
|
-
- Verify transactions before trusting them
|
|
176
|
-
- Check both script execution and SPV proofs
|
|
177
|
-
- Validate input data before verification
|
|
178
|
-
|
|
179
|
-
### Multiple Sources
|
|
180
|
-
|
|
181
|
-
- Use multiple chain trackers for redundancy
|
|
182
|
-
- Cross-check verification results
|
|
183
|
-
- Implement fallback mechanisms
|
|
184
|
-
|
|
185
|
-
### Resource Limits
|
|
186
|
-
|
|
187
|
-
- Set appropriate memory limits
|
|
188
|
-
- Timeout long-running verifications
|
|
189
|
-
- Monitor verification performance
|
|
190
|
-
|
|
191
|
-
## Common Use Cases
|
|
192
|
-
|
|
193
|
-
### Payment Verification
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
// Verify received payment
|
|
197
|
-
const payment = Transaction.fromHex(paymentHex)
|
|
198
|
-
const isValid = await payment.verify(chainTracker)
|
|
199
|
-
|
|
200
|
-
if (isValid) {
|
|
201
|
-
// Process confirmed payment
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### Historical Transaction Audit
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
// Verify old transactions
|
|
209
|
-
for (const txHex of historicalTransactions) {
|
|
210
|
-
const tx = Transaction.fromHex(txHex)
|
|
211
|
-
const result = await tx.verify(chainTracker)
|
|
212
|
-
console.log(`Transaction ${tx.id()}: ${result ? 'Valid' : 'Invalid'}`)
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
## Integration Patterns
|
|
217
|
-
|
|
218
|
-
### Wallet Integration
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
// Wallets typically handle verification
|
|
222
|
-
const wallet = new WalletClient()
|
|
223
|
-
const action = await wallet.createAction({
|
|
224
|
-
outputs: [/* outputs */]
|
|
225
|
-
})
|
|
226
|
-
// Wallet verifies before broadcasting
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Application Verification
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
// Applications verify received transactions
|
|
233
|
-
async function processIncomingTransaction(txHex: string) {
|
|
234
|
-
const tx = Transaction.fromHex(txHex)
|
|
235
|
-
|
|
236
|
-
if (await tx.verify(chainTracker)) {
|
|
237
|
-
// Process verified transaction
|
|
238
|
-
await handleValidTransaction(tx)
|
|
239
|
-
} else {
|
|
240
|
-
// Reject invalid transaction
|
|
241
|
-
throw new Error('Invalid transaction received')
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
## Next Steps
|
|
247
|
-
|
|
248
|
-
- Learn about [SPV Verification](./spv-verification.md) concepts
|
|
249
|
-
- Understand [Digital Signatures](./signatures.md) validation
|
|
250
|
-
- Explore [BEEF Format](./beef.md) for efficient verification
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# Wallet Integration
|
|
2
|
-
|
|
3
|
-
How the BSV TypeScript SDK connects with Bitcoin wallets and manages user authentication.
|
|
4
|
-
|
|
5
|
-
## Wallet Connection Model
|
|
6
|
-
|
|
7
|
-
The SDK uses a standardized approach to connect with Bitcoin wallets:
|
|
8
|
-
|
|
9
|
-
```typescript
|
|
10
|
-
import { WalletClient } from '@bsv/sdk'
|
|
11
|
-
|
|
12
|
-
// Connect to a wallet
|
|
13
|
-
const wallet = new WalletClient('https://wallet-url')
|
|
14
|
-
|
|
15
|
-
// Authenticate with the wallet
|
|
16
|
-
await wallet.authenticate()
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## BRC-100 Compliance
|
|
20
|
-
|
|
21
|
-
The SDK follows the BRC-100 standard for wallet communication:
|
|
22
|
-
|
|
23
|
-
- **Standardized APIs**: Consistent interface across different wallets
|
|
24
|
-
- **Authentication**: Secure identity verification
|
|
25
|
-
- **Transaction Signing**: Wallet handles private key operations
|
|
26
|
-
- **UTXO Management**: Wallet manages available funds
|
|
27
|
-
|
|
28
|
-
## Authentication Flow
|
|
29
|
-
|
|
30
|
-
1. **Connection**: Establish connection to wallet service
|
|
31
|
-
2. **Identity**: Wallet provides user identity information
|
|
32
|
-
3. **Capabilities**: Discover what the wallet can do
|
|
33
|
-
4. **Authorization**: User grants permission for specific operations
|
|
34
|
-
|
|
35
|
-
## Transaction Creation
|
|
36
|
-
|
|
37
|
-
The wallet handles sensitive operations:
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
40
|
-
// Create a transaction action
|
|
41
|
-
const action = await wallet.createAction({
|
|
42
|
-
description: 'Payment transaction',
|
|
43
|
-
outputs: [{
|
|
44
|
-
satoshis: 1000,
|
|
45
|
-
lockingScript: recipientScript
|
|
46
|
-
}]
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
// Wallet signs and broadcasts automatically
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Key Benefits
|
|
53
|
-
|
|
54
|
-
### Security
|
|
55
|
-
|
|
56
|
-
- Private keys never leave the wallet
|
|
57
|
-
- User controls transaction approval
|
|
58
|
-
- Secure authentication protocols
|
|
59
|
-
|
|
60
|
-
### User Experience
|
|
61
|
-
|
|
62
|
-
- Familiar wallet interface
|
|
63
|
-
- Consistent across applications
|
|
64
|
-
- Single sign-on capabilities
|
|
65
|
-
|
|
66
|
-
### Developer Simplicity
|
|
67
|
-
|
|
68
|
-
- No key management complexity
|
|
69
|
-
- Standardized APIs
|
|
70
|
-
- Automatic UTXO handling
|
|
71
|
-
|
|
72
|
-
## Wallet Types
|
|
73
|
-
|
|
74
|
-
The SDK works with various wallet implementations:
|
|
75
|
-
|
|
76
|
-
- **Desktop Wallets**: Local applications with full control
|
|
77
|
-
- **Web Wallets**: Browser-based wallet services
|
|
78
|
-
- **Mobile Wallets**: Smartphone applications
|
|
79
|
-
- **Hardware Wallets**: Secure hardware devices
|
|
80
|
-
|
|
81
|
-
## Error Handling
|
|
82
|
-
|
|
83
|
-
Common wallet integration scenarios:
|
|
84
|
-
|
|
85
|
-
- Wallet not available or offline
|
|
86
|
-
- User denies transaction approval
|
|
87
|
-
- Insufficient funds in wallet
|
|
88
|
-
- Network connectivity issues
|
|
89
|
-
|
|
90
|
-
## Best Practices
|
|
91
|
-
|
|
92
|
-
- Always handle wallet connection failures gracefully
|
|
93
|
-
- Provide clear transaction descriptions to users
|
|
94
|
-
- Implement retry logic for network issues
|
|
95
|
-
- Cache wallet capabilities to improve performance
|
|
96
|
-
|
|
97
|
-
## Next Steps
|
|
98
|
-
|
|
99
|
-
- Learn about [Chain Tracking](./chain-tracking.md) for network data
|
|
100
|
-
- Understand [Key Management](./key-management.md) concepts
|
|
101
|
-
- Explore [Trust Model](./trust-model.md) considerations
|
|
@@ -1,374 +0,0 @@
|
|
|
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)
|