@btc-vision/transaction 1.6.0 → 1.6.4
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/epoch/ChallengeSolution.d.ts +3 -3
- package/browser/epoch/validator/EpochValidator.d.ts +5 -6
- 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/keypair/AddressVerificator.d.ts +2 -1
- package/browser/transaction/TransactionFactory.d.ts +2 -2
- package/browser/transaction/builders/DeploymentTransaction.d.ts +1 -1
- package/browser/transaction/builders/TransactionBuilder.d.ts +3 -0
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +1 -0
- package/browser/transaction/shared/TweakedTransaction.d.ts +18 -0
- package/browser/utxo/OPNetLimitedProvider.d.ts +0 -4
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/epoch/ChallengeSolution.d.ts +3 -3
- package/build/epoch/ChallengeSolution.js +4 -4
- package/build/epoch/validator/EpochValidator.d.ts +5 -6
- package/build/epoch/validator/EpochValidator.js +16 -17
- package/build/generators/builders/DeploymentGenerator.d.ts +1 -1
- package/build/generators/builders/DeploymentGenerator.js +5 -5
- package/build/generators/builders/LegacyCalldataGenerator.d.ts +1 -1
- package/build/generators/builders/LegacyCalldataGenerator.js +2 -2
- package/build/keypair/AddressVerificator.d.ts +2 -1
- package/build/keypair/AddressVerificator.js +4 -0
- package/build/transaction/TransactionFactory.d.ts +2 -2
- package/build/transaction/TransactionFactory.js +2 -2
- package/build/transaction/builders/DeploymentTransaction.d.ts +1 -1
- package/build/transaction/builders/DeploymentTransaction.js +4 -4
- package/build/transaction/builders/TransactionBuilder.d.ts +3 -0
- package/build/transaction/builders/TransactionBuilder.js +18 -3
- package/build/transaction/interfaces/ITransactionParameters.d.ts +1 -0
- package/build/transaction/shared/TweakedTransaction.d.ts +18 -0
- package/build/transaction/shared/TweakedTransaction.js +135 -18
- package/build/utxo/OPNetLimitedProvider.d.ts +0 -4
- package/build/utxo/OPNetLimitedProvider.js +0 -7
- package/package.json +2 -2
- package/src/_version.ts +1 -1
- package/src/epoch/ChallengeSolution.ts +10 -10
- package/src/epoch/validator/EpochValidator.ts +18 -22
- package/src/generators/builders/DeploymentGenerator.ts +6 -6
- package/src/generators/builders/LegacyCalldataGenerator.ts +3 -3
- package/src/keypair/AddressVerificator.ts +7 -1
- package/src/transaction/TransactionFactory.ts +4 -4
- package/src/transaction/builders/DeploymentTransaction.ts +5 -5
- package/src/transaction/builders/TransactionBuilder.ts +30 -3
- package/src/transaction/interfaces/ITransactionParameters.ts +1 -0
- package/src/transaction/shared/TweakedTransaction.ts +210 -23
- package/src/utxo/OPNetLimitedProvider.ts +0 -17
|
@@ -5,7 +5,8 @@ export declare enum AddressTypes {
|
|
|
5
5
|
P2SH_OR_P2SH_P2WPKH = "P2SH_OR_P2SH-P2WPKH",
|
|
6
6
|
P2PK = "P2PK",
|
|
7
7
|
P2TR = "P2TR",
|
|
8
|
-
P2WPKH = "P2WPKH"
|
|
8
|
+
P2WPKH = "P2WPKH",
|
|
9
|
+
P2WSH = "P2WSH"
|
|
9
10
|
}
|
|
10
11
|
export declare class AddressVerificator {
|
|
11
12
|
static isValidP2TRAddress(inAddress: string, network: Network): boolean;
|
|
@@ -11,7 +11,7 @@ export interface DeploymentResult {
|
|
|
11
11
|
readonly transaction: [string, string];
|
|
12
12
|
readonly contractAddress: string;
|
|
13
13
|
readonly contractPubKey: string;
|
|
14
|
-
readonly
|
|
14
|
+
readonly challenge: RawChallenge;
|
|
15
15
|
readonly utxos: UTXO[];
|
|
16
16
|
}
|
|
17
17
|
export interface FundingTransactionResponse {
|
|
@@ -30,7 +30,7 @@ export interface InteractionResponse {
|
|
|
30
30
|
readonly interactionTransaction: string;
|
|
31
31
|
readonly estimatedFees: bigint;
|
|
32
32
|
readonly nextUTXOs: UTXO[];
|
|
33
|
-
readonly
|
|
33
|
+
readonly challenge: RawChallenge;
|
|
34
34
|
}
|
|
35
35
|
export interface BitcoinTransferResponse extends BitcoinTransferBase {
|
|
36
36
|
readonly original: FundingTransaction;
|
|
@@ -9,7 +9,7 @@ import { ChallengeSolution } from '../../epoch/ChallengeSolution.js';
|
|
|
9
9
|
export declare class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
|
|
10
10
|
static readonly MAXIMUM_CONTRACT_SIZE: number;
|
|
11
11
|
type: TransactionType.DEPLOYMENT;
|
|
12
|
-
protected readonly
|
|
12
|
+
protected readonly challenge: ChallengeSolution;
|
|
13
13
|
protected readonly epochChallenge: ITimeLockOutput;
|
|
14
14
|
protected readonly _contractAddress: Address;
|
|
15
15
|
protected tapLeafScript: TapLeafScript | null;
|
|
@@ -8,6 +8,7 @@ import { TweakedTransaction } from '../shared/TweakedTransaction.js';
|
|
|
8
8
|
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
9
9
|
export declare const MINIMUM_AMOUNT_REWARD: bigint;
|
|
10
10
|
export declare const MINIMUM_AMOUNT_CA: bigint;
|
|
11
|
+
export declare const ANCHOR_SCRIPT: Buffer<ArrayBuffer>;
|
|
11
12
|
export declare abstract class TransactionBuilder<T extends TransactionType> extends TweakedTransaction {
|
|
12
13
|
static readonly LOCK_LEAF_SCRIPT: Buffer;
|
|
13
14
|
static readonly MINIMUM_DUST: bigint;
|
|
@@ -33,11 +34,13 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
|
|
|
33
34
|
protected from: string;
|
|
34
35
|
protected _maximumFeeRate: number;
|
|
35
36
|
protected isPubKeyDestination: boolean;
|
|
37
|
+
protected anchor: boolean;
|
|
36
38
|
protected note?: Buffer;
|
|
37
39
|
protected constructor(parameters: ITransactionParameters);
|
|
38
40
|
static getFrom(from: string | undefined, keypair: ECPairInterface | Signer, network: Network): string;
|
|
39
41
|
static witnessStackToScriptWitness(witness: Buffer[]): Buffer;
|
|
40
42
|
addOPReturn(buffer: Buffer): void;
|
|
43
|
+
addAnchor(): void;
|
|
41
44
|
getFundingTransactionParameters(): Promise<IFundingTransactionParameters>;
|
|
42
45
|
setDestinationAddress(address: string): void;
|
|
43
46
|
setMaximumFeeRate(feeRate: number): void;
|
|
@@ -17,6 +17,7 @@ export interface ITransactionParameters extends ITweakedTransactionData {
|
|
|
17
17
|
chainId?: ChainId;
|
|
18
18
|
noSignatures?: boolean;
|
|
19
19
|
readonly note?: string | Buffer;
|
|
20
|
+
readonly anchor?: boolean;
|
|
20
21
|
readonly feeRate: number;
|
|
21
22
|
readonly priorityFee: bigint;
|
|
22
23
|
readonly gasSatFee: bigint;
|
|
@@ -5,6 +5,7 @@ import { UTXO } from '../../utxo/interfaces/IUTXO.js';
|
|
|
5
5
|
import { TapLeafScript } from '../interfaces/Tap.js';
|
|
6
6
|
import { ChainId } from '../../network/ChainId.js';
|
|
7
7
|
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
8
|
+
export type SupportedTransactionVersion = 1 | 2 | 3;
|
|
8
9
|
export interface ITweakedTransactionData {
|
|
9
10
|
readonly signer: Signer | ECPairInterface | UnisatSigner;
|
|
10
11
|
readonly network: Network;
|
|
@@ -12,11 +13,16 @@ export interface ITweakedTransactionData {
|
|
|
12
13
|
readonly nonWitnessUtxo?: Buffer;
|
|
13
14
|
readonly noSignatures?: boolean;
|
|
14
15
|
readonly unlockScript?: Buffer[];
|
|
16
|
+
readonly txVersion?: SupportedTransactionVersion;
|
|
15
17
|
}
|
|
16
18
|
export declare enum TransactionSequence {
|
|
17
19
|
REPLACE_BY_FEE = 4294967293,
|
|
18
20
|
FINAL = 4294967295
|
|
19
21
|
}
|
|
22
|
+
export declare enum CSVModes {
|
|
23
|
+
BLOCKS = 0,
|
|
24
|
+
TIMESTAMPS = 1
|
|
25
|
+
}
|
|
20
26
|
export declare abstract class TweakedTransaction extends Logger {
|
|
21
27
|
readonly logColor: string;
|
|
22
28
|
finalized: boolean;
|
|
@@ -33,10 +39,13 @@ export declare abstract class TweakedTransaction extends Logger {
|
|
|
33
39
|
protected tapLeafScript: TapLeafScript | null;
|
|
34
40
|
protected nonWitnessUtxo?: Buffer;
|
|
35
41
|
protected readonly isBrowser: boolean;
|
|
42
|
+
protected csvInputIndices: Set<number>;
|
|
43
|
+
protected anchorInputIndices: Set<number>;
|
|
36
44
|
protected regenerated: boolean;
|
|
37
45
|
protected ignoreSignatureErrors: boolean;
|
|
38
46
|
protected noSignatures: boolean;
|
|
39
47
|
protected unlockScript: Buffer[] | undefined;
|
|
48
|
+
protected txVersion: SupportedTransactionVersion;
|
|
40
49
|
protected constructor(data: ITweakedTransactionData);
|
|
41
50
|
static readScriptWitnessToWitnessStack(Buffer: Buffer): Buffer[];
|
|
42
51
|
static preEstimateTaprootTransactionFees(feeRate: bigint, numInputs: bigint, numOutputs: bigint, numWitnessElements: bigint, witnessElementSize: bigint, emptyWitness: bigint, taprootControlWitnessSize?: bigint, taprootScriptSize?: bigint): bigint;
|
|
@@ -70,11 +79,20 @@ export declare abstract class TweakedTransaction extends Logger {
|
|
|
70
79
|
outputScript: Buffer;
|
|
71
80
|
} | undefined;
|
|
72
81
|
protected generatePsbtInputExtended(utxo: UTXO, i: number, _extra?: boolean): PsbtInputExtended;
|
|
82
|
+
protected processP2WSHInput(utxo: UTXO, input: PsbtInputExtended, i: number): void;
|
|
83
|
+
protected secondsToCSVTimeUnits(seconds: number): number;
|
|
84
|
+
protected createTimeBasedCSV(seconds: number): number;
|
|
85
|
+
protected isCSVEnabled(sequence: number): boolean;
|
|
86
|
+
protected extractCSVValue(sequence: number): number;
|
|
73
87
|
protected customFinalizerP2SH: (inputIndex: number, input: PsbtInput, scriptA: Buffer, isSegwit: boolean, isP2SH: boolean, isP2WSH: boolean) => {
|
|
74
88
|
finalScriptSig: Buffer | undefined;
|
|
75
89
|
finalScriptWitness: Buffer | undefined;
|
|
76
90
|
};
|
|
77
91
|
protected signInputsWalletBased(transaction: Psbt): Promise<void>;
|
|
92
|
+
protected isCSVScript(decompiled: (number | Buffer)[]): boolean;
|
|
93
|
+
protected setCSVSequence(csvBlocks: number, currentSequence: number): number;
|
|
94
|
+
protected getCSVType(csvValue: number): CSVModes;
|
|
95
|
+
private extractCSVBlocks;
|
|
78
96
|
private attemptSignTaproot;
|
|
79
97
|
private isTaprootScriptSpend;
|
|
80
98
|
private signTaprootInput;
|
|
@@ -7,9 +7,6 @@ export interface WalletUTXOs {
|
|
|
7
7
|
readonly pending: RawUTXOResponse[];
|
|
8
8
|
readonly spentTransactions: RawUTXOResponse[];
|
|
9
9
|
}
|
|
10
|
-
export interface PreimageData {
|
|
11
|
-
readonly preimage: Buffer;
|
|
12
|
-
}
|
|
13
10
|
export declare class OPNetLimitedProvider {
|
|
14
11
|
private readonly opnetAPIUrl;
|
|
15
12
|
private readonly utxoPath;
|
|
@@ -18,7 +15,6 @@ export declare class OPNetLimitedProvider {
|
|
|
18
15
|
fetchUTXO(settings: FetchUTXOParams): Promise<UTXO[]>;
|
|
19
16
|
fetchUTXOMultiAddr(settings: FetchUTXOParamsMultiAddress): Promise<UTXO[]>;
|
|
20
17
|
broadcastTransaction(transaction: string, psbt: boolean): Promise<BroadcastResponse | undefined>;
|
|
21
|
-
getPreimage(): Promise<PreimageData | undefined>;
|
|
22
18
|
splitUTXOs(wallet: Wallet, network: Network, splitInputsInto: number, amountPerUTXO: bigint): Promise<BroadcastResponse | {
|
|
23
19
|
error: string;
|
|
24
20
|
}>;
|
package/build/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "1.6.
|
|
1
|
+
export declare const version = "1.6.4";
|
package/build/_version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.6.
|
|
1
|
+
export const version = '1.6.4';
|
|
@@ -29,14 +29,14 @@ export declare class ChallengeSolution implements IChallengeSolution {
|
|
|
29
29
|
readonly verification: ChallengeVerification;
|
|
30
30
|
private readonly submission?;
|
|
31
31
|
constructor(data: RawChallenge);
|
|
32
|
-
static validateRaw(data: RawChallenge):
|
|
32
|
+
static validateRaw(data: RawChallenge): boolean;
|
|
33
33
|
verifySubmissionSignature(): boolean;
|
|
34
34
|
getSubmission(): ChallengeSubmission | undefined;
|
|
35
|
-
verify():
|
|
35
|
+
verify(): boolean;
|
|
36
36
|
toBuffer(): Buffer;
|
|
37
37
|
toHex(): string;
|
|
38
38
|
toRaw(): RawChallenge;
|
|
39
|
-
calculateSolution():
|
|
39
|
+
calculateSolution(): Buffer;
|
|
40
40
|
checkDifficulty(minDifficulty: number): {
|
|
41
41
|
valid: boolean;
|
|
42
42
|
difficulty: number;
|
|
@@ -47,7 +47,7 @@ export class ChallengeSolution {
|
|
|
47
47
|
? new ChallengeSubmission(data.submission, this.epochNumber + 2n)
|
|
48
48
|
: data.submission;
|
|
49
49
|
}
|
|
50
|
-
static
|
|
50
|
+
static validateRaw(data) {
|
|
51
51
|
return EpochValidator.validateEpochWinner(data);
|
|
52
52
|
}
|
|
53
53
|
verifySubmissionSignature() {
|
|
@@ -65,8 +65,8 @@ export class ChallengeSolution {
|
|
|
65
65
|
}
|
|
66
66
|
return this.submission;
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
return EpochValidator.
|
|
68
|
+
verify() {
|
|
69
|
+
return EpochValidator.validateChallengeSolution(this);
|
|
70
70
|
}
|
|
71
71
|
toBuffer() {
|
|
72
72
|
return this.solution;
|
|
@@ -93,7 +93,7 @@ export class ChallengeSolution {
|
|
|
93
93
|
},
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
-
|
|
96
|
+
calculateSolution() {
|
|
97
97
|
return EpochValidator.calculateSolution(this.verification.targetChecksum, this.publicKey.toBuffer(), this.salt);
|
|
98
98
|
}
|
|
99
99
|
checkDifficulty(minDifficulty) {
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { IChallengeSolution, RawChallenge } from '../interfaces/IChallengeSolution.js';
|
|
2
2
|
export declare class EpochValidator {
|
|
3
3
|
private static readonly BLOCKS_PER_EPOCH;
|
|
4
|
-
private static readonly GRAFFITI_LENGTH;
|
|
5
4
|
static bufferToUint8Array(buffer: Buffer): Uint8Array;
|
|
6
5
|
static uint8ArrayToBuffer(array: Uint8Array): Buffer;
|
|
7
|
-
static sha1(data: Uint8Array):
|
|
6
|
+
static sha1(data: Uint8Array | Buffer): Buffer;
|
|
8
7
|
static calculatePreimage(checksumRoot: Buffer, publicKey: Buffer, salt: Buffer): Buffer;
|
|
9
8
|
static countMatchingBits(hash1: Buffer, hash2: Buffer): number;
|
|
10
|
-
static verifySolution(
|
|
9
|
+
static verifySolution(challenge: IChallengeSolution, log?: boolean): boolean;
|
|
11
10
|
static getMiningTargetBlock(epochNumber: bigint): bigint | null;
|
|
12
|
-
static validateEpochWinner(epochData: RawChallenge):
|
|
13
|
-
static
|
|
14
|
-
static calculateSolution(targetChecksum: Buffer, publicKey: Buffer, salt: Buffer):
|
|
11
|
+
static validateEpochWinner(epochData: RawChallenge): boolean;
|
|
12
|
+
static validateChallengeSolution(challenge: IChallengeSolution): boolean;
|
|
13
|
+
static calculateSolution(targetChecksum: Buffer, publicKey: Buffer, salt: Buffer): Buffer;
|
|
15
14
|
static checkDifficulty(solution: Buffer, targetHash: Buffer, minDifficulty: number): {
|
|
16
15
|
valid: boolean;
|
|
17
16
|
difficulty: number;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ChallengeSolution } from '../ChallengeSolution.js';
|
|
2
|
+
import { crypto } from '@btc-vision/bitcoin';
|
|
2
3
|
export class EpochValidator {
|
|
3
4
|
static bufferToUint8Array(buffer) {
|
|
4
5
|
return new Uint8Array(buffer);
|
|
@@ -6,9 +7,8 @@ export class EpochValidator {
|
|
|
6
7
|
static uint8ArrayToBuffer(array) {
|
|
7
8
|
return Buffer.from(array);
|
|
8
9
|
}
|
|
9
|
-
static
|
|
10
|
-
|
|
11
|
-
return new Uint8Array(hashBuffer);
|
|
10
|
+
static sha1(data) {
|
|
11
|
+
return crypto.sha1(Buffer.isBuffer(data) ? data : Buffer.from(data));
|
|
12
12
|
}
|
|
13
13
|
static calculatePreimage(checksumRoot, publicKey, salt) {
|
|
14
14
|
if (checksumRoot.length !== 32 || publicKey.length !== 32 || salt.length !== 32) {
|
|
@@ -45,20 +45,20 @@ export class EpochValidator {
|
|
|
45
45
|
}
|
|
46
46
|
return matchingBits;
|
|
47
47
|
}
|
|
48
|
-
static
|
|
48
|
+
static verifySolution(challenge, log = false) {
|
|
49
49
|
try {
|
|
50
|
-
const verification =
|
|
51
|
-
const calculatedPreimage = this.calculatePreimage(verification.targetChecksum,
|
|
52
|
-
const computedSolution =
|
|
50
|
+
const verification = challenge.verification;
|
|
51
|
+
const calculatedPreimage = this.calculatePreimage(verification.targetChecksum, challenge.publicKey.toBuffer(), challenge.salt);
|
|
52
|
+
const computedSolution = this.sha1(calculatedPreimage);
|
|
53
53
|
const computedSolutionBuffer = this.uint8ArrayToBuffer(computedSolution);
|
|
54
|
-
if (!computedSolutionBuffer.equals(
|
|
54
|
+
if (!computedSolutionBuffer.equals(challenge.solution)) {
|
|
55
55
|
return false;
|
|
56
56
|
}
|
|
57
57
|
const matchingBits = this.countMatchingBits(computedSolutionBuffer, verification.targetHash);
|
|
58
|
-
if (matchingBits !==
|
|
58
|
+
if (matchingBits !== challenge.difficulty) {
|
|
59
59
|
return false;
|
|
60
60
|
}
|
|
61
|
-
const expectedStartBlock =
|
|
61
|
+
const expectedStartBlock = challenge.epochNumber * this.BLOCKS_PER_EPOCH;
|
|
62
62
|
const expectedEndBlock = expectedStartBlock + this.BLOCKS_PER_EPOCH - 1n;
|
|
63
63
|
return !(verification.startBlock !== expectedStartBlock ||
|
|
64
64
|
verification.endBlock !== expectedEndBlock);
|
|
@@ -75,16 +75,16 @@ export class EpochValidator {
|
|
|
75
75
|
}
|
|
76
76
|
return epochNumber * this.BLOCKS_PER_EPOCH - 1n;
|
|
77
77
|
}
|
|
78
|
-
static
|
|
78
|
+
static validateEpochWinner(epochData) {
|
|
79
79
|
const preimage = new ChallengeSolution(epochData);
|
|
80
|
-
return
|
|
80
|
+
return this.verifySolution(preimage);
|
|
81
81
|
}
|
|
82
|
-
static
|
|
83
|
-
return
|
|
82
|
+
static validateChallengeSolution(challenge) {
|
|
83
|
+
return this.verifySolution(challenge);
|
|
84
84
|
}
|
|
85
|
-
static
|
|
85
|
+
static calculateSolution(targetChecksum, publicKey, salt) {
|
|
86
86
|
const preimage = this.calculatePreimage(targetChecksum, publicKey, salt);
|
|
87
|
-
const hash =
|
|
87
|
+
const hash = this.sha1(this.bufferToUint8Array(preimage));
|
|
88
88
|
return this.uint8ArrayToBuffer(hash);
|
|
89
89
|
}
|
|
90
90
|
static checkDifficulty(solution, targetHash, minDifficulty) {
|
|
@@ -96,4 +96,3 @@ export class EpochValidator {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
EpochValidator.BLOCKS_PER_EPOCH = 5n;
|
|
99
|
-
EpochValidator.GRAFFITI_LENGTH = 16;
|
|
@@ -6,6 +6,6 @@ export declare const OPNET_DEPLOYMENT_VERSION = 0;
|
|
|
6
6
|
export declare const versionBuffer: Buffer<ArrayBuffer>;
|
|
7
7
|
export declare class DeploymentGenerator extends Generator {
|
|
8
8
|
constructor(senderPubKey: Buffer, contractSaltPubKey: Buffer, network?: Network);
|
|
9
|
-
compile(contractBytecode: Buffer, contractSalt: Buffer,
|
|
9
|
+
compile(contractBytecode: Buffer, contractSalt: Buffer, challenge: ChallengeSolution, maxPriority: bigint, calldata?: Buffer, features?: Feature<Features>[]): Buffer;
|
|
10
10
|
private getAsm;
|
|
11
11
|
}
|
|
@@ -6,8 +6,8 @@ export class DeploymentGenerator extends Generator {
|
|
|
6
6
|
constructor(senderPubKey, contractSaltPubKey, network = networks.bitcoin) {
|
|
7
7
|
super(senderPubKey, contractSaltPubKey, network);
|
|
8
8
|
}
|
|
9
|
-
compile(contractBytecode, contractSalt,
|
|
10
|
-
const asm = this.getAsm(contractBytecode, contractSalt,
|
|
9
|
+
compile(contractBytecode, contractSalt, challenge, maxPriority, calldata, features) {
|
|
10
|
+
const asm = this.getAsm(contractBytecode, contractSalt, challenge, maxPriority, calldata, features);
|
|
11
11
|
const compiled = script.compile(asm);
|
|
12
12
|
const decompiled = script.decompile(compiled);
|
|
13
13
|
if (!decompiled) {
|
|
@@ -15,7 +15,7 @@ export class DeploymentGenerator extends Generator {
|
|
|
15
15
|
}
|
|
16
16
|
return compiled;
|
|
17
17
|
}
|
|
18
|
-
getAsm(contractBytecode, contractSalt,
|
|
18
|
+
getAsm(contractBytecode, contractSalt, challenge, maxPriority, calldata, features) {
|
|
19
19
|
if (!this.contractSaltPubKey)
|
|
20
20
|
throw new Error('Contract salt public key not set');
|
|
21
21
|
const dataChunks = this.splitBufferIntoChunks(contractBytecode);
|
|
@@ -33,9 +33,9 @@ export class DeploymentGenerator extends Generator {
|
|
|
33
33
|
const compiledData = [
|
|
34
34
|
this.getHeader(maxPriority, featuresList),
|
|
35
35
|
opcodes.OP_TOALTSTACK,
|
|
36
|
-
|
|
36
|
+
challenge.publicKey.originalPublicKeyBuffer(),
|
|
37
37
|
opcodes.OP_TOALTSTACK,
|
|
38
|
-
|
|
38
|
+
challenge.solution,
|
|
39
39
|
opcodes.OP_TOALTSTACK,
|
|
40
40
|
this.xSenderPubKey,
|
|
41
41
|
opcodes.OP_DUP,
|
|
@@ -4,5 +4,5 @@ import { Feature, Features } from '../Features.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, challenge: Buffer, maxPriority: bigint, features?: Feature<Features>[]): Buffer;
|
|
8
8
|
}
|
|
@@ -24,7 +24,7 @@ export class LegacyCalldataGenerator extends Generator {
|
|
|
24
24
|
}
|
|
25
25
|
return compressed;
|
|
26
26
|
}
|
|
27
|
-
compile(calldata, contractSecret,
|
|
27
|
+
compile(calldata, contractSecret, challenge, maxPriority, features = []) {
|
|
28
28
|
const dataChunks = this.splitBufferIntoChunks(calldata);
|
|
29
29
|
if (!dataChunks.length)
|
|
30
30
|
throw new Error('No data chunks found');
|
|
@@ -39,7 +39,7 @@ export class LegacyCalldataGenerator extends Generator {
|
|
|
39
39
|
let compiledData = [
|
|
40
40
|
this.getHeader(maxPriority, featuresList),
|
|
41
41
|
opcodes.OP_TOALTSTACK,
|
|
42
|
-
|
|
42
|
+
challenge,
|
|
43
43
|
opcodes.OP_TOALTSTACK,
|
|
44
44
|
this.senderPubKey,
|
|
45
45
|
opcodes.OP_DUP,
|
|
@@ -5,7 +5,8 @@ export declare enum AddressTypes {
|
|
|
5
5
|
P2SH_OR_P2SH_P2WPKH = "P2SH_OR_P2SH-P2WPKH",
|
|
6
6
|
P2PK = "P2PK",
|
|
7
7
|
P2TR = "P2TR",
|
|
8
|
-
P2WPKH = "P2WPKH"
|
|
8
|
+
P2WPKH = "P2WPKH",
|
|
9
|
+
P2WSH = "P2WSH"
|
|
9
10
|
}
|
|
10
11
|
export declare class AddressVerificator {
|
|
11
12
|
static isValidP2TRAddress(inAddress: string, network: Network): boolean;
|
|
@@ -11,6 +11,7 @@ export var AddressTypes;
|
|
|
11
11
|
AddressTypes["P2PK"] = "P2PK";
|
|
12
12
|
AddressTypes["P2TR"] = "P2TR";
|
|
13
13
|
AddressTypes["P2WPKH"] = "P2WPKH";
|
|
14
|
+
AddressTypes["P2WSH"] = "P2WSH";
|
|
14
15
|
})(AddressTypes || (AddressTypes = {}));
|
|
15
16
|
export class AddressVerificator {
|
|
16
17
|
static isValidP2TRAddress(inAddress, network) {
|
|
@@ -112,6 +113,9 @@ export class AddressVerificator {
|
|
|
112
113
|
if (decodedBech32.version === 0 && decodedBech32.data.length === 20) {
|
|
113
114
|
return AddressTypes.P2WPKH;
|
|
114
115
|
}
|
|
116
|
+
if (decodedBech32.version === 0 && decodedBech32.data.length === 32) {
|
|
117
|
+
return AddressTypes.P2WSH;
|
|
118
|
+
}
|
|
115
119
|
if (decodedBech32.version === 1 && decodedBech32.data.length === 32) {
|
|
116
120
|
return AddressTypes.P2TR;
|
|
117
121
|
}
|
|
@@ -11,7 +11,7 @@ export interface DeploymentResult {
|
|
|
11
11
|
readonly transaction: [string, string];
|
|
12
12
|
readonly contractAddress: string;
|
|
13
13
|
readonly contractPubKey: string;
|
|
14
|
-
readonly
|
|
14
|
+
readonly challenge: RawChallenge;
|
|
15
15
|
readonly utxos: UTXO[];
|
|
16
16
|
}
|
|
17
17
|
export interface FundingTransactionResponse {
|
|
@@ -30,7 +30,7 @@ export interface InteractionResponse {
|
|
|
30
30
|
readonly interactionTransaction: string;
|
|
31
31
|
readonly estimatedFees: bigint;
|
|
32
32
|
readonly nextUTXOs: UTXO[];
|
|
33
|
-
readonly
|
|
33
|
+
readonly challenge: RawChallenge;
|
|
34
34
|
}
|
|
35
35
|
export interface BitcoinTransferResponse extends BitcoinTransferBase {
|
|
36
36
|
readonly original: FundingTransaction;
|
|
@@ -133,7 +133,7 @@ export class TransactionFactory {
|
|
|
133
133
|
interactionTransaction: outTx.toHex(),
|
|
134
134
|
estimatedFees: preTransaction.estimatedFees,
|
|
135
135
|
nextUTXOs: this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.from, 1),
|
|
136
|
-
|
|
136
|
+
challenge: preTransaction.getPreimage().toRaw(),
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
139
|
async signDeployment(deploymentParameters) {
|
|
@@ -211,7 +211,7 @@ export class TransactionFactory {
|
|
|
211
211
|
contractAddress: finalTransaction.getContractAddress(),
|
|
212
212
|
contractPubKey: finalTransaction.contractPubKey,
|
|
213
213
|
utxos: [refundUTXO],
|
|
214
|
-
|
|
214
|
+
challenge: preTransaction.getPreimage().toRaw(),
|
|
215
215
|
};
|
|
216
216
|
}
|
|
217
217
|
async createBTCTransfer(parameters) {
|
|
@@ -9,7 +9,7 @@ import { ChallengeSolution } from '../../epoch/ChallengeSolution.js';
|
|
|
9
9
|
export declare class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
|
|
10
10
|
static readonly MAXIMUM_CONTRACT_SIZE: number;
|
|
11
11
|
type: TransactionType.DEPLOYMENT;
|
|
12
|
-
protected readonly
|
|
12
|
+
protected readonly challenge: ChallengeSolution;
|
|
13
13
|
protected readonly epochChallenge: ITimeLockOutput;
|
|
14
14
|
protected readonly _contractAddress: Address;
|
|
15
15
|
protected tapLeafScript: TapLeafScript | null;
|
|
@@ -45,12 +45,12 @@ export class DeploymentTransaction extends TransactionBuilder {
|
|
|
45
45
|
if (!parameters.challenge)
|
|
46
46
|
throw new Error('Challenge solution is required');
|
|
47
47
|
this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
|
|
48
|
-
this.
|
|
49
|
-
this.epochChallenge = TimeLockGenerator.generateTimeLockAddress(this.
|
|
48
|
+
this.challenge = parameters.challenge;
|
|
49
|
+
this.epochChallenge = TimeLockGenerator.generateTimeLockAddress(this.challenge.publicKey.originalPublicKeyBuffer(), this.network);
|
|
50
50
|
this.contractSeed = this.getContractSeed();
|
|
51
51
|
this.contractSigner = EcKeyPair.fromSeedKeyPair(this.contractSeed, this.network);
|
|
52
52
|
this.deploymentGenerator = new DeploymentGenerator(Buffer.from(this.signer.publicKey), this.contractSignerXOnlyPubKey(), this.network);
|
|
53
|
-
this.compiledTargetScript = this.deploymentGenerator.compile(this.bytecode, this.randomBytes, this.
|
|
53
|
+
this.compiledTargetScript = this.deploymentGenerator.compile(this.bytecode, this.randomBytes, this.challenge, this.priorityFee, this.calldata, this.generateFeatures(parameters));
|
|
54
54
|
this.scriptTree = this.getScriptTree();
|
|
55
55
|
this.internalInit();
|
|
56
56
|
this._contractPubKey = '0x' + this.contractSeed.toString('hex');
|
|
@@ -69,7 +69,7 @@ export class DeploymentTransaction extends TransactionBuilder {
|
|
|
69
69
|
return this.randomBytes;
|
|
70
70
|
}
|
|
71
71
|
getPreimage() {
|
|
72
|
-
return this.
|
|
72
|
+
return this.challenge;
|
|
73
73
|
}
|
|
74
74
|
getContractAddress() {
|
|
75
75
|
if (this._computedAddress) {
|
|
@@ -8,6 +8,7 @@ import { TweakedTransaction } from '../shared/TweakedTransaction.js';
|
|
|
8
8
|
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
9
9
|
export declare const MINIMUM_AMOUNT_REWARD: bigint;
|
|
10
10
|
export declare const MINIMUM_AMOUNT_CA: bigint;
|
|
11
|
+
export declare const ANCHOR_SCRIPT: Buffer<ArrayBuffer>;
|
|
11
12
|
export declare abstract class TransactionBuilder<T extends TransactionType> extends TweakedTransaction {
|
|
12
13
|
static readonly LOCK_LEAF_SCRIPT: Buffer;
|
|
13
14
|
static readonly MINIMUM_DUST: bigint;
|
|
@@ -33,11 +34,13 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
|
|
|
33
34
|
protected from: string;
|
|
34
35
|
protected _maximumFeeRate: number;
|
|
35
36
|
protected isPubKeyDestination: boolean;
|
|
37
|
+
protected anchor: boolean;
|
|
36
38
|
protected note?: Buffer;
|
|
37
39
|
protected constructor(parameters: ITransactionParameters);
|
|
38
40
|
static getFrom(from: string | undefined, keypair: ECPairInterface | Signer, network: Network): string;
|
|
39
41
|
static witnessStackToScriptWitness(witness: Buffer[]): Buffer;
|
|
40
42
|
addOPReturn(buffer: Buffer): void;
|
|
43
|
+
addAnchor(): void;
|
|
41
44
|
getFundingTransactionParameters(): Promise<IFundingTransactionParameters>;
|
|
42
45
|
setDestinationAddress(address: string): void;
|
|
43
46
|
setMaximumFeeRate(feeRate: number): void;
|
|
@@ -6,6 +6,7 @@ import { TweakedTransaction } from '../shared/TweakedTransaction.js';
|
|
|
6
6
|
initEccLib(ecc);
|
|
7
7
|
export const MINIMUM_AMOUNT_REWARD = 540n;
|
|
8
8
|
export const MINIMUM_AMOUNT_CA = 297n;
|
|
9
|
+
export const ANCHOR_SCRIPT = Buffer.from('51024e73', 'hex');
|
|
9
10
|
export class TransactionBuilder extends TweakedTransaction {
|
|
10
11
|
constructor(parameters) {
|
|
11
12
|
super(parameters);
|
|
@@ -36,6 +37,7 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
36
37
|
this.note = parameters.note;
|
|
37
38
|
}
|
|
38
39
|
}
|
|
40
|
+
this.anchor = parameters.anchor ?? false;
|
|
39
41
|
this.isPubKeyDestination = this.to
|
|
40
42
|
? AddressVerificator.isValidPublicKey(this.to, this.network)
|
|
41
43
|
: false;
|
|
@@ -48,6 +50,7 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
48
50
|
}
|
|
49
51
|
this.transaction = new Psbt({
|
|
50
52
|
network: this.network,
|
|
53
|
+
version: this.txVersion,
|
|
51
54
|
});
|
|
52
55
|
}
|
|
53
56
|
static getFrom(from, keypair, network) {
|
|
@@ -82,6 +85,12 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
82
85
|
script: compileScript,
|
|
83
86
|
});
|
|
84
87
|
}
|
|
88
|
+
addAnchor() {
|
|
89
|
+
this.addOutput({
|
|
90
|
+
value: 0,
|
|
91
|
+
script: ANCHOR_SCRIPT,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
85
94
|
async getFundingTransactionParameters() {
|
|
86
95
|
if (!this.estimatedFees) {
|
|
87
96
|
this.estimatedFees = await this.estimateTransactionFees();
|
|
@@ -164,8 +173,8 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
164
173
|
if (script.script.length < 2) {
|
|
165
174
|
throw new Error('Output script is too short');
|
|
166
175
|
}
|
|
167
|
-
if (script.script[0] !== opcodes.OP_RETURN) {
|
|
168
|
-
throw new Error('Output script must start with OP_RETURN when value is 0');
|
|
176
|
+
if (script.script[0] !== opcodes.OP_RETURN && !script.script.equals(ANCHOR_SCRIPT)) {
|
|
177
|
+
throw new Error('Output script must start with OP_RETURN or be an ANCHOR when value is 0');
|
|
169
178
|
}
|
|
170
179
|
}
|
|
171
180
|
else if (output.value < TransactionBuilder.MINIMUM_DUST) {
|
|
@@ -201,7 +210,10 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
201
210
|
}
|
|
202
211
|
}
|
|
203
212
|
async rebuildFromBase64(base64) {
|
|
204
|
-
this.transaction = Psbt.fromBase64(base64, {
|
|
213
|
+
this.transaction = Psbt.fromBase64(base64, {
|
|
214
|
+
network: this.network,
|
|
215
|
+
version: this.txVersion,
|
|
216
|
+
});
|
|
205
217
|
this.signed = false;
|
|
206
218
|
this.sighashTypes = [Transaction.SIGHASH_ANYONECANPAY, Transaction.SIGHASH_ALL];
|
|
207
219
|
return await this.signPSBT();
|
|
@@ -231,6 +243,9 @@ export class TransactionBuilder extends TweakedTransaction {
|
|
|
231
243
|
if (this.note) {
|
|
232
244
|
this.addOPReturn(this.note);
|
|
233
245
|
}
|
|
246
|
+
if (this.anchor) {
|
|
247
|
+
this.addAnchor();
|
|
248
|
+
}
|
|
234
249
|
const sendBackAmount = this.totalInputAmount - amountSpent;
|
|
235
250
|
if (sendBackAmount >= TransactionBuilder.MINIMUM_DUST) {
|
|
236
251
|
if (AddressVerificator.isValidP2TRAddress(this.from, this.network)) {
|
|
@@ -17,6 +17,7 @@ export interface ITransactionParameters extends ITweakedTransactionData {
|
|
|
17
17
|
chainId?: ChainId;
|
|
18
18
|
noSignatures?: boolean;
|
|
19
19
|
readonly note?: string | Buffer;
|
|
20
|
+
readonly anchor?: boolean;
|
|
20
21
|
readonly feeRate: number;
|
|
21
22
|
readonly priorityFee: bigint;
|
|
22
23
|
readonly gasSatFee: bigint;
|
|
@@ -5,6 +5,7 @@ import { UTXO } from '../../utxo/interfaces/IUTXO.js';
|
|
|
5
5
|
import { TapLeafScript } from '../interfaces/Tap.js';
|
|
6
6
|
import { ChainId } from '../../network/ChainId.js';
|
|
7
7
|
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
8
|
+
export type SupportedTransactionVersion = 1 | 2 | 3;
|
|
8
9
|
export interface ITweakedTransactionData {
|
|
9
10
|
readonly signer: Signer | ECPairInterface | UnisatSigner;
|
|
10
11
|
readonly network: Network;
|
|
@@ -12,11 +13,16 @@ export interface ITweakedTransactionData {
|
|
|
12
13
|
readonly nonWitnessUtxo?: Buffer;
|
|
13
14
|
readonly noSignatures?: boolean;
|
|
14
15
|
readonly unlockScript?: Buffer[];
|
|
16
|
+
readonly txVersion?: SupportedTransactionVersion;
|
|
15
17
|
}
|
|
16
18
|
export declare enum TransactionSequence {
|
|
17
19
|
REPLACE_BY_FEE = 4294967293,
|
|
18
20
|
FINAL = 4294967295
|
|
19
21
|
}
|
|
22
|
+
export declare enum CSVModes {
|
|
23
|
+
BLOCKS = 0,
|
|
24
|
+
TIMESTAMPS = 1
|
|
25
|
+
}
|
|
20
26
|
export declare abstract class TweakedTransaction extends Logger {
|
|
21
27
|
readonly logColor: string;
|
|
22
28
|
finalized: boolean;
|
|
@@ -33,10 +39,13 @@ export declare abstract class TweakedTransaction extends Logger {
|
|
|
33
39
|
protected tapLeafScript: TapLeafScript | null;
|
|
34
40
|
protected nonWitnessUtxo?: Buffer;
|
|
35
41
|
protected readonly isBrowser: boolean;
|
|
42
|
+
protected csvInputIndices: Set<number>;
|
|
43
|
+
protected anchorInputIndices: Set<number>;
|
|
36
44
|
protected regenerated: boolean;
|
|
37
45
|
protected ignoreSignatureErrors: boolean;
|
|
38
46
|
protected noSignatures: boolean;
|
|
39
47
|
protected unlockScript: Buffer[] | undefined;
|
|
48
|
+
protected txVersion: SupportedTransactionVersion;
|
|
40
49
|
protected constructor(data: ITweakedTransactionData);
|
|
41
50
|
static readScriptWitnessToWitnessStack(Buffer: Buffer): Buffer[];
|
|
42
51
|
static preEstimateTaprootTransactionFees(feeRate: bigint, numInputs: bigint, numOutputs: bigint, numWitnessElements: bigint, witnessElementSize: bigint, emptyWitness: bigint, taprootControlWitnessSize?: bigint, taprootScriptSize?: bigint): bigint;
|
|
@@ -70,11 +79,20 @@ export declare abstract class TweakedTransaction extends Logger {
|
|
|
70
79
|
outputScript: Buffer;
|
|
71
80
|
} | undefined;
|
|
72
81
|
protected generatePsbtInputExtended(utxo: UTXO, i: number, _extra?: boolean): PsbtInputExtended;
|
|
82
|
+
protected processP2WSHInput(utxo: UTXO, input: PsbtInputExtended, i: number): void;
|
|
83
|
+
protected secondsToCSVTimeUnits(seconds: number): number;
|
|
84
|
+
protected createTimeBasedCSV(seconds: number): number;
|
|
85
|
+
protected isCSVEnabled(sequence: number): boolean;
|
|
86
|
+
protected extractCSVValue(sequence: number): number;
|
|
73
87
|
protected customFinalizerP2SH: (inputIndex: number, input: PsbtInput, scriptA: Buffer, isSegwit: boolean, isP2SH: boolean, isP2WSH: boolean) => {
|
|
74
88
|
finalScriptSig: Buffer | undefined;
|
|
75
89
|
finalScriptWitness: Buffer | undefined;
|
|
76
90
|
};
|
|
77
91
|
protected signInputsWalletBased(transaction: Psbt): Promise<void>;
|
|
92
|
+
protected isCSVScript(decompiled: (number | Buffer)[]): boolean;
|
|
93
|
+
protected setCSVSequence(csvBlocks: number, currentSequence: number): number;
|
|
94
|
+
protected getCSVType(csvValue: number): CSVModes;
|
|
95
|
+
private extractCSVBlocks;
|
|
78
96
|
private attemptSignTaproot;
|
|
79
97
|
private isTaprootScriptSpend;
|
|
80
98
|
private signTaprootInput;
|