diff --git a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts index 3e2d3ba3f7..d75567643c 100644 --- a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts +++ b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts @@ -218,6 +218,7 @@ export type TSSRecoverOptions = RecoverOptionsWithBytes | NonTSSRecoverOptions; export type RecoverOptions = { userKey: string; backupKey: string; + bitgoKey?: string; walletPassphrase?: string; walletContractAddress: string; // use this as walletBaseAddress for TSS recoveryDestination: string; @@ -1812,6 +1813,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin { // Clean up whitespace from entered values const userPublicOrPrivateKeyShare = params.userKey.replace(/\s/g, ''); const backupPrivateOrPublicKeyShare = params.backupKey.replace(/\s/g, ''); + const bitgoCommonKeychain = params.bitgoKey?.replace(/\s/g, ''); const gasLimit = new optionalDeps.ethUtil.BN(this.setGasLimit(params.gasLimit)); const gasPrice = params.eip1559 @@ -1822,10 +1824,19 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin { getIsUnsignedSweep({ userKey: userPublicOrPrivateKeyShare, backupKey: backupPrivateOrPublicKeyShare, + bitgoKey: bitgoCommonKeychain, isTss: params.isTss, }) ) { - const backupKeyPair = new KeyPairLib({ pub: backupPrivateOrPublicKeyShare }); + let backupKeyPair: KeyPairLib; + if (bitgoCommonKeychain) { + const MPC = new Ecdsa(); + const derivedCommonKeyChain = MPC.deriveUnhardened(bitgoCommonKeychain, 'm/0'); + backupKeyPair = new KeyPairLib({ pub: derivedCommonKeyChain.slice(0, 66) }); + } else { + backupKeyPair = new KeyPairLib({ pub: backupPrivateOrPublicKeyShare }); + } + const baseAddress = backupKeyPair.getAddress(); const { txInfo, tx, nonce } = await this.buildTssRecoveryTxn(baseAddress, gasPrice, gasLimit, params); return this.formatForOfflineVaultTSS( diff --git a/modules/bitgo/test/v2/lib/recovery-nocks.ts b/modules/bitgo/test/v2/lib/recovery-nocks.ts index 734b767360..1e7247a432 100644 --- a/modules/bitgo/test/v2/lib/recovery-nocks.ts +++ b/modules/bitgo/test/v2/lib/recovery-nocks.ts @@ -263,6 +263,30 @@ const nockEthData: any[] = [ result: '2200000000000000000', }, }, + { + params: { + module: 'account', + action: 'txlist', + address: '0xd18ee37daeab8468020dd65fa7f6f6b9ac741584', + }, + response: { + status: '0', + message: 'No transactions found', + result: [], + }, + }, + { + params: { + module: 'account', + action: 'balance', + address: '0xd18ee37daeab8468020dd65fa7f6f6b9ac741584', + }, + response: { + status: '1', + message: 'OK', + result: '2200000000000000000', + }, + }, { params: { module: 'proxy', diff --git a/modules/bitgo/test/v2/unit/recovery.ts b/modules/bitgo/test/v2/unit/recovery.ts index 9d3e3619f0..c86e41dc34 100644 --- a/modules/bitgo/test/v2/unit/recovery.ts +++ b/modules/bitgo/test/v2/unit/recovery.ts @@ -1098,12 +1098,13 @@ describe('Recovery:', function () { const basecoin = bitgo.coin('hteth'); - const userKey = '03f8606a595917de4cf2244e27b7fba172505469392ad385d2dd2b3588a6bb878c'; - const backupKey = '03f8606a595917de4cf2244e27b7fba172505469392ad385d2dd2b3588a6bb878c'; + const bitgoKey = + '03ffd706c97ce5438ffa38016f3708a3e4ffa7126a2d03d3e02a087767950d72c9197ee747c5c146ae62f8d80fe313c943139190ce3e49727a9707e9626b15fc0d'; recoveryParams = { - userKey: userKey, - backupKey: backupKey, + userKey: '', + backupKey: '', + bitgoKey: bitgoKey, walletContractAddress: '0xe7406dc43d13f698fb41a345c7783d39a4c2d191', recoveryDestination: '0xac05da78464520aa7c9d4c19bd7a440b111b3054', walletPassphrase: TestBitGo.V2.TEST_RECOVERY_PASSCODE, diff --git a/modules/sdk-core/src/bitgo/recovery/initiate.ts b/modules/sdk-core/src/bitgo/recovery/initiate.ts index c94ef4de2f..0ca455393a 100644 --- a/modules/sdk-core/src/bitgo/recovery/initiate.ts +++ b/modules/sdk-core/src/bitgo/recovery/initiate.ts @@ -78,12 +78,17 @@ export function getIsKrsRecovery({ backupKey, userKey }: { backupKey: string; us export function getIsUnsignedSweep({ backupKey, userKey, + bitgoKey, isTss, }: { backupKey: string; userKey: string; + bitgoKey?: string; isTss?: boolean; }): boolean { + if (isTss && bitgoKey) { + return true; + } if (isTss) { try { return typeof JSON.parse(backupKey) === 'string' && typeof JSON.parse(userKey) === 'string';