@@ -2,36 +2,53 @@ import { networks, Psbt, Transaction } from "bitcoinjs-lib";
22import { StakingParams , VersionedStakingParams } from "../types/params" ;
33import { TransactionResult , UTXO } from "../types" ;
44import { StakerInfo , Staking } from "." ;
5- import { fromBech32 } from "@cosmjs/encoding" ;
65import {
76 btccheckpoint ,
87 btcstaking ,
98 btcstakingtx ,
109} from "@babylonlabs-io/babylon-proto-ts" ;
1110import {
11+ BIP322Sig ,
1212 BTCSigType ,
1313 ProofOfPossessionBTC ,
1414} from "@babylonlabs-io/babylon-proto-ts/dist/generated/babylon/btcstaking/v1/pop" ;
1515import { BABYLON_REGISTRY_TYPE_URLS } from "../constants/registry" ;
1616import { createCovenantWitness } from "./transactions" ;
1717import { getBabylonParamByBtcHeight , getBabylonParamByVersion } from "../utils/staking/param" ;
18- import { reverseBuffer , uint8ArrayToHex } from "../utils" ;
18+ import { reverseBuffer } from "../utils" ;
1919import { deriveStakingOutputInfo } from "../utils/staking" ;
2020import { findMatchingTxOutputIndex } from "../utils/staking" ;
2121import { isValidBabylonAddress } from "../utils/babylon" ;
2222import { StakingError } from "../error" ;
2323import { StakingErrorCode } from "../error" ;
24+ import { isNativeSegwit , isTaproot } from "../utils/btc" ;
2425
2526export interface BtcProvider {
2627 // Sign a PSBT
28+ // Expecting the PSBT to be encoded in hex format.
2729 signPsbt ( signingStep : SigningStep , psbtHex : string ) : Promise < string > ;
28- // Sign a message using the ECDSA type
29- // This is optional and only required if you would like to use the
30- // `createProofOfPossession` function
31- signMessage ?: ( signingStep : SigningStep , message : string , type : "ecdsa" ) => Promise < string > ;
30+
31+ // Signs a message using either ECDSA or BIP-322, depending on the address type.
32+ // - Taproot and Native Segwit addresses will use BIP-322.
33+ // - Legacy addresses will use ECDSA.
34+ // Expecting the message to be encoded in base64 format.
35+ signMessage : (
36+ signingStep : SigningStep , message : string , type : "ecdsa" | "bip322-simple"
37+ ) => Promise < string > ;
3238}
3339
3440export interface BabylonProvider {
41+ /**
42+ * Signs a Babylon chain transaction using the provided signing step.
43+ * This is primarily used for signing MsgCreateBTCDelegation transactions
44+ * which register the BTC delegation on the Babylon Genesis chain.
45+ *
46+ * @param {SigningStep } signingStep - The current signing step context
47+ * @param {object } msg - The Cosmos SDK transaction message to sign
48+ * @param {string } msg.typeUrl - The Protobuf type URL identifying the message type
49+ * @param {T } msg.value - The transaction message data matching the typeUrl
50+ * @returns {Promise<Uint8Array> } The signed transaction bytes
51+ */
3552 signTransaction : < T extends object > (
3653 signingStep : SigningStep ,
3754 msg : {
@@ -106,7 +123,9 @@ export class BabylonBtcStakingManager {
106123 * @param babylonBtcTipHeight - The Babylon BTC tip height.
107124 * @param inputUTXOs - The UTXOs that will be used to pay for the staking
108125 * transaction.
109- * @param feeRate - The fee rate in satoshis per byte.
126+ * @param feeRate - The fee rate in satoshis per byte. Typical value for the
127+ * fee rate is above 1. If the fee rate is too low, the transaction will not
128+ * be included in a block.
110129 * @param babylonAddress - The Babylon bech32 encoded address of the staker.
111130 * @returns The signed babylon pre-staking registration transaction in base64
112131 * format.
@@ -182,7 +201,8 @@ export class BabylonBtcStakingManager {
182201 * @param stakingTxHeight - The BTC height in which the staking transaction
183202 * is included.
184203 * @param stakingInput - The staking inputs.
185- * @param inclusionProof - The inclusion proof of the staking transaction.
204+ * @param inclusionProof - Merkle Proof of Inclusion: Verifies transaction
205+ * inclusion in a Bitcoin block that is k-deep.
186206 * @param babylonAddress - The Babylon bech32 encoded address of the staker.
187207 * @returns The signed babylon transaction in base64 format.
188208 */
@@ -249,7 +269,9 @@ export class BabylonBtcStakingManager {
249269 * @param stakingInput - The staking inputs.
250270 * @param inputUTXOs - The UTXOs that will be used to pay for the staking
251271 * transaction.
252- * @param feeRate - The fee rate in satoshis per byte.
272+ * @param feeRate - The fee rate in satoshis per byte. Typical value for the
273+ * fee rate is above 1. If the fee rate is too low, the transaction will not
274+ * be included in a block.
253275 * @returns The estimated BTC fee in satoshis.
254276 */
255277 estimateBtcStakingFee (
@@ -462,7 +484,9 @@ export class BabylonBtcStakingManager {
462484 * @param stakingParamsVersion - The params version that was used to create the
463485 * delegation in Babylon chain
464486 * @param earlyUnbondingTx - The early unbonding transaction.
465- * @param feeRate - The fee rate in satoshis per byte.
487+ * @param feeRate - The fee rate in satoshis per byte. Typical value for the
488+ * fee rate is above 1. If the fee rate is too low, the transaction will not
489+ * be included in a block.
466490 * @returns The signed withdrawal transaction and its fee.
467491 */
468492 async createSignedBtcWithdrawEarlyUnbondedTransaction (
@@ -509,7 +533,9 @@ export class BabylonBtcStakingManager {
509533 * @param stakingParamsVersion - The params version that was used to create the
510534 * delegation in Babylon chain
511535 * @param stakingTx - The staking transaction.
512- * @param feeRate - The fee rate in satoshis per byte.
536+ * @param feeRate - The fee rate in satoshis per byte. Typical value for the
537+ * fee rate is above 1. If the fee rate is too low, the transaction will not
538+ * be included in a block.
513539 * @returns The signed withdrawal transaction and its fee.
514540 */
515541 async createSignedBtcWithdrawStakingExpiredTransaction (
@@ -556,7 +582,9 @@ export class BabylonBtcStakingManager {
556582 * @param stakingParamsVersion - The params version that was used to create the
557583 * delegation in Babylon chain
558584 * @param slashingTx - The slashing transaction.
559- * @param feeRate - The fee rate in satoshis per byte.
585+ * @param feeRate - The fee rate in satoshis per byte. Typical value for the
586+ * fee rate is above 1. If the fee rate is too low, the transaction will not
587+ * be included in a block.
560588 * @returns The signed withdrawal transaction and its fee.
561589 */
562590 async createSignedBtcWithdrawSlashingTransaction (
@@ -601,22 +629,42 @@ export class BabylonBtcStakingManager {
601629 */
602630 async createProofOfPossession (
603631 bech32Address : string ,
632+ stakerBtcAddress : string ,
604633 ) : Promise < ProofOfPossessionBTC > {
605- if ( ! this . btcProvider . signMessage ) {
606- throw new Error ( "Sign message function not found" ) ;
634+ let sigType : BTCSigType = BTCSigType . ECDSA ;
635+
636+ // For Taproot or Native SegWit addresses, use the BIP322 signature scheme
637+ // in the proof of possession as it uses the same signature type as the regular
638+ // input UTXO spend. For legacy addresses, use the ECDSA signature scheme.
639+ if (
640+ isTaproot ( stakerBtcAddress , this . network )
641+ || isNativeSegwit ( stakerBtcAddress , this . network )
642+ ) {
643+ sigType = BTCSigType . BIP322 ;
607644 }
608- // Create Proof of Possession
609- const bech32AddressHex = uint8ArrayToHex ( fromBech32 ( bech32Address ) . data ) ;
610-
645+
611646 const signedBabylonAddress = await this . btcProvider . signMessage (
612647 SigningStep . PROOF_OF_POSSESSION ,
613- bech32AddressHex ,
614- "ecdsa" ,
648+ bech32Address ,
649+ sigType === BTCSigType . BIP322 ? "bip322-simple" : "ecdsa" ,
615650 ) ;
616- const ecdsaSig = Uint8Array . from ( Buffer . from ( signedBabylonAddress , "base64" ) ) ;
651+
652+ let btcSig : Uint8Array ;
653+ if ( sigType === BTCSigType . BIP322 ) {
654+ const bip322Sig = BIP322Sig . fromPartial ( {
655+ address : stakerBtcAddress ,
656+ sig : Buffer . from ( signedBabylonAddress , "base64" ) ,
657+ } ) ;
658+ // Encode the BIP322 protobuf message to a Uint8Array
659+ btcSig = BIP322Sig . encode ( bip322Sig ) . finish ( ) ;
660+ } else {
661+ // Encode the ECDSA signature to a Uint8Array
662+ btcSig = Buffer . from ( signedBabylonAddress , "base64" ) ;
663+ }
664+
617665 return {
618- btcSigType : BTCSigType . ECDSA ,
619- btcSig : ecdsaSig ,
666+ btcSigType : sigType ,
667+ btcSig
620668 } ;
621669 }
622670
@@ -710,7 +758,10 @@ export class BabylonBtcStakingManager {
710758 }
711759
712760 // Create proof of possession
713- const proofOfPossession = await this . createProofOfPossession ( bech32Address ) ;
761+ const proofOfPossession = await this . createProofOfPossession (
762+ bech32Address ,
763+ stakerBtcInfo . address ,
764+ ) ;
714765
715766 // Prepare the final protobuf message
716767 const msg : btcstakingtx . MsgCreateBTCDelegation =
0 commit comments