@btc-vision/transaction 1.1.12 → 1.1.14
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/buffer/BinaryReader.d.ts +2 -2
- package/browser/buffer/BinaryWriter.d.ts +2 -2
- package/browser/index.js +1 -1
- package/browser/index.js.LICENSE.txt +2 -0
- package/browser/opnet.d.ts +26 -24
- package/browser/transaction/browser/extensions/XverseSigner.d.ts +36 -0
- package/browser/transaction/browser/types/Xverse.d.ts +79 -0
- package/browser/transaction/builders/TransactionBuilder.d.ts +1 -0
- package/browser/utils/lengths.d.ts +16 -0
- package/browser/utils/types.d.ts +0 -1
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/buffer/BinaryReader.d.ts +2 -2
- package/build/buffer/BinaryReader.js +12 -12
- package/build/buffer/BinaryWriter.d.ts +2 -2
- package/build/buffer/BinaryWriter.js +12 -12
- package/build/deterministic/AddressMap.js +1 -1
- package/build/keypair/Address.js +10 -8
- package/build/opnet.d.ts +26 -24
- package/build/opnet.js +26 -24
- package/build/transaction/TransactionFactory.js +17 -5
- package/build/transaction/browser/extensions/XverseSigner.d.ts +36 -0
- package/build/transaction/browser/extensions/XverseSigner.js +299 -0
- package/build/transaction/browser/types/Xverse.d.ts +79 -0
- package/build/transaction/browser/types/Xverse.js +6 -0
- package/build/transaction/builders/CustomScriptTransaction.js +1 -1
- package/build/transaction/builders/DeploymentTransaction.js +1 -1
- package/build/transaction/builders/FundingTransaction.js +1 -1
- package/build/transaction/builders/SharedInteractionTransaction.js +2 -1
- package/build/transaction/builders/TransactionBuilder.d.ts +1 -0
- package/build/transaction/builders/TransactionBuilder.js +10 -1
- package/build/utils/BufferHelper.js +2 -1
- package/build/utils/lengths.d.ts +16 -0
- package/build/utils/lengths.js +15 -0
- package/build/utils/types.d.ts +0 -1
- package/build/utils/types.js +1 -1
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/buffer/BinaryReader.ts +21 -12
- package/src/buffer/BinaryWriter.ts +23 -15
- package/src/deterministic/AddressMap.ts +1 -1
- package/src/keypair/Address.ts +11 -9
- package/src/opnet.ts +26 -24
- package/src/transaction/TransactionFactory.ts +18 -6
- package/src/transaction/browser/extensions/XverseSigner.ts +429 -0
- package/src/transaction/browser/types/Xverse.ts +104 -0
- package/src/transaction/builders/CustomScriptTransaction.ts +1 -1
- package/src/transaction/builders/DeploymentTransaction.ts +1 -1
- package/src/transaction/builders/FundingTransaction.ts +1 -1
- package/src/transaction/builders/SharedInteractionTransaction.ts +2 -1
- package/src/transaction/builders/TransactionBuilder.ts +12 -2
- package/src/utils/BufferHelper.ts +2 -1
- package/src/utils/lengths.ts +20 -0
- package/src/utils/types.ts +0 -2
|
@@ -21,7 +21,8 @@ export class TransactionFactory {
|
|
|
21
21
|
parameters.utxos = interactionParameters.utxos;
|
|
22
22
|
parameters.amount =
|
|
23
23
|
(await preTransaction.estimateTransactionFees()) +
|
|
24
|
-
this.getPriorityFee(interactionParameters)
|
|
24
|
+
this.getPriorityFee(interactionParameters) +
|
|
25
|
+
preTransaction.getOptionalOutputValue();
|
|
25
26
|
const feeEstimationFundingTransaction = await this.createFundTransaction({ ...parameters });
|
|
26
27
|
if (!feeEstimationFundingTransaction) {
|
|
27
28
|
throw new Error('Could not sign funding transaction.');
|
|
@@ -54,6 +55,9 @@ export class TransactionFactory {
|
|
|
54
55
|
if (!interactionParameters.from) {
|
|
55
56
|
throw new Error('Field "from" not provided.');
|
|
56
57
|
}
|
|
58
|
+
if (!interactionParameters.utxos[0]) {
|
|
59
|
+
throw new Error('Missing at least one UTXO.');
|
|
60
|
+
}
|
|
57
61
|
const preTransaction = new InteractionTransaction({
|
|
58
62
|
...interactionParameters,
|
|
59
63
|
utxos: [interactionParameters.utxos[0]],
|
|
@@ -63,13 +67,20 @@ export class TransactionFactory {
|
|
|
63
67
|
parameters.utxos = interactionParameters.utxos;
|
|
64
68
|
parameters.amount =
|
|
65
69
|
(await preTransaction.estimateTransactionFees()) +
|
|
66
|
-
this.getPriorityFee(interactionParameters)
|
|
67
|
-
|
|
70
|
+
this.getPriorityFee(interactionParameters) +
|
|
71
|
+
preTransaction.getOptionalOutputValue();
|
|
72
|
+
const feeEstimationFundingTransaction = await this.createFundTransaction({
|
|
73
|
+
...parameters,
|
|
74
|
+
optionalOutputs: [],
|
|
75
|
+
});
|
|
68
76
|
if (!feeEstimationFundingTransaction) {
|
|
69
77
|
throw new Error('Could not sign funding transaction.');
|
|
70
78
|
}
|
|
71
79
|
parameters.estimatedFees = feeEstimationFundingTransaction.estimatedFees;
|
|
72
|
-
const signedTransaction = await this.createFundTransaction(
|
|
80
|
+
const signedTransaction = await this.createFundTransaction({
|
|
81
|
+
...parameters,
|
|
82
|
+
optionalOutputs: [],
|
|
83
|
+
});
|
|
73
84
|
if (!signedTransaction) {
|
|
74
85
|
throw new Error('Could not sign funding transaction.');
|
|
75
86
|
}
|
|
@@ -95,7 +106,8 @@ export class TransactionFactory {
|
|
|
95
106
|
const parameters = await preTransaction.getFundingTransactionParameters();
|
|
96
107
|
parameters.amount =
|
|
97
108
|
(await preTransaction.estimateTransactionFees()) +
|
|
98
|
-
this.getPriorityFee(deploymentParameters)
|
|
109
|
+
this.getPriorityFee(deploymentParameters) +
|
|
110
|
+
preTransaction.getOptionalOutputValue();
|
|
99
111
|
const fundingTransaction = new FundingTransaction(parameters);
|
|
100
112
|
const signedTransaction = await fundingTransaction.signTransaction();
|
|
101
113
|
if (!signedTransaction) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Network, Psbt } from '@btc-vision/bitcoin';
|
|
2
|
+
import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
3
|
+
import { Xverse } from '../types/Xverse.js';
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
BitcoinProvider?: Xverse;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export declare class XverseSigner extends CustomKeypair {
|
|
10
|
+
private isInitialized;
|
|
11
|
+
constructor();
|
|
12
|
+
private _p2tr;
|
|
13
|
+
get p2tr(): string;
|
|
14
|
+
private _p2wpkh;
|
|
15
|
+
get p2wpkh(): string;
|
|
16
|
+
private _addresses;
|
|
17
|
+
get addresses(): string[];
|
|
18
|
+
private _publicKey;
|
|
19
|
+
get publicKey(): Buffer;
|
|
20
|
+
_network: Network | undefined;
|
|
21
|
+
get network(): Network;
|
|
22
|
+
get BitcoinProvider(): Xverse;
|
|
23
|
+
init(): Promise<void>;
|
|
24
|
+
getPublicKey(): Buffer;
|
|
25
|
+
sign(_hash: Buffer, _lowR?: boolean): Buffer;
|
|
26
|
+
signSchnorr(_hash: Buffer): Buffer;
|
|
27
|
+
verify(_hash: Buffer, _signature: Buffer): boolean;
|
|
28
|
+
signTaprootInput(transaction: Psbt, i: number, sighashTypes: number[]): Promise<void>;
|
|
29
|
+
signInput(transaction: Psbt, i: number, sighashTypes: number[]): Promise<void>;
|
|
30
|
+
multiSignPsbt(transactions: Psbt[]): Promise<void>;
|
|
31
|
+
private hasAlreadySignedTapScriptSig;
|
|
32
|
+
private hasAlreadyPartialSig;
|
|
33
|
+
private combine;
|
|
34
|
+
private signAllTweaked;
|
|
35
|
+
private getNonDuplicateScriptSig;
|
|
36
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { crypto as bitCrypto, script as bitScript, networks, opcodes, Psbt, } from '@btc-vision/bitcoin';
|
|
2
|
+
import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
|
|
3
|
+
import { EcKeyPair } from '../../../keypair/EcKeyPair.js';
|
|
4
|
+
import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
5
|
+
export class XverseSigner extends CustomKeypair {
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
8
|
+
this.isInitialized = false;
|
|
9
|
+
if (!window) {
|
|
10
|
+
throw new Error('XverseSigner can only be used in a browser environment');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
get p2tr() {
|
|
14
|
+
if (!this._p2tr) {
|
|
15
|
+
throw new Error('P2TR address not set');
|
|
16
|
+
}
|
|
17
|
+
return this._p2tr;
|
|
18
|
+
}
|
|
19
|
+
get p2wpkh() {
|
|
20
|
+
if (!this._p2wpkh) {
|
|
21
|
+
throw new Error('P2PKH address not set');
|
|
22
|
+
}
|
|
23
|
+
return this._p2wpkh;
|
|
24
|
+
}
|
|
25
|
+
get addresses() {
|
|
26
|
+
if (!this._addresses) {
|
|
27
|
+
throw new Error('Addresses not set');
|
|
28
|
+
}
|
|
29
|
+
return this._addresses;
|
|
30
|
+
}
|
|
31
|
+
get publicKey() {
|
|
32
|
+
if (!this._publicKey) {
|
|
33
|
+
throw new Error('Public key not set');
|
|
34
|
+
}
|
|
35
|
+
return this._publicKey;
|
|
36
|
+
}
|
|
37
|
+
get network() {
|
|
38
|
+
if (!this._network) {
|
|
39
|
+
throw new Error('Network not set');
|
|
40
|
+
}
|
|
41
|
+
return this._network;
|
|
42
|
+
}
|
|
43
|
+
get BitcoinProvider() {
|
|
44
|
+
const module = window.BitcoinProvider;
|
|
45
|
+
if (!module) {
|
|
46
|
+
throw new Error('Xverse Wallet extension not found');
|
|
47
|
+
}
|
|
48
|
+
return module;
|
|
49
|
+
}
|
|
50
|
+
async init() {
|
|
51
|
+
if (this.isInitialized)
|
|
52
|
+
return;
|
|
53
|
+
const connectResult = (await this.BitcoinProvider.request('wallet_connect', null));
|
|
54
|
+
if ('error' in connectResult)
|
|
55
|
+
throw new Error(connectResult.error.message);
|
|
56
|
+
const payementAddress = connectResult.result.addresses.find((address) => address.purpose === 'payment');
|
|
57
|
+
if (!payementAddress) {
|
|
58
|
+
throw new Error('Payment address not found');
|
|
59
|
+
}
|
|
60
|
+
const network = payementAddress.address.startsWith('tb')
|
|
61
|
+
? networks.testnet
|
|
62
|
+
: payementAddress.address.startsWith('bc')
|
|
63
|
+
? networks.bitcoin
|
|
64
|
+
: null;
|
|
65
|
+
if (!network)
|
|
66
|
+
throw new Error('Network not supported');
|
|
67
|
+
this._network = network;
|
|
68
|
+
this._publicKey = Buffer.from(payementAddress.publicKey, 'hex');
|
|
69
|
+
this._p2wpkh = EcKeyPair.getP2WPKHAddress(this, this.network);
|
|
70
|
+
this._p2tr = EcKeyPair.getTaprootAddress(this, this.network);
|
|
71
|
+
this._addresses = [this._p2wpkh, this._p2tr];
|
|
72
|
+
this.isInitialized = true;
|
|
73
|
+
}
|
|
74
|
+
getPublicKey() {
|
|
75
|
+
if (!this.isInitialized) {
|
|
76
|
+
throw new Error('UnisatSigner not initialized');
|
|
77
|
+
}
|
|
78
|
+
return this.publicKey;
|
|
79
|
+
}
|
|
80
|
+
sign(_hash, _lowR) {
|
|
81
|
+
throw new Error('Not implemented: sign');
|
|
82
|
+
}
|
|
83
|
+
signSchnorr(_hash) {
|
|
84
|
+
throw new Error('Not implemented: signSchnorr');
|
|
85
|
+
}
|
|
86
|
+
verify(_hash, _signature) {
|
|
87
|
+
throw new Error('Not implemented: verify');
|
|
88
|
+
}
|
|
89
|
+
async signTaprootInput(transaction, i, sighashTypes) {
|
|
90
|
+
const input = transaction.data.inputs[i];
|
|
91
|
+
if (input.tapKeySig ||
|
|
92
|
+
input.finalScriptSig ||
|
|
93
|
+
(Array.isArray(input.partialSig) &&
|
|
94
|
+
input.partialSig.length &&
|
|
95
|
+
this.hasAlreadyPartialSig(input.partialSig)) ||
|
|
96
|
+
(Array.isArray(input.tapScriptSig) &&
|
|
97
|
+
input.tapScriptSig.length &&
|
|
98
|
+
this.hasAlreadySignedTapScriptSig(input.tapScriptSig))) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const firstSignature = await this.signAllTweaked(transaction, sighashTypes, false);
|
|
102
|
+
this.combine(transaction, firstSignature, i);
|
|
103
|
+
}
|
|
104
|
+
async signInput(transaction, i, sighashTypes) {
|
|
105
|
+
const input = transaction.data.inputs[i];
|
|
106
|
+
if (input.tapKeySig ||
|
|
107
|
+
input.finalScriptSig ||
|
|
108
|
+
(Array.isArray(input.partialSig) &&
|
|
109
|
+
input.partialSig.length &&
|
|
110
|
+
this.hasAlreadyPartialSig(input.partialSig)) ||
|
|
111
|
+
(Array.isArray(input.tapScriptSig) &&
|
|
112
|
+
input.tapScriptSig.length &&
|
|
113
|
+
this.hasAlreadySignedTapScriptSig(input.tapScriptSig))) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const firstSignature = await this.signAllTweaked(transaction, sighashTypes, true);
|
|
117
|
+
this.combine(transaction, firstSignature, i);
|
|
118
|
+
}
|
|
119
|
+
async multiSignPsbt(transactions) {
|
|
120
|
+
const toSignPsbts = [];
|
|
121
|
+
const options = [];
|
|
122
|
+
for (const psbt of transactions) {
|
|
123
|
+
const hex = psbt.toHex();
|
|
124
|
+
toSignPsbts.push(hex);
|
|
125
|
+
const toSignInputs = psbt.data.inputs
|
|
126
|
+
.map((input, i) => {
|
|
127
|
+
let needsToSign = false;
|
|
128
|
+
let viaTaproot = false;
|
|
129
|
+
if (isTaprootInput(input)) {
|
|
130
|
+
if (input.tapLeafScript && input.tapLeafScript.length > 0) {
|
|
131
|
+
for (const tapLeafScript of input.tapLeafScript) {
|
|
132
|
+
if (pubkeyInScript(this.publicKey, tapLeafScript.script)) {
|
|
133
|
+
needsToSign = true;
|
|
134
|
+
viaTaproot = false;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (!needsToSign && input.tapInternalKey) {
|
|
140
|
+
const tapInternalKey = input.tapInternalKey;
|
|
141
|
+
const xOnlyPubKey = toXOnly(this.publicKey);
|
|
142
|
+
if (tapInternalKey.equals(xOnlyPubKey)) {
|
|
143
|
+
needsToSign = true;
|
|
144
|
+
viaTaproot = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
const script = getInputRelevantScript(input);
|
|
150
|
+
if (script && pubkeyInScript(this.publicKey, script)) {
|
|
151
|
+
needsToSign = true;
|
|
152
|
+
viaTaproot = false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (needsToSign) {
|
|
156
|
+
return {
|
|
157
|
+
index: i,
|
|
158
|
+
publicKey: this.publicKey.toString('hex'),
|
|
159
|
+
disableTweakSigner: !viaTaproot,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
.filter((v) => v !== null);
|
|
167
|
+
options.push({
|
|
168
|
+
autoFinalized: false,
|
|
169
|
+
toSignInputs: toSignInputs,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const callSign = (await this.BitcoinProvider.request('signPsbt', {
|
|
173
|
+
psbt: toSignPsbts[0],
|
|
174
|
+
signInputs: options[0].toSignInputs,
|
|
175
|
+
}));
|
|
176
|
+
if ('error' in callSign)
|
|
177
|
+
throw new Error(callSign.error.message);
|
|
178
|
+
const signedPsbts = Psbt.fromBase64(callSign.result.psbt);
|
|
179
|
+
transactions[0].combine(signedPsbts);
|
|
180
|
+
}
|
|
181
|
+
hasAlreadySignedTapScriptSig(input) {
|
|
182
|
+
for (let i = 0; i < input.length; i++) {
|
|
183
|
+
const item = input[i];
|
|
184
|
+
const buf = Buffer.from(item.pubkey);
|
|
185
|
+
if (buf.equals(this.publicKey) && item.signature) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
hasAlreadyPartialSig(input) {
|
|
192
|
+
for (let i = 0; i < input.length; i++) {
|
|
193
|
+
const item = input[i];
|
|
194
|
+
const buf = Buffer.from(item.pubkey);
|
|
195
|
+
if (buf.equals(this.publicKey) && item.signature) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
combine(transaction, newPsbt, i) {
|
|
202
|
+
const signedInput = newPsbt.data.inputs[i];
|
|
203
|
+
const originalInput = transaction.data.inputs[i];
|
|
204
|
+
if (signedInput.partialSig) {
|
|
205
|
+
transaction.updateInput(i, { partialSig: signedInput.partialSig });
|
|
206
|
+
}
|
|
207
|
+
if (signedInput.tapKeySig && !originalInput.tapKeySig) {
|
|
208
|
+
transaction.updateInput(i, { tapKeySig: signedInput.tapKeySig });
|
|
209
|
+
}
|
|
210
|
+
if (signedInput.tapScriptSig?.length) {
|
|
211
|
+
const lastScriptSig = originalInput.tapScriptSig;
|
|
212
|
+
if (lastScriptSig) {
|
|
213
|
+
const getNonDuplicate = this.getNonDuplicateScriptSig(lastScriptSig, signedInput.tapScriptSig);
|
|
214
|
+
if (getNonDuplicate.length) {
|
|
215
|
+
transaction.updateInput(i, { tapScriptSig: getNonDuplicate });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
transaction.updateInput(i, { tapScriptSig: signedInput.tapScriptSig });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async signAllTweaked(transaction, sighashTypes, disableTweakSigner = false) {
|
|
224
|
+
const pubKey = this.publicKey.toString('hex');
|
|
225
|
+
const toSign = transaction.data.inputs.map((_, i) => {
|
|
226
|
+
return [
|
|
227
|
+
{
|
|
228
|
+
index: i,
|
|
229
|
+
publicKey: pubKey,
|
|
230
|
+
sighashTypes,
|
|
231
|
+
disableTweakSigner: disableTweakSigner,
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
});
|
|
235
|
+
const opts = {
|
|
236
|
+
autoFinalized: false,
|
|
237
|
+
toSignInputs: toSign.flat(),
|
|
238
|
+
};
|
|
239
|
+
const psbt = transaction.toBase64();
|
|
240
|
+
const callSign = (await this.BitcoinProvider.request('signPsbt', {
|
|
241
|
+
psbt,
|
|
242
|
+
signInputs: opts.toSignInputs,
|
|
243
|
+
}));
|
|
244
|
+
if ('error' in callSign)
|
|
245
|
+
throw new Error(callSign.error.message);
|
|
246
|
+
return Psbt.fromBase64(callSign.result.psbt);
|
|
247
|
+
}
|
|
248
|
+
getNonDuplicateScriptSig(scriptSig1, scriptSig2) {
|
|
249
|
+
const nonDuplicate = [];
|
|
250
|
+
for (let i = 0; i < scriptSig2.length; i++) {
|
|
251
|
+
const found = scriptSig1.find((item) => item.pubkey.equals(scriptSig2[i].pubkey));
|
|
252
|
+
if (!found) {
|
|
253
|
+
nonDuplicate.push(scriptSig2[i]);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return nonDuplicate;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function isTaprootInput(input) {
|
|
260
|
+
if (input.tapInternalKey || input.tapKeySig || input.tapScriptSig || input.tapLeafScript) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
if (input.witnessUtxo) {
|
|
264
|
+
const script = input.witnessUtxo.script;
|
|
265
|
+
return script.length === 34 && script[0] === opcodes.OP_1 && script[1] === 0x20;
|
|
266
|
+
}
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
function getInputRelevantScript(input) {
|
|
270
|
+
if (input.redeemScript) {
|
|
271
|
+
return input.redeemScript;
|
|
272
|
+
}
|
|
273
|
+
if (input.witnessScript) {
|
|
274
|
+
return input.witnessScript;
|
|
275
|
+
}
|
|
276
|
+
if (input.witnessUtxo) {
|
|
277
|
+
return input.witnessUtxo.script;
|
|
278
|
+
}
|
|
279
|
+
if (input.nonWitnessUtxo) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
function pubkeyInScript(pubkey, script) {
|
|
285
|
+
return pubkeyPositionInScript(pubkey, script) !== -1;
|
|
286
|
+
}
|
|
287
|
+
function pubkeyPositionInScript(pubkey, script) {
|
|
288
|
+
const pubkeyHash = bitCrypto.hash160(pubkey);
|
|
289
|
+
const pubkeyXOnly = toXOnly(pubkey);
|
|
290
|
+
const decompiled = bitScript.decompile(script);
|
|
291
|
+
if (decompiled === null)
|
|
292
|
+
throw new Error('Unknown script error');
|
|
293
|
+
return decompiled.findIndex((element) => {
|
|
294
|
+
if (typeof element === 'number')
|
|
295
|
+
return false;
|
|
296
|
+
return (Buffer.isBuffer(element) &&
|
|
297
|
+
(element.equals(pubkey) || element.equals(pubkeyHash) || element.equals(pubkeyXOnly)));
|
|
298
|
+
});
|
|
299
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export declare enum XverseNetwork {
|
|
2
|
+
mainnet = "mainnet",
|
|
3
|
+
testnet = "testnet",
|
|
4
|
+
signet = "Signet"
|
|
5
|
+
}
|
|
6
|
+
export type XverseRPCResponse<T = unknown> = {
|
|
7
|
+
id: string;
|
|
8
|
+
jsonrpc: string;
|
|
9
|
+
result: T;
|
|
10
|
+
};
|
|
11
|
+
export type XverseRPCError = {
|
|
12
|
+
id: string;
|
|
13
|
+
jsonrpc: string;
|
|
14
|
+
error: {
|
|
15
|
+
code: number;
|
|
16
|
+
message: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export type XverseRPCGetAccountResponse = XverseRPCResponse<{
|
|
20
|
+
addresses: {
|
|
21
|
+
address: string;
|
|
22
|
+
addressType: string;
|
|
23
|
+
publicKey: string;
|
|
24
|
+
purpose: string;
|
|
25
|
+
}[];
|
|
26
|
+
}> | XverseRPCError;
|
|
27
|
+
export type XverseRPCSignPsbtResponse = XverseRPCResponse<{
|
|
28
|
+
psbt: string;
|
|
29
|
+
}> | XverseRPCError;
|
|
30
|
+
interface InscriptionData {
|
|
31
|
+
address: string;
|
|
32
|
+
amount: number;
|
|
33
|
+
asset: string;
|
|
34
|
+
fee: number;
|
|
35
|
+
nonce: number;
|
|
36
|
+
recipient: string;
|
|
37
|
+
}
|
|
38
|
+
interface InscriptionResult {
|
|
39
|
+
txid: string;
|
|
40
|
+
}
|
|
41
|
+
interface RepeatInscriptionsData {
|
|
42
|
+
inscriptions: InscriptionData[];
|
|
43
|
+
}
|
|
44
|
+
interface TransactionResult {
|
|
45
|
+
txid: string;
|
|
46
|
+
}
|
|
47
|
+
interface SignedMessageResult {
|
|
48
|
+
signature: string;
|
|
49
|
+
}
|
|
50
|
+
interface BtcTransaction {
|
|
51
|
+
inputs: {
|
|
52
|
+
address: string;
|
|
53
|
+
amount: number;
|
|
54
|
+
asset: string;
|
|
55
|
+
nonce: number;
|
|
56
|
+
}[];
|
|
57
|
+
outputs: {
|
|
58
|
+
address: string;
|
|
59
|
+
amount: number;
|
|
60
|
+
asset: string;
|
|
61
|
+
}[];
|
|
62
|
+
fee: number;
|
|
63
|
+
}
|
|
64
|
+
interface SignedTransactionResult {
|
|
65
|
+
txid: string;
|
|
66
|
+
raw: string;
|
|
67
|
+
}
|
|
68
|
+
export interface Xverse {
|
|
69
|
+
connect: () => Promise<void>;
|
|
70
|
+
addListener: (event: string, callback: (...args: unknown[]) => void) => void;
|
|
71
|
+
createInscription: (data: InscriptionData) => Promise<InscriptionResult>;
|
|
72
|
+
createRepeatInscriptions: (data: RepeatInscriptionsData) => Promise<InscriptionResult[]>;
|
|
73
|
+
request: (method: string, params: unknown) => Promise<XverseRPCResponse>;
|
|
74
|
+
sendBtcTransaction: (transaction: BtcTransaction) => Promise<TransactionResult>;
|
|
75
|
+
signMessage: (message: string) => Promise<SignedMessageResult>;
|
|
76
|
+
signMultipleTransactions: (transactions: BtcTransaction[]) => Promise<SignedTransactionResult[]>;
|
|
77
|
+
signTransaction: (transaction: BtcTransaction) => Promise<SignedTransactionResult>;
|
|
78
|
+
}
|
|
79
|
+
export {};
|
|
@@ -78,7 +78,7 @@ export class CustomScriptTransaction extends TransactionBuilder {
|
|
|
78
78
|
value: Number(amountSpent),
|
|
79
79
|
address: this.to,
|
|
80
80
|
});
|
|
81
|
-
await this.addRefundOutput(amountSpent);
|
|
81
|
+
await this.addRefundOutput(amountSpent + this.addOptionalOutputsAndGetAmount());
|
|
82
82
|
}
|
|
83
83
|
async signInputs(transaction) {
|
|
84
84
|
if (!this.contractSigner) {
|
|
@@ -93,7 +93,7 @@ export class DeploymentTransaction extends TransactionBuilder {
|
|
|
93
93
|
value: Number(amountSpent),
|
|
94
94
|
address: this.contractAddress.p2tr(this.network),
|
|
95
95
|
});
|
|
96
|
-
await this.addRefundOutput(amountSpent);
|
|
96
|
+
await this.addRefundOutput(amountSpent + this.addOptionalOutputsAndGetAmount());
|
|
97
97
|
}
|
|
98
98
|
async signInputsWalletBased(transaction) {
|
|
99
99
|
const signer = this.signer;
|
|
@@ -28,7 +28,7 @@ export class FundingTransaction extends TransactionBuilder {
|
|
|
28
28
|
address: this.to,
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
await this.addRefundOutput(this.amount);
|
|
31
|
+
await this.addRefundOutput(this.amount + this.addOptionalOutputsAndGetAmount());
|
|
32
32
|
}
|
|
33
33
|
splitInputs(amountSpent) {
|
|
34
34
|
if (!this.to) {
|
|
@@ -79,8 +79,9 @@ export class SharedInteractionTransaction extends TransactionBuilder {
|
|
|
79
79
|
value: Number(amountSpent),
|
|
80
80
|
address: this.to,
|
|
81
81
|
});
|
|
82
|
+
const amount = this.addOptionalOutputsAndGetAmount();
|
|
82
83
|
if (!this.disableAutoRefund) {
|
|
83
|
-
await this.addRefundOutput(amountSpent);
|
|
84
|
+
await this.addRefundOutput(amountSpent + amount);
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
async signInputs(transaction) {
|
|
@@ -47,6 +47,7 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
|
|
|
47
47
|
setPSBT(psbt: Psbt): void;
|
|
48
48
|
getInputs(): PsbtInputExtended[];
|
|
49
49
|
getOutputs(): PsbtOutputExtended[];
|
|
50
|
+
getOptionalOutputValue(): bigint;
|
|
50
51
|
protected addRefundOutput(amountSpent: bigint): Promise<void>;
|
|
51
52
|
protected addValueToToOutput(value: number | bigint): void;
|
|
52
53
|
protected getTransactionOPNetFee(): bigint;
|
|
@@ -186,8 +186,17 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
186
186
|
outputs.push(this.feeOutput);
|
|
187
187
|
return outputs;
|
|
188
188
|
}
|
|
189
|
+
getOptionalOutputValue() {
|
|
190
|
+
if (!this.optionalOutputs)
|
|
191
|
+
return 0n;
|
|
192
|
+
let total = 0n;
|
|
193
|
+
for (let i = 0; i < this.optionalOutputs.length; i++) {
|
|
194
|
+
total += BigInt(this.optionalOutputs[i].value);
|
|
195
|
+
}
|
|
196
|
+
return total;
|
|
197
|
+
}
|
|
189
198
|
async addRefundOutput(amountSpent) {
|
|
190
|
-
const sendBackAmount = this.totalInputAmount - amountSpent
|
|
199
|
+
const sendBackAmount = this.totalInputAmount - amountSpent;
|
|
191
200
|
if (sendBackAmount >= TransactionBuilder.MINIMUM_DUST) {
|
|
192
201
|
if (AddressVerificator.isValidP2TRAddress(this.from, this.network)) {
|
|
193
202
|
await this.setFeeOutput({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { U256_BYTE_LENGTH } from './lengths.js';
|
|
1
2
|
export class BufferHelper {
|
|
2
3
|
static bufferToUint8Array(buffer) {
|
|
3
4
|
if (Buffer.isBuffer(buffer)) {
|
|
@@ -36,7 +37,7 @@ export class BufferHelper {
|
|
|
36
37
|
const hex = BufferHelper.uint8ArrayToHex(input);
|
|
37
38
|
return BigInt('0x' + hex);
|
|
38
39
|
}
|
|
39
|
-
static valueToUint8Array(value, length =
|
|
40
|
+
static valueToUint8Array(value, length = U256_BYTE_LENGTH) {
|
|
40
41
|
const valueHex = value.toString(16).padStart(length * 2, '0');
|
|
41
42
|
return BufferHelper.hexToUint8Array(valueHex);
|
|
42
43
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { i32 } from './types';
|
|
2
|
+
export declare const ADDRESS_BYTE_LENGTH: i32;
|
|
3
|
+
export declare const SELECTOR_BYTE_LENGTH: i32;
|
|
4
|
+
export declare const U256_BYTE_LENGTH: i32;
|
|
5
|
+
export declare const U128_BYTE_LENGTH: i32;
|
|
6
|
+
export declare const U64_BYTE_LENGTH: i32;
|
|
7
|
+
export declare const U32_BYTE_LENGTH: i32;
|
|
8
|
+
export declare const U16_BYTE_LENGTH: i32;
|
|
9
|
+
export declare const U8_BYTE_LENGTH: i32;
|
|
10
|
+
export declare const I256_BYTE_LENGTH: i32;
|
|
11
|
+
export declare const I128_BYTE_LENGTH: i32;
|
|
12
|
+
export declare const I64_BYTE_LENGTH: i32;
|
|
13
|
+
export declare const I32_BYTE_LENGTH: i32;
|
|
14
|
+
export declare const I16_BYTE_LENGTH: i32;
|
|
15
|
+
export declare const I8_BYTE_LENGTH: i32;
|
|
16
|
+
export declare const BOOLEAN_BYTE_LENGTH: i32;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const ADDRESS_BYTE_LENGTH = 32;
|
|
2
|
+
export const SELECTOR_BYTE_LENGTH = 4;
|
|
3
|
+
export const U256_BYTE_LENGTH = 32;
|
|
4
|
+
export const U128_BYTE_LENGTH = 16;
|
|
5
|
+
export const U64_BYTE_LENGTH = 8;
|
|
6
|
+
export const U32_BYTE_LENGTH = 4;
|
|
7
|
+
export const U16_BYTE_LENGTH = 2;
|
|
8
|
+
export const U8_BYTE_LENGTH = 1;
|
|
9
|
+
export const I256_BYTE_LENGTH = 32;
|
|
10
|
+
export const I128_BYTE_LENGTH = 16;
|
|
11
|
+
export const I64_BYTE_LENGTH = 8;
|
|
12
|
+
export const I32_BYTE_LENGTH = 4;
|
|
13
|
+
export const I16_BYTE_LENGTH = 2;
|
|
14
|
+
export const I8_BYTE_LENGTH = 1;
|
|
15
|
+
export const BOOLEAN_BYTE_LENGTH = 1;
|
package/build/utils/types.d.ts
CHANGED
package/build/utils/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export {};
|
package/package.json
CHANGED
package/src/_version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.1.
|
|
1
|
+
export const version = '1.1.14';
|