From ff8325fcdb7f22569f0487e2de4c3a00bae72aa4 Mon Sep 17 00:00:00 2001 From: Simhon Chourasia Date: Thu, 7 Nov 2024 11:41:32 -0500 Subject: [PATCH] fix(abstract-eth): add support for commonkeychain in TSS recovery for eth-like coins Ticket: WP-2971 --- modules/abstract-eth/package.json | 3 ++- .../abstract-eth/src/abstractEthLikeNewCoins.ts | 16 +++++++++++++++- modules/bitgo/test/v2/unit/recovery.ts | 13 +++++++------ modules/sdk-core/src/bitgo/recovery/initiate.ts | 5 +++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/modules/abstract-eth/package.json b/modules/abstract-eth/package.json index 933b042f60..6a7fc3e06e 100644 --- a/modules/abstract-eth/package.json +++ b/modules/abstract-eth/package.json @@ -59,6 +59,7 @@ }, "devDependencies": { "@bitgo/sdk-api": "^1.56.1", - "@bitgo/sdk-test": "^8.0.48" + "@bitgo/sdk-test": "^8.0.48", + "@bitgo/sdk-lib-mpc": "^10.1.0" } } diff --git a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts index 3e2d3ba3f7..39157508b9 100644 --- a/modules/abstract-eth/src/abstractEthLikeNewCoins.ts +++ b/modules/abstract-eth/src/abstractEthLikeNewCoins.ts @@ -68,6 +68,7 @@ import { TransactionBuilder, TransferBuilder, } from './lib'; +import { getDerivationPath } from '@bitgo/sdk-lib-mpc'; /** * The prebuilt hop transaction returned from the HSM @@ -218,6 +219,8 @@ export type TSSRecoverOptions = RecoverOptionsWithBytes | NonTSSRecoverOptions; export type RecoverOptions = { userKey: string; backupKey: string; + bitgoKey?: string; + seed?: string; walletPassphrase?: string; walletContractAddress: string; // use this as walletBaseAddress for TSS recoveryDestination: string; @@ -1812,6 +1815,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 +1826,20 @@ 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 path = params.seed ? getDerivationPath(params.seed) + '/0' : 'm/0'; + const derivedCommonKeyChain = MPC.deriveUnhardened(bitgoCommonKeychain, path); + 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/unit/recovery.ts b/modules/bitgo/test/v2/unit/recovery.ts index 9d3e3619f0..b4e161d4d8 100644 --- a/modules/bitgo/test/v2/unit/recovery.ts +++ b/modules/bitgo/test/v2/unit/recovery.ts @@ -708,7 +708,7 @@ describe('Recovery:', function () { params: { module: 'account', action: 'txlist', - address: '0xe7406dc43d13f698fb41a345c7783d39a4c2d191', + address: '0xd18ee37daeab8468020dd65fa7f6f6b9ac741584', }, response: { status: '0', @@ -720,7 +720,7 @@ describe('Recovery:', function () { params: { module: 'account', action: 'balance', - address: '0xe7406dc43d13f698fb41a345c7783d39a4c2d191', + address: '0xd18ee37daeab8468020dd65fa7f6f6b9ac741584', }, response: { status: '1', @@ -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';