Skip to content

Commit 6be6567

Browse files
feat(mbe): fix comments
1 parent 7bdffed commit 6be6567

File tree

5 files changed

+99
-52
lines changed

5 files changed

+99
-52
lines changed

src/__tests__/api/master/accelerate.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import nock from 'nock';
55
import { app as expressApp } from '../../../masterExpressApp';
66
import { AppMode, MasterExpressConfig, TlsMode } from '../../../shared/types';
77
import { Environments, Wallet } from '@bitgo/sdk-core';
8-
import { Tbtc } from '@bitgo/sdk-coin-btc';
98

109
describe('POST /api/:coin/wallet/:walletId/accelerate', () => {
1110
let agent: request.SuperAgentTest;
@@ -70,7 +69,7 @@ describe('POST /api/:coin/wallet/:walletId/accelerate', () => {
7069
.stub(Wallet.prototype, 'accelerateTransaction')
7170
.resolves({
7271
txid: 'accelerated-tx-id',
73-
tx: "accerated-transaction-hex",
72+
tx: 'accerated-transaction-hex',
7473
status: 'signed',
7574
});
7675

@@ -121,7 +120,7 @@ describe('POST /api/:coin/wallet/:walletId/accelerate', () => {
121120
.resolves({
122121
txid: 'accelerated-tx-id',
123122
status: 'signed',
124-
tx: "accelerated-transaction-hex",
123+
tx: 'accelerated-transaction-hex',
125124
});
126125

127126
const response = await agent
@@ -262,7 +261,7 @@ describe('POST /api/:coin/wallet/:walletId/accelerate', () => {
262261
.resolves({
263262
txid: 'accelerated-tx-id',
264263
status: 'signed',
265-
tx: "accelerated-transaction-hex",
264+
tx: 'accelerated-transaction-hex',
266265
});
267266

268267
const response = await agent
@@ -284,4 +283,4 @@ describe('POST /api/:coin/wallet/:walletId/accelerate', () => {
284283
keychainGetNock.done();
285284
sinon.assert.calledOnce(accelerateTransactionStub);
286285
});
287-
});
286+
});
Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
import { RequestTracer, KeyIndices } from '@bitgo/sdk-core';
22
import logger from '../../../logger';
33
import { MasterApiSpecRouteRequest } from '../routers/masterApiSpec';
4+
import { getWalletAndSigningKeychain, makeCustomSigningFunction } from '../../../shared/coinUtils';
45

56
export async function handleAccelerate(
67
req: MasterApiSpecRouteRequest<'v1.wallet.accelerate', 'post'>,
78
) {
89
const enclavedExpressClient = req.enclavedExpressClient;
910
const reqId = new RequestTracer();
1011
const bitgo = req.bitgo;
11-
const baseCoin = bitgo.coin(req.params.coin);
1212
const params = req.decoded;
1313
const walletId = req.params.walletId;
14-
const wallet = await baseCoin.wallets().get({ id: walletId, reqId });
15-
16-
// Log the runtime class name of the wallet object
17-
logger.info('Wallet runtime class name: %s', wallet?.constructor.name);
18-
logger.info('Wallet prototype chain: %s', Object.getPrototypeOf(wallet)?.constructor.name);
14+
const coin = req.params.coin;
15+
16+
const { wallet, signingKeychain } = await getWalletAndSigningKeychain({
17+
bitgo,
18+
coin,
19+
walletId,
20+
params,
21+
reqId,
22+
KeyIndices,
23+
});
1924

2025
if (!wallet) {
2126
throw new Error(`Wallet ${walletId} not found`);
2227
}
2328

24-
// Get the signing keychain based on source
25-
const keyIdIndex = params.source === 'user' ? KeyIndices.USER : KeyIndices.BACKUP;
26-
const signingKeychain = await baseCoin.keychains().get({
27-
id: wallet.keyIds()[keyIdIndex],
28-
});
29-
3029
if (!signingKeychain || !signingKeychain.pub) {
3130
throw new Error(`Signing keychain for ${params.source} not found`);
3231
}
@@ -37,14 +36,11 @@ export async function handleAccelerate(
3736

3837
try {
3938
// Create custom signing function that delegates to EBE
40-
const customSigningFunction = async (signParams: any) => {
41-
const signedTx = await enclavedExpressClient.signMultisig({
42-
txPrebuild: signParams.txPrebuild,
43-
source: params.source,
44-
pub: signingKeychain.pub!,
45-
});
46-
return signedTx;
47-
};
39+
const customSigningFunction = makeCustomSigningFunction({
40+
enclavedExpressClient,
41+
source: params.source,
42+
pub: signingKeychain.pub!,
43+
});
4844

4945
// Prepare acceleration parameters
5046
const accelerationParams = {
@@ -62,4 +58,4 @@ export async function handleAccelerate(
6258
logger.error('Failed to accelerate transaction: %s', err.message);
6359
throw err;
6460
}
65-
}
61+
}

src/api/master/handlers/handleConsolidate.ts

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
import { RequestTracer, KeyIndices } from '@bitgo/sdk-core';
22
import logger from '../../../logger';
33
import { MasterApiSpecRouteRequest } from '../routers/masterApiSpec';
4+
import { getWalletAndSigningKeychain, makeCustomSigningFunction } from '../../../shared/coinUtils';
45

56
export async function handleConsolidate(
67
req: MasterApiSpecRouteRequest<'v1.wallet.consolidate', 'post'>,
78
) {
89
const enclavedExpressClient = req.enclavedExpressClient;
910
const reqId = new RequestTracer();
1011
const bitgo = req.bitgo;
11-
const baseCoin = bitgo.coin(req.params.coin);
1212
const params = req.decoded;
1313
const walletId = req.params.walletId;
14-
const wallet = await baseCoin.wallets().get({ id: walletId, reqId });
14+
const coin = req.params.coin;
1515

16-
if (!wallet) {
17-
throw new Error(`Wallet ${walletId} not found`);
18-
}
16+
const { baseCoin, wallet, signingKeychain } = await getWalletAndSigningKeychain({
17+
bitgo,
18+
coin,
19+
walletId,
20+
params,
21+
reqId,
22+
KeyIndices,
23+
});
1924

2025
// Check if the coin supports account consolidations
2126
if (!baseCoin.allowsAccountConsolidations()) {
@@ -27,30 +32,17 @@ export async function handleConsolidate(
2732
throw new Error('consolidateAddresses must be an array of addresses');
2833
}
2934

30-
// Get the signing keychain based on source
31-
const keyIdIndex = params.source === 'user' ? KeyIndices.USER : KeyIndices.BACKUP;
32-
const signingKeychain = await baseCoin.keychains().get({
33-
id: wallet.keyIds()[keyIdIndex],
34-
});
35-
36-
if (!signingKeychain || !signingKeychain.pub) {
37-
throw new Error(`Signing keychain for ${params.source} not found`);
38-
}
39-
4035
if (params.pubkey && params.pubkey !== signingKeychain.pub) {
4136
throw new Error(`Pub provided does not match the keychain on wallet for ${params.source}`);
4237
}
4338

4439
try {
4540
// Create custom signing function that delegates to EBE
46-
const customSigningFunction = async (signParams: any) => {
47-
const signedTx = await enclavedExpressClient.signMultisig({
48-
txPrebuild: signParams.txPrebuild,
49-
source: params.source,
50-
pub: signingKeychain.pub!,
51-
});
52-
return signedTx;
53-
};
41+
const customSigningFunction = makeCustomSigningFunction({
42+
enclavedExpressClient,
43+
source: params.source,
44+
pub: signingKeychain.pub!,
45+
});
5446

5547
// Prepare consolidation parameters
5648
const consolidationParams = {

src/api/master/routers/masterApiSpec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ export const AccelerateRequest = {
138138
const AccelerateResponse: HttpResponse = {
139139
// TODO: Get type from public types repo / Wallet Platform
140140
200: t.type({
141-
"txid": t.string,
142-
"tx": t.string,
141+
txid: t.string,
142+
tx: t.string,
143143
}),
144144
500: t.type({
145145
error: t.string,

src/shared/coinUtils.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { FormattedOfflineVaultTxInfo, BackupKeyRecoveryTransansaction } from '@bitgo/abstract-utxo';
22
import { AbstractEthLikeNewCoins } from '@bitgo/abstract-eth';
33
import { CoinFamily } from '@bitgo/statics';
4-
import { BaseCoin } from 'bitgo';
4+
import { BaseCoin, BitGo } from 'bitgo';
55
import { AbstractUtxoCoin, Eos, Stx, Xtz } from 'bitgo/dist/types/src/v2/coins';
6+
import { RequestTracer } from '@bitgo/sdk-core';
7+
import { EnclavedExpressClient } from '../api/master/clients/enclavedExpressClient';
68

79
export function isEthLikeCoin(coin: BaseCoin): coin is AbstractEthLikeNewCoins {
810
const isEthPure = isFamily(coin, CoinFamily.ETH);
@@ -61,3 +63,61 @@ export function isFormattedOfflineVaultTxInfo(
6163
): obj is FormattedOfflineVaultTxInfo {
6264
return obj && 'txInfo' in obj && 'txHex' in obj && 'feeInfo' in obj;
6365
}
66+
67+
/**
68+
* Fetch wallet and signing keychain, with validation for source and pubkey.
69+
* Throws with a clear error if not found or mismatched.
70+
*/
71+
export async function getWalletAndSigningKeychain({
72+
bitgo,
73+
coin,
74+
walletId,
75+
params,
76+
reqId,
77+
KeyIndices,
78+
}: {
79+
bitgo: BitGo;
80+
coin: string;
81+
walletId: string;
82+
params: { source: 'user' | 'backup'; pubkey?: string };
83+
reqId: RequestTracer;
84+
KeyIndices: { USER: number; BACKUP: number; BITGO: number };
85+
}) {
86+
const baseCoin = bitgo.coin(coin);
87+
const wallet = await baseCoin.wallets().get({ id: walletId, reqId });
88+
if (!wallet) {
89+
throw new Error(`Wallet ${walletId} not found`);
90+
}
91+
const keyIdIndex = params.source === 'user' ? KeyIndices.USER : KeyIndices.BACKUP;
92+
const signingKeychain = await baseCoin.keychains().get({
93+
id: wallet.keyIds()[keyIdIndex],
94+
});
95+
if (!signingKeychain || !signingKeychain.pub) {
96+
throw new Error(`Signing keychain for ${params.source} not found`);
97+
}
98+
if (params.pubkey && params.pubkey !== signingKeychain.pub) {
99+
throw new Error(`Pub provided does not match the keychain on wallet for ${params.source}`);
100+
}
101+
return { baseCoin, wallet, signingKeychain };
102+
}
103+
104+
/**
105+
* Create a custom signing function that delegates to enclavedExpressClient.signMultisig.
106+
*/
107+
export function makeCustomSigningFunction({
108+
enclavedExpressClient,
109+
source,
110+
pub,
111+
}: {
112+
enclavedExpressClient: EnclavedExpressClient;
113+
source: 'user' | 'backup';
114+
pub: string;
115+
}) {
116+
return async function customSigningFunction(signParams: any) {
117+
return enclavedExpressClient.signMultisig({
118+
txPrebuild: signParams.txPrebuild,
119+
source,
120+
pub,
121+
});
122+
};
123+
}

0 commit comments

Comments
 (0)