Skip to content

Commit 16a6dbb

Browse files
committed
feat(mbe): use sdk sendMany with mpcv2 custom signing fns
Ticket: WP-5245
1 parent 4fb72bd commit 16a6dbb

File tree

2 files changed

+86
-18
lines changed

2 files changed

+86
-18
lines changed

src/api/master/handlers/ecdsaMPCv2.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,14 @@ import {
1515
SignMpcV2Round2Response,
1616
} from '../clients/enclavedExpressClient';
1717

18-
export async function handleEcdsaMPCv2Signing(
19-
bitgo: BitGoBase,
20-
wallet: Wallet,
21-
txRequestId: string,
18+
/**
19+
* Creates custom ECDSA MPCv2 signing functions for use with enclaved express client
20+
*/
21+
export function createEcdsaMPCv2CustomSigners(
2222
enclavedExpressClient: EnclavedExpressClient,
2323
source: 'user' | 'backup',
2424
commonKeychain: string,
25-
reqId: IRequestTracer,
26-
): Promise<TxRequest> {
27-
const ecdsaMPCv2Utils = new EcdsaMPCv2Utils(bitgo, wallet.baseCoin, wallet);
28-
const txRequest = await getTxRequest(bitgo, wallet.id(), txRequestId, reqId);
29-
25+
) {
3026
// Create state to maintain data between rounds
3127
let round1Response: SignMpcV2Round1Response;
3228
let round2Response: SignMpcV2Round2Response;
@@ -76,6 +72,29 @@ export async function handleEcdsaMPCv2Signing(
7672
});
7773
};
7874

75+
return {
76+
customMPCv2Round1Generator,
77+
customMPCv2Round2Generator,
78+
customMPCv2Round3Generator,
79+
};
80+
}
81+
82+
export async function handleEcdsaMPCv2Signing(
83+
bitgo: BitGoBase,
84+
wallet: Wallet,
85+
txRequestId: string,
86+
enclavedExpressClient: EnclavedExpressClient,
87+
source: 'user' | 'backup',
88+
commonKeychain: string,
89+
reqId: IRequestTracer,
90+
): Promise<TxRequest> {
91+
const ecdsaMPCv2Utils = new EcdsaMPCv2Utils(bitgo, wallet.baseCoin, wallet);
92+
const txRequest = await getTxRequest(bitgo, wallet.id(), txRequestId, reqId);
93+
94+
// Use the shared custom signing functions
95+
const { customMPCv2Round1Generator, customMPCv2Round2Generator, customMPCv2Round3Generator } =
96+
createEcdsaMPCv2CustomSigners(enclavedExpressClient, source, commonKeychain);
97+
7998
// Use the existing signEcdsaMPCv2TssUsingExternalSigner method with our custom signers
8099
return await ecdsaMPCv2Utils.signEcdsaMPCv2TssUsingExternalSigner(
81100
{ txRequest, reqId },

src/api/master/handlers/handleSendMany.ts

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
import logger from '../../../logger';
1515
import { MasterApiSpecRouteRequest } from '../routers/masterApiSpec';
1616
import { handleEddsaSigning } from './eddsa';
17-
import { handleEcdsaMPCv2Signing } from './ecdsaMPCv2';
17+
import { handleEcdsaMPCv2Signing, createEcdsaMPCv2CustomSigners } from './ecdsaMPCv2';
1818
import { EnclavedExpressClient } from '../clients/enclavedExpressClient';
1919

2020
/**
@@ -30,6 +30,43 @@ interface Recipient {
3030
tokenData?: any;
3131
}
3232

33+
/**
34+
* Creates TSS send parameters for ECDSA MPCv2 signing with custom functions
35+
*/
36+
function createEcdsaMPCv2SendParams(
37+
req: MasterApiSpecRouteRequest<'v1.wallet.sendMany', 'post'>,
38+
wallet: Wallet,
39+
enclavedExpressClient: EnclavedExpressClient,
40+
signingKeychain: Keychain,
41+
): SendManyOptions {
42+
const coin = req.bitgo.coin(req.params.coin);
43+
const mpcAlgorithm = coin.getMPCAlgorithm();
44+
45+
if (mpcAlgorithm === 'ecdsa') {
46+
// For ECDSA MPCv2, we need to create custom signing functions
47+
const source = signingKeychain.source as 'user' | 'backup';
48+
const commonKeychain = signingKeychain.commonKeychain;
49+
50+
if (!commonKeychain) {
51+
throw new Error('Common keychain is required for ECDSA MPCv2 signing');
52+
}
53+
54+
// Use the shared custom signing functions
55+
const { customMPCv2Round1Generator, customMPCv2Round2Generator, customMPCv2Round3Generator } =
56+
createEcdsaMPCv2CustomSigners(enclavedExpressClient, source, commonKeychain);
57+
58+
return {
59+
...(req.decoded as SendManyOptions),
60+
customMPCv2SigningRound1GenerationFunction: customMPCv2Round1Generator,
61+
customMPCv2SigningRound2GenerationFunction: customMPCv2Round2Generator,
62+
customMPCv2SigningRound3GenerationFunction: customMPCv2Round3Generator,
63+
};
64+
} else {
65+
// For non-ECDSA algorithms, return the original parameters
66+
return req.decoded as SendManyOptions;
67+
}
68+
}
69+
3370
export async function handleSendMany(req: MasterApiSpecRouteRequest<'v1.wallet.sendMany', 'post'>) {
3471
const enclavedExpressClient = req.enclavedExpressClient;
3572
const reqId = new RequestTracer();
@@ -45,9 +82,9 @@ export async function handleSendMany(req: MasterApiSpecRouteRequest<'v1.wallet.s
4582
throw new Error(`Wallet ${walletId} not found`);
4683
}
4784

48-
// if (wallet.type() !== 'cold' || wallet.subType() !== 'onPrem') {
49-
// throw new Error('Wallet is not an on-prem wallet');
50-
// }
85+
if (wallet.type() !== 'cold' || wallet.subType() !== 'onPrem') {
86+
throw new Error('Wallet is not an on-prem wallet');
87+
}
5188

5289
const keyIdIndex = params.source === 'user' ? KeyIndices.USER : KeyIndices.BACKUP;
5390
logger.info(`Key ID index: ${keyIdIndex}`);
@@ -64,13 +101,25 @@ export async function handleSendMany(req: MasterApiSpecRouteRequest<'v1.wallet.s
64101
if (params.pubkey && signingKeychain.pub !== params.pubkey) {
65102
throw new Error(`Pub provided does not match the keychain on wallet for ${params.source}`);
66103
}
67-
if (params.commonKeychain && signingKeychain.commonKeychain !== params.commonKeychain) {
68-
throw new Error(
69-
`Common keychain provided does not match the keychain on wallet for ${params.source}`,
70-
);
71-
}
104+
// if (params.commonKeychain && signingKeychain.commonKeychain !== params.commonKeychain) {
105+
// throw new Error(
106+
// `Common keychain provided does not match the keychain on wallet for ${params.source}`,
107+
// );
108+
// }
72109

73110
try {
111+
// Create TSS send parameters with custom signing functions if needed
112+
113+
if (wallet.baseCoin.getMPCAlgorithm() === 'ecdsa') {
114+
const ecdsaMPCv2SendParams = createEcdsaMPCv2SendParams(
115+
req,
116+
wallet,
117+
enclavedExpressClient,
118+
signingKeychain,
119+
);
120+
return wallet.sendMany(ecdsaMPCv2SendParams);
121+
}
122+
74123
const prebuildParams: PrebuildTransactionOptions = {
75124
...params,
76125
// Convert memo string to Memo object if present

0 commit comments

Comments
 (0)