@btc-vision/transaction 1.8.0-rc.1 → 1.8.0-rc.2
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/browser/_version.d.ts +1 -1
- package/browser/_version.d.ts.map +1 -1
- package/browser/btc-vision-bitcoin.js +3560 -3170
- package/browser/buffer/BinaryWriter.d.ts +1 -1
- package/browser/buffer/BinaryWriter.d.ts.map +1 -1
- package/browser/bytecode/Compressor.d.ts +6 -6
- package/browser/bytecode/Compressor.d.ts.map +1 -1
- package/browser/epoch/ChallengeSolution.d.ts +14 -14
- package/browser/epoch/ChallengeSolution.d.ts.map +1 -1
- package/browser/generators/MLDSAData.d.ts +4 -4
- package/browser/generators/MLDSAData.d.ts.map +1 -1
- package/browser/index.js +966 -967
- package/browser/noble-curves.js +1 -1
- package/browser/noble-hashes.js +867 -1758
- package/browser/transaction/browser/types/Unisat.d.ts +1 -1
- package/browser/transaction/browser/types/Unisat.d.ts.map +1 -1
- package/browser/transaction/builders/CustomScriptTransaction.d.ts +1 -1
- package/browser/transaction/builders/DeploymentTransaction.d.ts +2 -2
- package/browser/transaction/builders/MultiSignTransaction.d.ts +5 -5
- package/browser/transaction/builders/SharedInteractionTransaction.d.ts +5 -5
- package/browser/transaction/builders/TransactionBuilder.d.ts +4 -4
- package/browser/transaction/offline/OfflineTransactionManager.d.ts +1 -1
- package/browser/transaction/shared/P2TR_MS.d.ts +1 -1
- package/browser/transaction/shared/TweakedTransaction.d.ts +2 -2
- package/browser/transaction/shared/TweakedTransaction.d.ts.map +1 -1
- package/browser/utils/BitcoinUtils.d.ts +5 -5
- package/browser/utils/BitcoinUtils.d.ts.map +1 -1
- package/browser/utils/BufferHelper.d.ts +1 -1
- package/browser/utils/BufferHelper.d.ts.map +1 -1
- package/browser/utils/StringToBuffer.d.ts +1 -1
- package/browser/utils/StringToBuffer.d.ts.map +1 -1
- package/browser/utils/types.d.ts +1 -1
- package/browser/utils/types.d.ts.map +1 -1
- package/browser/utxo/OPNetLimitedProvider.d.ts.map +1 -1
- package/browser/vendors.js +7732 -13160
- package/build/_version.d.ts +1 -1
- package/build/_version.d.ts.map +1 -1
- package/build/_version.js +1 -1
- package/build/_version.js.map +1 -1
- package/build/abi/ABICoder.js +3 -3
- package/build/abi/ABICoder.js.map +1 -1
- package/build/buffer/BinaryReader.js +1 -1
- package/build/buffer/BinaryReader.js.map +1 -1
- package/build/buffer/BinaryWriter.d.ts +1 -1
- package/build/buffer/BinaryWriter.d.ts.map +1 -1
- package/build/buffer/BinaryWriter.js.map +1 -1
- package/build/bytecode/Compressor.d.ts +6 -6
- package/build/bytecode/Compressor.d.ts.map +1 -1
- package/build/bytecode/Compressor.js +6 -6
- package/build/bytecode/Compressor.js.map +1 -1
- package/build/epoch/ChallengeSolution.d.ts +14 -14
- package/build/epoch/ChallengeSolution.d.ts.map +1 -1
- package/build/epoch/ChallengeSolution.js +11 -10
- package/build/epoch/ChallengeSolution.js.map +1 -1
- package/build/generators/MLDSAData.d.ts +4 -4
- package/build/generators/MLDSAData.d.ts.map +1 -1
- package/build/transaction/browser/types/Unisat.d.ts +1 -1
- package/build/transaction/browser/types/Unisat.d.ts.map +1 -1
- package/build/transaction/builders/CancelTransaction.js +1 -1
- package/build/transaction/builders/CancelTransaction.js.map +1 -1
- package/build/transaction/builders/ChallengeSolutionTransaction.js +5 -5
- package/build/transaction/builders/CustomScriptTransaction.d.ts +1 -1
- package/build/transaction/builders/CustomScriptTransaction.js +1 -1
- package/build/transaction/builders/DeploymentTransaction.d.ts +2 -2
- package/build/transaction/builders/DeploymentTransaction.js +2 -2
- package/build/transaction/builders/MultiSignTransaction.d.ts +5 -5
- package/build/transaction/builders/MultiSignTransaction.js +5 -5
- package/build/transaction/builders/SharedInteractionTransaction.d.ts +5 -5
- package/build/transaction/builders/SharedInteractionTransaction.js +5 -5
- package/build/transaction/builders/TransactionBuilder.d.ts +4 -4
- package/build/transaction/builders/TransactionBuilder.js +4 -4
- package/build/transaction/offline/OfflineTransactionManager.d.ts +1 -1
- package/build/transaction/offline/OfflineTransactionManager.js +1 -1
- package/build/transaction/shared/P2TR_MS.d.ts +1 -1
- package/build/transaction/shared/P2TR_MS.js +1 -1
- package/build/transaction/shared/TweakedTransaction.d.ts +2 -2
- package/build/transaction/shared/TweakedTransaction.d.ts.map +1 -1
- package/build/transaction/shared/TweakedTransaction.js +2 -13
- package/build/transaction/shared/TweakedTransaction.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/build/utils/BitcoinUtils.d.ts +5 -5
- package/build/utils/BitcoinUtils.d.ts.map +1 -1
- package/build/utils/BitcoinUtils.js +7 -7
- package/build/utils/BitcoinUtils.js.map +1 -1
- package/build/utils/BufferHelper.d.ts +1 -1
- package/build/utils/BufferHelper.d.ts.map +1 -1
- package/build/utils/BufferHelper.js.map +1 -1
- package/build/utils/StringToBuffer.d.ts +1 -1
- package/build/utils/StringToBuffer.d.ts.map +1 -1
- package/build/utils/StringToBuffer.js +2 -1
- package/build/utils/StringToBuffer.js.map +1 -1
- package/build/utils/types.d.ts +1 -1
- package/build/utils/types.d.ts.map +1 -1
- package/build/utxo/OPNetLimitedProvider.d.ts +1 -1
- package/build/utxo/OPNetLimitedProvider.d.ts.map +1 -1
- package/build/utxo/OPNetLimitedProvider.js +2 -1
- package/build/utxo/OPNetLimitedProvider.js.map +1 -1
- package/documentation/README.md +322 -25
- package/documentation/abi/abi-coder.md +440 -0
- package/documentation/addresses/address-types.md +459 -0
- package/documentation/api-reference/interfaces.md +806 -0
- package/documentation/api-reference/response-types.md +480 -0
- package/documentation/api-reference/transaction-types.md +348 -0
- package/documentation/binary/binary-reader.md +526 -0
- package/documentation/binary/binary-writer.md +484 -0
- package/documentation/browser/wallet-extensions.md +278 -0
- package/documentation/browser/web3-provider.md +300 -0
- package/documentation/deterministic/deterministic-collections.md +489 -0
- package/documentation/epoch/challenge-solution.md +462 -0
- package/documentation/epoch/epoch-validator.md +316 -0
- package/documentation/generators/generators.md +636 -0
- package/documentation/getting-started/installation.md +256 -0
- package/documentation/getting-started/overview.md +348 -0
- package/documentation/getting-started/quick-start.md +582 -0
- package/documentation/keypair/address-verificator.md +459 -0
- package/documentation/keypair/address.md +702 -0
- package/documentation/keypair/ec-keypair.md +558 -0
- package/documentation/keypair/message-signer.md +840 -0
- package/documentation/keypair/mnemonic.md +560 -0
- package/documentation/keypair/wallet.md +401 -0
- package/documentation/offline/offline-transaction-signing.md +819 -0
- package/documentation/quantum-support/04-message-signing.md +244 -10
- package/documentation/signer/address-rotation.md +419 -0
- package/documentation/signer/parallel-signer.md +245 -0
- package/documentation/signer/tweaked-signer.md +214 -0
- package/documentation/transaction-building/cancel-transactions.md +285 -0
- package/documentation/transaction-building/consolidated-transactions.md +441 -0
- package/documentation/transaction-building/custom-script-transactions.md +280 -0
- package/documentation/transaction-building/deployment-transactions.md +241 -0
- package/documentation/transaction-building/funding-transactions.md +282 -0
- package/documentation/transaction-building/interaction-transactions.md +292 -0
- package/documentation/transaction-building/multisig-transactions.md +340 -0
- package/documentation/transaction-building/transaction-factory-interfaces.md +726 -0
- package/documentation/transaction-building/transaction-factory.md +746 -0
- package/documentation/utils/bitcoin-utils.md +196 -0
- package/documentation/utils/buffer-helper.md +259 -0
- package/documentation/utils/compressor.md +182 -0
- package/documentation/utils/types-and-constants.md +259 -0
- package/documentation/utxo/opnet-limited-provider.md +363 -0
- package/package.json +4 -4
- package/src/_version.ts +1 -1
- package/src/abi/ABICoder.ts +4 -4
- package/src/buffer/BinaryReader.ts +1 -1
- package/src/buffer/BinaryWriter.ts +1 -1
- package/src/bytecode/Compressor.ts +8 -8
- package/src/epoch/ChallengeSolution.ts +23 -22
- package/src/generators/MLDSAData.ts +4 -4
- package/src/shims/zlib-browser.js +4 -4
- package/src/transaction/browser/types/Unisat.ts +1 -1
- package/src/transaction/builders/CancelTransaction.ts +1 -1
- package/src/transaction/builders/ChallengeSolutionTransaction.ts +5 -5
- package/src/transaction/builders/CustomScriptTransaction.ts +1 -1
- package/src/transaction/builders/DeploymentTransaction.ts +2 -2
- package/src/transaction/builders/MultiSignTransaction.ts +5 -5
- package/src/transaction/builders/SharedInteractionTransaction.ts +5 -5
- package/src/transaction/builders/TransactionBuilder.ts +4 -4
- package/src/transaction/offline/OfflineTransactionManager.ts +1 -1
- package/src/transaction/shared/P2TR_MS.ts +1 -1
- package/src/transaction/shared/TweakedTransaction.ts +3 -15
- package/src/utils/BitcoinUtils.ts +11 -11
- package/src/utils/BufferHelper.ts +1 -1
- package/src/utils/StringToBuffer.ts +4 -2
- package/src/utils/types.ts +1 -1
- package/src/utxo/OPNetLimitedProvider.ts +2 -2
- package/documentation/offline-transaction-signing.md +0 -652
- package/documentation/transaction-building.md +0 -603
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# Funding Transactions (BTC Transfers)
|
|
2
|
+
|
|
3
|
+
Simple Bitcoin transfers using `FundingTransaction`.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
A `FundingTransaction` creates a standard Bitcoin transfer from one address to another. It handles UTXO selection, fee calculation, change outputs, and optional output splitting.
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
flowchart LR
|
|
11
|
+
subgraph Inputs["Input UTXOs"]
|
|
12
|
+
U1["UTXO 1"]
|
|
13
|
+
U2["UTXO 2"]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
subgraph FundingTx["FundingTransaction"]
|
|
17
|
+
direction TB
|
|
18
|
+
Select["Select inputs"]
|
|
19
|
+
Calc["Calculate fees"]
|
|
20
|
+
Build["Build outputs"]
|
|
21
|
+
Sign["Sign & finalize"]
|
|
22
|
+
Select --> Calc --> Build --> Sign
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
subgraph Outputs
|
|
26
|
+
O1["Recipient Output<br/>(amount)"]
|
|
27
|
+
O2["Change Output<br/>(leftover - fees)"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
U1 --> FundingTx
|
|
31
|
+
U2 --> FundingTx
|
|
32
|
+
FundingTx --> O1
|
|
33
|
+
FundingTx --> O2
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Factory Methods
|
|
37
|
+
|
|
38
|
+
Funding transactions are created through `TransactionFactory`:
|
|
39
|
+
|
|
40
|
+
| Method | Description |
|
|
41
|
+
|--------|-------------|
|
|
42
|
+
| `TransactionFactory.createBTCTransfer()` | Create and sign a BTC transfer, returning the hex-encoded transaction |
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { TransactionFactory } from '@btc-vision/transaction';
|
|
46
|
+
|
|
47
|
+
const factory = new TransactionFactory();
|
|
48
|
+
const result = await factory.createBTCTransfer(parameters);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Parameters
|
|
52
|
+
|
|
53
|
+
`IFundingTransactionParameters` extends the base `ITransactionParameters`:
|
|
54
|
+
|
|
55
|
+
| Parameter | Type | Required | Default | Description |
|
|
56
|
+
|-----------|------|----------|---------|-------------|
|
|
57
|
+
| `signer` | `Signer \| UniversalSigner` | Yes | - | Key pair used to sign inputs |
|
|
58
|
+
| `network` | `Network` | Yes | - | Bitcoin network (`networks.bitcoin`, `networks.testnet`, `networks.regtest`) |
|
|
59
|
+
| `utxos` | `UTXO[]` | Yes | - | Available UTXOs to spend |
|
|
60
|
+
| `from` | `string` | Yes | - | Sender address (for change output) |
|
|
61
|
+
| `to` | `string` | Yes | - | Recipient address |
|
|
62
|
+
| `feeRate` | `number` | Yes | - | Fee rate in sat/vB |
|
|
63
|
+
| `priorityFee` | `bigint` | Yes | - | OPNet priority fee (use `0n` for plain BTC transfers) |
|
|
64
|
+
| `gasSatFee` | `bigint` | Yes | - | OPNet gas fee (use `0n` for plain BTC transfers) |
|
|
65
|
+
| `amount` | `bigint` | Yes | - | Amount to send in satoshis |
|
|
66
|
+
| `splitInputsInto` | `number` | No | `1` | Split the output into N equal UTXOs |
|
|
67
|
+
| `autoAdjustAmount` | `boolean` | No | `false` | Deduct fees from output (send-max mode) |
|
|
68
|
+
| `feeUtxos` | `UTXO[]` | No | `undefined` | Separate UTXOs used exclusively to cover fees |
|
|
69
|
+
| `mldsaSigner` | `QuantumBIP32Interface \| null` | No | - | ML-DSA (quantum-resistant) signer |
|
|
70
|
+
| `optionalOutputs` | `PsbtOutputExtended[]` | No | - | Additional outputs (e.g., OP_RETURN notes) |
|
|
71
|
+
| `note` | `string \| Uint8Array` | No | - | Embed an OP_RETURN note in the transaction |
|
|
72
|
+
|
|
73
|
+
## Response Type
|
|
74
|
+
|
|
75
|
+
`BitcoinTransferResponse`:
|
|
76
|
+
|
|
77
|
+
| Field | Type | Description |
|
|
78
|
+
|-------|------|-------------|
|
|
79
|
+
| `tx` | `string` | Signed transaction in hex format, ready to broadcast |
|
|
80
|
+
| `estimatedFees` | `bigint` | Total fees paid in satoshis |
|
|
81
|
+
| `nextUTXOs` | `UTXO[]` | Change UTXOs belonging to the sender, for use in subsequent transactions |
|
|
82
|
+
| `inputUtxos` | `UTXO[]` | The UTXOs that were consumed as inputs |
|
|
83
|
+
| `original` | `FundingTransaction` | The underlying `FundingTransaction` instance |
|
|
84
|
+
|
|
85
|
+
## Send-Max Mode
|
|
86
|
+
|
|
87
|
+
Setting `autoAdjustAmount: true` sends the entire balance minus fees. When the requested `amount` equals or exceeds the total UTXO value, the builder estimates fees first, then reduces the output amount accordingly.
|
|
88
|
+
|
|
89
|
+
```mermaid
|
|
90
|
+
flowchart TB
|
|
91
|
+
Start["amount >= totalInputAmount?"]
|
|
92
|
+
Start -->|"Yes"| Estimate["Estimate fee with<br/>temporary output"]
|
|
93
|
+
Estimate --> Adjust["adjustedAmount =<br/>totalInput - estimatedFee"]
|
|
94
|
+
Adjust --> Check{"adjustedAmount<br/>< dust?"}
|
|
95
|
+
Check -->|"Yes"| Error["Error: Insufficient funds"]
|
|
96
|
+
Check -->|"No"| Build["Build transaction<br/>with adjusted amount"]
|
|
97
|
+
Start -->|"No"| Normal["Build transaction<br/>with original amount"]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Send entire balance
|
|
102
|
+
const result = await factory.createBTCTransfer({
|
|
103
|
+
signer,
|
|
104
|
+
mldsaSigner: null,
|
|
105
|
+
network,
|
|
106
|
+
utxos,
|
|
107
|
+
from: myAddress,
|
|
108
|
+
to: recipientAddress,
|
|
109
|
+
feeRate: 10,
|
|
110
|
+
priorityFee: 0n,
|
|
111
|
+
gasSatFee: 0n,
|
|
112
|
+
amount: totalBalance, // Set to total UTXO value
|
|
113
|
+
autoAdjustAmount: true, // Fees deducted from output
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// result.tx contains the full balance minus fees
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Output Splitting
|
|
120
|
+
|
|
121
|
+
Use `splitInputsInto` to divide the output amount across multiple equal UTXOs at the same address. This is useful for preparing UTXOs for future parallel transactions.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const result = await factory.createBTCTransfer({
|
|
125
|
+
signer,
|
|
126
|
+
mldsaSigner: null,
|
|
127
|
+
network,
|
|
128
|
+
utxos,
|
|
129
|
+
from: myAddress,
|
|
130
|
+
to: recipientAddress,
|
|
131
|
+
feeRate: 10,
|
|
132
|
+
priorityFee: 0n,
|
|
133
|
+
gasSatFee: 0n,
|
|
134
|
+
amount: 100000n,
|
|
135
|
+
splitInputsInto: 4, // Creates 4 outputs of 25,000 sat each
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Fee UTXOs
|
|
140
|
+
|
|
141
|
+
Use `feeUtxos` to pay transaction fees from a separate set of UTXOs. The output amount stays exact and fees are drawn from the fee UTXOs. Any leftover becomes the change output.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const result = await factory.createBTCTransfer({
|
|
145
|
+
signer,
|
|
146
|
+
mldsaSigner: null,
|
|
147
|
+
network,
|
|
148
|
+
utxos: [paymentUtxo], // Used for the payment output
|
|
149
|
+
feeUtxos: [feeOnlyUtxo], // Used exclusively to cover fees
|
|
150
|
+
from: myAddress,
|
|
151
|
+
to: recipientAddress,
|
|
152
|
+
feeRate: 10,
|
|
153
|
+
priorityFee: 0n,
|
|
154
|
+
gasSatFee: 0n,
|
|
155
|
+
amount: 50000n,
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Internally, `feeUtxos` are merged into the input set:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// From FundingTransaction constructor:
|
|
163
|
+
const mergedParams = parameters.feeUtxos?.length
|
|
164
|
+
? { ...parameters, utxos: [...parameters.utxos, ...parameters.feeUtxos] }
|
|
165
|
+
: parameters;
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Complete Example
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { TransactionFactory, EcKeyPair, UTXO } from '@btc-vision/transaction';
|
|
172
|
+
import { networks } from '@btc-vision/bitcoin';
|
|
173
|
+
|
|
174
|
+
async function transferBTC() {
|
|
175
|
+
const network = networks.bitcoin;
|
|
176
|
+
const factory = new TransactionFactory();
|
|
177
|
+
|
|
178
|
+
// Create signer
|
|
179
|
+
const signer = EcKeyPair.fromWIF(process.env.PRIVATE_KEY!, network);
|
|
180
|
+
const address = EcKeyPair.getTaprootAddress(signer, network);
|
|
181
|
+
|
|
182
|
+
// Fetch your UTXOs (from a provider or local state)
|
|
183
|
+
const utxos: UTXO[] = [
|
|
184
|
+
{
|
|
185
|
+
transactionId: 'abcd1234...'.padEnd(64, '0'),
|
|
186
|
+
outputIndex: 0,
|
|
187
|
+
value: 100000n,
|
|
188
|
+
scriptPubKey: {
|
|
189
|
+
hex: '5120...',
|
|
190
|
+
address: address,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
// Send 50,000 sats
|
|
196
|
+
const result = await factory.createBTCTransfer({
|
|
197
|
+
signer,
|
|
198
|
+
mldsaSigner: null,
|
|
199
|
+
network,
|
|
200
|
+
utxos,
|
|
201
|
+
from: address,
|
|
202
|
+
to: 'bc1p...recipient',
|
|
203
|
+
feeRate: 10,
|
|
204
|
+
priorityFee: 0n,
|
|
205
|
+
gasSatFee: 0n,
|
|
206
|
+
amount: 50000n,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
console.log('Transaction hex:', result.tx);
|
|
210
|
+
console.log('Fees paid:', result.estimatedFees, 'sats');
|
|
211
|
+
console.log('Change UTXOs:', result.nextUTXOs);
|
|
212
|
+
|
|
213
|
+
// Broadcast the transaction
|
|
214
|
+
await broadcastTransaction(result.tx);
|
|
215
|
+
|
|
216
|
+
// Track the change UTXOs for your next transaction
|
|
217
|
+
const availableUtxos = result.nextUTXOs;
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## UTXO Tracking
|
|
222
|
+
|
|
223
|
+
Always track the `nextUTXOs` returned from each transaction. These are your new spendable outputs and must be used as inputs for subsequent transactions.
|
|
224
|
+
|
|
225
|
+
```mermaid
|
|
226
|
+
flowchart LR
|
|
227
|
+
TX1["Transfer 1"] -->|"nextUTXOs"| TX2["Transfer 2"]
|
|
228
|
+
TX2 -->|"nextUTXOs"| TX3["Transfer 3"]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
let currentUtxos = initialUtxos;
|
|
233
|
+
|
|
234
|
+
// First transfer
|
|
235
|
+
const result1 = await factory.createBTCTransfer({
|
|
236
|
+
...params,
|
|
237
|
+
utxos: currentUtxos,
|
|
238
|
+
amount: 30000n,
|
|
239
|
+
});
|
|
240
|
+
currentUtxos = result1.nextUTXOs;
|
|
241
|
+
|
|
242
|
+
// Second transfer (uses change from first)
|
|
243
|
+
const result2 = await factory.createBTCTransfer({
|
|
244
|
+
...params,
|
|
245
|
+
utxos: currentUtxos,
|
|
246
|
+
amount: 20000n,
|
|
247
|
+
});
|
|
248
|
+
currentUtxos = result2.nextUTXOs;
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Error Handling
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
try {
|
|
255
|
+
const result = await factory.createBTCTransfer(params);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
const message = (error as Error).message;
|
|
258
|
+
|
|
259
|
+
if (message.includes('Recipient address is required')) {
|
|
260
|
+
// The 'to' field is missing
|
|
261
|
+
} else if (message.includes('Insufficient funds')) {
|
|
262
|
+
// UTXOs do not cover amount + fees (thrown during autoAdjust)
|
|
263
|
+
} else if (message.includes('below minimum dust')) {
|
|
264
|
+
// After fee deduction, remaining amount is below 330 sats
|
|
265
|
+
} else if (message.includes('Field "from" not provided')) {
|
|
266
|
+
// The 'from' field is missing (thrown by TransactionFactory)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Best Practices
|
|
272
|
+
|
|
273
|
+
1. **Set realistic fee rates.** Query mempool fee estimates before building a transaction.
|
|
274
|
+
2. **Track change UTXOs.** Always use `nextUTXOs` as inputs for follow-up transactions to avoid double-spending.
|
|
275
|
+
3. **Use `autoAdjustAmount` for sweeps.** When sending the entire balance, let the builder subtract fees automatically.
|
|
276
|
+
4. **Use `feeUtxos` for exact amounts.** When the recipient must receive an exact amount, pay fees from separate UTXOs.
|
|
277
|
+
5. **Consolidate dust.** Periodically combine many small UTXOs into fewer larger ones to reduce future transaction sizes and fees.
|
|
278
|
+
6. **Set OPNet fees to `0n` for plain transfers.** The `priorityFee` and `gasSatFee` fields are only relevant for OPNet contract operations.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
[< Back to README](../README.md) | [Deployment Transactions >](./deployment-transactions.md)
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# Interaction Transactions
|
|
2
|
+
|
|
3
|
+
Call smart contract functions using `InteractionTransaction`.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
An `InteractionTransaction` calls a function on a deployed OPNet smart contract. Like deployments, interactions use a **two-transaction model**: a funding transaction sends BTC to a derived Taproot script address, and the interaction transaction spends that UTXO while embedding the calldata in the Taproot witness.
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
flowchart LR
|
|
11
|
+
subgraph TX1["Transaction 1: Funding"]
|
|
12
|
+
U["User UTXOs"] --> SA["Script Address<br/>(P2TR)"]
|
|
13
|
+
U --> Change["Change Output"]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
subgraph TX2["Transaction 2: Interaction"]
|
|
17
|
+
SA2["Script UTXO"] --> EP["Epoch Reward<br/>(Challenge)"]
|
|
18
|
+
SA2 --> RF["Refund"]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
SA -->|"creates UTXO"| SA2
|
|
22
|
+
|
|
23
|
+
subgraph Contract["OPNet Execution"]
|
|
24
|
+
CD["Calldata decoded<br/>by validators"]
|
|
25
|
+
ST["State updated<br/>on-chain"]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
TX2 --> Contract
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Factory Method
|
|
32
|
+
|
|
33
|
+
Interactions are created through `TransactionFactory.signInteraction()`:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { TransactionFactory } from '@btc-vision/transaction';
|
|
37
|
+
|
|
38
|
+
const factory = new TransactionFactory();
|
|
39
|
+
const result = await factory.signInteraction(parameters);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Architecture
|
|
43
|
+
|
|
44
|
+
`InteractionTransaction` extends `SharedInteractionTransaction`, which provides the common logic for calldata compression, script-path signing, and reward outputs. The class hierarchy is:
|
|
45
|
+
|
|
46
|
+
```mermaid
|
|
47
|
+
flowchart TB
|
|
48
|
+
TT["TweakedTransaction"]
|
|
49
|
+
TB["TransactionBuilder<T>"]
|
|
50
|
+
SIT["SharedInteractionTransaction<T><br/>(calldata, script signer, rewards)"]
|
|
51
|
+
IT["InteractionTransaction<br/>(contract secret, access list)"]
|
|
52
|
+
|
|
53
|
+
TT --> TB --> SIT --> IT
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`SharedInteractionTransaction` handles:
|
|
57
|
+
- Calldata compression via `Compressor`
|
|
58
|
+
- Script signer generation from random bytes
|
|
59
|
+
- Taproot script tree construction (target script + lock leaf)
|
|
60
|
+
- Epoch reward output creation
|
|
61
|
+
- Dual-signature signing (script signer + wallet signer)
|
|
62
|
+
|
|
63
|
+
`InteractionTransaction` adds:
|
|
64
|
+
- Contract secret (derived from the contract's public key)
|
|
65
|
+
- Access list support for gas optimization
|
|
66
|
+
- Feature generation (epoch submission, ML-DSA linking)
|
|
67
|
+
|
|
68
|
+
## Parameters
|
|
69
|
+
|
|
70
|
+
`IInteractionParameters` extends `SharedInteractionParameters`:
|
|
71
|
+
|
|
72
|
+
| Parameter | Type | Required | Default | Description |
|
|
73
|
+
|-----------|------|----------|---------|-------------|
|
|
74
|
+
| `signer` | `Signer \| UniversalSigner` | Yes | - | Key pair used to sign inputs |
|
|
75
|
+
| `mldsaSigner` | `QuantumBIP32Interface \| null` | No | - | ML-DSA (quantum-resistant) signer |
|
|
76
|
+
| `network` | `Network` | Yes | - | Bitcoin network |
|
|
77
|
+
| `utxos` | `UTXO[]` | Yes | - | Available UTXOs to fund the interaction |
|
|
78
|
+
| `from` | `string` | Yes | - | Sender address |
|
|
79
|
+
| `to` | `string` | Yes | - | Contract's P2TR address |
|
|
80
|
+
| `feeRate` | `number` | Yes | - | Fee rate in sat/vB |
|
|
81
|
+
| `priorityFee` | `bigint` | Yes | - | OPNet priority fee in satoshis |
|
|
82
|
+
| `gasSatFee` | `bigint` | Yes | - | OPNet gas fee in satoshis |
|
|
83
|
+
| `calldata` | `Uint8Array` | Yes | - | ABI-encoded function call |
|
|
84
|
+
| `contract` | `string` | Yes | - | Contract public key (hex, `0x`-prefixed, 32 bytes) |
|
|
85
|
+
| `challenge` | `IChallengeSolution` | Yes | - | Epoch challenge solution |
|
|
86
|
+
| `randomBytes` | `Uint8Array` | No | Auto-generated | 32-byte random salt |
|
|
87
|
+
| `loadedStorage` | `LoadedStorage` | No | - | Access list for gas optimization |
|
|
88
|
+
| `disableAutoRefund` | `boolean` | No | `false` | Skip the automatic refund output |
|
|
89
|
+
|
|
90
|
+
### Constraints
|
|
91
|
+
|
|
92
|
+
| Constraint | Value | Description |
|
|
93
|
+
|------------|-------|-------------|
|
|
94
|
+
| Maximum calldata size | **1 MB** (`1024 * 1024` bytes) | Before compression. Enforced by `SharedInteractionTransaction.MAXIMUM_CALLDATA_SIZE`. |
|
|
95
|
+
| Contract secret length | **32 bytes** | The `contract` parameter must decode to exactly 32 bytes. |
|
|
96
|
+
|
|
97
|
+
## Response Type
|
|
98
|
+
|
|
99
|
+
`InteractionResponse`:
|
|
100
|
+
|
|
101
|
+
| Field | Type | Description |
|
|
102
|
+
|-------|------|-------------|
|
|
103
|
+
| `fundingTransaction` | `string \| null` | Funding transaction hex (`null` for P2WDA interactions) |
|
|
104
|
+
| `interactionTransaction` | `string` | Interaction transaction hex |
|
|
105
|
+
| `estimatedFees` | `bigint` | Total fees in satoshis |
|
|
106
|
+
| `nextUTXOs` | `UTXO[]` | Change UTXOs for subsequent transactions |
|
|
107
|
+
| `fundingUTXOs` | `UTXO[]` | The UTXO(s) created by the funding transaction |
|
|
108
|
+
| `fundingInputUtxos` | `UTXO[]` | Original UTXOs consumed as inputs |
|
|
109
|
+
| `challenge` | `RawChallenge` | The raw epoch challenge used |
|
|
110
|
+
| `interactionAddress` | `string \| null` | The Taproot script address used for the interaction |
|
|
111
|
+
| `compiledTargetScript` | `string \| null` | The compiled target script (hex) for cancellation recovery |
|
|
112
|
+
|
|
113
|
+
## Access List Support
|
|
114
|
+
|
|
115
|
+
The access list (`loadedStorage`) pre-declares which contract storage slots the interaction will read. This allows validators to optimize gas costs by pre-loading the required state.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const loadedStorage: LoadedStorage = {
|
|
119
|
+
// contract address -> array of storage slot keys
|
|
120
|
+
'bc1p...contractAddress': [
|
|
121
|
+
'0x0000...storageSlot1',
|
|
122
|
+
'0x0000...storageSlot2',
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const result = await factory.signInteraction({
|
|
127
|
+
// ... other params
|
|
128
|
+
loadedStorage,
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The access list is encoded as a transaction feature with `Features.ACCESS_LIST` priority:
|
|
133
|
+
|
|
134
|
+
```mermaid
|
|
135
|
+
flowchart LR
|
|
136
|
+
AL["loadedStorage<br/>{addr: [slots]}"] --> F["Feature<br/>ACCESS_LIST"]
|
|
137
|
+
F --> CS["Compiled into<br/>target script"]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Two-Transaction Flow
|
|
141
|
+
|
|
142
|
+
The factory handles the complete two-transaction flow:
|
|
143
|
+
|
|
144
|
+
```mermaid
|
|
145
|
+
sequenceDiagram
|
|
146
|
+
participant App
|
|
147
|
+
participant Factory as TransactionFactory
|
|
148
|
+
participant FT as FundingTransaction
|
|
149
|
+
participant IT as InteractionTransaction
|
|
150
|
+
|
|
151
|
+
App->>Factory: signInteraction(params)
|
|
152
|
+
Factory->>Factory: Iterate funding amount<br/>(simulate & converge)
|
|
153
|
+
Factory->>FT: Create & sign funding tx
|
|
154
|
+
FT-->>Factory: Signed funding tx + script UTXO
|
|
155
|
+
Factory->>IT: Create interaction tx<br/>(uses funding UTXO)
|
|
156
|
+
Factory->>IT: Sign interaction tx<br/>(script signer + wallet signer)
|
|
157
|
+
IT-->>Factory: Signed interaction tx
|
|
158
|
+
Factory-->>App: InteractionResponse
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
1. The factory iteratively estimates the required funding amount.
|
|
162
|
+
2. A `FundingTransaction` sends BTC to the derived Taproot script address.
|
|
163
|
+
3. An `InteractionTransaction` spends that UTXO, revealing the calldata in the witness.
|
|
164
|
+
4. Both transactions are returned for sequential broadcast.
|
|
165
|
+
|
|
166
|
+
## Signing Process
|
|
167
|
+
|
|
168
|
+
Interaction transactions use a dual-signature scheme. Input 0 (the script-path input) requires two signatures:
|
|
169
|
+
|
|
170
|
+
```mermaid
|
|
171
|
+
flowchart TB
|
|
172
|
+
subgraph Input0["Input 0 (Script Path)"]
|
|
173
|
+
SS["Script Signer<br/>(derived from randomBytes)"]
|
|
174
|
+
WS["Wallet Signer<br/>(user's key)"]
|
|
175
|
+
SS --> CF["Custom Finalizer<br/>[contractSecret, sig1, sig2,<br/>script, controlBlock]"]
|
|
176
|
+
WS --> CF
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
subgraph InputN["Inputs 1+ (Key Path)"]
|
|
180
|
+
WS2["Wallet Signer"] --> SF["Standard Finalizer"]
|
|
181
|
+
end
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The witness stack for the script-path input contains:
|
|
185
|
+
1. The contract secret (32 bytes)
|
|
186
|
+
2. Script signer's Schnorr signature
|
|
187
|
+
3. Wallet signer's Schnorr signature
|
|
188
|
+
4. The compiled target script
|
|
189
|
+
5. The Taproot control block
|
|
190
|
+
|
|
191
|
+
## Complete Example
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import {
|
|
195
|
+
TransactionFactory,
|
|
196
|
+
EcKeyPair,
|
|
197
|
+
ABICoder,
|
|
198
|
+
ChallengeSolution,
|
|
199
|
+
UTXO,
|
|
200
|
+
} from '@btc-vision/transaction';
|
|
201
|
+
import { networks } from '@btc-vision/bitcoin';
|
|
202
|
+
|
|
203
|
+
async function callContract() {
|
|
204
|
+
const network = networks.bitcoin;
|
|
205
|
+
const factory = new TransactionFactory();
|
|
206
|
+
|
|
207
|
+
// Create signer
|
|
208
|
+
const signer = EcKeyPair.fromWIF(process.env.PRIVATE_KEY!, network);
|
|
209
|
+
const address = EcKeyPair.getTaprootAddress(signer, network);
|
|
210
|
+
|
|
211
|
+
// Fetch UTXOs
|
|
212
|
+
const utxos: UTXO[] = await fetchUTXOs(address);
|
|
213
|
+
|
|
214
|
+
// Encode the function call
|
|
215
|
+
const coder = new ABICoder();
|
|
216
|
+
const calldata = coder.encodeSelector('transfer')
|
|
217
|
+
.addAddress('bc1p...recipientAddress')
|
|
218
|
+
.addUint256(1000000n)
|
|
219
|
+
.compile();
|
|
220
|
+
|
|
221
|
+
// Obtain epoch challenge
|
|
222
|
+
const challenge: ChallengeSolution = await solveEpochChallenge(/* ... */);
|
|
223
|
+
|
|
224
|
+
// Contract details
|
|
225
|
+
const contractAddress = 'bc1p...contractP2TR';
|
|
226
|
+
const contractPubKey = '0x...contractPubKey'; // 32 bytes hex
|
|
227
|
+
|
|
228
|
+
// Execute interaction
|
|
229
|
+
const result = await factory.signInteraction({
|
|
230
|
+
signer,
|
|
231
|
+
mldsaSigner: null,
|
|
232
|
+
network,
|
|
233
|
+
utxos,
|
|
234
|
+
from: address,
|
|
235
|
+
to: contractAddress,
|
|
236
|
+
feeRate: 10,
|
|
237
|
+
priorityFee: 10000n,
|
|
238
|
+
gasSatFee: 5000n,
|
|
239
|
+
calldata,
|
|
240
|
+
contract: contractPubKey,
|
|
241
|
+
challenge,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Broadcast both transactions in order
|
|
245
|
+
await broadcastTransaction(result.fundingTransaction!);
|
|
246
|
+
await broadcastTransaction(result.interactionTransaction);
|
|
247
|
+
|
|
248
|
+
console.log('Interaction sent!');
|
|
249
|
+
console.log('Fees:', result.estimatedFees, 'sats');
|
|
250
|
+
console.log('Change UTXOs:', result.nextUTXOs);
|
|
251
|
+
|
|
252
|
+
// Save compiledTargetScript for potential cancellation
|
|
253
|
+
const compiledScript = result.compiledTargetScript;
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Error Handling
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
try {
|
|
261
|
+
const result = await factory.signInteraction(params);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
const message = (error as Error).message;
|
|
264
|
+
|
|
265
|
+
if (message.includes('parameters.contract is required')) {
|
|
266
|
+
// The 'contract' parameter is missing
|
|
267
|
+
} else if (message.includes('Invalid contract secret length')) {
|
|
268
|
+
// Contract public key does not decode to 32 bytes
|
|
269
|
+
} else if (message.includes('Calldata is required')) {
|
|
270
|
+
// The calldata parameter is missing
|
|
271
|
+
} else if (message.includes('Challenge solution is required')) {
|
|
272
|
+
// The challenge parameter is missing
|
|
273
|
+
} else if (message.includes('Field "to" not provided')) {
|
|
274
|
+
// Contract address (to) is missing
|
|
275
|
+
} else if (message.includes('Could not sign funding transaction')) {
|
|
276
|
+
// Insufficient UTXOs or funding step failed
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Best Practices
|
|
282
|
+
|
|
283
|
+
1. **Save the `compiledTargetScript`.** If the interaction gets stuck, you need this script to create a `CancelTransaction` for recovery.
|
|
284
|
+
2. **Use access lists when possible.** Pre-declaring storage slots via `loadedStorage` reduces gas costs for the validator.
|
|
285
|
+
3. **Broadcast sequentially.** The funding transaction must reach the mempool before the interaction transaction.
|
|
286
|
+
4. **Track change UTXOs.** Use `result.nextUTXOs` for subsequent transactions.
|
|
287
|
+
5. **Set appropriate fees.** Both `priorityFee` and `gasSatFee` affect how validators prioritize your interaction.
|
|
288
|
+
6. **Handle P2WDA automatically.** If your UTXOs are P2WDA type, the factory automatically uses the single-transaction P2WDA path (no funding transaction needed).
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
[< Deployment Transactions](./deployment-transactions.md) | [MultiSig Transactions >](./multisig-transactions.md)
|