@btc-vision/transaction 1.0.122 → 1.1.0
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/consensus/ConsensusConfig.d.ts +0 -4
- package/browser/index.js +1 -1
- package/browser/opnet.d.ts +0 -6
- package/browser/transaction/TransactionFactory.d.ts +1 -13
- package/browser/transaction/browser/Web3Provider.d.ts +2 -6
- package/browser/transaction/browser/extensions/UnisatSigner.d.ts +3 -0
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +0 -14
- package/browser/transaction/processor/PsbtTransaction.d.ts +0 -15
- package/browser/utils/BitcoinUtils.d.ts +0 -3
- package/browser/utxo/OPNetLimitedProvider.d.ts +1 -5
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/consensus/ConsensusConfig.d.ts +0 -4
- package/build/consensus/metadata/RoswellConsensus.js +0 -4
- package/build/opnet.d.ts +0 -6
- package/build/opnet.js +0 -6
- package/build/transaction/TransactionFactory.d.ts +1 -13
- package/build/transaction/TransactionFactory.js +1 -161
- package/build/transaction/browser/Web3Provider.d.ts +2 -6
- package/build/transaction/browser/extensions/UnisatSigner.d.ts +3 -0
- package/build/transaction/browser/extensions/UnisatSigner.js +65 -3
- package/build/transaction/builders/SharedInteractionTransaction.js +4 -4
- package/build/transaction/interfaces/ITransactionParameters.d.ts +0 -14
- package/build/transaction/processor/PsbtTransaction.d.ts +0 -15
- package/build/transaction/processor/PsbtTransaction.js +0 -9
- package/build/utils/BitcoinUtils.d.ts +0 -3
- package/build/utils/BitcoinUtils.js +0 -19
- package/build/utxo/OPNetLimitedProvider.d.ts +1 -5
- package/build/utxo/OPNetLimitedProvider.js +0 -28
- package/package.json +1 -2
- package/src/_version.ts +1 -1
- package/src/consensus/ConsensusConfig.ts +4 -4
- package/src/consensus/metadata/RoswellConsensus.ts +4 -4
- package/src/opnet.ts +6 -6
- package/src/transaction/TransactionFactory.ts +13 -25
- package/src/transaction/browser/Web3Provider.ts +1 -9
- package/src/transaction/browser/extensions/UnisatSigner.ts +83 -3
- package/src/transaction/builders/SharedInteractionTransaction.ts +16 -6
- package/src/transaction/builders/{WrapTransaction.ts → WrapTransaction.ts.disabled} +1 -1
- package/src/transaction/interfaces/ITransactionParameters.ts +2 -5
- package/src/transaction/processor/PsbtTransaction.ts +4 -4
- package/src/utils/BitcoinUtils.ts +4 -5
- package/src/utxo/OPNetLimitedProvider.ts +5 -9
- package/{src/wbtc/Generate.ts → wbtc_disabled/Generate.ts.disabled} +1 -1
- package/{src/wbtc/UnwrapGeneration.ts → wbtc_disabled/UnwrapGeneration.ts.disabled} +1 -1
- package/browser/metadata/contracts/wBTC.d.ts +0 -13
- package/browser/transaction/builders/UnwrapSegwitTransaction.d.ts +0 -32
- package/browser/transaction/builders/UnwrapTransaction.d.ts +0 -41
- package/browser/transaction/builders/WrapTransaction.d.ts +0 -29
- package/browser/wbtc/Generate.d.ts +0 -18
- package/browser/wbtc/UnwrapGeneration.d.ts +0 -7
- package/browser/wbtc/WrappedGenerationParameters.d.ts +0 -10
- package/build/metadata/contracts/wBTC.d.ts +0 -13
- package/build/metadata/contracts/wBTC.js +0 -34
- package/build/transaction/builders/UnwrapSegwitTransaction.d.ts +0 -32
- package/build/transaction/builders/UnwrapSegwitTransaction.js +0 -179
- package/build/transaction/builders/UnwrapTransaction.d.ts +0 -41
- package/build/transaction/builders/UnwrapTransaction.js +0 -258
- package/build/transaction/builders/WrapTransaction.d.ts +0 -29
- package/build/transaction/builders/WrapTransaction.js +0 -146
- package/build/wbtc/Generate.d.ts +0 -18
- package/build/wbtc/Generate.js +0 -1
- package/build/wbtc/UnwrapGeneration.d.ts +0 -7
- package/build/wbtc/UnwrapGeneration.js +0 -6
- package/build/wbtc/WrappedGenerationParameters.d.ts +0 -10
- package/build/wbtc/WrappedGenerationParameters.js +0 -10
- package/src/metadata/contracts/wBTC.ts +0 -59
- /package/src/transaction/builders/{UnwrapSegwitTransaction.ts → UnwrapSegwitTransaction.ts.disabled} +0 -0
- /package/src/transaction/builders/{UnwrapTransaction.ts → UnwrapTransaction.ts.disabled} +0 -0
- /package/{src/wbtc/WrappedGenerationParameters.ts → wbtc_disabled/WrappedGenerationParameters.ts.disabled} +0 -0
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
import { TransactionType } from '../enums/TransactionType.js';
|
|
2
|
-
import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
|
|
3
|
-
import { TransactionBuilder } from './TransactionBuilder.js';
|
|
4
|
-
import { wBTC } from '../../metadata/contracts/wBTC.js';
|
|
5
|
-
import { payments, } from '@btc-vision/bitcoin';
|
|
6
|
-
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
7
|
-
import { PsbtTransaction } from '../processor/PsbtTransaction.js';
|
|
8
|
-
import { MultiSignGenerator } from '../../generators/builders/MultiSignGenerator.js';
|
|
9
|
-
import { MultiSignTransaction } from './MultiSignTransaction.js';
|
|
10
|
-
import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
|
|
11
|
-
import { CalldataGenerator } from '../../generators/builders/CalldataGenerator.js';
|
|
12
|
-
import { currentConsensusConfig } from '../../consensus/ConsensusConfig.js';
|
|
13
|
-
import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
|
|
14
|
-
import { Features } from '../../generators/Features.js';
|
|
15
|
-
import { ABICoder } from '../../abi/ABICoder.js';
|
|
16
|
-
import { BinaryWriter } from '../../buffer/BinaryWriter.js';
|
|
17
|
-
const abiCoder = new ABICoder();
|
|
18
|
-
const numsPoint = Buffer.from('50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0', 'hex');
|
|
19
|
-
export class UnwrapTransaction extends SharedInteractionTransaction {
|
|
20
|
-
constructor(parameters) {
|
|
21
|
-
if (parameters.amount < TransactionBuilder.MINIMUM_DUST) {
|
|
22
|
-
throw new Error('Amount is below dust limit');
|
|
23
|
-
}
|
|
24
|
-
parameters.disableAutoRefund = true;
|
|
25
|
-
parameters.calldata = UnwrapTransaction.generateBurnCalldata(parameters.amount);
|
|
26
|
-
super(parameters);
|
|
27
|
-
this.type = TransactionType.WBTC_UNWRAP;
|
|
28
|
-
this.sighashTypes = [];
|
|
29
|
-
this.estimatedFeeLoss = 0n;
|
|
30
|
-
this.calculatedSignHash = PsbtTransaction.calculateSignHash(this.sighashTypes);
|
|
31
|
-
this.wbtc = new wBTC(parameters.network, parameters.chainId);
|
|
32
|
-
this.to = this.wbtc.getAddress();
|
|
33
|
-
this.vaultUTXOs = parameters.unwrapUTXOs;
|
|
34
|
-
this.estimatedFeeLoss = UnwrapTransaction.preEstimateTaprootTransactionFees(BigInt(this.feeRate), this.calculateNumInputs(this.vaultUTXOs), 2n, this.calculateNumSignatures(this.vaultUTXOs), 65n, this.calculateNumEmptyWitnesses(this.vaultUTXOs));
|
|
35
|
-
this.amount = parameters.amount;
|
|
36
|
-
this.contractSecret = this.generateSecret();
|
|
37
|
-
this.calldataGenerator = new CalldataGenerator(Buffer.from(this.signer.publicKey), this.scriptSignerXOnlyPubKey(), this.network);
|
|
38
|
-
this.compiledTargetScript = this.calldataGenerator.compile(this.calldata, this.contractSecret, [Features.UNWRAP]);
|
|
39
|
-
this.scriptTree = this.getScriptTree();
|
|
40
|
-
this.internalInit();
|
|
41
|
-
}
|
|
42
|
-
static generateBurnCalldata(amount) {
|
|
43
|
-
if (!amount)
|
|
44
|
-
throw new Error('Amount is required');
|
|
45
|
-
const bufWriter = new BinaryWriter();
|
|
46
|
-
bufWriter.writeSelector(UnwrapTransaction.UNWRAP_SELECTOR);
|
|
47
|
-
bufWriter.writeU256(amount);
|
|
48
|
-
return Buffer.from(bufWriter.getBuffer());
|
|
49
|
-
}
|
|
50
|
-
async signPSBT() {
|
|
51
|
-
if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
|
|
52
|
-
throw new Error('Invalid contract address. The contract address must be a taproot address.');
|
|
53
|
-
}
|
|
54
|
-
if (!this.vaultUTXOs.length) {
|
|
55
|
-
throw new Error('No vault UTXOs provided');
|
|
56
|
-
}
|
|
57
|
-
await this.buildTransaction();
|
|
58
|
-
this.ignoreSignatureError();
|
|
59
|
-
this.mergeVaults();
|
|
60
|
-
const builtTx = await this.internalBuildTransaction(this.transaction);
|
|
61
|
-
if (builtTx) {
|
|
62
|
-
return this.transaction;
|
|
63
|
-
}
|
|
64
|
-
throw new Error('Could not sign transaction');
|
|
65
|
-
}
|
|
66
|
-
getRefund() {
|
|
67
|
-
let losses = -currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT;
|
|
68
|
-
for (const vault of this.vaultUTXOs) {
|
|
69
|
-
for (let i = 0; i < vault.utxos.length; i++) {
|
|
70
|
-
losses += currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return losses;
|
|
74
|
-
}
|
|
75
|
-
getFeeLossOrRefund() {
|
|
76
|
-
const refund = this.getRefund();
|
|
77
|
-
return refund - this.estimatedFeeLoss;
|
|
78
|
-
}
|
|
79
|
-
mergeVaults() {
|
|
80
|
-
const totalInputAmount = this.getVaultTotalOutputAmount(this.vaultUTXOs);
|
|
81
|
-
let refund = this.getRefund();
|
|
82
|
-
const outputLeftAmount = totalInputAmount - refund - this.amount;
|
|
83
|
-
if (outputLeftAmount === currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT) {
|
|
84
|
-
refund += currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT;
|
|
85
|
-
}
|
|
86
|
-
else if (outputLeftAmount < currentConsensusConfig.VAULT_MINIMUM_AMOUNT) {
|
|
87
|
-
throw new Error(`Output left amount is below the minimum amount: ${outputLeftAmount} below ${currentConsensusConfig.VAULT_MINIMUM_AMOUNT}`);
|
|
88
|
-
}
|
|
89
|
-
const outAmount = this.amount + refund - this.estimatedFeeLoss;
|
|
90
|
-
const bestVault = BitcoinUtils.findVaultWithMostPublicKeys(this.vaultUTXOs);
|
|
91
|
-
if (!bestVault) {
|
|
92
|
-
throw new Error('No vaults provided');
|
|
93
|
-
}
|
|
94
|
-
const hasConsolidation = outputLeftAmount > currentConsensusConfig.VAULT_MINIMUM_AMOUNT &&
|
|
95
|
-
outputLeftAmount - currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT !== 0n;
|
|
96
|
-
if (hasConsolidation) {
|
|
97
|
-
this.success(`Consolidating output with ${outputLeftAmount} sat.`);
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
this.warn(`No consolidation in this transaction.`);
|
|
101
|
-
}
|
|
102
|
-
if (outputLeftAmount - currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT !==
|
|
103
|
-
0n) {
|
|
104
|
-
this.addOutput({
|
|
105
|
-
address: bestVault.vault,
|
|
106
|
-
value: Number(outputLeftAmount),
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
if (outAmount < TransactionBuilder.MINIMUM_DUST) {
|
|
110
|
-
throw new Error(`Amount is below dust limit. The requested amount can not be unwrapped since, after fees, it is below the dust limit. Dust: ${outAmount} sat. Are your bitcoin fees too high?`);
|
|
111
|
-
}
|
|
112
|
-
const percentageLossOverInitialAmount = (outAmount * 100n) / this.amount;
|
|
113
|
-
if (percentageLossOverInitialAmount <= 60n) {
|
|
114
|
-
throw new Error(`For user safety, OPNet will decline this transaction since you will lose ${100n - percentageLossOverInitialAmount}% of your btc by doing this transaction due to bitcoin fees. Are your bitcoin fees too high?`);
|
|
115
|
-
}
|
|
116
|
-
this.addOutput({
|
|
117
|
-
address: this.from,
|
|
118
|
-
value: Number(outAmount),
|
|
119
|
-
});
|
|
120
|
-
for (const vault of this.vaultUTXOs) {
|
|
121
|
-
this.addVaultInputs(vault);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
calculateNumEmptyWitnesses(vault) {
|
|
125
|
-
let numSignatures = 0n;
|
|
126
|
-
for (const v of vault) {
|
|
127
|
-
numSignatures += BigInt(v.publicKeys.length - v.minimum) * BigInt(v.utxos.length);
|
|
128
|
-
}
|
|
129
|
-
return numSignatures;
|
|
130
|
-
}
|
|
131
|
-
calculateNumSignatures(vault) {
|
|
132
|
-
let numSignatures = 0n;
|
|
133
|
-
for (const v of vault) {
|
|
134
|
-
numSignatures += BigInt(v.minimum * v.utxos.length);
|
|
135
|
-
}
|
|
136
|
-
return numSignatures;
|
|
137
|
-
}
|
|
138
|
-
calculateNumInputs(vault) {
|
|
139
|
-
let numSignatures = 0n;
|
|
140
|
-
for (const v of vault) {
|
|
141
|
-
numSignatures += BigInt(v.utxos.length);
|
|
142
|
-
}
|
|
143
|
-
return numSignatures;
|
|
144
|
-
}
|
|
145
|
-
internalPubKeyToXOnly() {
|
|
146
|
-
return toXOnly(numsPoint);
|
|
147
|
-
}
|
|
148
|
-
generateTapDataForInput(pubkeys, minimumSignatures) {
|
|
149
|
-
const compiledTargetScript = MultiSignGenerator.compile(pubkeys, minimumSignatures);
|
|
150
|
-
const scriptTree = [
|
|
151
|
-
{
|
|
152
|
-
output: compiledTargetScript,
|
|
153
|
-
version: 192,
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
output: MultiSignTransaction.LOCK_LEAF_SCRIPT,
|
|
157
|
-
version: 192,
|
|
158
|
-
},
|
|
159
|
-
];
|
|
160
|
-
const redeem = {
|
|
161
|
-
output: compiledTargetScript,
|
|
162
|
-
redeemVersion: 192,
|
|
163
|
-
};
|
|
164
|
-
return {
|
|
165
|
-
internalPubkey: this.internalPubKeyToXOnly(),
|
|
166
|
-
network: this.network,
|
|
167
|
-
scriptTree: scriptTree,
|
|
168
|
-
redeem: redeem,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
getScriptSolution(input) {
|
|
172
|
-
if (!input.tapScriptSig) {
|
|
173
|
-
throw new Error('Tap script signature is required');
|
|
174
|
-
}
|
|
175
|
-
return [
|
|
176
|
-
this.contractSecret,
|
|
177
|
-
toXOnly(Buffer.from(this.signer.publicKey)),
|
|
178
|
-
input.tapScriptSig[0].signature,
|
|
179
|
-
input.tapScriptSig[1].signature,
|
|
180
|
-
];
|
|
181
|
-
}
|
|
182
|
-
async internalBuildTransaction(transaction, checkPartialSigs = false) {
|
|
183
|
-
if (transaction.data.inputs.length === 0) {
|
|
184
|
-
const inputs = this.getInputs();
|
|
185
|
-
const outputs = this.getOutputs();
|
|
186
|
-
transaction.setMaximumFeeRate(this._maximumFeeRate);
|
|
187
|
-
transaction.addInputs(inputs, checkPartialSigs);
|
|
188
|
-
for (let i = 0; i < this.updateInputs.length; i++) {
|
|
189
|
-
transaction.updateInput(i, this.updateInputs[i]);
|
|
190
|
-
}
|
|
191
|
-
transaction.addOutputs(outputs);
|
|
192
|
-
}
|
|
193
|
-
try {
|
|
194
|
-
try {
|
|
195
|
-
await this.signInputs(transaction);
|
|
196
|
-
}
|
|
197
|
-
catch (e) {
|
|
198
|
-
console.log(e);
|
|
199
|
-
}
|
|
200
|
-
if (this.finalized) {
|
|
201
|
-
this.transactionFee = BigInt(transaction.getFee());
|
|
202
|
-
}
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
catch (e) {
|
|
206
|
-
const err = e;
|
|
207
|
-
this.error(`[internalBuildTransaction] Something went wrong while getting building the transaction: ${err.stack}`);
|
|
208
|
-
}
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
addVaultUTXO(utxo, pubkeys, minimumSignatures) {
|
|
212
|
-
const tapInput = this.generateTapDataForInput(pubkeys, minimumSignatures);
|
|
213
|
-
const tap = payments.p2tr(tapInput);
|
|
214
|
-
if (!tap.witness)
|
|
215
|
-
throw new Error('Failed to generate taproot witness');
|
|
216
|
-
const controlBlock = tap.witness[tap.witness.length - 1];
|
|
217
|
-
const input = {
|
|
218
|
-
hash: utxo.hash,
|
|
219
|
-
index: utxo.outputIndex,
|
|
220
|
-
witnessUtxo: {
|
|
221
|
-
script: Buffer.from(utxo.output, 'base64'),
|
|
222
|
-
value: Number(utxo.value),
|
|
223
|
-
},
|
|
224
|
-
sequence: this.sequence,
|
|
225
|
-
tapLeafScript: [
|
|
226
|
-
{
|
|
227
|
-
leafVersion: tapInput.redeem.redeemVersion,
|
|
228
|
-
script: tapInput.redeem.output,
|
|
229
|
-
controlBlock: controlBlock,
|
|
230
|
-
},
|
|
231
|
-
],
|
|
232
|
-
};
|
|
233
|
-
if (this.calculatedSignHash) {
|
|
234
|
-
input.sighashType = this.calculatedSignHash;
|
|
235
|
-
}
|
|
236
|
-
this.addInput(input);
|
|
237
|
-
}
|
|
238
|
-
addVaultInputs(vault) {
|
|
239
|
-
const pubKeys = vault.publicKeys.map((key) => Buffer.from(key, 'base64'));
|
|
240
|
-
for (const utxo of vault.utxos) {
|
|
241
|
-
this.addVaultUTXO(utxo, pubKeys, vault.minimum);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
calculateOutputLeftAmountFromVaults(vaults) {
|
|
245
|
-
const total = this.getVaultTotalOutputAmount(vaults);
|
|
246
|
-
return total - this.amount;
|
|
247
|
-
}
|
|
248
|
-
getVaultTotalOutputAmount(vaults) {
|
|
249
|
-
let total = BigInt(0);
|
|
250
|
-
for (const vault of vaults) {
|
|
251
|
-
for (const utxo of vault.utxos) {
|
|
252
|
-
total += BigInt(utxo.value);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return total;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
UnwrapTransaction.UNWRAP_SELECTOR = Number('0x' + abiCoder.encodeSelector('burn'));
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { Taptree } from '@btc-vision/bitcoin/src/types.js';
|
|
2
|
-
import { TransactionType } from '../enums/TransactionType.js';
|
|
3
|
-
import { TapLeafScript } from '../interfaces/Tap.js';
|
|
4
|
-
import { IWrapParameters } from '../interfaces/ITransactionParameters.js';
|
|
5
|
-
import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
|
|
6
|
-
import { WrappedGeneration } from '../../wbtc/WrappedGenerationParameters.js';
|
|
7
|
-
import { Address } from '../../keypair/Address.js';
|
|
8
|
-
export declare class WrapTransaction extends SharedInteractionTransaction<TransactionType.WBTC_WRAP> {
|
|
9
|
-
private static readonly WRAP_SELECTOR;
|
|
10
|
-
type: TransactionType.WBTC_WRAP;
|
|
11
|
-
readonly vault: string;
|
|
12
|
-
readonly amount: bigint;
|
|
13
|
-
readonly receiver: Address;
|
|
14
|
-
protected readonly compiledTargetScript: Buffer;
|
|
15
|
-
protected readonly scriptTree: Taptree;
|
|
16
|
-
protected tapLeafScript: TapLeafScript | null;
|
|
17
|
-
protected readonly contractSecret: Buffer;
|
|
18
|
-
protected readonly interactionPubKeys: Buffer[];
|
|
19
|
-
protected readonly minimumSignatures: number;
|
|
20
|
-
private readonly wbtc;
|
|
21
|
-
constructor(parameters: IWrapParameters);
|
|
22
|
-
private static generateMintCalldata;
|
|
23
|
-
verifyPublicKeysConstraints(generation: WrappedGeneration): boolean;
|
|
24
|
-
protected buildTransaction(): Promise<void>;
|
|
25
|
-
private verifyRequiredValue;
|
|
26
|
-
private addVaultOutput;
|
|
27
|
-
private generateVaultAddress;
|
|
28
|
-
private generateChecksumSalt;
|
|
29
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { TransactionType } from '../enums/TransactionType.js';
|
|
2
|
-
import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
|
|
3
|
-
import { wBTC } from '../../metadata/contracts/wBTC.js';
|
|
4
|
-
import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
|
|
5
|
-
import { P2TR_MS } from '../shared/P2TR_MS.js';
|
|
6
|
-
import { currentConsensusConfig } from '../../consensus/ConsensusConfig.js';
|
|
7
|
-
import { ABICoder } from '../../abi/ABICoder.js';
|
|
8
|
-
import { BinaryWriter } from '../../buffer/BinaryWriter.js';
|
|
9
|
-
import { Address } from '../../keypair/Address.js';
|
|
10
|
-
const abiCoder = new ABICoder();
|
|
11
|
-
export class WrapTransaction extends SharedInteractionTransaction {
|
|
12
|
-
constructor(parameters) {
|
|
13
|
-
if (parameters.amount < currentConsensusConfig.VAULT_MINIMUM_AMOUNT) {
|
|
14
|
-
throw new Error(`Amount is below the minimum required of ${currentConsensusConfig.VAULT_MINIMUM_AMOUNT} sat.`);
|
|
15
|
-
}
|
|
16
|
-
const receiver = parameters.receiver || new Address(parameters.signer.publicKey);
|
|
17
|
-
parameters.calldata = WrapTransaction.generateMintCalldata(parameters.amount, receiver, parameters.network);
|
|
18
|
-
super(parameters);
|
|
19
|
-
this.type = TransactionType.WBTC_WRAP;
|
|
20
|
-
this.tapLeafScript = null;
|
|
21
|
-
this.interactionPubKeys = [];
|
|
22
|
-
this.minimumSignatures = 0;
|
|
23
|
-
this.wbtc = new wBTC(parameters.network, parameters.chainId);
|
|
24
|
-
this.vault = parameters.generationParameters.vault;
|
|
25
|
-
this.to = this.wbtc.getAddress();
|
|
26
|
-
this.receiver = receiver;
|
|
27
|
-
this.amount = parameters.amount;
|
|
28
|
-
this.verifyRequiredValue();
|
|
29
|
-
this.interactionPubKeys = parameters.generationParameters.pubKeys;
|
|
30
|
-
this.minimumSignatures = parameters.generationParameters.constraints.minimum;
|
|
31
|
-
this.contractSecret = this.generateSecret();
|
|
32
|
-
if (!this.verifyPublicKeysConstraints(parameters.generationParameters)) {
|
|
33
|
-
throw new Error('Oops. Your wrapping request have been decline! It failed security checks!');
|
|
34
|
-
}
|
|
35
|
-
this.compiledTargetScript = this.calldataGenerator.compile(this.calldata, this.contractSecret, [], this.interactionPubKeys, this.minimumSignatures);
|
|
36
|
-
this.scriptTree = this.getScriptTree();
|
|
37
|
-
this.internalInit();
|
|
38
|
-
}
|
|
39
|
-
static generateMintCalldata(amount, to, network) {
|
|
40
|
-
if (!amount)
|
|
41
|
-
throw new Error('Amount is required');
|
|
42
|
-
if (!to)
|
|
43
|
-
throw new Error('To address is required');
|
|
44
|
-
if (!to.isValid(network)) {
|
|
45
|
-
throw new Error(`Oops! The address ${to} is not a valid P2TR address! If you wrap at this address, your funds will be lost!`);
|
|
46
|
-
}
|
|
47
|
-
const bufWriter = new BinaryWriter();
|
|
48
|
-
bufWriter.writeSelector(WrapTransaction.WRAP_SELECTOR);
|
|
49
|
-
bufWriter.writeAddress(to);
|
|
50
|
-
bufWriter.writeU256(amount);
|
|
51
|
-
return Buffer.from(bufWriter.getBuffer());
|
|
52
|
-
}
|
|
53
|
-
verifyPublicKeysConstraints(generation) {
|
|
54
|
-
if (generation.constraints.minimum < 2) {
|
|
55
|
-
throw new Error('Minimum signatures must be at least 2');
|
|
56
|
-
}
|
|
57
|
-
if (generation.keys.length < generation.constraints.transactionMinimum ||
|
|
58
|
-
generation.keys.length < generation.constraints.minimum) {
|
|
59
|
-
throw new Error('Not enough pub keys');
|
|
60
|
-
}
|
|
61
|
-
if (generation.keys.length > 255) {
|
|
62
|
-
throw new Error('Too many pub keys');
|
|
63
|
-
}
|
|
64
|
-
const generatedVault = this.generateVaultAddress(generation.pubKeys, generation.constraints.minimum);
|
|
65
|
-
if (generatedVault !== generation.vault) {
|
|
66
|
-
throw new Error(`Invalid vault address. Expected: ${generatedVault} Got: ${generation.vault}`);
|
|
67
|
-
}
|
|
68
|
-
const passChecksum = this.generateChecksumSalt(generation, this.amount, generation.vault);
|
|
69
|
-
const checksum = BitcoinUtils.opnetHash(passChecksum);
|
|
70
|
-
if (checksum !== generation.signature) {
|
|
71
|
-
throw new Error(`Invalid checksum. Expected: ${checksum} Got: ${generation.signature}`);
|
|
72
|
-
}
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
async buildTransaction() {
|
|
76
|
-
if (!this.to)
|
|
77
|
-
throw new Error('To address is required');
|
|
78
|
-
const selectedRedeem = this.scriptSigner
|
|
79
|
-
? this.targetScriptRedeem
|
|
80
|
-
: this.leftOverFundsScriptRedeem;
|
|
81
|
-
if (!selectedRedeem) {
|
|
82
|
-
throw new Error('Left over funds script redeem is required');
|
|
83
|
-
}
|
|
84
|
-
if (!selectedRedeem.redeemVersion) {
|
|
85
|
-
throw new Error('Left over funds script redeem version is required');
|
|
86
|
-
}
|
|
87
|
-
if (!selectedRedeem.output) {
|
|
88
|
-
throw new Error('Left over funds script redeem output is required');
|
|
89
|
-
}
|
|
90
|
-
this.tapLeafScript = {
|
|
91
|
-
leafVersion: selectedRedeem.redeemVersion,
|
|
92
|
-
script: selectedRedeem.output,
|
|
93
|
-
controlBlock: this.getWitness(),
|
|
94
|
-
};
|
|
95
|
-
this.addInputsFromUTXO();
|
|
96
|
-
const amountSpent = this.getTransactionOPNetFee();
|
|
97
|
-
this.addOutput({
|
|
98
|
-
value: Number(amountSpent),
|
|
99
|
-
address: this.to,
|
|
100
|
-
});
|
|
101
|
-
this.addVaultOutput();
|
|
102
|
-
await this.addRefundOutput(amountSpent +
|
|
103
|
-
this.amount +
|
|
104
|
-
currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT);
|
|
105
|
-
}
|
|
106
|
-
verifyRequiredValue() {
|
|
107
|
-
if (this.totalInputAmount < this.amount) {
|
|
108
|
-
throw new Error(`Not enough funds to wrap the amount specified. ${this.totalInputAmount} < ${this.amount}`);
|
|
109
|
-
}
|
|
110
|
-
const valueToVault = this.amount + currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT;
|
|
111
|
-
if (this.totalInputAmount < valueToVault) {
|
|
112
|
-
throw new Error(`Not enough funds to wrap the amount specified. ${this.totalInputAmount} < ${valueToVault}. Make sure that your inputs cover the amount to wrap, the priority fee and the unwrap prepaid fees.`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
addVaultOutput() {
|
|
116
|
-
if (!this.vault) {
|
|
117
|
-
throw new Error(`No vault address provided`);
|
|
118
|
-
}
|
|
119
|
-
const valueToSend = this.amount + currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT;
|
|
120
|
-
const amountOutput = {
|
|
121
|
-
address: this.vault,
|
|
122
|
-
value: Number(valueToSend),
|
|
123
|
-
};
|
|
124
|
-
this.addOutput(amountOutput);
|
|
125
|
-
}
|
|
126
|
-
generateVaultAddress(keys, minimumSignatureRequired) {
|
|
127
|
-
return P2TR_MS.generateMultiSigAddress(keys, minimumSignatureRequired, this.network);
|
|
128
|
-
}
|
|
129
|
-
generateChecksumSalt(param, amount, vault) {
|
|
130
|
-
const version = param.constraints.version;
|
|
131
|
-
const timestamp = param.constraints.timestamp;
|
|
132
|
-
const params = Buffer.alloc(12 + version.length);
|
|
133
|
-
params.writeBigInt64BE(BigInt(timestamp), 0);
|
|
134
|
-
params.writeInt16BE(param.constraints.minimum, 8);
|
|
135
|
-
params.writeInt16BE(param.constraints.transactionMinimum, 10);
|
|
136
|
-
params.write(version, 12, version.length, 'utf-8');
|
|
137
|
-
return Buffer.concat([
|
|
138
|
-
...param.pubKeys,
|
|
139
|
-
...param.entities.map((entity) => Buffer.from(entity, 'utf-8')),
|
|
140
|
-
params,
|
|
141
|
-
Buffer.from(amount.toString(), 'utf-8'),
|
|
142
|
-
Buffer.from(vault, 'utf-8'),
|
|
143
|
-
]);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
WrapTransaction.WRAP_SELECTOR = Number('0x' + abiCoder.encodeSelector('mint'));
|
package/build/wbtc/Generate.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { VaultUTXOs } from '../transaction/processor/PsbtTransaction.js';
|
|
2
|
-
export interface GenerationConstraints {
|
|
3
|
-
readonly timestamp: number;
|
|
4
|
-
readonly version: string;
|
|
5
|
-
readonly minimum: number;
|
|
6
|
-
readonly transactionMinimum: number;
|
|
7
|
-
}
|
|
8
|
-
export interface WrappedGenerationParameters {
|
|
9
|
-
readonly keys: string[];
|
|
10
|
-
readonly vault: string;
|
|
11
|
-
readonly entities: string[];
|
|
12
|
-
readonly signature: string;
|
|
13
|
-
readonly constraints: GenerationConstraints;
|
|
14
|
-
}
|
|
15
|
-
export interface UnwrappedGenerationParameters {
|
|
16
|
-
readonly vaultUTXOs: VaultUTXOs[];
|
|
17
|
-
readonly balance: string;
|
|
18
|
-
}
|
package/build/wbtc/Generate.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { UnwrappedGenerationParameters } from './Generate.js';
|
|
2
|
-
import { VaultUTXOs } from '../transaction/processor/PsbtTransaction.js';
|
|
3
|
-
export declare class UnwrapGeneration implements Omit<UnwrappedGenerationParameters, 'balance'> {
|
|
4
|
-
readonly vaultUTXOs: VaultUTXOs[];
|
|
5
|
-
readonly balance: bigint;
|
|
6
|
-
constructor(params: UnwrappedGenerationParameters);
|
|
7
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { GenerationConstraints, WrappedGenerationParameters } from './Generate.js';
|
|
2
|
-
export declare class WrappedGeneration implements WrappedGenerationParameters {
|
|
3
|
-
readonly constraints: GenerationConstraints;
|
|
4
|
-
readonly entities: string[];
|
|
5
|
-
readonly keys: string[];
|
|
6
|
-
readonly signature: string;
|
|
7
|
-
readonly vault: string;
|
|
8
|
-
readonly pubKeys: Buffer[];
|
|
9
|
-
constructor(params: WrappedGenerationParameters);
|
|
10
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export class WrappedGeneration {
|
|
2
|
-
constructor(params) {
|
|
3
|
-
this.constraints = params.constraints;
|
|
4
|
-
this.entities = params.entities;
|
|
5
|
-
this.keys = params.keys;
|
|
6
|
-
this.signature = params.signature;
|
|
7
|
-
this.vault = params.vault;
|
|
8
|
-
this.pubKeys = this.keys.map((key) => Buffer.from(key, 'base64'));
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Network, networks } from '@btc-vision/bitcoin';
|
|
2
|
-
import { ChainId } from '../../network/ChainId.js';
|
|
3
|
-
import { ContractBaseMetadata } from '../ContractBaseMetadata.js';
|
|
4
|
-
import { WBTC_ADDRESS_FRACTAL, WBTC_ADDRESS_REGTEST, WBTC_ADDRESS_TESTNET } from '../tokens.js';
|
|
5
|
-
import { Address } from '../../keypair/Address.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @description Wrapped Bitcoin (wBTC) contract metadata.
|
|
9
|
-
* */
|
|
10
|
-
export class wBTC extends ContractBaseMetadata {
|
|
11
|
-
/**
|
|
12
|
-
* @description Token Name
|
|
13
|
-
*/
|
|
14
|
-
public readonly tokenName: string = 'Wrapped Bitcoin';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @description Token Symbol
|
|
18
|
-
*/
|
|
19
|
-
public readonly tokenSymbol: string = 'wBTC';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @description Token Decimals, same as Bitcoin
|
|
23
|
-
*/
|
|
24
|
-
public readonly decimals: number = 8;
|
|
25
|
-
|
|
26
|
-
protected readonly address: string;
|
|
27
|
-
|
|
28
|
-
constructor(
|
|
29
|
-
protected network: Network = networks.bitcoin,
|
|
30
|
-
chainId: ChainId = ChainId.Bitcoin,
|
|
31
|
-
) {
|
|
32
|
-
super(network);
|
|
33
|
-
|
|
34
|
-
this.address = wBTC.getAddress(network, chainId);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public static getAddress(network: Network = networks.bitcoin, chainId?: ChainId): string {
|
|
38
|
-
switch (network.bech32) {
|
|
39
|
-
case networks.bitcoin.bech32:
|
|
40
|
-
return this.getWBTCAddressForChain(chainId ?? ChainId.Bitcoin).p2tr(network);
|
|
41
|
-
case networks.regtest.bech32:
|
|
42
|
-
return WBTC_ADDRESS_REGTEST.p2tr(network);
|
|
43
|
-
case networks.testnet.bech32:
|
|
44
|
-
return WBTC_ADDRESS_TESTNET.p2tr(network);
|
|
45
|
-
default:
|
|
46
|
-
throw new Error(`Invalid network: ${network.bech32}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private static getWBTCAddressForChain(chainId: ChainId): Address {
|
|
51
|
-
switch (chainId) {
|
|
52
|
-
//case ChainId.Bitcoin:
|
|
53
|
-
case ChainId.Fractal:
|
|
54
|
-
return WBTC_ADDRESS_FRACTAL;
|
|
55
|
-
default:
|
|
56
|
-
throw new Error(`Unsupported chainId: ${chainId}`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
/package/src/transaction/builders/{UnwrapSegwitTransaction.ts → UnwrapSegwitTransaction.ts.disabled}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|