Skip to content

Commit f40fe4c

Browse files
committed
feat(sdk-coin-sol): add MPCv2 support to recoverConsolidations
- Detect MPCv2 once at the top of recoverConsolidations instead of relying on per-iteration keycard decryption in recover(). This avoids decrypting the same keycard N times across the scan loop. - For MPCv2 wallets, derive the base destination address (index 0) using deriveUnhardenedMps instead of MPC.deriveUnhardened, so funds are swept to the correct MPCv2 address. - Thread multisigTypeVersion='MPCv2' into each recover() call so recover() short-circuits isMpcv2SigningMaterial and skips redundant detection. - Add multisigTypeVersion field to SolRecoveryOptions interface to support pre-resolved route threading. - Add unit tests for MPCv2 signed native SOL and SPL token consolidation, single-detection assertion, unsigned cold path regression, and MPCv1 signed consolidation regression. Ticket: WCI-496 Session-Id: 71c94edb-c9b3-41bf-9ddb-e895b1efb51a Task-Id: 1e1b82e3-1575-4f53-b072-ce133a0dce65
1 parent f509a08 commit f40fe4c

2 files changed

Lines changed: 358 additions & 5 deletions

File tree

modules/sdk-coin-sol/src/sol.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ export interface SolRecoveryOptions extends MPCRecoveryOptions {
187187
tokenMintAddress?: string;
188188
programId?: string; // programId of the token
189189
apiKey?: string; // API key for node requests
190+
// Pre-resolved signing route; when set, skips per-call keycard decryption in recover().
191+
multisigTypeVersion?: 'MPCv2';
190192
}
191193

192194
export interface SolConsolidationRecoveryOptions extends MPCConsolidationRecoveryOptions {
@@ -1252,8 +1254,13 @@ export class Sol extends BaseCoin {
12521254
const bitgoKey = params.bitgoKey.replace(/\s/g, '');
12531255
const isUnsignedSweep = !params.walletPassphrase;
12541256

1255-
// Validate signing keys and detect MPCv2 format early for signed recovery
1256-
const isMpcV2 = await this.isMpcv2SigningMaterial(params.userKey, params.backupKey, params.walletPassphrase);
1257+
// Validate signing keys and detect MPCv2 format early for signed recovery.
1258+
// When multisigTypeVersion is pre-resolved by the caller (e.g. recoverConsolidations),
1259+
// skip keycard decryption to avoid redundant work on each loop iteration.
1260+
const isMpcV2 =
1261+
params.multisigTypeVersion === 'MPCv2'
1262+
? true
1263+
: await this.isMpcv2SigningMaterial(params.userKey, params.backupKey, params.walletPassphrase);
12571264

12581265
let balance = 0;
12591266

@@ -1810,13 +1817,22 @@ export class Sol extends BaseCoin {
18101817
}
18111818

18121819
const bitgoKey = params.bitgoKey.replace(/\s/g, '');
1813-
const MPC = await EDDSAMethods.getInitializedMpcInstance();
1820+
const userKey = params.userKey?.replace(/\s/g, '') ?? '';
1821+
1822+
// Detect once at the top to avoid decrypting the keycard on every iteration of the scan loop.
1823+
// For unsigned sweep (no passphrase), isMpcV2 is false — cold MPCv2 is out of scope.
1824+
const isMpcV2 = params.walletPassphrase
1825+
? !(await EDDSAUtils.isEddsaMpcV1SigningMaterial(userKey, params.walletPassphrase, this.bitgo))
1826+
: false;
1827+
18141828
const baseAddressIndex = 0;
18151829
const baseAddressPath = params.seed
18161830
? getDerivationPath(params.seed) + `/${baseAddressIndex}`
18171831
: `m/${baseAddressIndex}`;
1818-
const accountId = MPC.deriveUnhardened(bitgoKey, baseAddressPath).slice(0, 64);
1819-
const baseAddress = new SolKeyPair({ pub: accountId }).getAddress();
1832+
const baseAccountId = isMpcV2
1833+
? deriveUnhardenedMps(bitgoKey, baseAddressPath).slice(0, 64)
1834+
: (await EDDSAMethods.getInitializedMpcInstance()).deriveUnhardened(bitgoKey, baseAddressPath).slice(0, 64);
1835+
const baseAddress = new SolKeyPair({ pub: baseAccountId }).getAddress();
18201836

18211837
let durableNoncePubKeysIndex = 0;
18221838
const durableNoncePubKeysLength = params.durableNonces.publicKeys.length;
@@ -1829,6 +1845,7 @@ export class Sol extends BaseCoin {
18291845
backupKey: params.backupKey,
18301846
bitgoKey: params.bitgoKey,
18311847
walletPassphrase: params.walletPassphrase,
1848+
multisigTypeVersion: isMpcV2 ? ('MPCv2' as const) : undefined,
18321849
recoveryDestination: baseAddress,
18331850
seed: params.seed,
18341851
index: i,

0 commit comments

Comments
 (0)