diff --git a/backend/services/mpc-service/src/infrastructure/external/tss-lib/tss-wrapper.ts b/backend/services/mpc-service/src/infrastructure/external/tss-lib/tss-wrapper.ts index c4d2021c..b08ec25a 100644 --- a/backend/services/mpc-service/src/infrastructure/external/tss-lib/tss-wrapper.ts +++ b/backend/services/mpc-service/src/infrastructure/external/tss-lib/tss-wrapper.ts @@ -255,20 +255,51 @@ export class TSSWrapper implements TSSProtocolDomainService { /** * Create a keygen session via account-service. * This will also notify server-party-1/2/3 to participate. + * + * Note: account-service requires exactly threshold_n participants. + * For a 2-of-3 setup, we need 3 participants: + * - user-party (the user's share, returned to client) + * - server-party-1 (stored on server) + * - server-party-2 (backup, stored on server) */ private async createKeygenSession( participants: TSSParticipant[], threshold: Threshold, ): Promise { + // Build the full participant list for threshold_n parties + // If we have fewer participants, add the default server parties + const allParticipants: Array<{ party_id: string; device_type: string }> = []; + + // Add provided participants + for (const p of participants) { + allParticipants.push({ + party_id: p.partyId, + device_type: 'server', + }); + } + + // Ensure we have exactly threshold_n participants + // Default server party IDs for 2-of-3 setup + const defaultPartyIds = ['user-party', 'server-party-1', 'server-party-2']; + const existingPartyIds = new Set(allParticipants.map(p => p.party_id)); + + for (const partyId of defaultPartyIds) { + if (!existingPartyIds.has(partyId) && allParticipants.length < threshold.n) { + allParticipants.push({ + party_id: partyId, + device_type: partyId === 'user-party' ? 'client' : 'server', + }); + } + } + + this.logger.log(`Creating keygen session with ${allParticipants.length} participants: ${allParticipants.map(p => p.party_id).join(', ')}`); + const response = await this.axiosClient.post( `${this.accountServiceUrl}/api/v1/mpc/keygen`, { threshold_n: threshold.n, threshold_t: threshold.t, - participants: participants.map(p => ({ - party_id: p.partyId, - device_type: 'server', - })), + participants: allParticipants, }, ); return response.data;