From 350722396863cf10f46ec6dbbcc252496cedd3aa Mon Sep 17 00:00:00 2001 From: Support Bot Date: Wed, 8 Jul 2026 16:34:30 +0000 Subject: [PATCH 1/2] feat(awm): add EdDSA MPCv2 keygen types and route stubs Add io-ts request/response types and three new route entries to AdvancedWalletManagerApiSpec for the EdDSA MPCv2 DKG protocol: - POST /api/{coin}/eddsampcv2/keygen/initialize - POST /api/{coin}/eddsampcv2/keygen/round1 - POST /api/{coin}/eddsampcv2/keygen/finalize Each route is wired in createKeyGenRouter with a NotImplementedError stub; the real handlers land in WCI-892. The type exports are needed by the ME client added in the next PR (WCI-893). Ticket: WCI-895 Session-Id: 4df43c40-1cea-4bcc-ae92-080304169427 Task-Id: 04666b37-650f-4c07-97b0-76a62e98f1ad --- .../routers/advancedWalletManagerApiSpec.ts | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/src/advancedWalletManager/routers/advancedWalletManagerApiSpec.ts b/src/advancedWalletManager/routers/advancedWalletManagerApiSpec.ts index 8999ffd7..f83cd3ee 100644 --- a/src/advancedWalletManager/routers/advancedWalletManagerApiSpec.ts +++ b/src/advancedWalletManager/routers/advancedWalletManagerApiSpec.ts @@ -310,6 +310,73 @@ const MpcV2RecoveryResponse = { const MpcV2RecoveryResponseType = t.type(MpcV2RecoveryResponse); export type MpcV2RecoveryResponseType = t.TypeOf; +// EdDSA MPCv2 key generation types +const EddsaMPCv2KeyGenSignedMessage = t.type({ + message: t.string, + signature: t.string, +}); + +const EddsaMPCv2KeyGenInitializeRequest = { + source: t.union([t.literal('user'), t.literal('backup')]), + enterprise: t.string, + bitgoPublicGpgKey: t.string, +}; +const EddsaMPCv2KeyGenInitializeRequestType = t.type(EddsaMPCv2KeyGenInitializeRequest); +export type EddsaMPCv2KeyGenInitializeRequestType = t.TypeOf< + typeof EddsaMPCv2KeyGenInitializeRequestType +>; + +const EddsaMPCv2KeyGenInitializeResponse = { + gpgPublicKey: t.string, + signedMsg1: EddsaMPCv2KeyGenSignedMessage, + encryptedState: t.string, + encryptedStateKey: t.string, +}; +const EddsaMPCv2KeyGenInitializeResponseType = t.type(EddsaMPCv2KeyGenInitializeResponse); +export type EddsaMPCv2KeyGenInitializeResponseType = t.TypeOf< + typeof EddsaMPCv2KeyGenInitializeResponseType +>; + +const EddsaMPCv2KeyGenRound1Request = { + source: t.union([t.literal('user'), t.literal('backup')]), + bitgoMsg1: EddsaMPCv2KeyGenSignedMessage, + encryptedState: t.string, + encryptedStateKey: t.string, +}; +const EddsaMPCv2KeyGenRound1RequestType = t.type(EddsaMPCv2KeyGenRound1Request); +export type EddsaMPCv2KeyGenRound1RequestType = t.TypeOf; + +const EddsaMPCv2KeyGenRound1Response = { + signedMsg2: EddsaMPCv2KeyGenSignedMessage, + encryptedState: t.string, + encryptedStateKey: t.string, +}; +const EddsaMPCv2KeyGenRound1ResponseType = t.type(EddsaMPCv2KeyGenRound1Response); +export type EddsaMPCv2KeyGenRound1ResponseType = t.TypeOf< + typeof EddsaMPCv2KeyGenRound1ResponseType +>; + +const EddsaMPCv2KeyGenFinalizeRequest = { + source: t.union([t.literal('user'), t.literal('backup')]), + bitgoMsg2: EddsaMPCv2KeyGenSignedMessage, + commonPublicKeychain: t.string, + encryptedState: t.string, + encryptedStateKey: t.string, +}; +const EddsaMPCv2KeyGenFinalizeRequestType = t.type(EddsaMPCv2KeyGenFinalizeRequest); +export type EddsaMPCv2KeyGenFinalizeRequestType = t.TypeOf< + typeof EddsaMPCv2KeyGenFinalizeRequestType +>; + +const EddsaMPCv2KeyGenFinalizeResponse = { + source: t.union([t.literal('user'), t.literal('backup')]), + commonKeychain: t.string, +}; +const EddsaMPCv2KeyGenFinalizeResponseType = t.type(EddsaMPCv2KeyGenFinalizeResponse); +export type EddsaMPCv2KeyGenFinalizeResponseType = t.TypeOf< + typeof EddsaMPCv2KeyGenFinalizeResponseType +>; + // API Specification export const AdvancedWalletManagerApiSpec = apiSpec({ 'v1.multisig.sign': { @@ -481,6 +548,51 @@ export const AdvancedWalletManagerApiSpec = apiSpec({ description: 'Recover a MPC transaction', }), }, + 'v1.eddsampcv2.keygen.initialize': { + post: httpRoute({ + method: 'POST', + path: '/api/{coin}/eddsampcv2/keygen/initialize', + request: httpRequest({ + params: { coin: t.string }, + body: EddsaMPCv2KeyGenInitializeRequest, + }), + response: { + 200: EddsaMPCv2KeyGenInitializeResponseType, + ...ErrorResponses, + }, + description: 'Initialize EdDSA MPCv2 key generation', + }), + }, + 'v1.eddsampcv2.keygen.round1': { + post: httpRoute({ + method: 'POST', + path: '/api/{coin}/eddsampcv2/keygen/round1', + request: httpRequest({ + params: { coin: t.string }, + body: EddsaMPCv2KeyGenRound1Request, + }), + response: { + 200: EddsaMPCv2KeyGenRound1ResponseType, + ...ErrorResponses, + }, + description: 'EdDSA MPCv2 key generation round 1', + }), + }, + 'v1.eddsampcv2.keygen.finalize': { + post: httpRoute({ + method: 'POST', + path: '/api/{coin}/eddsampcv2/keygen/finalize', + request: httpRequest({ + params: { coin: t.string }, + body: EddsaMPCv2KeyGenFinalizeRequest, + }), + response: { + 200: EddsaMPCv2KeyGenFinalizeResponseType, + ...ErrorResponses, + }, + description: 'Finalize EdDSA MPCv2 key generation', + }), + }, }); export type AkmApiSpecRouteHandler< @@ -613,5 +725,23 @@ export function createKeyGenRouter( }), ]); + router.post('v1.eddsampcv2.keygen.initialize', [ + responseHandler(async (_req) => { + throw new NotImplementedError('EdDSA MPCv2 key generation initialize not implemented'); + }), + ]); + + router.post('v1.eddsampcv2.keygen.round1', [ + responseHandler(async (_req) => { + throw new NotImplementedError('EdDSA MPCv2 key generation round1 not implemented'); + }), + ]); + + router.post('v1.eddsampcv2.keygen.finalize', [ + responseHandler(async (_req) => { + throw new NotImplementedError('EdDSA MPCv2 key generation finalize not implemented'); + }), + ]); + return router; } From b758edce595c13e575861c169ac6db771df1fca1 Mon Sep 17 00:00:00 2001 From: Support Bot Date: Wed, 8 Jul 2026 16:36:30 +0000 Subject: [PATCH 2/2] feat(mbe): add EdDSA MPCv2 AWM client methods and ME callback factory Add three methods to AdvancedWalletManagerClient (WCI-893): - eddsaMPCv2KeyGenInitialize - eddsaMPCv2KeyGenRound1 - eddsaMPCv2KeyGenFinalize Each method calls the corresponding AWM endpoint added in the previous PR, with mTLS agent support. Add createEddsaMPCv2KeyGenCallbacks factory in walletGenerationCallbacks.ts (WCI-895): wraps user and backup AWM clients into an EddsaMPCv2KeyGenCallbacks object whose initialize, round1, and finalize callbacks fan both clients out in parallel and merge results for the SDK orchestrator (WCI-916). This replaces the inline WASM/GPG/DKG key gen logic with AWM-delegated calls, enabling hardware-backed key generation in the AKM pattern. Local EddsaMPCv2KeyGenCallbacks type mirrors the WCI-894 shape; it will be replaced by the SDK import once published. Three unit tests verify parallel fan-out and result merging for each callback phase using nock. Ticket: WCI-895 Session-Id: 4df43c40-1cea-4bcc-ae92-080304169427 Task-Id: 04666b37-650f-4c07-97b0-76a62e98f1ad --- .../master/walletGenerationCallbacks.test.ts | 149 +++++++++++++++- .../clients/advancedWalletManagerClient.ts | 105 +++++++++++ .../handlers/walletGenerationCallbacks.ts | 166 ++++++++++++++++++ 3 files changed, 419 insertions(+), 1 deletion(-) diff --git a/src/__tests__/api/master/walletGenerationCallbacks.test.ts b/src/__tests__/api/master/walletGenerationCallbacks.test.ts index 5f81aaca..c986f8b6 100644 --- a/src/__tests__/api/master/walletGenerationCallbacks.test.ts +++ b/src/__tests__/api/master/walletGenerationCallbacks.test.ts @@ -6,7 +6,10 @@ import { createAwmClient, AdvancedWalletManagerClient, } from '../../../masterBitgoExpress/clients/advancedWalletManagerClient'; -import { createOnchainKeyGenCallback } from '../../../masterBitgoExpress/handlers/walletGenerationCallbacks'; +import { + createOnchainKeyGenCallback, + createEddsaMPCv2KeyGenCallbacks, +} from '../../../masterBitgoExpress/handlers/walletGenerationCallbacks'; import { AppMode, KeySource, MasterExpressConfig, TlsMode } from '../../../shared/types'; import { DEFAULT_ASYNC_MODE_CONFIG } from './testUtils'; @@ -150,4 +153,148 @@ describe('walletGenerationCallbacks', () => { }).should.be.rejectedWith('Unexpected key source for onchain key generation: bitgo'); }); }); + + describe('createEddsaMPCv2KeyGenCallbacks', () => { + const enterprise = 'test-enterprise'; + const bitgoPublicGpgKey = 'test-bitgo-gpg-key'; + + beforeEach(() => { + const config = makeConfig({ advancedWalletManagerBackupUrl: backupAwmUrl }); + awmUserClient = createAwmClient(config, coin)!; + awmBackupClient = createAwmBackupClient(config, coin)!; + assert(awmUserClient); + assert(awmBackupClient); + }); + + it('initializeCallback fans out to user and backup AWM in parallel', async () => { + const userInitNock = nock(advancedWalletManagerUrl) + .post(`/api/${coin}/eddsampcv2/keygen/initialize`, { + source: 'user', + enterprise, + bitgoPublicGpgKey, + }) + .reply(200, { + gpgPublicKey: 'user-gpg-pub', + signedMsg1: { message: 'user-msg1', signature: 'user-sig1' }, + encryptedState: 'user-enc-state', + encryptedStateKey: 'user-enc-state-key', + }); + + const backupInitNock = nock(backupAwmUrl) + .post(`/api/${coin}/eddsampcv2/keygen/initialize`, { + source: 'backup', + enterprise, + bitgoPublicGpgKey, + }) + .reply(200, { + gpgPublicKey: 'backup-gpg-pub', + signedMsg1: { message: 'backup-msg1', signature: 'backup-sig1' }, + encryptedState: 'backup-enc-state', + encryptedStateKey: 'backup-enc-state-key', + }); + + const callbacks = createEddsaMPCv2KeyGenCallbacks(awmUserClient, awmBackupClient); + const result = await callbacks.initializeCallback({ enterprise, bitgoPublicGpgKey }); + + result.userGpgPublicKey.should.equal('user-gpg-pub'); + result.backupGpgPublicKey.should.equal('backup-gpg-pub'); + result.userSignedMsg1.message.should.equal('user-msg1'); + result.backupSignedMsg1.message.should.equal('backup-msg1'); + result.userEncryptedState.should.equal('user-enc-state'); + result.backupEncryptedState.should.equal('backup-enc-state'); + userInitNock.done(); + backupInitNock.done(); + }); + + it('round1Callback fans out to user and backup AWM in parallel', async () => { + const bitgoMsg1 = { message: 'bitgo-msg1', signature: 'bitgo-sig1' }; + + const userR1Nock = nock(advancedWalletManagerUrl) + .post(`/api/${coin}/eddsampcv2/keygen/round1`, { + source: 'user', + bitgoMsg1, + encryptedState: 'user-enc-state', + encryptedStateKey: 'user-enc-state-key', + }) + .reply(200, { + signedMsg2: { message: 'user-msg2', signature: 'user-sig2' }, + encryptedState: 'user-enc-state-r1', + encryptedStateKey: 'user-enc-state-key-r1', + }); + + const backupR1Nock = nock(backupAwmUrl) + .post(`/api/${coin}/eddsampcv2/keygen/round1`, { + source: 'backup', + bitgoMsg1, + encryptedState: 'backup-enc-state', + encryptedStateKey: 'backup-enc-state-key', + }) + .reply(200, { + signedMsg2: { message: 'backup-msg2', signature: 'backup-sig2' }, + encryptedState: 'backup-enc-state-r1', + encryptedStateKey: 'backup-enc-state-key-r1', + }); + + const callbacks = createEddsaMPCv2KeyGenCallbacks(awmUserClient, awmBackupClient); + const result = await callbacks.round1Callback({ + bitgoMsg1, + userEncryptedState: 'user-enc-state', + userEncryptedStateKey: 'user-enc-state-key', + backupEncryptedState: 'backup-enc-state', + backupEncryptedStateKey: 'backup-enc-state-key', + }); + + result.userSignedMsg2.message.should.equal('user-msg2'); + result.backupSignedMsg2.message.should.equal('backup-msg2'); + result.userEncryptedState.should.equal('user-enc-state-r1'); + result.backupEncryptedState.should.equal('backup-enc-state-r1'); + userR1Nock.done(); + backupR1Nock.done(); + }); + + it('finalizeCallback fans out to user and backup AWM in parallel', async () => { + const bitgoMsg2 = { message: 'bitgo-msg2', signature: 'bitgo-sig2' }; + const commonPublicKeychain = 'common-keychain-abc123'; + + const userFinalizeNock = nock(advancedWalletManagerUrl) + .post(`/api/${coin}/eddsampcv2/keygen/finalize`, { + source: 'user', + bitgoMsg2, + commonPublicKeychain, + encryptedState: 'user-enc-state', + encryptedStateKey: 'user-enc-state-key', + }) + .reply(200, { + source: 'user', + commonKeychain: commonPublicKeychain, + }); + + const backupFinalizeNock = nock(backupAwmUrl) + .post(`/api/${coin}/eddsampcv2/keygen/finalize`, { + source: 'backup', + bitgoMsg2, + commonPublicKeychain, + encryptedState: 'backup-enc-state', + encryptedStateKey: 'backup-enc-state-key', + }) + .reply(200, { + source: 'backup', + commonKeychain: commonPublicKeychain, + }); + + const callbacks = createEddsaMPCv2KeyGenCallbacks(awmUserClient, awmBackupClient); + const result = await callbacks.finalizeCallback({ + bitgoMsg2, + commonPublicKeychain, + userEncryptedState: 'user-enc-state', + userEncryptedStateKey: 'user-enc-state-key', + backupEncryptedState: 'backup-enc-state', + backupEncryptedStateKey: 'backup-enc-state-key', + }); + + result.commonKeychain.should.equal(commonPublicKeychain); + userFinalizeNock.done(); + backupFinalizeNock.done(); + }); + }); }); diff --git a/src/masterBitgoExpress/clients/advancedWalletManagerClient.ts b/src/masterBitgoExpress/clients/advancedWalletManagerClient.ts index a576a31b..f8f9a696 100644 --- a/src/masterBitgoExpress/clients/advancedWalletManagerClient.ts +++ b/src/masterBitgoExpress/clients/advancedWalletManagerClient.ts @@ -39,6 +39,9 @@ import { MpcV2InitializeResponseType, MpcV2RecoveryResponseType, MpcV2RoundResponseType, + EddsaMPCv2KeyGenInitializeResponseType, + EddsaMPCv2KeyGenRound1ResponseType, + EddsaMPCv2KeyGenFinalizeResponseType, } from '../../advancedWalletManager/routers/advancedWalletManagerApiSpec'; import { FormattedOfflineVaultTxInfo } from '@bitgo-beta/abstract-utxo'; import { RecoveryTxRequest } from '@bitgo-beta/sdk-core'; @@ -822,6 +825,108 @@ export class AdvancedWalletManagerClient { } } + /** + * Initialize EdDSA MPCv2 key generation + */ + async eddsaMPCv2KeyGenInitialize(params: { + source: 'user' | 'backup'; + enterprise: string; + bitgoPublicGpgKey: string; + }): Promise { + if (!this.coin) { + throw new Error('Coin must be specified for EdDSA MPCv2 key generation initialize'); + } + + try { + let request = this.apiClient['v1.eddsampcv2.keygen.initialize'].post({ + coin: this.coin, + ...params, + }); + + if (this.tlsMode === TlsMode.MTLS) { + request = request.agent(this.createHttpsAgent()); + } + + const response = await request.decodeExpecting(200); + return response.body; + } catch (error) { + logger.error( + 'Failed to initialize EdDSA MPCv2 key generation: %s', + (error as DecodeError).decodedResponse?.body, + ); + throw error; + } + } + + /** + * EdDSA MPCv2 key generation round 1 + */ + async eddsaMPCv2KeyGenRound1(params: { + source: 'user' | 'backup'; + bitgoMsg1: { message: string; signature: string }; + encryptedState: string; + encryptedStateKey: string; + }): Promise { + if (!this.coin) { + throw new Error('Coin must be specified for EdDSA MPCv2 key generation round 1'); + } + + try { + let request = this.apiClient['v1.eddsampcv2.keygen.round1'].post({ + coin: this.coin, + ...params, + }); + + if (this.tlsMode === TlsMode.MTLS) { + request = request.agent(this.createHttpsAgent()); + } + + const response = await request.decodeExpecting(200); + return response.body; + } catch (error) { + logger.error( + 'Failed EdDSA MPCv2 key generation round 1: %s', + (error as DecodeError).decodedResponse?.body, + ); + throw error; + } + } + + /** + * Finalize EdDSA MPCv2 key generation + */ + async eddsaMPCv2KeyGenFinalize(params: { + source: 'user' | 'backup'; + bitgoMsg2: { message: string; signature: string }; + commonPublicKeychain: string; + encryptedState: string; + encryptedStateKey: string; + }): Promise { + if (!this.coin) { + throw new Error('Coin must be specified for EdDSA MPCv2 key generation finalize'); + } + + try { + let request = this.apiClient['v1.eddsampcv2.keygen.finalize'].post({ + coin: this.coin, + ...params, + }); + + if (this.tlsMode === TlsMode.MTLS) { + request = request.agent(this.createHttpsAgent()); + } + + const response = await request.decodeExpecting(200); + return response.body; + } catch (error) { + logger.error( + 'Failed to finalize EdDSA MPCv2 key generation: %s', + (error as DecodeError).decodedResponse?.body, + ); + throw error; + } + } + async recoverEcdsaMpcV2Wallet(params: { txHex: string; pub: string; diff --git a/src/masterBitgoExpress/handlers/walletGenerationCallbacks.ts b/src/masterBitgoExpress/handlers/walletGenerationCallbacks.ts index 9f8bf37a..5bcc1aa0 100644 --- a/src/masterBitgoExpress/handlers/walletGenerationCallbacks.ts +++ b/src/masterBitgoExpress/handlers/walletGenerationCallbacks.ts @@ -5,6 +5,172 @@ import { IndependentKeychainResponse, } from '../clients/advancedWalletManagerClient'; +/** + * Callback types for EdDSA MPCv2 key generation via external signer. + * + * These mirror the EddsaMPCv2KeyGenCallbacks shape defined in BitGoJS (WCI-894). + * Once that type is published to @bitgo-beta/sdk-core it can replace this local + * definition. + */ +export type EddsaMPCv2KeyGenInitializeParams = { + enterprise: string; + bitgoPublicGpgKey: string; +}; + +export type EddsaMPCv2KeyGenInitializeResult = { + userGpgPublicKey: string; + backupGpgPublicKey: string; + userSignedMsg1: { message: string; signature: string }; + backupSignedMsg1: { message: string; signature: string }; + userEncryptedState: string; + userEncryptedStateKey: string; + backupEncryptedState: string; + backupEncryptedStateKey: string; +}; + +export type EddsaMPCv2KeyGenRound1Params = { + bitgoMsg1: { message: string; signature: string }; + userEncryptedState: string; + userEncryptedStateKey: string; + backupEncryptedState: string; + backupEncryptedStateKey: string; +}; + +export type EddsaMPCv2KeyGenRound1Result = { + userSignedMsg2: { message: string; signature: string }; + backupSignedMsg2: { message: string; signature: string }; + userEncryptedState: string; + userEncryptedStateKey: string; + backupEncryptedState: string; + backupEncryptedStateKey: string; +}; + +export type EddsaMPCv2KeyGenFinalizeParams = { + bitgoMsg2: { message: string; signature: string }; + commonPublicKeychain: string; + userEncryptedState: string; + userEncryptedStateKey: string; + backupEncryptedState: string; + backupEncryptedStateKey: string; +}; + +export type EddsaMPCv2KeyGenFinalizeResult = { + commonKeychain: string; +}; + +export type EddsaMPCv2KeyGenCallbacks = { + initializeCallback: ( + params: EddsaMPCv2KeyGenInitializeParams, + ) => Promise; + round1Callback: (params: EddsaMPCv2KeyGenRound1Params) => Promise; + finalizeCallback: ( + params: EddsaMPCv2KeyGenFinalizeParams, + ) => Promise; +}; + +/** + * Creates EdDSA MPCv2 key generation callbacks that delegate WASM/GPG/DKG + * operations to the AWM service. Each callback fans out to both AWM clients + * in parallel and merges the results before returning to the SDK orchestrator. + */ +export function createEddsaMPCv2KeyGenCallbacks( + awmUserClient: AdvancedWalletManagerClient, + awmBackupClient: AdvancedWalletManagerClient, +): EddsaMPCv2KeyGenCallbacks { + return { + initializeCallback: async ({ + enterprise, + bitgoPublicGpgKey, + }: EddsaMPCv2KeyGenInitializeParams): Promise => { + const [userInit, backupInit] = await Promise.all([ + awmUserClient.eddsaMPCv2KeyGenInitialize({ + source: 'user', + enterprise, + bitgoPublicGpgKey, + }), + awmBackupClient.eddsaMPCv2KeyGenInitialize({ + source: 'backup', + enterprise, + bitgoPublicGpgKey, + }), + ]); + + return { + userGpgPublicKey: userInit.gpgPublicKey, + backupGpgPublicKey: backupInit.gpgPublicKey, + userSignedMsg1: userInit.signedMsg1, + backupSignedMsg1: backupInit.signedMsg1, + userEncryptedState: userInit.encryptedState, + userEncryptedStateKey: userInit.encryptedStateKey, + backupEncryptedState: backupInit.encryptedState, + backupEncryptedStateKey: backupInit.encryptedStateKey, + }; + }, + + round1Callback: async ({ + bitgoMsg1, + userEncryptedState, + userEncryptedStateKey, + backupEncryptedState, + backupEncryptedStateKey, + }: EddsaMPCv2KeyGenRound1Params): Promise => { + const [userR1, backupR1] = await Promise.all([ + awmUserClient.eddsaMPCv2KeyGenRound1({ + source: 'user', + bitgoMsg1, + encryptedState: userEncryptedState, + encryptedStateKey: userEncryptedStateKey, + }), + awmBackupClient.eddsaMPCv2KeyGenRound1({ + source: 'backup', + bitgoMsg1, + encryptedState: backupEncryptedState, + encryptedStateKey: backupEncryptedStateKey, + }), + ]); + + return { + userSignedMsg2: userR1.signedMsg2, + backupSignedMsg2: backupR1.signedMsg2, + userEncryptedState: userR1.encryptedState, + userEncryptedStateKey: userR1.encryptedStateKey, + backupEncryptedState: backupR1.encryptedState, + backupEncryptedStateKey: backupR1.encryptedStateKey, + }; + }, + + finalizeCallback: async ({ + bitgoMsg2, + commonPublicKeychain, + userEncryptedState, + userEncryptedStateKey, + backupEncryptedState, + backupEncryptedStateKey, + }: EddsaMPCv2KeyGenFinalizeParams): Promise => { + const [userFinalize] = await Promise.all([ + awmUserClient.eddsaMPCv2KeyGenFinalize({ + source: 'user', + bitgoMsg2, + commonPublicKeychain, + encryptedState: userEncryptedState, + encryptedStateKey: userEncryptedStateKey, + }), + awmBackupClient.eddsaMPCv2KeyGenFinalize({ + source: 'backup', + bitgoMsg2, + commonPublicKeychain, + encryptedState: backupEncryptedState, + encryptedStateKey: backupEncryptedStateKey, + }), + ]); + + return { + commonKeychain: userFinalize.commonKeychain, + }; + }, + }; +} + export function createOnchainKeyGenCallback( awmUserClient: AdvancedWalletManagerClient, awmBackupClient: AdvancedWalletManagerClient,