@btc-vision/transaction 1.7.19 → 1.7.22
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/LICENSE +190 -21
- package/README.md +1 -1
- package/browser/_version.d.ts +1 -1
- package/browser/generators/builders/HashCommitmentGenerator.d.ts +49 -0
- package/browser/index.js +1 -1
- package/browser/keypair/Address.d.ts +3 -1
- package/browser/opnet.d.ts +6 -1
- package/browser/signer/AddressRotation.d.ts +12 -0
- package/browser/transaction/TransactionFactory.d.ts +14 -0
- package/browser/transaction/builders/ConsolidatedInteractionTransaction.d.ts +44 -0
- package/browser/transaction/enums/TransactionType.d.ts +3 -1
- package/browser/transaction/interfaces/IConsolidatedTransactionParameters.d.ts +31 -0
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +2 -0
- package/browser/transaction/offline/OfflineTransactionManager.d.ts +69 -0
- package/browser/transaction/offline/TransactionReconstructor.d.ts +28 -0
- package/browser/transaction/offline/TransactionSerializer.d.ts +50 -0
- package/browser/transaction/offline/TransactionStateCapture.d.ts +52 -0
- package/browser/transaction/offline/index.d.ts +5 -0
- package/browser/transaction/offline/interfaces/ISerializableState.d.ts +62 -0
- package/browser/transaction/offline/interfaces/ITypeSpecificData.d.ts +62 -0
- package/browser/transaction/offline/interfaces/index.d.ts +2 -0
- package/browser/transaction/shared/TweakedTransaction.d.ts +12 -1
- package/browser/utxo/interfaces/IUTXO.d.ts +2 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/generators/builders/HashCommitmentGenerator.d.ts +49 -0
- package/build/generators/builders/HashCommitmentGenerator.js +229 -0
- package/build/keypair/Address.d.ts +3 -1
- package/build/keypair/Address.js +87 -54
- package/build/opnet.d.ts +6 -1
- package/build/opnet.js +6 -1
- package/build/signer/AddressRotation.d.ts +12 -0
- package/build/signer/AddressRotation.js +16 -0
- package/build/transaction/TransactionFactory.d.ts +14 -0
- package/build/transaction/TransactionFactory.js +36 -0
- package/build/transaction/builders/ConsolidatedInteractionTransaction.d.ts +44 -0
- package/build/transaction/builders/ConsolidatedInteractionTransaction.js +259 -0
- package/build/transaction/builders/TransactionBuilder.js +2 -0
- package/build/transaction/enums/TransactionType.d.ts +3 -1
- package/build/transaction/enums/TransactionType.js +2 -0
- package/build/transaction/interfaces/IConsolidatedTransactionParameters.d.ts +31 -0
- package/build/transaction/interfaces/IConsolidatedTransactionParameters.js +1 -0
- package/build/transaction/interfaces/ITransactionParameters.d.ts +2 -0
- package/build/transaction/offline/OfflineTransactionManager.d.ts +69 -0
- package/build/transaction/offline/OfflineTransactionManager.js +255 -0
- package/build/transaction/offline/TransactionReconstructor.d.ts +28 -0
- package/build/transaction/offline/TransactionReconstructor.js +243 -0
- package/build/transaction/offline/TransactionSerializer.d.ts +50 -0
- package/build/transaction/offline/TransactionSerializer.js +700 -0
- package/build/transaction/offline/TransactionStateCapture.d.ts +52 -0
- package/build/transaction/offline/TransactionStateCapture.js +275 -0
- package/build/transaction/offline/index.d.ts +5 -0
- package/build/transaction/offline/index.js +5 -0
- package/build/transaction/offline/interfaces/ISerializableState.d.ts +62 -0
- package/build/transaction/offline/interfaces/ISerializableState.js +2 -0
- package/build/transaction/offline/interfaces/ITypeSpecificData.d.ts +62 -0
- package/build/transaction/offline/interfaces/ITypeSpecificData.js +19 -0
- package/build/transaction/offline/interfaces/index.d.ts +2 -0
- package/build/transaction/offline/interfaces/index.js +2 -0
- package/build/transaction/shared/TweakedTransaction.d.ts +12 -1
- package/build/transaction/shared/TweakedTransaction.js +75 -8
- package/build/utxo/interfaces/IUTXO.d.ts +2 -0
- package/documentation/README.md +5 -0
- package/documentation/offline-transaction-signing.md +650 -0
- package/documentation/transaction-building.md +603 -0
- package/package.json +2 -2
- package/src/_version.ts +1 -1
- package/src/generators/builders/HashCommitmentGenerator.ts +495 -0
- package/src/keypair/Address.ts +123 -70
- package/src/opnet.ts +8 -1
- package/src/signer/AddressRotation.ts +72 -0
- package/src/transaction/TransactionFactory.ts +90 -0
- package/src/transaction/builders/CancelTransaction.ts +4 -2
- package/src/transaction/builders/ConsolidatedInteractionTransaction.ts +568 -0
- package/src/transaction/builders/CustomScriptTransaction.ts +4 -2
- package/src/transaction/builders/MultiSignTransaction.ts +4 -2
- package/src/transaction/builders/TransactionBuilder.ts +8 -2
- package/src/transaction/enums/TransactionType.ts +2 -0
- package/src/transaction/interfaces/IConsolidatedTransactionParameters.ts +78 -0
- package/src/transaction/interfaces/ITransactionParameters.ts +8 -0
- package/src/transaction/offline/OfflineTransactionManager.ts +630 -0
- package/src/transaction/offline/TransactionReconstructor.ts +402 -0
- package/src/transaction/offline/TransactionSerializer.ts +920 -0
- package/src/transaction/offline/TransactionStateCapture.ts +469 -0
- package/src/transaction/offline/index.ts +8 -0
- package/src/transaction/offline/interfaces/ISerializableState.ts +141 -0
- package/src/transaction/offline/interfaces/ITypeSpecificData.ts +172 -0
- package/src/transaction/offline/interfaces/index.ts +2 -0
- package/src/transaction/shared/TweakedTransaction.ts +156 -9
- package/src/utxo/interfaces/IUTXO.ts +8 -0
- package/test/address-rotation.test.ts +553 -0
- package/test/offline-transaction.test.ts +2065 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
# Transaction Building Guide
|
|
2
|
+
|
|
3
|
+
Complete guide to building Bitcoin transactions with the OPNet Transaction Library.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The transaction building system provides a layered architecture for creating, signing, and broadcasting Bitcoin transactions with support for:
|
|
8
|
+
|
|
9
|
+
- All Bitcoin address types (P2PKH, P2WPKH, P2WSH, P2SH, P2TR)
|
|
10
|
+
- Smart contract deployment and interaction
|
|
11
|
+
- Multi-signature transactions
|
|
12
|
+
- Custom scripts
|
|
13
|
+
- Address rotation (per-UTXO signing)
|
|
14
|
+
- Quantum-resistant signatures (ML-DSA)
|
|
15
|
+
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
flowchart TB
|
|
20
|
+
TF["TransactionFactory<br/>(Main entry point)"]
|
|
21
|
+
TB["TransactionBuilder<T><br/>(UTXO management, fees, outputs)"]
|
|
22
|
+
TT["TweakedTransaction<br/>(Signing, PSBT, Taproot)"]
|
|
23
|
+
|
|
24
|
+
TF --> TB
|
|
25
|
+
TB --> TT
|
|
26
|
+
|
|
27
|
+
TT --> FT["FundingTransaction"]
|
|
28
|
+
TT --> DT["DeploymentTransaction"]
|
|
29
|
+
TT --> IT["InteractionTransaction"]
|
|
30
|
+
TT --> MT["MultiSignTransaction"]
|
|
31
|
+
TT --> CT["CustomScriptTransaction"]
|
|
32
|
+
TT --> XT["CancelTransaction"]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Transaction Types
|
|
36
|
+
|
|
37
|
+
| Type | Enum Value | Purpose |
|
|
38
|
+
|------|------------|---------|
|
|
39
|
+
| `FUNDING` | 1 | Simple BTC transfers |
|
|
40
|
+
| `DEPLOYMENT` | 2 | Deploy smart contracts |
|
|
41
|
+
| `INTERACTION` | 3 | Call contract functions |
|
|
42
|
+
| `MULTI_SIG` | 4 | Multi-signature transactions |
|
|
43
|
+
| `CUSTOM_CODE` | 5 | Custom script execution |
|
|
44
|
+
| `CANCEL` | 6 | Cancel/recover stuck transactions |
|
|
45
|
+
|
|
46
|
+
## UTXO Flow
|
|
47
|
+
|
|
48
|
+
UTXOs (Unspent Transaction Outputs) are the fundamental building blocks of Bitcoin transactions.
|
|
49
|
+
|
|
50
|
+
### UTXO Lifecycle
|
|
51
|
+
|
|
52
|
+
```mermaid
|
|
53
|
+
flowchart LR
|
|
54
|
+
subgraph PrevTx["Previous Transaction"]
|
|
55
|
+
U1["UTXO 1<br/>5 BTC"]
|
|
56
|
+
U2["UTXO 2<br/>3 BTC"]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
subgraph YourTx["Your Transaction"]
|
|
60
|
+
subgraph Inputs
|
|
61
|
+
I1["Input 1"]
|
|
62
|
+
I2["Input 2"]
|
|
63
|
+
end
|
|
64
|
+
subgraph Outputs
|
|
65
|
+
O1["Output 1<br/>2 BTC"]
|
|
66
|
+
O2["Output 2<br/>5.99 BTC"]
|
|
67
|
+
end
|
|
68
|
+
Fee["Fee: 0.01 BTC"]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
subgraph NewUTXOs["New UTXOs"]
|
|
72
|
+
NU1["Recipient UTXO"]
|
|
73
|
+
NU2["Change UTXO"]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
U1 -->|"spent"| I1
|
|
77
|
+
U2 -->|"spent"| I2
|
|
78
|
+
O1 --> NU1
|
|
79
|
+
O2 --> NU2
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Total In: 8 BTC = Total Out: 7.99 BTC + 0.01 BTC Fee**
|
|
83
|
+
|
|
84
|
+
### UTXO Interface
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface UTXO {
|
|
88
|
+
// Required fields
|
|
89
|
+
readonly transactionId: string; // Previous tx hash (64 hex chars)
|
|
90
|
+
readonly outputIndex: number; // Output index in previous tx
|
|
91
|
+
readonly value: bigint; // Amount in satoshis
|
|
92
|
+
readonly scriptPubKey: {
|
|
93
|
+
hex: string; // Locking script
|
|
94
|
+
address: string; // Derived address
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Optional fields (for specific script types)
|
|
98
|
+
redeemScript?: string | Buffer; // P2SH redeem script
|
|
99
|
+
witnessScript?: string | Buffer; // P2WSH witness script
|
|
100
|
+
nonWitnessUtxo?: string | Buffer; // Full previous tx (legacy)
|
|
101
|
+
|
|
102
|
+
// Address rotation support
|
|
103
|
+
signer?: RotationSigner; // Per-UTXO signer
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### UTXO Processing Flow
|
|
108
|
+
|
|
109
|
+
```mermaid
|
|
110
|
+
flowchart LR
|
|
111
|
+
subgraph Inputs["Input UTXOs"]
|
|
112
|
+
U1["UTXO 1<br/>50,000 sat"]
|
|
113
|
+
U2["UTXO 2<br/>30,000 sat"]
|
|
114
|
+
U3["UTXO 3<br/>20,000 sat"]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
subgraph Processing["TransactionBuilder"]
|
|
118
|
+
S1["1. calculateTotalAmount()<br/>Total: 100,000 sat"]
|
|
119
|
+
S2["2. addInputsFromUTXO()<br/>registerInputSigner()"]
|
|
120
|
+
S3["3. buildTransaction()<br/>Add outputs"]
|
|
121
|
+
S4["4. estimateTransactionFees()<br/>Calculate vSize"]
|
|
122
|
+
S5["5. addRefundOutput()<br/>Calculate change"]
|
|
123
|
+
S6["6. signTransaction()<br/>Finalize PSBT"]
|
|
124
|
+
|
|
125
|
+
S1 --> S2 --> S3 --> S4 --> S5 --> S6
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
subgraph Outputs["Outputs"]
|
|
129
|
+
O1["Payment"]
|
|
130
|
+
O2["Change"]
|
|
131
|
+
O3["Optional"]
|
|
132
|
+
Fee["Fee (miners)"]
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
Inputs --> S1
|
|
136
|
+
S6 --> Outputs
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## TransactionFactory
|
|
140
|
+
|
|
141
|
+
The `TransactionFactory` is the main entry point for creating transactions.
|
|
142
|
+
|
|
143
|
+
### Basic Usage
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { TransactionFactory, EcKeyPair, UTXO } from '@btc-vision/transaction';
|
|
147
|
+
import { networks } from '@btc-vision/bitcoin';
|
|
148
|
+
|
|
149
|
+
const network = networks.bitcoin;
|
|
150
|
+
const signer = EcKeyPair.fromWIF('your-private-key-wif', network);
|
|
151
|
+
const address = EcKeyPair.getTaprootAddress(signer, network);
|
|
152
|
+
|
|
153
|
+
// Your available UTXOs
|
|
154
|
+
const utxos: UTXO[] = [{
|
|
155
|
+
transactionId: 'abc123...'.padEnd(64, '0'),
|
|
156
|
+
outputIndex: 0,
|
|
157
|
+
value: 100000n,
|
|
158
|
+
scriptPubKey: {
|
|
159
|
+
hex: '5120...',
|
|
160
|
+
address: address,
|
|
161
|
+
},
|
|
162
|
+
}];
|
|
163
|
+
|
|
164
|
+
const factory = new TransactionFactory();
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Funding Transaction (Simple Transfer)
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const result = await factory.createBTCTransfer({
|
|
171
|
+
signer,
|
|
172
|
+
mldsaSigner: null,
|
|
173
|
+
network,
|
|
174
|
+
utxos,
|
|
175
|
+
from: address,
|
|
176
|
+
to: 'bc1p...recipient',
|
|
177
|
+
feeRate: 10, // sat/vB
|
|
178
|
+
priorityFee: 1000n, // OPNet priority fee
|
|
179
|
+
gasSatFee: 500n, // OPNet gas fee
|
|
180
|
+
amount: 50000n, // Amount to send (satoshis)
|
|
181
|
+
splitInputsInto: 1, // Optional: split into N outputs
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
console.log('Transaction hex:', result.tx);
|
|
185
|
+
console.log('Fee paid:', result.estimatedFees);
|
|
186
|
+
console.log('Change UTXOs:', result.nextUTXOs);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Contract Deployment
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const deployResult = await factory.signDeployment({
|
|
193
|
+
signer,
|
|
194
|
+
mldsaSigner: null,
|
|
195
|
+
network,
|
|
196
|
+
utxos,
|
|
197
|
+
from: address,
|
|
198
|
+
feeRate: 10,
|
|
199
|
+
priorityFee: 1000n,
|
|
200
|
+
gasSatFee: 500n,
|
|
201
|
+
bytecode: contractBytecode, // Contract bytecode (Buffer)
|
|
202
|
+
calldata: constructorData, // Constructor params (Buffer, optional)
|
|
203
|
+
challenge: epochChallenge, // ChallengeSolution
|
|
204
|
+
randomBytes: crypto.randomBytes(32),
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
console.log('Funding TX:', deployResult.transaction[0]);
|
|
208
|
+
console.log('Deployment TX:', deployResult.transaction[1]);
|
|
209
|
+
console.log('Contract Address:', deployResult.contractAddress);
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Contract Interaction
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const interactResult = await factory.signInteraction({
|
|
216
|
+
signer,
|
|
217
|
+
mldsaSigner: null,
|
|
218
|
+
network,
|
|
219
|
+
utxos,
|
|
220
|
+
from: address,
|
|
221
|
+
to: contractAddress,
|
|
222
|
+
feeRate: 10,
|
|
223
|
+
priorityFee: 1000n,
|
|
224
|
+
gasSatFee: 500n,
|
|
225
|
+
calldata: functionCalldata, // Encoded function call (Buffer)
|
|
226
|
+
challenge: epochChallenge,
|
|
227
|
+
randomBytes: crypto.randomBytes(32),
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
console.log('Funding TX:', interactResult.fundingTransaction);
|
|
231
|
+
console.log('Interaction TX:', interactResult.interactionTransaction);
|
|
232
|
+
console.log('Refund UTXOs:', interactResult.nextUTXOs);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Two-Transaction Model
|
|
236
|
+
|
|
237
|
+
Standard contract interactions use a two-transaction model:
|
|
238
|
+
|
|
239
|
+
```mermaid
|
|
240
|
+
flowchart LR
|
|
241
|
+
subgraph TX1["Transaction 1: Funding"]
|
|
242
|
+
I1["User UTXO 1"]
|
|
243
|
+
I2["User UTXO 2"]
|
|
244
|
+
O1["Contract Address"]
|
|
245
|
+
O2["Change"]
|
|
246
|
+
I1 --> O1
|
|
247
|
+
I2 --> O1
|
|
248
|
+
I1 --> O2
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
subgraph TX2["Transaction 2: Interaction"]
|
|
252
|
+
CI["Contract UTXO"]
|
|
253
|
+
EO["Execution Result"]
|
|
254
|
+
ER["Epoch Reward"]
|
|
255
|
+
RF["Refund"]
|
|
256
|
+
CI --> EO
|
|
257
|
+
CI --> ER
|
|
258
|
+
CI --> RF
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
O1 -->|"creates"| CI
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Fee Calculation
|
|
265
|
+
|
|
266
|
+
```mermaid
|
|
267
|
+
flowchart TB
|
|
268
|
+
subgraph TX["Transaction Structure"]
|
|
269
|
+
H["Header (10 bytes)<br/>Weight: 40"]
|
|
270
|
+
I["Inputs (41 bytes × N)<br/>Weight: 164×N"]
|
|
271
|
+
O["Outputs (varies)"]
|
|
272
|
+
W["Witness Data<br/>Weight: ×0.25 (75% discount)"]
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
subgraph Calc["Fee Calculation"]
|
|
276
|
+
VS["vSize = (non-witness × 4 + witness) / 4"]
|
|
277
|
+
FE["Fee = vSize × feeRate"]
|
|
278
|
+
VS --> FE
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
TX --> VS
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Fee Estimation Process
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
estimateTransactionFees():
|
|
288
|
+
1. Create dummy signatures for each input type:
|
|
289
|
+
- Schnorr (Taproot): 64 bytes
|
|
290
|
+
- ECDSA (Legacy/SegWit): 72 bytes
|
|
291
|
+
- Public key: 33 bytes
|
|
292
|
+
|
|
293
|
+
2. Build dummy witness stack per input:
|
|
294
|
+
- P2PKH: [sig, pubkey]
|
|
295
|
+
- P2WPKH: [sig, pubkey]
|
|
296
|
+
- P2WSH: [sig, witnessScript]
|
|
297
|
+
- P2TR key-path: [schnorr_sig]
|
|
298
|
+
- P2TR script-path: [data, sig, script, controlBlock]
|
|
299
|
+
|
|
300
|
+
3. Calculate virtual size with witness discount
|
|
301
|
+
|
|
302
|
+
4. Apply fee rate: fee = vSize × feeRate
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Signing Process
|
|
306
|
+
|
|
307
|
+
```mermaid
|
|
308
|
+
flowchart TB
|
|
309
|
+
ST["signTransaction()"]
|
|
310
|
+
|
|
311
|
+
subgraph Batch["For each input (batched in groups of 20)"]
|
|
312
|
+
GS["Get Signer<br/>inputSignerMap[i] or default"]
|
|
313
|
+
TR{"Is Taproot?"}
|
|
314
|
+
TW["getTweakedSigner()<br/>Apply tweak"]
|
|
315
|
+
EC["ECDSA Sign"]
|
|
316
|
+
|
|
317
|
+
GS --> TR
|
|
318
|
+
TR -->|"YES"| TW
|
|
319
|
+
TR -->|"NO"| EC
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
subgraph Finalize["Finalize Inputs"]
|
|
323
|
+
F1["P2PKH: [sig, pubkey]"]
|
|
324
|
+
F2["P2WPKH: [sig, pubkey]"]
|
|
325
|
+
F3["P2WSH: [sig, witnessScript]"]
|
|
326
|
+
F4["P2TR key: [schnorr_sig]"]
|
|
327
|
+
F5["P2TR script: [data, sig, script, ctrl]"]
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
EX["Extract TX Hex"]
|
|
331
|
+
|
|
332
|
+
ST --> Batch
|
|
333
|
+
Batch --> Finalize
|
|
334
|
+
Finalize --> EX
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Address Rotation (Per-UTXO Signing)
|
|
338
|
+
|
|
339
|
+
Different UTXOs can be signed by different signers:
|
|
340
|
+
|
|
341
|
+
```mermaid
|
|
342
|
+
flowchart LR
|
|
343
|
+
subgraph SignerMap["Signer Map"]
|
|
344
|
+
M1["addr1 → Signer A"]
|
|
345
|
+
M2["addr2 → Signer B"]
|
|
346
|
+
M3["addr3 → Signer C"]
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
subgraph UTXOs
|
|
350
|
+
U1["UTXO from addr1"]
|
|
351
|
+
U2["UTXO from addr2"]
|
|
352
|
+
U3["UTXO from addr1"]
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
subgraph Signed["Signed By"]
|
|
356
|
+
S1["Signer A"]
|
|
357
|
+
S2["Signer B"]
|
|
358
|
+
S3["Signer A"]
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
U1 --> S1
|
|
362
|
+
U2 --> S2
|
|
363
|
+
U3 --> S3
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
import { createSignerMap, createAddressRotation } from '@btc-vision/transaction';
|
|
368
|
+
|
|
369
|
+
// Create signer map
|
|
370
|
+
const signerMap = createSignerMap([
|
|
371
|
+
['bc1p...address1', signer1],
|
|
372
|
+
['bc1p...address2', signer2],
|
|
373
|
+
]);
|
|
374
|
+
|
|
375
|
+
// Use in transaction
|
|
376
|
+
const result = await factory.createBTCTransfer({
|
|
377
|
+
signer: defaultSigner,
|
|
378
|
+
utxos: mixedUtxos,
|
|
379
|
+
addressRotation: createAddressRotation(signerMap),
|
|
380
|
+
// ... other params
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## MultiSig Transactions
|
|
385
|
+
|
|
386
|
+
Create M-of-N multi-signature transactions:
|
|
387
|
+
|
|
388
|
+
```mermaid
|
|
389
|
+
flowchart LR
|
|
390
|
+
subgraph Keys["Public Keys (3)"]
|
|
391
|
+
A["PubKey A"]
|
|
392
|
+
B["PubKey B"]
|
|
393
|
+
C["PubKey C"]
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
Script["Taproot MultiSig Script<br/>2-of-3 required"]
|
|
397
|
+
|
|
398
|
+
Keys --> Script
|
|
399
|
+
|
|
400
|
+
subgraph Signing["Signing Flow"]
|
|
401
|
+
S1["Signer A<br/>(1/3)"] --> S2["Signer B<br/>(2/3)"] --> Done["2/3 reached!<br/>TX valid"]
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
Script --> Signing
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
import { MultiSignTransaction } from '@btc-vision/transaction';
|
|
409
|
+
|
|
410
|
+
const multiSigTx = new MultiSignTransaction({
|
|
411
|
+
network,
|
|
412
|
+
utxos: vaultUtxos,
|
|
413
|
+
feeRate: 10,
|
|
414
|
+
pubkeys: [pubkeyA, pubkeyB, pubkeyC],
|
|
415
|
+
minimumSignatures: 2,
|
|
416
|
+
receiver: recipientAddress,
|
|
417
|
+
requestedAmount: 100000n,
|
|
418
|
+
refundVault: vaultAddress,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
// First signer
|
|
422
|
+
const psbt = await multiSigTx.signPSBT();
|
|
423
|
+
const psbtBase64 = psbt.toBase64();
|
|
424
|
+
|
|
425
|
+
// Send to second signer...
|
|
426
|
+
// Use MultiSignTransaction.signPartial() for additional signatures
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Custom Script Transactions
|
|
430
|
+
|
|
431
|
+
Execute arbitrary Bitcoin scripts:
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
import { CustomScriptTransaction } from '@btc-vision/transaction';
|
|
435
|
+
import { opcodes } from '@btc-vision/bitcoin';
|
|
436
|
+
|
|
437
|
+
const customTx = new CustomScriptTransaction({
|
|
438
|
+
signer,
|
|
439
|
+
network,
|
|
440
|
+
utxos,
|
|
441
|
+
from: address,
|
|
442
|
+
to: recipientAddress,
|
|
443
|
+
feeRate: 10,
|
|
444
|
+
priorityFee: 1000n,
|
|
445
|
+
gasSatFee: 500n,
|
|
446
|
+
script: [
|
|
447
|
+
Buffer.from('hello'),
|
|
448
|
+
opcodes.OP_DROP,
|
|
449
|
+
opcodes.OP_TRUE,
|
|
450
|
+
],
|
|
451
|
+
witnesses: [Buffer.from('witness data')],
|
|
452
|
+
});
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## Cancel Transactions
|
|
456
|
+
|
|
457
|
+
Recover funds from stuck interactions:
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
import { CancelTransaction } from '@btc-vision/transaction';
|
|
461
|
+
|
|
462
|
+
const cancelTx = new CancelTransaction({
|
|
463
|
+
signer,
|
|
464
|
+
network,
|
|
465
|
+
utxos: stuckUtxos,
|
|
466
|
+
from: address,
|
|
467
|
+
to: recoveryAddress,
|
|
468
|
+
feeRate: 15, // Higher fee to ensure confirmation
|
|
469
|
+
priorityFee: 0n,
|
|
470
|
+
gasSatFee: 0n,
|
|
471
|
+
compiledTargetScript: originalScript,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
const signedCancel = await cancelTx.signTransaction();
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## Response Types
|
|
478
|
+
|
|
479
|
+
### BitcoinTransferResponse (Funding)
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
interface BitcoinTransferResponse {
|
|
483
|
+
tx: string; // Signed transaction hex
|
|
484
|
+
estimatedFees: bigint; // Fees paid
|
|
485
|
+
nextUTXOs: UTXO[]; // Change outputs (spendable)
|
|
486
|
+
inputUtxos: UTXO[]; // UTXOs that were spent
|
|
487
|
+
original: FundingTransaction;
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### DeploymentResult
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
interface DeploymentResult {
|
|
495
|
+
transaction: [string, string]; // [fundingTx, deploymentTx]
|
|
496
|
+
contractAddress: string;
|
|
497
|
+
contractPubKey: string;
|
|
498
|
+
challenge: RawChallenge;
|
|
499
|
+
utxos: UTXO[]; // Refund UTXOs
|
|
500
|
+
inputUtxos: UTXO[];
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### InteractionResponse
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
interface InteractionResponse {
|
|
508
|
+
fundingTransaction: string | null; // null for P2WDA
|
|
509
|
+
interactionTransaction: string;
|
|
510
|
+
estimatedFees: bigint;
|
|
511
|
+
nextUTXOs: UTXO[]; // Refund outputs
|
|
512
|
+
fundingUTXOs: UTXO[];
|
|
513
|
+
fundingInputUtxos: UTXO[];
|
|
514
|
+
challenge: RawChallenge;
|
|
515
|
+
interactionAddress: string | null;
|
|
516
|
+
compiledTargetScript: string | null;
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
## Supported Address Types
|
|
521
|
+
|
|
522
|
+
The library supports all major Bitcoin address types:
|
|
523
|
+
|
|
524
|
+
| Type | Prefix | Weight Efficiency | Support |
|
|
525
|
+
|------|--------|-------------------|---------|
|
|
526
|
+
| P2PKH | `1...` | 1x (legacy) | Full |
|
|
527
|
+
| P2SH | `3...` | 1x (legacy) | Full |
|
|
528
|
+
| P2WPKH | `bc1q...` | ~0.68x | Full |
|
|
529
|
+
| P2WSH | `bc1q...` (longer) | ~0.68x | Full |
|
|
530
|
+
| P2TR | `bc1p...` | ~0.57x | Full |
|
|
531
|
+
| P2A | Anchor | Minimal | Full |
|
|
532
|
+
|
|
533
|
+
## Error Handling
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
try {
|
|
537
|
+
const result = await factory.createBTCTransfer(params);
|
|
538
|
+
} catch (error) {
|
|
539
|
+
if (error.message.includes('Insufficient funds')) {
|
|
540
|
+
// Not enough UTXOs to cover amount + fees
|
|
541
|
+
} else if (error.message.includes('Invalid UTXO')) {
|
|
542
|
+
// UTXO validation failed
|
|
543
|
+
} else if (error.message.includes('Dust output')) {
|
|
544
|
+
// Output below minimum (330 sats)
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
## Best Practices
|
|
550
|
+
|
|
551
|
+
1. **UTXO Management**: Track and reuse change UTXOs from `nextUTXOs`
|
|
552
|
+
2. **Fee Estimation**: Use realistic fee rates from mempool data
|
|
553
|
+
3. **Address Rotation**: Use different addresses for privacy
|
|
554
|
+
4. **Error Recovery**: Implement retry logic for network issues
|
|
555
|
+
5. **UTXO Consolidation**: Periodically combine small UTXOs to reduce future fees
|
|
556
|
+
|
|
557
|
+
## Complete Example
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
import {
|
|
561
|
+
TransactionFactory,
|
|
562
|
+
EcKeyPair,
|
|
563
|
+
UTXO,
|
|
564
|
+
createSignerMap,
|
|
565
|
+
createAddressRotation,
|
|
566
|
+
} from '@btc-vision/transaction';
|
|
567
|
+
import { networks } from '@btc-vision/bitcoin';
|
|
568
|
+
|
|
569
|
+
async function sendBitcoin() {
|
|
570
|
+
const network = networks.bitcoin;
|
|
571
|
+
const factory = new TransactionFactory();
|
|
572
|
+
|
|
573
|
+
// Create signer from WIF
|
|
574
|
+
const signer = EcKeyPair.fromWIF(process.env.PRIVATE_KEY!, network);
|
|
575
|
+
const address = EcKeyPair.getTaprootAddress(signer, network);
|
|
576
|
+
|
|
577
|
+
// Fetch UTXOs from your provider
|
|
578
|
+
const utxos: UTXO[] = await fetchUTXOs(address);
|
|
579
|
+
|
|
580
|
+
// Create transfer
|
|
581
|
+
const result = await factory.createBTCTransfer({
|
|
582
|
+
signer,
|
|
583
|
+
mldsaSigner: null,
|
|
584
|
+
network,
|
|
585
|
+
utxos,
|
|
586
|
+
from: address,
|
|
587
|
+
to: 'bc1p...recipient',
|
|
588
|
+
feeRate: 10,
|
|
589
|
+
priorityFee: 0n,
|
|
590
|
+
gasSatFee: 0n,
|
|
591
|
+
amount: 50000n,
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
// Broadcast transaction
|
|
595
|
+
await broadcastTransaction(result.tx);
|
|
596
|
+
|
|
597
|
+
// Save change UTXOs for next transaction
|
|
598
|
+
saveUTXOs(result.nextUTXOs);
|
|
599
|
+
|
|
600
|
+
console.log('Transaction sent!');
|
|
601
|
+
console.log('Fee:', result.estimatedFees, 'sats');
|
|
602
|
+
}
|
|
603
|
+
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/transaction",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.7.
|
|
4
|
+
"version": "1.7.22",
|
|
5
5
|
"author": "BlobMaster41",
|
|
6
6
|
"description": "OPNet transaction library allows you to create and sign transactions for the OPNet network.",
|
|
7
7
|
"engines": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"smart inscriptions",
|
|
44
44
|
"ordinals"
|
|
45
45
|
],
|
|
46
|
-
"license": "
|
|
46
|
+
"license": "Apache-2.0",
|
|
47
47
|
"main": "build/index.js",
|
|
48
48
|
"types": "build/index.d.ts",
|
|
49
49
|
"typings": "build/index.d.ts",
|
package/src/_version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.7.
|
|
1
|
+
export const version = '1.7.22';
|