Skip to content

Commit ca8202e

Browse files
feat(utxo-staking): add createDelegationMessageFromPsbt utils
Added utility functions to create delegation message from PSBT, including staker info and transaction conversion helpers. Issue: BTC-1933
1 parent df2f341 commit ca8202e

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

modules/utxo-staking/src/babylon/delegationMessage.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ import * as babylonProtobuf from '@babylonlabs-io/babylon-proto-ts';
88
import * as bitcoinjslib from 'bitcoinjs-lib';
99
import * as utxolib from '@bitgo/utxo-lib';
1010
import { Descriptor } from '@bitgo/wasm-miniscript';
11+
import { toXOnlyPublicKey } from '@bitgo/utxo-core';
1112
import { toWrappedPsbt } from '@bitgo/utxo-core/descriptor';
1213

1314
import { BabylonDescriptorBuilder } from './descriptor';
1415
import { createStakingManager } from './stakingManager';
1516
import { getStakingParams } from './stakingParams';
17+
import { BabylonNetworkLike, toBitcoinJsNetwork } from './network';
1618

1719
export type ValueWithTypeUrl<T> = { typeUrl: string; value: T };
1820

@@ -86,6 +88,77 @@ type Result = {
8688
stakingTx: bitcoinjslib.Transaction;
8789
};
8890

91+
/**
92+
* @param stakingKey - this is the single-sig key that is used for co-signing the staking output
93+
* @param changeAddress - this is unrelated to the staking key and is used for the change output
94+
*/
95+
export function toStakerInfo(
96+
stakingKey: utxolib.ECPairInterface | Buffer | string,
97+
changeAddress: string
98+
): vendor.StakerInfo {
99+
if (typeof stakingKey === 'object' && 'publicKey' in stakingKey) {
100+
stakingKey = stakingKey.publicKey;
101+
}
102+
if (typeof stakingKey === 'string') {
103+
stakingKey = Buffer.from(stakingKey, 'hex');
104+
}
105+
return {
106+
publicKeyNoCoordHex: toXOnlyPublicKey(stakingKey).toString('hex'),
107+
address: changeAddress,
108+
};
109+
}
110+
111+
export function createStaking(
112+
network: BabylonNetworkLike,
113+
blockHeight: number,
114+
stakerBtcInfo: vendor.StakerInfo,
115+
stakingInput: vendor.StakingInputs,
116+
versionedParams: vendor.VersionedStakingParams[] = getStakingParams(network)
117+
): vendor.Staking {
118+
if (blockHeight === 0) {
119+
throw new Error('Babylon BTC tip height cannot be 0');
120+
}
121+
122+
// Get the Babylon params based on the BTC tip height from Babylon chain
123+
const params = vendor.getBabylonParamByBtcHeight(blockHeight, versionedParams);
124+
125+
return new vendor.Staking(
126+
toBitcoinJsNetwork(network),
127+
stakerBtcInfo,
128+
params,
129+
stakingInput.finalityProviderPkNoCoordHex,
130+
stakingInput.stakingTimelock
131+
);
132+
}
133+
134+
type TransactionLike =
135+
| bitcoinjslib.Psbt
136+
| bitcoinjslib.Transaction
137+
| utxolib.Transaction
138+
| utxolib.bitgo.UtxoTransaction<bigint | number>
139+
| utxolib.Psbt
140+
| utxolib.bitgo.UtxoPsbt;
141+
142+
function toStakingTransactionFromPsbt(
143+
psbt: bitcoinjslib.Psbt | utxolib.Psbt | utxolib.bitgo.UtxoPsbt
144+
): bitcoinjslib.Transaction {
145+
if (!(psbt instanceof utxolib.bitgo.UtxoPsbt)) {
146+
psbt = utxolib.bitgo.createPsbtFromBuffer(psbt.toBuffer(), utxolib.networks.bitcoin);
147+
}
148+
if (psbt instanceof utxolib.bitgo.UtxoPsbt) {
149+
// only utxolib.bitgo.UtxoPsbt has the getUnsignedTx method
150+
return bitcoinjslib.Transaction.fromHex(psbt.getUnsignedTx().toHex());
151+
}
152+
throw new Error('illegal state');
153+
}
154+
155+
export function toStakingTransaction(tx: TransactionLike): bitcoinjslib.Transaction {
156+
if (tx instanceof bitcoinjslib.Psbt || tx instanceof utxolib.Psbt) {
157+
return toStakingTransactionFromPsbt(tx);
158+
}
159+
return bitcoinjslib.Transaction.fromHex(tx.toHex());
160+
}
161+
89162
/*
90163
* This is mostly lifted from
91164
* https://github.com/babylonlabs-io/btc-staking-ts/blob/v0.4.0-rc.2/src/staking/manager.ts#L100-L172

0 commit comments

Comments
 (0)