Skip to content

Commit 0cba567

Browse files
authored
Merge pull request #5186 from BitGo/dkls-cold
feat(sdk-core): enable dkls cold and custody wallet creation
2 parents 5e70321 + 5360e06 commit 0cba567

File tree

2 files changed

+154
-43
lines changed

2 files changed

+154
-43
lines changed

modules/bitgo/test/v2/unit/wallets.ts

Lines changed: 136 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
getSharedSecret,
2525
BulkWalletShareOptions,
2626
KeychainWithEncryptedPrv,
27+
WalletWithKeychains,
2728
} from '@bitgo/sdk-core';
2829
import { BitGo } from '../../../src';
2930
import { afterEach } from 'mocha';
@@ -858,26 +859,36 @@ describe('V2 Wallets:', function () {
858859
eth: {
859860
walletCreationSettings: {
860861
multiSigTypeVersion: 'MPCv2',
862+
coldMultiSigTypeVersion: 'MPCv2',
863+
custodialMultiSigTypeVersion: 'MPCv2',
861864
},
862865
},
863866
bsc: {
864867
walletCreationSettings: {
865868
multiSigTypeVersion: 'MPCv2',
869+
coldMultiSigTypeVersion: 'MPCv2',
870+
custodialMultiSigTypeVersion: 'MPCv2',
866871
},
867872
},
868873
polygon: {
869874
walletCreationSettings: {
870875
multiSigTypeVersion: 'MPCv2',
876+
coldMultiSigTypeVersion: 'MPCv2',
877+
custodialMultiSigTypeVersion: 'MPCv2',
871878
},
872879
},
873880
atom: {
874881
walletCreationSettings: {
875882
multiSigTypeVersion: 'MPCv2',
883+
coldMultiSigTypeVersion: 'MPCv2',
884+
custodialMultiSigTypeVersion: 'MPCv2',
876885
},
877886
},
878887
tia: {
879888
walletCreationSettings: {
880889
multiSigTypeVersion: 'MPCv2',
890+
coldMultiSigTypeVersion: 'MPCv2',
891+
custodialMultiSigTypeVersion: 'MPCv2',
881892
},
882893
},
883894
},
@@ -891,7 +902,7 @@ describe('V2 Wallets:', function () {
891902
});
892903

893904
['hteth', 'tbsc', 'tpolygon', 'ttia', 'tatom'].forEach((coin) => {
894-
it(`should create a new ${coin} TSS MPCv2 wallet`, async function () {
905+
it(`should create a new ${coin} TSS MPCv2 hot wallet`, async function () {
895906
const testCoin = bitgo.coin(coin);
896907
const stubbedKeychainsTriplet: KeychainsTriplet = {
897908
userKeychain: {
@@ -942,6 +953,130 @@ describe('V2 Wallets:', function () {
942953
params.passphrase
943954
);
944955
});
956+
957+
it(`should create a new ${coin} TSS MPCv2 cold wallet`, async function () {
958+
const testCoin = bitgo.coin(coin);
959+
const bitgoKeyId = 'key123';
960+
const commonKeychain = '0xabc';
961+
962+
const bitgoKeyNock = nock('https://bitgo.fakeurl')
963+
.get(`/api/v2/${coin}/key/${bitgoKeyId}`)
964+
.times(1)
965+
.reply(200, {
966+
id: 'key123',
967+
pub: 'bitgoPub',
968+
type: 'tss',
969+
source: 'bitgo',
970+
commonKeychain,
971+
});
972+
973+
const userKeyNock = nock('https://bitgo.fakeurl')
974+
.post(`/api/v2/${coin}/key`, {
975+
source: 'user',
976+
keyType: 'tss',
977+
commonKeychain,
978+
derivedFromParentWithSeed: '37',
979+
})
980+
.times(1)
981+
.reply(200, {
982+
id: 'userKey123',
983+
pub: 'userPub',
984+
type: 'tss',
985+
source: 'user',
986+
});
987+
988+
const backupKeyNock = nock('https://bitgo.fakeurl')
989+
.post(`/api/v2/${coin}/key`, {
990+
source: 'backup',
991+
keyType: 'tss',
992+
commonKeychain,
993+
derivedFromParentWithSeed: '37',
994+
})
995+
.times(1)
996+
.reply(200, {
997+
id: 'backupKey123',
998+
pub: 'backupPub',
999+
type: 'tss',
1000+
source: 'backup',
1001+
});
1002+
1003+
const walletNock = nock('https://bitgo.fakeurl')
1004+
.post(`/api/v2/${coin}/wallet`, {
1005+
label: 'tss wallet',
1006+
m: 2,
1007+
n: 3,
1008+
keys: ['userKey123', 'backupKey123', 'key123'],
1009+
type: 'cold',
1010+
multisigType: 'tss',
1011+
enterprise: 'enterprise',
1012+
walletVersion: 5,
1013+
})
1014+
.reply(200);
1015+
1016+
const wallets = new Wallets(bitgo, testCoin);
1017+
1018+
const params: GenerateWalletOptions = {
1019+
label: 'tss wallet',
1020+
multisigType: 'tss' as const,
1021+
enterprise: 'enterprise',
1022+
passcodeEncryptionCode: 'originalPasscodeEncryptionCode',
1023+
walletVersion: 5,
1024+
type: 'cold',
1025+
bitgoKeyId: 'key123',
1026+
commonKeychain: '0xabc',
1027+
coldDerivationSeed: '37',
1028+
};
1029+
1030+
const response = (await wallets.generateWallet(params)) as WalletWithKeychains;
1031+
1032+
bitgoKeyNock.isDone().should.be.true();
1033+
userKeyNock.isDone().should.be.true();
1034+
backupKeyNock.isDone().should.be.true();
1035+
walletNock.isDone().should.be.true();
1036+
1037+
should.exist(response.wallet);
1038+
should.exist(response.userKeychain);
1039+
should.exist(response.backupKeychain);
1040+
should.exist(response.bitgoKeychain);
1041+
response.responseType.should.equal('WalletWithKeychains');
1042+
response.userKeychain.id.should.equal('userKey123');
1043+
response.backupKeychain.id.should.equal('backupKey123');
1044+
response.bitgoKeychain.id.should.equal('key123');
1045+
});
1046+
1047+
it(`should create a new ${coin} TSS MPCv2 custody wallet`, async function () {
1048+
const testCoin = bitgo.coin(coin);
1049+
const keys = ['userKey', 'backupKey', 'bitgoKey'];
1050+
1051+
const params: GenerateWalletOptions = {
1052+
label: 'tss wallet',
1053+
passphrase: 'tss password',
1054+
multisigType: 'tss' as const,
1055+
enterprise: 'enterprise',
1056+
passcodeEncryptionCode: 'originalPasscodeEncryptionCode',
1057+
walletVersion: 5,
1058+
type: 'custodial',
1059+
};
1060+
1061+
const walletNock = nock('https://bitgo.fakeurl')
1062+
.post(`/api/v2/${coin}/wallet`)
1063+
.times(1)
1064+
.reply(200, { ...params, keys });
1065+
1066+
const wallets = new Wallets(bitgo, testCoin);
1067+
1068+
const response = (await wallets.generateWallet(params)) as WalletWithKeychains;
1069+
1070+
walletNock.isDone().should.be.true();
1071+
should.exist(response.wallet);
1072+
should.exist(response.userKeychain);
1073+
should.exist(response.backupKeychain);
1074+
should.exist(response.bitgoKeychain);
1075+
response.responseType.should.equal('WalletWithKeychains');
1076+
response.userKeychain.id.should.equal(keys[0]);
1077+
response.backupKeychain.id.should.equal(keys[1]);
1078+
response.bitgoKeychain.id.should.equal(keys[2]);
1079+
});
9451080
});
9461081

9471082
it(`should create a new hteth TSS MPCv2 wallet with walletVersion 6`, async function () {
@@ -1057,42 +1192,6 @@ describe('V2 Wallets:', function () {
10571192
params.passphrase
10581193
);
10591194
});
1060-
1061-
it('should throw for a cold wallet using wallet version 5', async function () {
1062-
const hteth = bitgo.coin('hteth');
1063-
const wallets = new Wallets(bitgo, hteth);
1064-
1065-
await assert.rejects(
1066-
async () => {
1067-
await wallets.generateWallet({
1068-
label: 'tss wallet',
1069-
multisigType: 'tss',
1070-
enterprise: 'enterprise',
1071-
walletVersion: 5,
1072-
type: 'cold',
1073-
});
1074-
},
1075-
{ message: 'EVM TSS MPCv2 wallets are not supported for cold wallets' }
1076-
);
1077-
});
1078-
1079-
it('should throw for a custodial wallet using wallet version 5', async function () {
1080-
const hteth = bitgo.coin('hteth');
1081-
const wallets = new Wallets(bitgo, hteth);
1082-
1083-
await assert.rejects(
1084-
async () => {
1085-
await wallets.generateWallet({
1086-
label: 'tss wallet',
1087-
multisigType: 'tss',
1088-
enterprise: 'enterprise',
1089-
walletVersion: 5,
1090-
type: 'custodial',
1091-
});
1092-
},
1093-
{ message: 'EVM TSS MPCv2 wallets are not supported for custodial wallets' }
1094-
);
1095-
});
10961195
});
10971196

10981197
describe('Generate BLS-DKG wallet:', function () {

modules/sdk-core/src/bitgo/wallet/wallets.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,6 @@ export class Wallets implements IWallets {
313313
assert(enterprise, 'enterprise is required for TSS wallet');
314314

315315
if (type === 'cold') {
316-
if (params.walletVersion === 5 || params.walletVersion === 6) {
317-
throw new Error('EVM TSS MPCv2 wallets are not supported for cold wallets');
318-
}
319316
// validate
320317
assert(params.bitgoKeyId, 'bitgoKeyId is required for SMC TSS wallet');
321318
assert(params.commonKeychain, 'commonKeychain is required for SMC TSS wallet');
@@ -331,9 +328,6 @@ export class Wallets implements IWallets {
331328
}
332329

333330
if (type === 'custodial') {
334-
if (params.walletVersion === 5 || params.walletVersion === 6) {
335-
throw new Error('EVM TSS MPCv2 wallets are not supported for custodial wallets');
336-
}
337331
return this.generateCustodialMpcWallet({
338332
multisigType: 'tss',
339333
label,
@@ -1044,6 +1038,15 @@ export class Wallets implements IWallets {
10441038
const reqId = new RequestTracer();
10451039
this.bitgo.setRequestTracer(reqId);
10461040

1041+
if (multisigType === 'tss' && this.baseCoin.getMPCAlgorithm() === 'ecdsa') {
1042+
const tssSettings: TssSettings = await this.bitgo
1043+
.get(this.bitgo.microservicesUrl('/api/v2/tss/settings'))
1044+
.result();
1045+
const multisigTypeVersion =
1046+
tssSettings.coinSettings[this.baseCoin.getFamily()]?.walletCreationSettings?.coldMultiSigTypeVersion;
1047+
walletVersion = this.determineEcdsaMpcWalletVersion(walletVersion, multisigTypeVersion);
1048+
}
1049+
10471050
// Create MPC Keychains
10481051
const bitgoKeychain = await this.baseCoin.keychains().get({ id: bitgoKeyId });
10491052

@@ -1121,6 +1124,15 @@ export class Wallets implements IWallets {
11211124
const reqId = new RequestTracer();
11221125
this.bitgo.setRequestTracer(reqId);
11231126

1127+
if (multisigType === 'tss' && this.baseCoin.getMPCAlgorithm() === 'ecdsa') {
1128+
const tssSettings: TssSettings = await this.bitgo
1129+
.get(this.bitgo.microservicesUrl('/api/v2/tss/settings'))
1130+
.result();
1131+
const multisigTypeVersion =
1132+
tssSettings.coinSettings[this.baseCoin.getFamily()]?.walletCreationSettings?.custodialMultiSigTypeVersion;
1133+
walletVersion = this.determineEcdsaMpcWalletVersion(walletVersion, multisigTypeVersion);
1134+
}
1135+
11241136
const finalWalletParams = {
11251137
label,
11261138
multisigType,

0 commit comments

Comments
 (0)