@btc-vision/transaction 1.2.6 → 1.2.8
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/README.md +4 -19
- package/browser/_version.d.ts +1 -1
- package/browser/generators/Generator.d.ts +1 -0
- package/browser/generators/builders/CalldataGenerator.d.ts +1 -1
- package/browser/generators/builders/DeploymentGenerator.d.ts +1 -1
- package/browser/generators/builders/LegacyCalldataGenerator.d.ts +1 -1
- package/browser/index.js +1 -1
- package/browser/transaction/builders/MultiSignTransaction.d.ts +1 -1
- package/browser/transaction/builders/TransactionBuilder.d.ts +1 -0
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +1 -0
- package/browser/verification/TapscriptVerificator.d.ts +1 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/generators/Generator.d.ts +1 -0
- package/build/generators/Generator.js +7 -0
- package/build/generators/builders/CalldataGenerator.d.ts +1 -1
- package/build/generators/builders/CalldataGenerator.js +2 -2
- package/build/generators/builders/DeploymentGenerator.d.ts +1 -1
- package/build/generators/builders/DeploymentGenerator.js +4 -4
- package/build/generators/builders/LegacyCalldataGenerator.d.ts +1 -1
- package/build/generators/builders/LegacyCalldataGenerator.js +5 -23
- package/build/transaction/TransactionFactory.js +3 -2
- package/build/transaction/builders/DeploymentTransaction.js +1 -1
- package/build/transaction/builders/InteractionTransaction.js +1 -1
- package/build/transaction/builders/MultiSignTransaction.d.ts +1 -1
- package/build/transaction/builders/MultiSignTransaction.js +1 -0
- package/build/transaction/builders/SharedInteractionTransaction.js +3 -0
- package/build/transaction/builders/TransactionBuilder.d.ts +1 -0
- package/build/transaction/builders/TransactionBuilder.js +5 -2
- package/build/transaction/interfaces/ITransactionParameters.d.ts +1 -0
- package/build/utxo/OPNetLimitedProvider.js +2 -1
- package/build/verification/TapscriptVerificator.d.ts +1 -0
- package/build/verification/TapscriptVerificator.js +2 -2
- package/package.json +3 -3
- package/src/_version.ts +1 -1
- package/src/generators/Generator.ts +9 -0
- package/src/generators/builders/CalldataGenerator.ts +4 -1
- package/src/generators/builders/DeploymentGenerator.ts +6 -3
- package/src/generators/builders/LegacyCalldataGenerator.ts +11 -40
- package/src/transaction/TransactionFactory.ts +3 -2
- package/src/transaction/browser/extensions/UnisatSigner.ts +1 -1
- package/src/transaction/builders/DeploymentTransaction.ts +1 -0
- package/src/transaction/builders/InteractionTransaction.ts +1 -0
- package/src/transaction/builders/MultiSignTransaction.ts +2 -1
- package/src/transaction/builders/SharedInteractionTransaction.ts +4 -0
- package/src/transaction/builders/TransactionBuilder.ts +6 -2
- package/src/transaction/interfaces/ITransactionParameters.ts +1 -0
- package/src/utxo/OPNetLimitedProvider.ts +2 -1
- package/src/verification/TapscriptVerificator.ts +3 -0
|
@@ -3,7 +3,7 @@ import { TransactionBuilder } from './TransactionBuilder.js';
|
|
|
3
3
|
import { TransactionType } from '../enums/TransactionType.js';
|
|
4
4
|
import { ITransactionParameters } from '../interfaces/ITransactionParameters.js';
|
|
5
5
|
import { ECPairInterface } from 'ecpair';
|
|
6
|
-
export interface MultiSignParameters extends Omit<ITransactionParameters, 'priorityFee' | 'signer'> {
|
|
6
|
+
export interface MultiSignParameters extends Omit<ITransactionParameters, 'gasSatFee' | 'priorityFee' | 'signer'> {
|
|
7
7
|
readonly pubkeys: Buffer[];
|
|
8
8
|
readonly minimumSignatures: number;
|
|
9
9
|
readonly from?: undefined;
|
|
@@ -26,6 +26,7 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
|
|
|
26
26
|
protected readonly network: Network;
|
|
27
27
|
protected readonly feeRate: number;
|
|
28
28
|
protected priorityFee: bigint;
|
|
29
|
+
protected gasSatFee: bigint;
|
|
29
30
|
protected utxos: UTXO[];
|
|
30
31
|
protected to: string | undefined;
|
|
31
32
|
protected from: string;
|
|
@@ -12,6 +12,7 @@ export interface ITransactionParameters extends ITweakedTransactionData {
|
|
|
12
12
|
chainId?: ChainId;
|
|
13
13
|
readonly feeRate: number;
|
|
14
14
|
readonly priorityFee: bigint;
|
|
15
|
+
readonly gasSatFee: bigint;
|
|
15
16
|
}
|
|
16
17
|
export interface IFundingTransactionParameters extends ITransactionParameters {
|
|
17
18
|
amount: bigint;
|
package/build/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "1.2.
|
|
1
|
+
export declare const version = "1.2.7";
|
package/build/_version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.2.
|
|
1
|
+
export const version = '1.2.7';
|
|
@@ -8,6 +8,7 @@ export declare abstract class Generator {
|
|
|
8
8
|
protected readonly network: Network;
|
|
9
9
|
protected constructor(senderPubKey: Buffer, contractSaltPubKey?: Buffer, network?: Network);
|
|
10
10
|
get senderFirstByte(): Buffer;
|
|
11
|
+
getHeader(maxPriority: bigint): Buffer;
|
|
11
12
|
abstract compile(...args: unknown[]): Buffer;
|
|
12
13
|
protected splitBufferIntoChunks(buffer: Buffer, chunkSize?: number): Array<Buffer[]>;
|
|
13
14
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { networks, toXOnly } from '@btc-vision/bitcoin';
|
|
2
|
+
import { BinaryWriter } from '../buffer/BinaryWriter.js';
|
|
2
3
|
export class Generator {
|
|
3
4
|
constructor(senderPubKey, contractSaltPubKey, network = networks.bitcoin) {
|
|
4
5
|
this.network = networks.bitcoin;
|
|
@@ -10,6 +11,12 @@ export class Generator {
|
|
|
10
11
|
get senderFirstByte() {
|
|
11
12
|
return Buffer.from([this.senderPubKey[0], 0, 0, 0]);
|
|
12
13
|
}
|
|
14
|
+
getHeader(maxPriority) {
|
|
15
|
+
const writer = new BinaryWriter(8 + 4);
|
|
16
|
+
writer.writeBytes(this.senderFirstByte);
|
|
17
|
+
writer.writeU64(maxPriority);
|
|
18
|
+
return Buffer.from(writer.getBuffer());
|
|
19
|
+
}
|
|
13
20
|
splitBufferIntoChunks(buffer, chunkSize = Generator.DATA_CHUNK_SIZE) {
|
|
14
21
|
const chunks = [];
|
|
15
22
|
for (let i = 0; i < buffer.length; i += chunkSize) {
|
|
@@ -4,5 +4,5 @@ import { Generator } from '../Generator.js';
|
|
|
4
4
|
export declare class CalldataGenerator extends Generator {
|
|
5
5
|
constructor(senderPubKey: Buffer, contractSaltPubKey: Buffer, network?: Network);
|
|
6
6
|
static getPubKeyAsBuffer(witnessKeys: Buffer[], network: Network): Buffer;
|
|
7
|
-
compile(calldata: Buffer, contractSecret: Buffer, preimage: Buffer, features?: Features[]): Buffer;
|
|
7
|
+
compile(calldata: Buffer, contractSecret: Buffer, preimage: Buffer, maxPriority: bigint, features?: Features[]): Buffer;
|
|
8
8
|
}
|
|
@@ -25,14 +25,14 @@ export class CalldataGenerator extends Generator {
|
|
|
25
25
|
}
|
|
26
26
|
return compressed;
|
|
27
27
|
}
|
|
28
|
-
compile(calldata, contractSecret, preimage, features = []) {
|
|
28
|
+
compile(calldata, contractSecret, preimage, maxPriority, features = []) {
|
|
29
29
|
if (!this.contractSaltPubKey)
|
|
30
30
|
throw new Error('Contract salt public key not set');
|
|
31
31
|
const dataChunks = this.splitBufferIntoChunks(calldata);
|
|
32
32
|
if (!dataChunks.length)
|
|
33
33
|
throw new Error('No data chunks found');
|
|
34
34
|
let compiledData = [
|
|
35
|
-
this.
|
|
35
|
+
this.getHeader(maxPriority),
|
|
36
36
|
opcodes.OP_TOALTSTACK,
|
|
37
37
|
preimage,
|
|
38
38
|
opcodes.OP_TOALTSTACK,
|
|
@@ -2,6 +2,6 @@ import { Network } from '@btc-vision/bitcoin';
|
|
|
2
2
|
import { Generator } from '../Generator.js';
|
|
3
3
|
export declare class DeploymentGenerator extends Generator {
|
|
4
4
|
constructor(senderPubKey: Buffer, contractSaltPubKey: Buffer, network?: Network);
|
|
5
|
-
compile(contractBytecode: Buffer, contractSalt: Buffer, preimage: Buffer, calldata?: Buffer): Buffer;
|
|
5
|
+
compile(contractBytecode: Buffer, contractSalt: Buffer, preimage: Buffer, maxPriority: bigint, calldata?: Buffer): Buffer;
|
|
6
6
|
private getAsm;
|
|
7
7
|
}
|
|
@@ -4,8 +4,8 @@ export class DeploymentGenerator extends Generator {
|
|
|
4
4
|
constructor(senderPubKey, contractSaltPubKey, network = networks.bitcoin) {
|
|
5
5
|
super(senderPubKey, contractSaltPubKey, network);
|
|
6
6
|
}
|
|
7
|
-
compile(contractBytecode, contractSalt, preimage, calldata) {
|
|
8
|
-
const asm = this.getAsm(contractBytecode, contractSalt, preimage, calldata);
|
|
7
|
+
compile(contractBytecode, contractSalt, preimage, maxPriority, calldata) {
|
|
8
|
+
const asm = this.getAsm(contractBytecode, contractSalt, preimage, maxPriority, calldata);
|
|
9
9
|
const compiled = script.compile(asm);
|
|
10
10
|
const decompiled = script.decompile(compiled);
|
|
11
11
|
if (!decompiled) {
|
|
@@ -13,13 +13,13 @@ export class DeploymentGenerator extends Generator {
|
|
|
13
13
|
}
|
|
14
14
|
return compiled;
|
|
15
15
|
}
|
|
16
|
-
getAsm(contractBytecode, contractSalt, preimage, calldata) {
|
|
16
|
+
getAsm(contractBytecode, contractSalt, preimage, maxPriority, calldata) {
|
|
17
17
|
if (!this.contractSaltPubKey)
|
|
18
18
|
throw new Error('Contract salt public key not set');
|
|
19
19
|
const dataChunks = this.splitBufferIntoChunks(contractBytecode);
|
|
20
20
|
const calldataChunks = calldata ? this.splitBufferIntoChunks(calldata) : [];
|
|
21
21
|
const compiledData = [
|
|
22
|
-
this.
|
|
22
|
+
this.getHeader(maxPriority),
|
|
23
23
|
opcodes.OP_TOALTSTACK,
|
|
24
24
|
preimage,
|
|
25
25
|
opcodes.OP_TOALTSTACK,
|
|
@@ -4,5 +4,5 @@ import { Generator } from '../Generator.js';
|
|
|
4
4
|
export declare class LegacyCalldataGenerator extends Generator {
|
|
5
5
|
constructor(senderPubKey: Buffer, network?: Network);
|
|
6
6
|
static getPubKeyAsBuffer(witnessKeys: Buffer[], network: Network): Buffer;
|
|
7
|
-
compile(calldata: Buffer, contractSecret: Buffer,
|
|
7
|
+
compile(calldata: Buffer, contractSecret: Buffer, preimage: Buffer, maxPriority: bigint, features?: Features[]): Buffer;
|
|
8
8
|
}
|
|
@@ -25,11 +25,15 @@ export class LegacyCalldataGenerator extends Generator {
|
|
|
25
25
|
}
|
|
26
26
|
return compressed;
|
|
27
27
|
}
|
|
28
|
-
compile(calldata, contractSecret,
|
|
28
|
+
compile(calldata, contractSecret, preimage, maxPriority, features = []) {
|
|
29
29
|
const dataChunks = this.splitBufferIntoChunks(calldata);
|
|
30
30
|
if (!dataChunks.length)
|
|
31
31
|
throw new Error('No data chunks found');
|
|
32
32
|
let compiledData = [
|
|
33
|
+
this.getHeader(maxPriority),
|
|
34
|
+
opcodes.OP_TOALTSTACK,
|
|
35
|
+
preimage,
|
|
36
|
+
opcodes.OP_TOALTSTACK,
|
|
33
37
|
this.senderPubKey,
|
|
34
38
|
opcodes.OP_DUP,
|
|
35
39
|
opcodes.OP_HASH256,
|
|
@@ -44,28 +48,6 @@ export class LegacyCalldataGenerator extends Generator {
|
|
|
44
48
|
opcodes.OP_IF,
|
|
45
49
|
Generator.MAGIC,
|
|
46
50
|
];
|
|
47
|
-
if (vaultPublicKeys.length > 0) {
|
|
48
|
-
const pubKeyBuffer = LegacyCalldataGenerator.getPubKeyAsBuffer(vaultPublicKeys, this.network);
|
|
49
|
-
const pubKeyDataChunks = this.splitBufferIntoChunks(pubKeyBuffer);
|
|
50
|
-
compiledData = compiledData.concat(...[
|
|
51
|
-
opcodes.OP_0,
|
|
52
|
-
...pubKeyDataChunks,
|
|
53
|
-
]);
|
|
54
|
-
if (minimumSignatures) {
|
|
55
|
-
if (minimumSignatures > 255) {
|
|
56
|
-
throw new Error('Minimum signatures cannot exceed 255');
|
|
57
|
-
}
|
|
58
|
-
const minSigBuffer = Buffer.alloc(2);
|
|
59
|
-
minSigBuffer.writeUint16LE(minimumSignatures, 0);
|
|
60
|
-
compiledData = compiledData.concat(...[
|
|
61
|
-
opcodes.OP_1,
|
|
62
|
-
minSigBuffer,
|
|
63
|
-
]);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
throw new Error('Minimum signatures must be provided');
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
51
|
const featureOpcodes = features.map((feature) => FeatureOpCodes[feature]);
|
|
70
52
|
compiledData = compiledData.concat(...featureOpcodes, ...[opcodes.OP_1NEGATE, ...dataChunks, opcodes.OP_ELSE, opcodes.OP_1, opcodes.OP_ENDIF]);
|
|
71
53
|
const asm = compiledData.flat();
|
|
@@ -255,10 +255,11 @@ export class TransactionFactory {
|
|
|
255
255
|
return Buffer.concat([header, buf]).toString('hex');
|
|
256
256
|
}
|
|
257
257
|
getPriorityFee(params) {
|
|
258
|
-
|
|
258
|
+
const totalFee = params.priorityFee + params.gasSatFee;
|
|
259
|
+
if (totalFee < TransactionBuilder.MINIMUM_DUST) {
|
|
259
260
|
return TransactionBuilder.MINIMUM_DUST;
|
|
260
261
|
}
|
|
261
|
-
return
|
|
262
|
+
return totalFee;
|
|
262
263
|
}
|
|
263
264
|
getUTXOAsTransaction(tx, to, index) {
|
|
264
265
|
if (!tx.outs[index])
|
|
@@ -47,7 +47,7 @@ export class DeploymentTransaction extends TransactionBuilder {
|
|
|
47
47
|
this.contractSeed = this.getContractSeed();
|
|
48
48
|
this.contractSigner = EcKeyPair.fromSeedKeyPair(this.contractSeed, this.network);
|
|
49
49
|
this.deploymentGenerator = new DeploymentGenerator(Buffer.from(this.signer.publicKey), this.contractSignerXOnlyPubKey(), this.network);
|
|
50
|
-
this.compiledTargetScript = this.deploymentGenerator.compile(this.bytecode, this.randomBytes, this.preimage, this.calldata);
|
|
50
|
+
this.compiledTargetScript = this.deploymentGenerator.compile(this.bytecode, this.randomBytes, this.preimage, this.priorityFee, this.calldata);
|
|
51
51
|
this.scriptTree = this.getScriptTree();
|
|
52
52
|
this.internalInit();
|
|
53
53
|
this._contractPubKey = '0x' + this.contractSeed.toString('hex');
|
|
@@ -6,7 +6,7 @@ export class InteractionTransaction extends SharedInteractionTransaction {
|
|
|
6
6
|
this.type = TransactionType.INTERACTION;
|
|
7
7
|
this.tapLeafScript = null;
|
|
8
8
|
this.contractSecret = this.generateSecret();
|
|
9
|
-
this.compiledTargetScript = this.calldataGenerator.compile(this.calldata, this.contractSecret, this.preimage);
|
|
9
|
+
this.compiledTargetScript = this.calldataGenerator.compile(this.calldata, this.contractSecret, this.preimage, this.priorityFee);
|
|
10
10
|
this.scriptTree = this.getScriptTree();
|
|
11
11
|
this.internalInit();
|
|
12
12
|
}
|
|
@@ -3,7 +3,7 @@ import { TransactionBuilder } from './TransactionBuilder.js';
|
|
|
3
3
|
import { TransactionType } from '../enums/TransactionType.js';
|
|
4
4
|
import { ITransactionParameters } from '../interfaces/ITransactionParameters.js';
|
|
5
5
|
import { ECPairInterface } from 'ecpair';
|
|
6
|
-
export interface MultiSignParameters extends Omit<ITransactionParameters, 'priorityFee' | 'signer'> {
|
|
6
|
+
export interface MultiSignParameters extends Omit<ITransactionParameters, 'gasSatFee' | 'priorityFee' | 'signer'> {
|
|
7
7
|
readonly pubkeys: Buffer[];
|
|
8
8
|
readonly minimumSignatures: number;
|
|
9
9
|
readonly from?: undefined;
|
|
@@ -18,6 +18,7 @@ export class MultiSignTransaction extends TransactionBuilder {
|
|
|
18
18
|
...parameters,
|
|
19
19
|
signer: EcKeyPair.fromPrivateKey(bitcoinCrypto.sha256(Buffer.from('aaaaaaaa', 'utf-8'))),
|
|
20
20
|
priorityFee: 0n,
|
|
21
|
+
gasSatFee: 0n,
|
|
21
22
|
});
|
|
22
23
|
this.type = TransactionType.MULTI_SIG;
|
|
23
24
|
this.targetScriptRedeem = null;
|
|
@@ -48,6 +48,9 @@ export class SharedInteractionTransaction extends TransactionBuilder {
|
|
|
48
48
|
generateSecret() {
|
|
49
49
|
if (!this.to)
|
|
50
50
|
throw new Error('To address is required');
|
|
51
|
+
if (this.to.startsWith('0x')) {
|
|
52
|
+
throw new Error(`Legacy not support at this time. Reserved for future use.`);
|
|
53
|
+
}
|
|
51
54
|
return address.fromBech32(this.to).data;
|
|
52
55
|
}
|
|
53
56
|
scriptSignerXOnlyPubKey() {
|
|
@@ -26,6 +26,7 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
|
|
|
26
26
|
protected readonly network: Network;
|
|
27
27
|
protected readonly feeRate: number;
|
|
28
28
|
protected priorityFee: bigint;
|
|
29
|
+
protected gasSatFee: bigint;
|
|
29
30
|
protected utxos: UTXO[];
|
|
30
31
|
protected to: string | undefined;
|
|
31
32
|
protected from: string;
|
|
@@ -24,6 +24,7 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
24
24
|
this.network = parameters.network;
|
|
25
25
|
this.feeRate = parameters.feeRate;
|
|
26
26
|
this.priorityFee = parameters.priorityFee ?? 0n;
|
|
27
|
+
this.gasSatFee = parameters.gasSatFee ?? 0n;
|
|
27
28
|
this.utxos = parameters.utxos;
|
|
28
29
|
this.to = parameters.to || undefined;
|
|
29
30
|
this.isPubKeyDestination = this.to
|
|
@@ -76,6 +77,7 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
76
77
|
network: this.network,
|
|
77
78
|
feeRate: this.feeRate,
|
|
78
79
|
priorityFee: this.priorityFee ?? 0n,
|
|
80
|
+
gasSatFee: this.gasSatFee ?? 0n,
|
|
79
81
|
from: this.from,
|
|
80
82
|
amount: this.estimatedFees,
|
|
81
83
|
optionalOutputs: this.optionalOutputs,
|
|
@@ -241,8 +243,9 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
241
243
|
throw new Error('Output not found');
|
|
242
244
|
}
|
|
243
245
|
getTransactionOPNetFee() {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
+
const totalFee = this.priorityFee + this.gasSatFee;
|
|
247
|
+
if (totalFee > TransactionBuilder.MINIMUM_DUST) {
|
|
248
|
+
return totalFee;
|
|
246
249
|
}
|
|
247
250
|
return TransactionBuilder.MINIMUM_DUST;
|
|
248
251
|
}
|
|
@@ -12,6 +12,7 @@ export interface ITransactionParameters extends ITweakedTransactionData {
|
|
|
12
12
|
chainId?: ChainId;
|
|
13
13
|
readonly feeRate: number;
|
|
14
14
|
readonly priorityFee: bigint;
|
|
15
|
+
readonly gasSatFee: bigint;
|
|
15
16
|
}
|
|
16
17
|
export interface IFundingTransactionParameters extends ITransactionParameters {
|
|
17
18
|
amount: bigint;
|
|
@@ -122,7 +122,8 @@ export class OPNetLimitedProvider {
|
|
|
122
122
|
network,
|
|
123
123
|
to: wallet.p2tr,
|
|
124
124
|
splitInputsInto,
|
|
125
|
-
priorityFee:
|
|
125
|
+
priorityFee: 0n,
|
|
126
|
+
gasSatFee: 330n,
|
|
126
127
|
};
|
|
127
128
|
const transactionFactory = new TransactionFactory();
|
|
128
129
|
const fundingTx = await transactionFactory.createBTCTransfer(fundingTransactionParameters);
|
|
@@ -5,7 +5,7 @@ export class TapscriptVerificator {
|
|
|
5
5
|
static getContractAddress(params) {
|
|
6
6
|
const network = params.network || networks.bitcoin;
|
|
7
7
|
const scriptBuilder = new DeploymentGenerator(params.deployerPubKey, toXOnly(params.contractSaltPubKey), network);
|
|
8
|
-
const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt, params.preimage, params.calldata);
|
|
8
|
+
const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt, params.preimage, params.priorityFee, params.calldata);
|
|
9
9
|
const scriptTree = [
|
|
10
10
|
{
|
|
11
11
|
output: compiledTargetScript,
|
|
@@ -21,7 +21,7 @@ export class TapscriptVerificator {
|
|
|
21
21
|
static verifyControlBlock(params, controlBlock) {
|
|
22
22
|
const network = params.network || networks.bitcoin;
|
|
23
23
|
const scriptBuilder = new DeploymentGenerator(params.deployerPubKey, toXOnly(params.contractSaltPubKey), network);
|
|
24
|
-
const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt, params.preimage, params.calldata);
|
|
24
|
+
const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt, params.preimage, params.priorityFee, params.calldata);
|
|
25
25
|
const scriptTree = [
|
|
26
26
|
{
|
|
27
27
|
output: compiledTargetScript,
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/transaction",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.8",
|
|
5
5
|
"author": "BlobMaster41",
|
|
6
6
|
"description": "OPNet transaction library allows you to create and sign transactions for the OPNet network.",
|
|
7
7
|
"engines": {
|
|
8
|
-
"node": ">=
|
|
8
|
+
"node": ">=20.0.0"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"dependencies": {
|
|
90
90
|
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
|
|
91
91
|
"@bitcoinerlab/secp256k1": "^1.1.1",
|
|
92
|
-
"@btc-vision/bitcoin": "^6.3.
|
|
92
|
+
"@btc-vision/bitcoin": "^6.3.4",
|
|
93
93
|
"@btc-vision/bitcoin-rpc": "^1.0.0",
|
|
94
94
|
"@btc-vision/logger": "^1.0.6",
|
|
95
95
|
"@eslint/js": "^9.14.0",
|
package/src/_version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.2.
|
|
1
|
+
export const version = '1.2.7';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Network, networks, toXOnly } from '@btc-vision/bitcoin';
|
|
2
|
+
import { BinaryWriter } from '../buffer/BinaryWriter.js';
|
|
2
3
|
|
|
3
4
|
/** Bitcoin Script Generator */
|
|
4
5
|
export abstract class Generator {
|
|
@@ -51,6 +52,14 @@ export abstract class Generator {
|
|
|
51
52
|
return Buffer.from([this.senderPubKey[0], 0, 0, 0]);
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
public getHeader(maxPriority: bigint): Buffer {
|
|
56
|
+
const writer = new BinaryWriter(8 + 4);
|
|
57
|
+
writer.writeBytes(this.senderFirstByte);
|
|
58
|
+
writer.writeU64(maxPriority);
|
|
59
|
+
|
|
60
|
+
return Buffer.from(writer.getBuffer());
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
/**
|
|
55
64
|
* Compile the script
|
|
56
65
|
* @param args - The arguments to use when compiling the script
|
|
@@ -4,6 +4,7 @@ import { Compressor } from '../../bytecode/Compressor.js';
|
|
|
4
4
|
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
5
5
|
import { FeatureOpCodes, Features } from '../Features.js';
|
|
6
6
|
import { Generator } from '../Generator.js';
|
|
7
|
+
import { BinaryWriter } from '../../buffer/BinaryWriter.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Class to generate bitcoin script for interaction transactions
|
|
@@ -57,6 +58,7 @@ export class CalldataGenerator extends Generator {
|
|
|
57
58
|
* @param {Buffer} calldata - The calldata to use
|
|
58
59
|
* @param {Buffer} contractSecret - The contract secret
|
|
59
60
|
* @param preimage
|
|
61
|
+
* @param maxPriority - Amount of satoshis to spend max on priority fee
|
|
60
62
|
* @param {number[]} [features=[]] - The features to use (optional)
|
|
61
63
|
* @returns {Buffer} - The compiled script
|
|
62
64
|
* @throws {Error} - If something goes wrong
|
|
@@ -65,6 +67,7 @@ export class CalldataGenerator extends Generator {
|
|
|
65
67
|
calldata: Buffer,
|
|
66
68
|
contractSecret: Buffer,
|
|
67
69
|
preimage: Buffer,
|
|
70
|
+
maxPriority: bigint,
|
|
68
71
|
features: Features[] = [],
|
|
69
72
|
): Buffer {
|
|
70
73
|
if (!this.contractSaltPubKey) throw new Error('Contract salt public key not set');
|
|
@@ -73,7 +76,7 @@ export class CalldataGenerator extends Generator {
|
|
|
73
76
|
if (!dataChunks.length) throw new Error('No data chunks found');
|
|
74
77
|
|
|
75
78
|
let compiledData = [
|
|
76
|
-
this.
|
|
79
|
+
this.getHeader(maxPriority),
|
|
77
80
|
opcodes.OP_TOALTSTACK,
|
|
78
81
|
|
|
79
82
|
// CHALLENGE PREIMAGE FOR REWARD,
|
|
@@ -15,6 +15,7 @@ export class DeploymentGenerator extends Generator {
|
|
|
15
15
|
* @param {Buffer} contractBytecode - The contract bytecode
|
|
16
16
|
* @param {Buffer} contractSalt - The contract salt
|
|
17
17
|
* @param {Buffer} preimage - The preimage for reward
|
|
18
|
+
* @param {bigint} maxPriority - The maximum priority for the contract
|
|
18
19
|
* @param {Buffer} [calldata] - The calldata to be passed to the contract
|
|
19
20
|
* @returns {Buffer} - The compiled script
|
|
20
21
|
*/
|
|
@@ -22,9 +23,10 @@ export class DeploymentGenerator extends Generator {
|
|
|
22
23
|
contractBytecode: Buffer,
|
|
23
24
|
contractSalt: Buffer,
|
|
24
25
|
preimage: Buffer,
|
|
26
|
+
maxPriority: bigint,
|
|
25
27
|
calldata?: Buffer,
|
|
26
28
|
): Buffer {
|
|
27
|
-
const asm = this.getAsm(contractBytecode, contractSalt, preimage, calldata);
|
|
29
|
+
const asm = this.getAsm(contractBytecode, contractSalt, preimage, maxPriority, calldata);
|
|
28
30
|
const compiled = script.compile(asm);
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -42,15 +44,16 @@ export class DeploymentGenerator extends Generator {
|
|
|
42
44
|
contractBytecode: Buffer,
|
|
43
45
|
contractSalt: Buffer,
|
|
44
46
|
preimage: Buffer,
|
|
47
|
+
maxPriority: bigint,
|
|
45
48
|
calldata?: Buffer,
|
|
46
49
|
): (number | Buffer)[] {
|
|
47
50
|
if (!this.contractSaltPubKey) throw new Error('Contract salt public key not set');
|
|
48
51
|
|
|
49
52
|
const dataChunks: Buffer[][] = this.splitBufferIntoChunks(contractBytecode);
|
|
50
53
|
const calldataChunks: Buffer[][] = calldata ? this.splitBufferIntoChunks(calldata) : [];
|
|
51
|
-
|
|
54
|
+
|
|
52
55
|
const compiledData = [
|
|
53
|
-
this.
|
|
56
|
+
this.getHeader(maxPriority),
|
|
54
57
|
opcodes.OP_TOALTSTACK,
|
|
55
58
|
|
|
56
59
|
// CHALLENGE PREIMAGE FOR REWARD,
|
|
@@ -52,23 +52,30 @@ export class LegacyCalldataGenerator extends Generator {
|
|
|
52
52
|
* Compile an interaction bitcoin script
|
|
53
53
|
* @param {Buffer} calldata - The calldata to use
|
|
54
54
|
* @param {Buffer} contractSecret - The contract secret
|
|
55
|
+
* @param {Buffer} preimage - The preimage to use
|
|
56
|
+
* @param {bigint} maxPriority - The maximum priority
|
|
55
57
|
* @param {number[]} [features=[]] - The features to use (optional)
|
|
56
|
-
* @param {Buffer[]} [vaultPublicKeys=[]] - The public keys of the vault (optional)
|
|
57
|
-
* @param {number} [minimumSignatures=0] - The minimum number of signatures (optional)
|
|
58
58
|
* @returns {Buffer} - The compiled script
|
|
59
59
|
* @throws {Error} - If something goes wrong
|
|
60
60
|
*/
|
|
61
61
|
public compile(
|
|
62
62
|
calldata: Buffer,
|
|
63
63
|
contractSecret: Buffer,
|
|
64
|
+
preimage: Buffer,
|
|
65
|
+
maxPriority: bigint,
|
|
64
66
|
features: Features[] = [],
|
|
65
|
-
vaultPublicKeys: Buffer[] = [],
|
|
66
|
-
minimumSignatures: number = 0,
|
|
67
67
|
): Buffer {
|
|
68
68
|
const dataChunks: Buffer[][] = this.splitBufferIntoChunks(calldata);
|
|
69
69
|
if (!dataChunks.length) throw new Error('No data chunks found');
|
|
70
70
|
|
|
71
71
|
let compiledData = [
|
|
72
|
+
this.getHeader(maxPriority),
|
|
73
|
+
opcodes.OP_TOALTSTACK,
|
|
74
|
+
|
|
75
|
+
// CHALLENGE PREIMAGE FOR REWARD,
|
|
76
|
+
preimage,
|
|
77
|
+
opcodes.OP_TOALTSTACK,
|
|
78
|
+
|
|
72
79
|
this.senderPubKey,
|
|
73
80
|
opcodes.OP_DUP,
|
|
74
81
|
opcodes.OP_HASH256,
|
|
@@ -87,42 +94,6 @@ export class LegacyCalldataGenerator extends Generator {
|
|
|
87
94
|
Generator.MAGIC,
|
|
88
95
|
];
|
|
89
96
|
|
|
90
|
-
// write pub keys, when requested.
|
|
91
|
-
if (vaultPublicKeys.length > 0) {
|
|
92
|
-
const pubKeyBuffer = LegacyCalldataGenerator.getPubKeyAsBuffer(
|
|
93
|
-
vaultPublicKeys,
|
|
94
|
-
this.network,
|
|
95
|
-
);
|
|
96
|
-
const pubKeyDataChunks: Buffer[][] = this.splitBufferIntoChunks(pubKeyBuffer);
|
|
97
|
-
|
|
98
|
-
compiledData = compiledData.concat(
|
|
99
|
-
...[
|
|
100
|
-
opcodes.OP_0, // provide opnet public keys
|
|
101
|
-
...pubKeyDataChunks,
|
|
102
|
-
],
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
if (minimumSignatures) {
|
|
106
|
-
// verify that the minimum is not greater than 255
|
|
107
|
-
if (minimumSignatures > 255) {
|
|
108
|
-
throw new Error('Minimum signatures cannot exceed 255');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// we use a 2 bytes buffer even if we limit to 255 so it does not use an opcode for the number
|
|
112
|
-
const minSigBuffer = Buffer.alloc(2);
|
|
113
|
-
minSigBuffer.writeUint16LE(minimumSignatures, 0);
|
|
114
|
-
|
|
115
|
-
compiledData = compiledData.concat(
|
|
116
|
-
...[
|
|
117
|
-
opcodes.OP_1, // provide minimum signatures
|
|
118
|
-
minSigBuffer,
|
|
119
|
-
],
|
|
120
|
-
);
|
|
121
|
-
} else {
|
|
122
|
-
throw new Error('Minimum signatures must be provided');
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
97
|
const featureOpcodes = features.map((feature) => FeatureOpCodes[feature]); // Get the opcodes for the features
|
|
127
98
|
|
|
128
99
|
// Write calldata
|
|
@@ -462,11 +462,12 @@ export class TransactionFactory {
|
|
|
462
462
|
}
|
|
463
463
|
|
|
464
464
|
private getPriorityFee(params: ITransactionParameters): bigint {
|
|
465
|
-
|
|
465
|
+
const totalFee = params.priorityFee + params.gasSatFee;
|
|
466
|
+
if (totalFee < TransactionBuilder.MINIMUM_DUST) {
|
|
466
467
|
return TransactionBuilder.MINIMUM_DUST;
|
|
467
468
|
}
|
|
468
469
|
|
|
469
|
-
return
|
|
470
|
+
return totalFee;
|
|
470
471
|
}
|
|
471
472
|
|
|
472
473
|
private getUTXOAsTransaction(tx: Transaction, to: string, index: number): UTXO[] {
|
|
@@ -21,7 +21,7 @@ import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
|
21
21
|
import { ECPairInterface } from 'ecpair';
|
|
22
22
|
|
|
23
23
|
export interface MultiSignParameters
|
|
24
|
-
extends Omit<ITransactionParameters, 'priorityFee' | 'signer'> {
|
|
24
|
+
extends Omit<ITransactionParameters, 'gasSatFee' | 'priorityFee' | 'signer'> {
|
|
25
25
|
readonly pubkeys: Buffer[];
|
|
26
26
|
readonly minimumSignatures: number;
|
|
27
27
|
readonly from?: undefined;
|
|
@@ -97,6 +97,7 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
|
|
|
97
97
|
bitcoinCrypto.sha256(Buffer.from('aaaaaaaa', 'utf-8')),
|
|
98
98
|
),
|
|
99
99
|
priorityFee: 0n,
|
|
100
|
+
gasSatFee: 0n,
|
|
100
101
|
});
|
|
101
102
|
|
|
102
103
|
if (!parameters.pubkeys) {
|
|
@@ -119,6 +119,10 @@ export abstract class SharedInteractionTransaction<
|
|
|
119
119
|
protected generateSecret(): Buffer {
|
|
120
120
|
if (!this.to) throw new Error('To address is required');
|
|
121
121
|
|
|
122
|
+
if (this.to.startsWith('0x')) {
|
|
123
|
+
throw new Error(`Legacy not support at this time. Reserved for future use.`);
|
|
124
|
+
}
|
|
125
|
+
|
|
122
126
|
return address.fromBech32(this.to).data;
|
|
123
127
|
}
|
|
124
128
|
|