-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathbtc-account.ts
101 lines (90 loc) · 2.61 KB
/
btc-account.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import {
addressToScriptPublicKeyHex,
networkTypeToNetwork,
remove0x,
toXOnly,
transactionToHex,
tweakSigner,
} from 'rgbpp/btc';
import { AddressType, NetworkType, bitcoin, ECPair } from 'rgbpp/btc';
import { BtcAssetsApi } from 'rgbpp/service';
export interface BtcAccount {
from: string;
fromPubkey?: string;
keyPair: bitcoin.Signer;
payment: bitcoin.Payment;
addressType: AddressType;
networkType: NetworkType;
}
export function createBtcAccount(privateKey: string, addressType: AddressType, networkType: NetworkType): BtcAccount {
const network = networkTypeToNetwork(networkType);
const key = Buffer.from(remove0x(privateKey), 'hex');
const keyPair = ECPair.fromPrivateKey(key, { network });
if (addressType === AddressType.P2WPKH) {
const p2wpkh = bitcoin.payments.p2wpkh({
pubkey: keyPair.publicKey,
network,
});
return {
from: p2wpkh.address!,
payment: p2wpkh,
keyPair,
addressType,
networkType,
};
} else if (addressType === AddressType.P2TR) {
const p2tr = bitcoin.payments.p2tr({
internalPubkey: toXOnly(keyPair.publicKey),
network,
});
return {
from: p2tr.address!,
fromPubkey: keyPair.publicKey.toString('hex'),
payment: p2tr,
keyPair,
addressType,
networkType,
};
} else {
throw new Error('Unsupported address type, only support P2WPKH and P2TR');
}
}
export function signPsbt(psbt: bitcoin.Psbt, account: BtcAccount): bitcoin.Psbt {
const accountScript = addressToScriptPublicKeyHex(account.from, account.networkType);
const tweakedSigner = tweakSigner(account.keyPair, {
network: account.payment.network,
});
psbt.data.inputs.forEach((input, index) => {
if (input.witnessUtxo) {
const script = input.witnessUtxo.script.toString('hex');
if (script === accountScript && account.addressType === AddressType.P2WPKH) {
psbt.signInput(index, account.keyPair);
}
if (script === accountScript && account.addressType === AddressType.P2TR) {
psbt.signInput(index, tweakedSigner);
}
}
});
return psbt;
}
export async function signAndSendPsbt(
psbt: bitcoin.Psbt,
account: BtcAccount,
service: BtcAssetsApi,
): Promise<{
txId: string;
txHex: string;
rawTxHex: string;
}> {
signPsbt(psbt, account);
psbt.finalizeAllInputs();
const tx = psbt.extractTransaction(true);
const txHex = tx.toHex();
const { txid } = await service.sendBtcTransaction(txHex);
return {
txHex,
txId: txid,
// Exclude witness from the BTC_TX for unlocking RGBPP assets
rawTxHex: transactionToHex(tx, false),
};
}