Skip to content

Commit 288d4d5

Browse files
committed
feat(sdk-core): add MPC EdDSA address verification
TICKET: WP-6378
1 parent 47b5f34 commit 288d4d5

File tree

4 files changed

+60
-5
lines changed

4 files changed

+60
-5
lines changed

modules/sdk-core/src/bitgo/baseCoin/baseCoin.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747
VerifyTransactionOptions,
4848
AuditKeyParams,
4949
AuditDecryptedKeyParams,
50+
TssVerifyAddressOptions,
5051
} from './iBaseCoin';
5152
import { IInscriptionBuilder } from '../inscriptionBuilder';
5253
import {
@@ -346,7 +347,7 @@ export abstract class BaseCoin implements IBaseCoin {
346347
* @param params
347348
* @return true iff address is a wallet address. Must return false if address is outside wallet.
348349
*/
349-
abstract isWalletAddress(params: VerifyAddressOptions): Promise<boolean>;
350+
abstract isWalletAddress(params: VerifyAddressOptions | TssVerifyAddressOptions): Promise<boolean>;
350351

351352
/**
352353
* convert address into desired address format.

modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,18 @@ export interface VerifyAddressOptions {
149149
addressType?: string;
150150
keychains?: {
151151
pub: string;
152-
commonKeychain?: string;
153152
}[];
154153
error?: string;
155154
coinSpecific?: AddressCoinSpecific;
156155
impliedForwarderVersion?: number;
157156
}
158157

159-
export interface TssVerifyAddressOptions extends VerifyAddressOptions {
160-
chain: string;
158+
export interface TssVerifyAddressOptions {
159+
address: string;
160+
keychains: {
161+
commonKeychain: string;
162+
}[];
163+
chain?: string;
161164
index: string;
162165
}
163166

@@ -552,7 +555,7 @@ export interface IBaseCoin {
552555
explainTransaction(options: Record<string, any>): Promise<ITransactionExplanation<any, string | number> | undefined>;
553556
verifyTransaction(params: VerifyTransactionOptions): Promise<boolean>;
554557
verifyAddress(params: VerifyAddressOptions): Promise<boolean>;
555-
isWalletAddress(params: VerifyAddressOptions, wallet?: IWallet): Promise<boolean>;
558+
isWalletAddress(params: VerifyAddressOptions | TssVerifyAddressOptions, wallet?: IWallet): Promise<boolean>;
556559
canonicalAddress(address: string, format: unknown): string;
557560
supportsBlockTarget(): boolean;
558561
supportsLightning(): boolean;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { InvalidAddressError, TssVerifyAddressOptions } from '../../baseCoin/iBaseCoin';
2+
import { EDDSAMethods } from '../../tss';
3+
4+
/**
5+
* Verifies if an address belongs to a wallet using EdDSA TSS MPC derivation.
6+
* This is a common implementation for EdDSA-based MPC coins (SOL, DOT, SUI, TON, IOTA, etc.)
7+
*
8+
* @param params - Verification options including keychains, address, and derivation index
9+
* @param isValidAddress - Coin-specific function to validate address format
10+
* @param getAddressFromPublicKey - Coin-specific function to convert public key to address
11+
* @returns true if the address matches the derived address, false otherwise
12+
* @throws {InvalidAddressError} if the address is invalid
13+
* @throws {Error} if required parameters are missing or invalid
14+
*/
15+
export async function verifyEddsaTssWalletAddress(
16+
params: TssVerifyAddressOptions,
17+
isValidAddress: (address: string) => boolean,
18+
getAddressFromPublicKey: (publicKey: string) => string
19+
): Promise<boolean> {
20+
const { keychains, address, index } = params;
21+
22+
if (!isValidAddress(address)) {
23+
throw new InvalidAddressError(`invalid address: ${address}`);
24+
}
25+
26+
if (!keychains || keychains.length === 0) {
27+
throw new Error('missing required param keychains');
28+
}
29+
30+
// For MPC coins, commonKeychain should be the same for all keychains
31+
const commonKeychain = keychains[0].commonKeychain as string;
32+
if (!commonKeychain) {
33+
throw new Error('missing required param commonKeychain');
34+
}
35+
36+
// Verify all keychains have the same commonKeychain
37+
for (const keychain of keychains) {
38+
if (keychain.commonKeychain !== commonKeychain) {
39+
throw new Error('all keychains must have the same commonKeychain for MPC coins');
40+
}
41+
}
42+
43+
// Only perform derivation once since commonKeychain is the same
44+
const MPC = await EDDSAMethods.getInitializedMpcInstance();
45+
const derivationPath = 'm/' + index;
46+
const derivedPublicKey = MPC.deriveUnhardened(commonKeychain, derivationPath).slice(0, 64);
47+
const expectedAddress = getAddressFromPublicKey(derivedPublicKey);
48+
49+
return address === expectedAddress;
50+
}

modules/sdk-core/src/bitgo/utils/tss/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ export { ITssUtils, IEddsaUtils, TxRequest, EddsaUnsignedTransaction } from './e
1414

1515
export * as BaseTssUtils from './baseTSSUtils';
1616
export * from './baseTypes';
17+
export * from './addressVerification';

0 commit comments

Comments
 (0)