@bitgo-beta/babylonlabs-io-btc-staking-ts 0.4.0-beta.86 → 0.4.0-beta.87
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/dist/index.cjs +75 -36
- package/dist/index.d.cts +38 -8
- package/dist/index.js +78 -39
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -51,6 +51,7 @@ __export(src_exports, {
|
|
|
51
51
|
getScriptType: () => getScriptType,
|
|
52
52
|
getUnbondingTxStakerSignature: () => getUnbondingTxStakerSignature,
|
|
53
53
|
initBTCCurve: () => initBTCCurve,
|
|
54
|
+
isNativeSegwit: () => isNativeSegwit,
|
|
54
55
|
isTaproot: () => isTaproot,
|
|
55
56
|
isValidBabylonAddress: () => isValidBabylonAddress,
|
|
56
57
|
isValidBitcoinAddress: () => isValidBitcoinAddress,
|
|
@@ -118,13 +119,13 @@ var StakingScriptData = class {
|
|
|
118
119
|
if (allPks.length !== allPksSet.size) {
|
|
119
120
|
return false;
|
|
120
121
|
}
|
|
121
|
-
if (this.covenantThreshold
|
|
122
|
+
if (this.covenantThreshold <= 0 || this.covenantThreshold > this.covenantKeys.length) {
|
|
122
123
|
return false;
|
|
123
124
|
}
|
|
124
|
-
if (this.stakingTimeLock
|
|
125
|
+
if (this.stakingTimeLock <= 0 || this.stakingTimeLock > 65535) {
|
|
125
126
|
return false;
|
|
126
127
|
}
|
|
127
|
-
if (this.unbondingTimeLock
|
|
128
|
+
if (this.unbondingTimeLock <= 0 || this.unbondingTimeLock > 65535) {
|
|
128
129
|
return false;
|
|
129
130
|
}
|
|
130
131
|
return true;
|
|
@@ -345,14 +346,28 @@ var isTaproot = (taprootAddress, network) => {
|
|
|
345
346
|
if (decoded.version !== 1) {
|
|
346
347
|
return false;
|
|
347
348
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
return taprootAddress.startsWith("tb1p") || taprootAddress.startsWith("sb1p");
|
|
353
|
-
default:
|
|
354
|
-
return false;
|
|
349
|
+
if (network.bech32 === import_bitcoinjs_lib2.networks.bitcoin.bech32) {
|
|
350
|
+
return taprootAddress.startsWith("bc1p");
|
|
351
|
+
} else if (network.bech32 === import_bitcoinjs_lib2.networks.testnet.bech32) {
|
|
352
|
+
return taprootAddress.startsWith("tb1p") || taprootAddress.startsWith("sb1p");
|
|
355
353
|
}
|
|
354
|
+
return false;
|
|
355
|
+
} catch (error) {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
var isNativeSegwit = (segwitAddress, network) => {
|
|
360
|
+
try {
|
|
361
|
+
const decoded = import_bitcoinjs_lib2.address.fromBech32(segwitAddress);
|
|
362
|
+
if (decoded.version !== 0) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
if (network.bech32 === import_bitcoinjs_lib2.networks.bitcoin.bech32) {
|
|
366
|
+
return segwitAddress.startsWith("bc1q");
|
|
367
|
+
} else if (network.bech32 === import_bitcoinjs_lib2.networks.testnet.bech32) {
|
|
368
|
+
return segwitAddress.startsWith("tb1q");
|
|
369
|
+
}
|
|
370
|
+
return false;
|
|
356
371
|
} catch (error) {
|
|
357
372
|
return false;
|
|
358
373
|
}
|
|
@@ -747,6 +762,7 @@ var REDEEM_VERSION = 192;
|
|
|
747
762
|
|
|
748
763
|
// src/staking/transactions.ts
|
|
749
764
|
var BTC_LOCKTIME_HEIGHT_TIME_CUTOFF = 5e8;
|
|
765
|
+
var BTC_SLASHING_FRACTION_DIGITS = 4;
|
|
750
766
|
function stakingTransaction(scripts, amount, changeAddress, inputUTXOs, network, feeRate, lockHeight) {
|
|
751
767
|
if (amount <= 0 || feeRate <= 0) {
|
|
752
768
|
throw new Error("Amount and fee rate must be bigger than 0");
|
|
@@ -960,7 +976,7 @@ function slashingTransaction(scripts, scriptTree, transaction, slashingPkScriptH
|
|
|
960
976
|
if (slashingRate <= 0 || slashingRate >= 1) {
|
|
961
977
|
throw new Error("Slashing rate must be between 0 and 1");
|
|
962
978
|
}
|
|
963
|
-
slashingRate = parseFloat(slashingRate.toFixed(
|
|
979
|
+
slashingRate = parseFloat(slashingRate.toFixed(BTC_SLASHING_FRACTION_DIGITS));
|
|
964
980
|
if (minimumFee <= 0 || !Number.isInteger(minimumFee)) {
|
|
965
981
|
throw new Error("Minimum fee must be a positve integer");
|
|
966
982
|
}
|
|
@@ -986,9 +1002,12 @@ function slashingTransaction(scripts, scriptTree, transaction, slashingPkScriptH
|
|
|
986
1002
|
controlBlock: p2tr.witness[p2tr.witness.length - 1]
|
|
987
1003
|
};
|
|
988
1004
|
const stakingAmount = transaction.outs[outputIndex].value;
|
|
989
|
-
const slashingAmount = Math.
|
|
990
|
-
|
|
991
|
-
|
|
1005
|
+
const slashingAmount = Math.round(stakingAmount * slashingRate);
|
|
1006
|
+
const slashingOutput = Buffer.from(slashingPkScriptHex, "hex");
|
|
1007
|
+
if (import_bitcoinjs_lib6.opcodes.OP_RETURN != slashingOutput[0]) {
|
|
1008
|
+
if (slashingAmount <= BTC_DUST_SAT) {
|
|
1009
|
+
throw new Error("Slashing amount is less than dust limit");
|
|
1010
|
+
}
|
|
992
1011
|
}
|
|
993
1012
|
const userFunds = stakingAmount - slashingAmount - minimumFee;
|
|
994
1013
|
if (userFunds <= BTC_DUST_SAT) {
|
|
@@ -1009,7 +1028,7 @@ function slashingTransaction(scripts, scriptTree, transaction, slashingPkScriptH
|
|
|
1009
1028
|
sequence: NON_RBF_SEQUENCE
|
|
1010
1029
|
});
|
|
1011
1030
|
psbt.addOutput({
|
|
1012
|
-
script:
|
|
1031
|
+
script: slashingOutput,
|
|
1013
1032
|
value: slashingAmount
|
|
1014
1033
|
});
|
|
1015
1034
|
const changeOutput = import_bitcoinjs_lib6.payments.p2tr({
|
|
@@ -1874,7 +1893,6 @@ var getBabylonParamByVersion = (version, babylonParams) => {
|
|
|
1874
1893
|
|
|
1875
1894
|
// src/staking/manager.ts
|
|
1876
1895
|
var import_bitcoinjs_lib10 = require("bitcoinjs-lib");
|
|
1877
|
-
var import_encoding2 = require("@cosmjs/encoding");
|
|
1878
1896
|
var import_babylon_proto_ts = require("@babylonlabs-io/babylon-proto-ts");
|
|
1879
1897
|
var import_pop = require("@babylonlabs-io/babylon-proto-ts/dist/generated/babylon/btcstaking/v1/pop");
|
|
1880
1898
|
|
|
@@ -1895,9 +1913,6 @@ var reverseBuffer = (buffer) => {
|
|
|
1895
1913
|
}
|
|
1896
1914
|
return clonedBuffer;
|
|
1897
1915
|
};
|
|
1898
|
-
var uint8ArrayToHex = (uint8Array) => {
|
|
1899
|
-
return Array.from(uint8Array).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1900
|
-
};
|
|
1901
1916
|
|
|
1902
1917
|
// src/staking/manager.ts
|
|
1903
1918
|
var SigningStep = /* @__PURE__ */ ((SigningStep2) => {
|
|
@@ -1931,7 +1946,9 @@ var BabylonBtcStakingManager = class {
|
|
|
1931
1946
|
* @param babylonBtcTipHeight - The Babylon BTC tip height.
|
|
1932
1947
|
* @param inputUTXOs - The UTXOs that will be used to pay for the staking
|
|
1933
1948
|
* transaction.
|
|
1934
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
1949
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
1950
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
1951
|
+
* be included in a block.
|
|
1935
1952
|
* @param babylonAddress - The Babylon bech32 encoded address of the staker.
|
|
1936
1953
|
* @returns The signed babylon pre-staking registration transaction in base64
|
|
1937
1954
|
* format.
|
|
@@ -1989,7 +2006,8 @@ var BabylonBtcStakingManager = class {
|
|
|
1989
2006
|
* @param stakingTxHeight - The BTC height in which the staking transaction
|
|
1990
2007
|
* is included.
|
|
1991
2008
|
* @param stakingInput - The staking inputs.
|
|
1992
|
-
* @param inclusionProof -
|
|
2009
|
+
* @param inclusionProof - Merkle Proof of Inclusion: Verifies transaction
|
|
2010
|
+
* inclusion in a Bitcoin block that is k-deep.
|
|
1993
2011
|
* @param babylonAddress - The Babylon bech32 encoded address of the staker.
|
|
1994
2012
|
* @returns The signed babylon transaction in base64 format.
|
|
1995
2013
|
*/
|
|
@@ -2037,7 +2055,9 @@ var BabylonBtcStakingManager = class {
|
|
|
2037
2055
|
* @param stakingInput - The staking inputs.
|
|
2038
2056
|
* @param inputUTXOs - The UTXOs that will be used to pay for the staking
|
|
2039
2057
|
* transaction.
|
|
2040
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
2058
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
2059
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
2060
|
+
* be included in a block.
|
|
2041
2061
|
* @returns The estimated BTC fee in satoshis.
|
|
2042
2062
|
*/
|
|
2043
2063
|
estimateBtcStakingFee(stakerBtcInfo, babylonBtcTipHeight, stakingInput, inputUTXOs, feeRate) {
|
|
@@ -2198,7 +2218,9 @@ var BabylonBtcStakingManager = class {
|
|
|
2198
2218
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
2199
2219
|
* delegation in Babylon chain
|
|
2200
2220
|
* @param earlyUnbondingTx - The early unbonding transaction.
|
|
2201
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
2221
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
2222
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
2223
|
+
* be included in a block.
|
|
2202
2224
|
* @returns The signed withdrawal transaction and its fee.
|
|
2203
2225
|
*/
|
|
2204
2226
|
async createSignedBtcWithdrawEarlyUnbondedTransaction(stakerBtcInfo, stakingInput, stakingParamsVersion, earlyUnbondingTx, feeRate) {
|
|
@@ -2235,7 +2257,9 @@ var BabylonBtcStakingManager = class {
|
|
|
2235
2257
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
2236
2258
|
* delegation in Babylon chain
|
|
2237
2259
|
* @param stakingTx - The staking transaction.
|
|
2238
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
2260
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
2261
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
2262
|
+
* be included in a block.
|
|
2239
2263
|
* @returns The signed withdrawal transaction and its fee.
|
|
2240
2264
|
*/
|
|
2241
2265
|
async createSignedBtcWithdrawStakingExpiredTransaction(stakerBtcInfo, stakingInput, stakingParamsVersion, stakingTx, feeRate) {
|
|
@@ -2272,7 +2296,9 @@ var BabylonBtcStakingManager = class {
|
|
|
2272
2296
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
2273
2297
|
* delegation in Babylon chain
|
|
2274
2298
|
* @param slashingTx - The slashing transaction.
|
|
2275
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
2299
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
2300
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
2301
|
+
* be included in a block.
|
|
2276
2302
|
* @returns The signed withdrawal transaction and its fee.
|
|
2277
2303
|
*/
|
|
2278
2304
|
async createSignedBtcWithdrawSlashingTransaction(stakerBtcInfo, stakingInput, stakingParamsVersion, slashingTx, feeRate) {
|
|
@@ -2305,20 +2331,29 @@ var BabylonBtcStakingManager = class {
|
|
|
2305
2331
|
* @param bech32Address - The staker's bech32 address.
|
|
2306
2332
|
* @returns The proof of possession.
|
|
2307
2333
|
*/
|
|
2308
|
-
async createProofOfPossession(bech32Address) {
|
|
2309
|
-
|
|
2310
|
-
|
|
2334
|
+
async createProofOfPossession(bech32Address, stakerBtcAddress) {
|
|
2335
|
+
let sigType = import_pop.BTCSigType.ECDSA;
|
|
2336
|
+
if (isTaproot(stakerBtcAddress, this.network) || isNativeSegwit(stakerBtcAddress, this.network)) {
|
|
2337
|
+
sigType = import_pop.BTCSigType.BIP322;
|
|
2311
2338
|
}
|
|
2312
|
-
const bech32AddressHex = uint8ArrayToHex((0, import_encoding2.fromBech32)(bech32Address).data);
|
|
2313
2339
|
const signedBabylonAddress = await this.btcProvider.signMessage(
|
|
2314
2340
|
"proof-of-possession" /* PROOF_OF_POSSESSION */,
|
|
2315
|
-
|
|
2316
|
-
"ecdsa"
|
|
2317
|
-
);
|
|
2318
|
-
|
|
2341
|
+
bech32Address,
|
|
2342
|
+
sigType === import_pop.BTCSigType.BIP322 ? "bip322-simple" : "ecdsa"
|
|
2343
|
+
);
|
|
2344
|
+
let btcSig;
|
|
2345
|
+
if (sigType === import_pop.BTCSigType.BIP322) {
|
|
2346
|
+
const bip322Sig = import_pop.BIP322Sig.fromPartial({
|
|
2347
|
+
address: stakerBtcAddress,
|
|
2348
|
+
sig: Buffer.from(signedBabylonAddress, "base64")
|
|
2349
|
+
});
|
|
2350
|
+
btcSig = import_pop.BIP322Sig.encode(bip322Sig).finish();
|
|
2351
|
+
} else {
|
|
2352
|
+
btcSig = Buffer.from(signedBabylonAddress, "base64");
|
|
2353
|
+
}
|
|
2319
2354
|
return {
|
|
2320
|
-
btcSigType:
|
|
2321
|
-
btcSig
|
|
2355
|
+
btcSigType: sigType,
|
|
2356
|
+
btcSig
|
|
2322
2357
|
};
|
|
2323
2358
|
}
|
|
2324
2359
|
/**
|
|
@@ -2386,7 +2421,10 @@ var BabylonBtcStakingManager = class {
|
|
|
2386
2421
|
if (!unbondingSignatures) {
|
|
2387
2422
|
throw new Error("No signature found in the unbonding output slashing PSBT");
|
|
2388
2423
|
}
|
|
2389
|
-
const proofOfPossession = await this.createProofOfPossession(
|
|
2424
|
+
const proofOfPossession = await this.createProofOfPossession(
|
|
2425
|
+
bech32Address,
|
|
2426
|
+
stakerBtcInfo.address
|
|
2427
|
+
);
|
|
2390
2428
|
const msg = import_babylon_proto_ts.btcstakingtx.MsgCreateBTCDelegation.fromPartial({
|
|
2391
2429
|
stakerAddr: bech32Address,
|
|
2392
2430
|
pop: proofOfPossession,
|
|
@@ -2504,6 +2542,7 @@ var getUnbondingTxStakerSignature = (unbondingTx) => {
|
|
|
2504
2542
|
getScriptType,
|
|
2505
2543
|
getUnbondingTxStakerSignature,
|
|
2506
2544
|
initBTCCurve,
|
|
2545
|
+
isNativeSegwit,
|
|
2507
2546
|
isTaproot,
|
|
2508
2547
|
isValidBabylonAddress,
|
|
2509
2548
|
isValidBitcoinAddress,
|
package/dist/index.d.cts
CHANGED
|
@@ -548,6 +548,14 @@ export declare const isValidBitcoinAddress: (btcAddress: string, network: networ
|
|
|
548
548
|
* @returns {boolean} - True if the address is a Taproot address, otherwise false.
|
|
549
549
|
*/
|
|
550
550
|
export declare const isTaproot: (taprootAddress: string, network: networks.Network) => boolean;
|
|
551
|
+
/**
|
|
552
|
+
* Check whether the given address is a Native SegWit address.
|
|
553
|
+
*
|
|
554
|
+
* @param {string} segwitAddress - The Bitcoin bech32 encoded address to check.
|
|
555
|
+
* @param {object} network - The Bitcoin network (e.g., bitcoin.networks.bitcoin).
|
|
556
|
+
* @returns {boolean} - True if the address is a Native SegWit address, otherwise false.
|
|
557
|
+
*/
|
|
558
|
+
export declare const isNativeSegwit: (segwitAddress: string, network: networks.Network) => boolean;
|
|
551
559
|
/**
|
|
552
560
|
* Check whether the given public key is a valid public key without a coordinate.
|
|
553
561
|
*
|
|
@@ -730,9 +738,20 @@ export declare const getBabylonParamByBtcHeight: (height: number, babylonParamsV
|
|
|
730
738
|
export declare const getBabylonParamByVersion: (version: number, babylonParams: VersionedStakingParams[]) => StakingParams;
|
|
731
739
|
export interface BtcProvider {
|
|
732
740
|
signPsbt(signingStep: SigningStep, psbtHex: string): Promise<string>;
|
|
733
|
-
signMessage
|
|
741
|
+
signMessage: (signingStep: SigningStep, message: string, type: "ecdsa" | "bip322-simple") => Promise<string>;
|
|
734
742
|
}
|
|
735
743
|
export interface BabylonProvider {
|
|
744
|
+
/**
|
|
745
|
+
* Signs a Babylon chain transaction using the provided signing step.
|
|
746
|
+
* This is primarily used for signing MsgCreateBTCDelegation transactions
|
|
747
|
+
* which register the BTC delegation on the Babylon Genesis chain.
|
|
748
|
+
*
|
|
749
|
+
* @param {SigningStep} signingStep - The current signing step context
|
|
750
|
+
* @param {object} msg - The Cosmos SDK transaction message to sign
|
|
751
|
+
* @param {string} msg.typeUrl - The Protobuf type URL identifying the message type
|
|
752
|
+
* @param {T} msg.value - The transaction message data matching the typeUrl
|
|
753
|
+
* @returns {Promise<Uint8Array>} The signed transaction bytes
|
|
754
|
+
*/
|
|
736
755
|
signTransaction: <T extends object>(signingStep: SigningStep, msg: {
|
|
737
756
|
typeUrl: string;
|
|
738
757
|
value: T;
|
|
@@ -774,7 +793,9 @@ export declare class BabylonBtcStakingManager {
|
|
|
774
793
|
* @param babylonBtcTipHeight - The Babylon BTC tip height.
|
|
775
794
|
* @param inputUTXOs - The UTXOs that will be used to pay for the staking
|
|
776
795
|
* transaction.
|
|
777
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
796
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
797
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
798
|
+
* be included in a block.
|
|
778
799
|
* @param babylonAddress - The Babylon bech32 encoded address of the staker.
|
|
779
800
|
* @returns The signed babylon pre-staking registration transaction in base64
|
|
780
801
|
* format.
|
|
@@ -794,7 +815,8 @@ export declare class BabylonBtcStakingManager {
|
|
|
794
815
|
* @param stakingTxHeight - The BTC height in which the staking transaction
|
|
795
816
|
* is included.
|
|
796
817
|
* @param stakingInput - The staking inputs.
|
|
797
|
-
* @param inclusionProof -
|
|
818
|
+
* @param inclusionProof - Merkle Proof of Inclusion: Verifies transaction
|
|
819
|
+
* inclusion in a Bitcoin block that is k-deep.
|
|
798
820
|
* @param babylonAddress - The Babylon bech32 encoded address of the staker.
|
|
799
821
|
* @returns The signed babylon transaction in base64 format.
|
|
800
822
|
*/
|
|
@@ -810,7 +832,9 @@ export declare class BabylonBtcStakingManager {
|
|
|
810
832
|
* @param stakingInput - The staking inputs.
|
|
811
833
|
* @param inputUTXOs - The UTXOs that will be used to pay for the staking
|
|
812
834
|
* transaction.
|
|
813
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
835
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
836
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
837
|
+
* be included in a block.
|
|
814
838
|
* @returns The estimated BTC fee in satoshis.
|
|
815
839
|
*/
|
|
816
840
|
estimateBtcStakingFee(stakerBtcInfo: StakerInfo, babylonBtcTipHeight: number, stakingInput: StakingInputs, inputUTXOs: UTXO[], feeRate: number): number;
|
|
@@ -868,7 +892,9 @@ export declare class BabylonBtcStakingManager {
|
|
|
868
892
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
869
893
|
* delegation in Babylon chain
|
|
870
894
|
* @param earlyUnbondingTx - The early unbonding transaction.
|
|
871
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
895
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
896
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
897
|
+
* be included in a block.
|
|
872
898
|
* @returns The signed withdrawal transaction and its fee.
|
|
873
899
|
*/
|
|
874
900
|
createSignedBtcWithdrawEarlyUnbondedTransaction(stakerBtcInfo: StakerInfo, stakingInput: StakingInputs, stakingParamsVersion: number, earlyUnbondingTx: Transaction, feeRate: number): Promise<TransactionResult>;
|
|
@@ -881,7 +907,9 @@ export declare class BabylonBtcStakingManager {
|
|
|
881
907
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
882
908
|
* delegation in Babylon chain
|
|
883
909
|
* @param stakingTx - The staking transaction.
|
|
884
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
910
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
911
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
912
|
+
* be included in a block.
|
|
885
913
|
* @returns The signed withdrawal transaction and its fee.
|
|
886
914
|
*/
|
|
887
915
|
createSignedBtcWithdrawStakingExpiredTransaction(stakerBtcInfo: StakerInfo, stakingInput: StakingInputs, stakingParamsVersion: number, stakingTx: Transaction, feeRate: number): Promise<TransactionResult>;
|
|
@@ -894,7 +922,9 @@ export declare class BabylonBtcStakingManager {
|
|
|
894
922
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
895
923
|
* delegation in Babylon chain
|
|
896
924
|
* @param slashingTx - The slashing transaction.
|
|
897
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
925
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
926
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
927
|
+
* be included in a block.
|
|
898
928
|
* @returns The signed withdrawal transaction and its fee.
|
|
899
929
|
*/
|
|
900
930
|
createSignedBtcWithdrawSlashingTransaction(stakerBtcInfo: StakerInfo, stakingInput: StakingInputs, stakingParamsVersion: number, slashingTx: Transaction, feeRate: number): Promise<TransactionResult>;
|
|
@@ -903,7 +933,7 @@ export declare class BabylonBtcStakingManager {
|
|
|
903
933
|
* @param bech32Address - The staker's bech32 address.
|
|
904
934
|
* @returns The proof of possession.
|
|
905
935
|
*/
|
|
906
|
-
createProofOfPossession(bech32Address: string): Promise<ProofOfPossessionBTC>;
|
|
936
|
+
createProofOfPossession(bech32Address: string, stakerBtcAddress: string): Promise<ProofOfPossessionBTC>;
|
|
907
937
|
/**
|
|
908
938
|
* Creates the unbonding, slashing, and unbonding slashing transactions and
|
|
909
939
|
* PSBTs.
|
package/dist/index.js
CHANGED
|
@@ -46,13 +46,13 @@ var StakingScriptData = class {
|
|
|
46
46
|
if (allPks.length !== allPksSet.size) {
|
|
47
47
|
return false;
|
|
48
48
|
}
|
|
49
|
-
if (this.covenantThreshold
|
|
49
|
+
if (this.covenantThreshold <= 0 || this.covenantThreshold > this.covenantKeys.length) {
|
|
50
50
|
return false;
|
|
51
51
|
}
|
|
52
|
-
if (this.stakingTimeLock
|
|
52
|
+
if (this.stakingTimeLock <= 0 || this.stakingTimeLock > 65535) {
|
|
53
53
|
return false;
|
|
54
54
|
}
|
|
55
|
-
if (this.unbondingTimeLock
|
|
55
|
+
if (this.unbondingTimeLock <= 0 || this.unbondingTimeLock > 65535) {
|
|
56
56
|
return false;
|
|
57
57
|
}
|
|
58
58
|
return true;
|
|
@@ -245,7 +245,7 @@ var StakingError = class _StakingError extends Error {
|
|
|
245
245
|
};
|
|
246
246
|
|
|
247
247
|
// src/staking/transactions.ts
|
|
248
|
-
import { Psbt, Transaction as Transaction2, payments as payments3, script as script2, address as address3 } from "bitcoinjs-lib";
|
|
248
|
+
import { Psbt, Transaction as Transaction2, payments as payments3, script as script2, address as address3, opcodes as opcodes3 } from "bitcoinjs-lib";
|
|
249
249
|
|
|
250
250
|
// src/constants/dustSat.ts
|
|
251
251
|
var BTC_DUST_SAT = 546;
|
|
@@ -273,14 +273,28 @@ var isTaproot = (taprootAddress, network) => {
|
|
|
273
273
|
if (decoded.version !== 1) {
|
|
274
274
|
return false;
|
|
275
275
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return taprootAddress.startsWith("tb1p") || taprootAddress.startsWith("sb1p");
|
|
281
|
-
default:
|
|
282
|
-
return false;
|
|
276
|
+
if (network.bech32 === networks.bitcoin.bech32) {
|
|
277
|
+
return taprootAddress.startsWith("bc1p");
|
|
278
|
+
} else if (network.bech32 === networks.testnet.bech32) {
|
|
279
|
+
return taprootAddress.startsWith("tb1p") || taprootAddress.startsWith("sb1p");
|
|
283
280
|
}
|
|
281
|
+
return false;
|
|
282
|
+
} catch (error) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
var isNativeSegwit = (segwitAddress, network) => {
|
|
287
|
+
try {
|
|
288
|
+
const decoded = address.fromBech32(segwitAddress);
|
|
289
|
+
if (decoded.version !== 0) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
if (network.bech32 === networks.bitcoin.bech32) {
|
|
293
|
+
return segwitAddress.startsWith("bc1q");
|
|
294
|
+
} else if (network.bech32 === networks.testnet.bech32) {
|
|
295
|
+
return segwitAddress.startsWith("tb1q");
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
284
298
|
} catch (error) {
|
|
285
299
|
return false;
|
|
286
300
|
}
|
|
@@ -675,6 +689,7 @@ var REDEEM_VERSION = 192;
|
|
|
675
689
|
|
|
676
690
|
// src/staking/transactions.ts
|
|
677
691
|
var BTC_LOCKTIME_HEIGHT_TIME_CUTOFF = 5e8;
|
|
692
|
+
var BTC_SLASHING_FRACTION_DIGITS = 4;
|
|
678
693
|
function stakingTransaction(scripts, amount, changeAddress, inputUTXOs, network, feeRate, lockHeight) {
|
|
679
694
|
if (amount <= 0 || feeRate <= 0) {
|
|
680
695
|
throw new Error("Amount and fee rate must be bigger than 0");
|
|
@@ -888,7 +903,7 @@ function slashingTransaction(scripts, scriptTree, transaction, slashingPkScriptH
|
|
|
888
903
|
if (slashingRate <= 0 || slashingRate >= 1) {
|
|
889
904
|
throw new Error("Slashing rate must be between 0 and 1");
|
|
890
905
|
}
|
|
891
|
-
slashingRate = parseFloat(slashingRate.toFixed(
|
|
906
|
+
slashingRate = parseFloat(slashingRate.toFixed(BTC_SLASHING_FRACTION_DIGITS));
|
|
892
907
|
if (minimumFee <= 0 || !Number.isInteger(minimumFee)) {
|
|
893
908
|
throw new Error("Minimum fee must be a positve integer");
|
|
894
909
|
}
|
|
@@ -914,9 +929,12 @@ function slashingTransaction(scripts, scriptTree, transaction, slashingPkScriptH
|
|
|
914
929
|
controlBlock: p2tr.witness[p2tr.witness.length - 1]
|
|
915
930
|
};
|
|
916
931
|
const stakingAmount = transaction.outs[outputIndex].value;
|
|
917
|
-
const slashingAmount = Math.
|
|
918
|
-
|
|
919
|
-
|
|
932
|
+
const slashingAmount = Math.round(stakingAmount * slashingRate);
|
|
933
|
+
const slashingOutput = Buffer.from(slashingPkScriptHex, "hex");
|
|
934
|
+
if (opcodes3.OP_RETURN != slashingOutput[0]) {
|
|
935
|
+
if (slashingAmount <= BTC_DUST_SAT) {
|
|
936
|
+
throw new Error("Slashing amount is less than dust limit");
|
|
937
|
+
}
|
|
920
938
|
}
|
|
921
939
|
const userFunds = stakingAmount - slashingAmount - minimumFee;
|
|
922
940
|
if (userFunds <= BTC_DUST_SAT) {
|
|
@@ -937,7 +955,7 @@ function slashingTransaction(scripts, scriptTree, transaction, slashingPkScriptH
|
|
|
937
955
|
sequence: NON_RBF_SEQUENCE
|
|
938
956
|
});
|
|
939
957
|
psbt.addOutput({
|
|
940
|
-
script:
|
|
958
|
+
script: slashingOutput,
|
|
941
959
|
value: slashingAmount
|
|
942
960
|
});
|
|
943
961
|
const changeOutput = payments3.p2tr({
|
|
@@ -1575,7 +1593,7 @@ var Staking = class {
|
|
|
1575
1593
|
};
|
|
1576
1594
|
|
|
1577
1595
|
// src/staking/observable/observableStakingScript.ts
|
|
1578
|
-
import { opcodes as
|
|
1596
|
+
import { opcodes as opcodes4, script as script3 } from "bitcoinjs-lib";
|
|
1579
1597
|
var ObservableStakingScriptData = class extends StakingScriptData {
|
|
1580
1598
|
constructor(stakerKey, finalityProviderKeys, covenantKeys, covenantThreshold, stakingTimelock, unbondingTimelock, magicBytes) {
|
|
1581
1599
|
super(
|
|
@@ -1618,7 +1636,7 @@ var ObservableStakingScriptData = class extends StakingScriptData {
|
|
|
1618
1636
|
this.finalityProviderKeys[0],
|
|
1619
1637
|
stakingTimeLock
|
|
1620
1638
|
]);
|
|
1621
|
-
return script3.compile([
|
|
1639
|
+
return script3.compile([opcodes4.OP_RETURN, serializedStakingData]);
|
|
1622
1640
|
}
|
|
1623
1641
|
/**
|
|
1624
1642
|
* Builds the staking scripts.
|
|
@@ -1802,13 +1820,13 @@ var getBabylonParamByVersion = (version, babylonParams) => {
|
|
|
1802
1820
|
|
|
1803
1821
|
// src/staking/manager.ts
|
|
1804
1822
|
import { Psbt as Psbt3 } from "bitcoinjs-lib";
|
|
1805
|
-
import { fromBech32 as fromBech322 } from "@cosmjs/encoding";
|
|
1806
1823
|
import {
|
|
1807
1824
|
btccheckpoint,
|
|
1808
1825
|
btcstaking,
|
|
1809
1826
|
btcstakingtx
|
|
1810
1827
|
} from "@babylonlabs-io/babylon-proto-ts";
|
|
1811
1828
|
import {
|
|
1829
|
+
BIP322Sig,
|
|
1812
1830
|
BTCSigType
|
|
1813
1831
|
} from "@babylonlabs-io/babylon-proto-ts/dist/generated/babylon/btcstaking/v1/pop";
|
|
1814
1832
|
|
|
@@ -1829,9 +1847,6 @@ var reverseBuffer = (buffer) => {
|
|
|
1829
1847
|
}
|
|
1830
1848
|
return clonedBuffer;
|
|
1831
1849
|
};
|
|
1832
|
-
var uint8ArrayToHex = (uint8Array) => {
|
|
1833
|
-
return Array.from(uint8Array).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1834
|
-
};
|
|
1835
1850
|
|
|
1836
1851
|
// src/staking/manager.ts
|
|
1837
1852
|
var SigningStep = /* @__PURE__ */ ((SigningStep2) => {
|
|
@@ -1865,7 +1880,9 @@ var BabylonBtcStakingManager = class {
|
|
|
1865
1880
|
* @param babylonBtcTipHeight - The Babylon BTC tip height.
|
|
1866
1881
|
* @param inputUTXOs - The UTXOs that will be used to pay for the staking
|
|
1867
1882
|
* transaction.
|
|
1868
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
1883
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
1884
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
1885
|
+
* be included in a block.
|
|
1869
1886
|
* @param babylonAddress - The Babylon bech32 encoded address of the staker.
|
|
1870
1887
|
* @returns The signed babylon pre-staking registration transaction in base64
|
|
1871
1888
|
* format.
|
|
@@ -1923,7 +1940,8 @@ var BabylonBtcStakingManager = class {
|
|
|
1923
1940
|
* @param stakingTxHeight - The BTC height in which the staking transaction
|
|
1924
1941
|
* is included.
|
|
1925
1942
|
* @param stakingInput - The staking inputs.
|
|
1926
|
-
* @param inclusionProof -
|
|
1943
|
+
* @param inclusionProof - Merkle Proof of Inclusion: Verifies transaction
|
|
1944
|
+
* inclusion in a Bitcoin block that is k-deep.
|
|
1927
1945
|
* @param babylonAddress - The Babylon bech32 encoded address of the staker.
|
|
1928
1946
|
* @returns The signed babylon transaction in base64 format.
|
|
1929
1947
|
*/
|
|
@@ -1971,7 +1989,9 @@ var BabylonBtcStakingManager = class {
|
|
|
1971
1989
|
* @param stakingInput - The staking inputs.
|
|
1972
1990
|
* @param inputUTXOs - The UTXOs that will be used to pay for the staking
|
|
1973
1991
|
* transaction.
|
|
1974
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
1992
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
1993
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
1994
|
+
* be included in a block.
|
|
1975
1995
|
* @returns The estimated BTC fee in satoshis.
|
|
1976
1996
|
*/
|
|
1977
1997
|
estimateBtcStakingFee(stakerBtcInfo, babylonBtcTipHeight, stakingInput, inputUTXOs, feeRate) {
|
|
@@ -2132,7 +2152,9 @@ var BabylonBtcStakingManager = class {
|
|
|
2132
2152
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
2133
2153
|
* delegation in Babylon chain
|
|
2134
2154
|
* @param earlyUnbondingTx - The early unbonding transaction.
|
|
2135
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
2155
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
2156
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
2157
|
+
* be included in a block.
|
|
2136
2158
|
* @returns The signed withdrawal transaction and its fee.
|
|
2137
2159
|
*/
|
|
2138
2160
|
async createSignedBtcWithdrawEarlyUnbondedTransaction(stakerBtcInfo, stakingInput, stakingParamsVersion, earlyUnbondingTx, feeRate) {
|
|
@@ -2169,7 +2191,9 @@ var BabylonBtcStakingManager = class {
|
|
|
2169
2191
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
2170
2192
|
* delegation in Babylon chain
|
|
2171
2193
|
* @param stakingTx - The staking transaction.
|
|
2172
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
2194
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
2195
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
2196
|
+
* be included in a block.
|
|
2173
2197
|
* @returns The signed withdrawal transaction and its fee.
|
|
2174
2198
|
*/
|
|
2175
2199
|
async createSignedBtcWithdrawStakingExpiredTransaction(stakerBtcInfo, stakingInput, stakingParamsVersion, stakingTx, feeRate) {
|
|
@@ -2206,7 +2230,9 @@ var BabylonBtcStakingManager = class {
|
|
|
2206
2230
|
* @param stakingParamsVersion - The params version that was used to create the
|
|
2207
2231
|
* delegation in Babylon chain
|
|
2208
2232
|
* @param slashingTx - The slashing transaction.
|
|
2209
|
-
* @param feeRate - The fee rate in satoshis per byte.
|
|
2233
|
+
* @param feeRate - The fee rate in satoshis per byte. Typical value for the
|
|
2234
|
+
* fee rate is above 1. If the fee rate is too low, the transaction will not
|
|
2235
|
+
* be included in a block.
|
|
2210
2236
|
* @returns The signed withdrawal transaction and its fee.
|
|
2211
2237
|
*/
|
|
2212
2238
|
async createSignedBtcWithdrawSlashingTransaction(stakerBtcInfo, stakingInput, stakingParamsVersion, slashingTx, feeRate) {
|
|
@@ -2239,20 +2265,29 @@ var BabylonBtcStakingManager = class {
|
|
|
2239
2265
|
* @param bech32Address - The staker's bech32 address.
|
|
2240
2266
|
* @returns The proof of possession.
|
|
2241
2267
|
*/
|
|
2242
|
-
async createProofOfPossession(bech32Address) {
|
|
2243
|
-
|
|
2244
|
-
|
|
2268
|
+
async createProofOfPossession(bech32Address, stakerBtcAddress) {
|
|
2269
|
+
let sigType = BTCSigType.ECDSA;
|
|
2270
|
+
if (isTaproot(stakerBtcAddress, this.network) || isNativeSegwit(stakerBtcAddress, this.network)) {
|
|
2271
|
+
sigType = BTCSigType.BIP322;
|
|
2245
2272
|
}
|
|
2246
|
-
const bech32AddressHex = uint8ArrayToHex(fromBech322(bech32Address).data);
|
|
2247
2273
|
const signedBabylonAddress = await this.btcProvider.signMessage(
|
|
2248
2274
|
"proof-of-possession" /* PROOF_OF_POSSESSION */,
|
|
2249
|
-
|
|
2250
|
-
"ecdsa"
|
|
2251
|
-
);
|
|
2252
|
-
|
|
2275
|
+
bech32Address,
|
|
2276
|
+
sigType === BTCSigType.BIP322 ? "bip322-simple" : "ecdsa"
|
|
2277
|
+
);
|
|
2278
|
+
let btcSig;
|
|
2279
|
+
if (sigType === BTCSigType.BIP322) {
|
|
2280
|
+
const bip322Sig = BIP322Sig.fromPartial({
|
|
2281
|
+
address: stakerBtcAddress,
|
|
2282
|
+
sig: Buffer.from(signedBabylonAddress, "base64")
|
|
2283
|
+
});
|
|
2284
|
+
btcSig = BIP322Sig.encode(bip322Sig).finish();
|
|
2285
|
+
} else {
|
|
2286
|
+
btcSig = Buffer.from(signedBabylonAddress, "base64");
|
|
2287
|
+
}
|
|
2253
2288
|
return {
|
|
2254
|
-
btcSigType:
|
|
2255
|
-
btcSig
|
|
2289
|
+
btcSigType: sigType,
|
|
2290
|
+
btcSig
|
|
2256
2291
|
};
|
|
2257
2292
|
}
|
|
2258
2293
|
/**
|
|
@@ -2320,7 +2355,10 @@ var BabylonBtcStakingManager = class {
|
|
|
2320
2355
|
if (!unbondingSignatures) {
|
|
2321
2356
|
throw new Error("No signature found in the unbonding output slashing PSBT");
|
|
2322
2357
|
}
|
|
2323
|
-
const proofOfPossession = await this.createProofOfPossession(
|
|
2358
|
+
const proofOfPossession = await this.createProofOfPossession(
|
|
2359
|
+
bech32Address,
|
|
2360
|
+
stakerBtcInfo.address
|
|
2361
|
+
);
|
|
2324
2362
|
const msg = btcstakingtx.MsgCreateBTCDelegation.fromPartial({
|
|
2325
2363
|
stakerAddr: bech32Address,
|
|
2326
2364
|
pop: proofOfPossession,
|
|
@@ -2437,6 +2475,7 @@ export {
|
|
|
2437
2475
|
getScriptType,
|
|
2438
2476
|
getUnbondingTxStakerSignature,
|
|
2439
2477
|
initBTCCurve,
|
|
2478
|
+
isNativeSegwit,
|
|
2440
2479
|
isTaproot,
|
|
2441
2480
|
isValidBabylonAddress,
|
|
2442
2481
|
isValidBitcoinAddress,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitgo-beta/babylonlabs-io-btc-staking-ts",
|
|
3
|
-
"version": "0.4.0-beta.
|
|
3
|
+
"version": "0.4.0-beta.87",
|
|
4
4
|
"description": "Library exposing methods for the creation and consumption of Bitcoin transactions pertaining to Babylon's Bitcoin Staking protocol.",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "14020d4881c54dbddf4e27de283d0e35ea016045"
|
|
49
49
|
}
|