11import _ from 'lodash' ;
22import * as utxolib from '@bitgo/utxo-lib' ;
3- import { Dimensions } from '@bitgo/unspents' ;
43import {
54 BitGoBase ,
65 ErrorNoInputToRecover ,
@@ -20,6 +19,7 @@ import { generateAddressWithChainAndIndex } from '../address';
2019import { forCoin , RecoveryProvider } from './RecoveryProvider' ;
2120import { MempoolApi } from './mempoolApi' ;
2221import { CoingeckoApi } from './coingeckoApi' ;
22+ import { createBackupKeyRecoveryPsbt , getRecoveryAmount } from './psbt' ;
2323
2424type ScriptType2Of3 = utxolib . bitgo . outputScripts . ScriptType2Of3 ;
2525type ChainCode = utxolib . bitgo . ChainCode ;
@@ -100,6 +100,7 @@ export interface RecoverParams {
100100 apiKey ?: string ;
101101 userKeyPath ?: string ;
102102 recoveryProvider ?: RecoveryProvider ;
103+ /** Satoshi per byte */
103104 feeRate ?: number ;
104105}
105106
@@ -331,10 +332,6 @@ export async function backupKeyRecovery(
331332 throw new ErrorNoInputToRecover ( ) ;
332333 }
333334
334- // Build the psbt
335- const psbt = utxolib . bitgo . createPsbtForNetwork ( { network : coin . network } ) ;
336- // xpubs can become handy for many things.
337- utxolib . bitgo . addXpubsToPsbt ( psbt , walletKeys ) ;
338335 const txInfo = { } as BackupKeyRecoveryTransansaction ;
339336 const feePerByte : number =
340337 params . feeRate !== undefined
@@ -346,10 +343,6 @@ export async function backupKeyRecovery(
346343 ? unspents . map ( ( u ) => ( { ...u , value : Number ( u . value ) , valueString : u . value . toString ( ) , prevTx : undefined } ) )
347344 : undefined ;
348345
349- unspents . forEach ( ( unspent ) => {
350- utxolib . bitgo . addWalletUnspentToPsbt ( psbt , unspent , walletKeys , 'user' , 'backup' ) ;
351- } ) ;
352-
353346 let krsFee = BigInt ( 0 ) ;
354347 if ( isKrsRecovery && params . krsProvider ) {
355348 try {
@@ -360,40 +353,26 @@ export async function backupKeyRecovery(
360353 }
361354 }
362355
363- const dimensions = Dimensions . fromPsbt ( psbt )
364- // Add the recovery output
365- . plus ( Dimensions . fromOutput ( { script : utxolib . address . toOutputScript ( params . recoveryDestination , coin . network ) } ) )
366- // KRS recovery transactions have a 2nd output to pay the recovery fee, like paygo fees.
367- . plus ( krsFee > BigInt ( 0 ) ? Dimensions . SingleOutput . p2wsh : Dimensions . ZERO ) ;
368- const approximateFee = BigInt ( dimensions . getVSize ( ) * feePerByte ) ;
369-
370- const recoveryAmount = totalInputAmount - approximateFee - krsFee ;
371-
372- if ( recoveryAmount < BigInt ( 0 ) ) {
373- throw new Error ( `this wallet\'s balance is too low to pay the fees specified by the KRS provider.
374- Existing balance on wallet: ${ totalInputAmount . toString ( ) } . Estimated network fee for the recovery transaction
375- : ${ approximateFee . toString ( ) } , KRS fee to pay: ${ krsFee . toString ( ) } . After deducting fees, your total
376- recoverable balance is ${ recoveryAmount . toString ( ) } ` ) ;
377- }
378-
379- const recoveryOutputScript = utxolib . address . toOutputScript ( params . recoveryDestination , coin . network ) ;
380- psbt . addOutput ( { script : recoveryOutputScript , value : recoveryAmount } ) ;
381-
356+ let krsFeeAddress : string | undefined ;
382357 if ( krsProvider && krsFee > BigInt ( 0 ) ) {
383358 if ( ! krsProvider . feeAddresses ) {
384359 throw new Error ( `keyProvider must define feeAddresses` ) ;
385360 }
386361
387- const krsFeeAddress = krsProvider . feeAddresses [ coin . getChain ( ) ] ;
362+ krsFeeAddress = krsProvider . feeAddresses [ coin . getChain ( ) ] ;
388363
389364 if ( ! krsFeeAddress ) {
390365 throw new Error ( 'this KRS provider has not configured their fee structure yet - recovery cannot be completed' ) ;
391366 }
392-
393- const krsFeeOutputScript = utxolib . address . toOutputScript ( krsFeeAddress , coin . network ) ;
394- psbt . addOutput ( { script : krsFeeOutputScript , value : krsFee } ) ;
395367 }
396368
369+ const psbt = createBackupKeyRecoveryPsbt ( coin . network , walletKeys , unspents , {
370+ feeRateSatVB : feePerByte ,
371+ recoveryDestination : params . recoveryDestination ,
372+ keyRecoveryServiceFee : krsFee ,
373+ keyRecoveryServiceFeeAddress : krsFeeAddress ,
374+ } ) ;
375+
397376 if ( isUnsignedSweep ) {
398377 return {
399378 txHex : psbt . toHex ( ) ,
@@ -421,6 +400,7 @@ export async function backupKeyRecovery(
421400 if ( isKrsRecovery ) {
422401 txInfo . coin = coin . getChain ( ) ;
423402 txInfo . backupKey = params . backupKey ;
403+ const recoveryAmount = getRecoveryAmount ( psbt , params . recoveryDestination ) ;
424404 txInfo . recoveryAmount = Number ( recoveryAmount ) ;
425405 txInfo . recoveryAmountString = recoveryAmount . toString ( ) ;
426406 }
0 commit comments