Skip to content

Commit e4a6b38

Browse files
OttoAllmendingerllm-git
andcommitted
feat(abstract-utxo): optimize backup key recovery with address generation
Creates a more efficient address generation function that directly creates addresses from wallet keys rather than using intermediate MultiSigAddress objects. This simplifies the code flow and removes the now-unused `createMultiSigAddress` method. Issue: BG-61926 Co-authored-by: llm-git <[email protected]>
1 parent e65fabb commit e4a6b38

File tree

2 files changed

+27
-35
lines changed

2 files changed

+27
-35
lines changed

modules/abstract-utxo/src/abstractUtxoCoin.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -814,27 +814,6 @@ export abstract class AbstractUtxoCoin extends BaseCoin {
814814
return explainTx(this.decodeTransactionFromPrebuild(params), params, this.network);
815815
}
816816

817-
/**
818-
* Create a multisig address of a given type from a list of keychains and a signing threshold
819-
* @param addressType
820-
* @param signatureThreshold
821-
* @param keys
822-
*/
823-
createMultiSigAddress(addressType: ScriptType2Of3, signatureThreshold: number, keys: Buffer[]): MultiSigAddress {
824-
const {
825-
scriptPubKey: outputScript,
826-
redeemScript,
827-
witnessScript,
828-
} = utxolib.bitgo.outputScripts.createOutputScript2of3(keys, addressType);
829-
830-
return {
831-
outputScript,
832-
redeemScript,
833-
witnessScript,
834-
address: utxolib.address.fromOutputScript(outputScript, this.network),
835-
};
836-
}
837-
838817
/**
839818
* @deprecated - use {@see backupKeyRecovery}
840819
* Builds a funds recovery transaction without BitGo

modules/abstract-utxo/src/recovery/backupKeyRecovery.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ import {
1515
} from '@bitgo/sdk-core';
1616
import { getMainnet, networks } from '@bitgo/utxo-lib';
1717

18-
import { AbstractUtxoCoin, MultiSigAddress } from '../abstractUtxoCoin';
18+
import { AbstractUtxoCoin } from '../abstractUtxoCoin';
1919
import { signAndVerifyPsbt } from '../sign';
20+
import { generateAddressWithChainAndIndex } from '../address';
2021

2122
import { forCoin, RecoveryProvider } from './RecoveryProvider';
2223
import { MempoolApi } from './mempoolApi';
@@ -125,12 +126,27 @@ export interface RecoverParams {
125126
feeRate?: number;
126127
}
127128

128-
function getFormattedAddress(coin: AbstractUtxoCoin, address: MultiSigAddress) {
129-
// Blockchair uses cashaddr format when querying the API for address information. Convert legacy addresses to cashaddr
130-
// before querying the API.
131-
return coin.getChain() === 'bch' || coin.getChain() === 'bcha'
132-
? coin.canonicalAddress(address.address, 'cashaddr').split(':')[1]
133-
: address.address;
129+
/**
130+
* Generate an address and format it for API queries
131+
* @param coin - The coin instance
132+
* @param network - The network to use
133+
* @param walletKeys - The wallet keys
134+
* @param chain - The chain code
135+
* @param addrIndex - The address index
136+
* @returns The formatted address (with cashaddr prefix stripped for BCH/BCHA)
137+
*/
138+
function getFormattedAddress(
139+
coin: AbstractUtxoCoin,
140+
network: utxolib.Network,
141+
walletKeys: RootWalletKeys,
142+
chain: ChainCode,
143+
addrIndex: number
144+
): string {
145+
const format = coin.getChain() === 'bch' || coin.getChain() === 'bcha' ? 'cashaddr' : undefined;
146+
const address = generateAddressWithChainAndIndex(network, walletKeys, chain, addrIndex, format);
147+
148+
// Blockchair uses cashaddr format when querying the API for address information. Strip the prefix for BCH/BCHA.
149+
return format === 'cashaddr' ? address.split(':')[1] : address;
134150
}
135151

136152
async function queryBlockchainUnspentsPath(
@@ -157,10 +173,7 @@ async function queryBlockchainUnspentsPath(
157173
}
158174

159175
async function gatherUnspents(addrIndex: number) {
160-
const walletKeysForUnspent = walletKeys.deriveForChainAndIndex(chain, addrIndex);
161-
const address = coin.createMultiSigAddress(scriptType, 2, walletKeysForUnspent.publicKeys);
162-
163-
const formattedAddress = getFormattedAddress(coin, address);
176+
const formattedAddress = getFormattedAddress(coin, coin.network, walletKeys, chain, addrIndex);
164177
const addrInfo = await recoveryProvider.getAddressInfo(formattedAddress);
165178
// we use txCount here because it implies usage - having tx'es means the addr was generated and used
166179
if (addrInfo.txCount === 0) {
@@ -169,7 +182,7 @@ async function queryBlockchainUnspentsPath(
169182
numSequentialAddressesWithoutTxs = 0;
170183

171184
if (addrInfo.balance > 0) {
172-
console.log(`Found an address with balance: ${address.address} with balance ${addrInfo.balance}`);
185+
console.log(`Found an address with balance: ${formattedAddress} with balance ${addrInfo.balance}`);
173186
const addressUnspents = await recoveryProvider.getUnspentsForAddresses([formattedAddress]);
174187
const processedUnspents = await Promise.all(
175188
addressUnspents.map(async (u): Promise<WalletUnspent<bigint>> => {
@@ -375,9 +388,9 @@ export async function backupKeyRecovery(
375388
const recoveryAmount = totalInputAmount - approximateFee - krsFee;
376389

377390
if (recoveryAmount < BigInt(0)) {
378-
throw new Error(`this wallet\'s balance is too low to pay the fees specified by the KRS provider.
391+
throw new Error(`this wallet\'s balance is too low to pay the fees specified by the KRS provider.
379392
Existing balance on wallet: ${totalInputAmount.toString()}. Estimated network fee for the recovery transaction
380-
: ${approximateFee.toString()}, KRS fee to pay: ${krsFee.toString()}. After deducting fees, your total
393+
: ${approximateFee.toString()}, KRS fee to pay: ${krsFee.toString()}. After deducting fees, your total
381394
recoverable balance is ${recoveryAmount.toString()}`);
382395
}
383396

0 commit comments

Comments
 (0)