Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/abstract-lightning/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
]
},
"dependencies": {
"@bitgo/public-types": "6.48.0",
"@bitgo/public-types": "6.50.0",
"@bitgo/sdk-core": "^38.4.0",
"@bitgo/statics": "^59.0.0",
"@bitgo/utxo-lib": "^11.24.1",
Expand Down
2 changes: 1 addition & 1 deletion modules/bitgo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
"superagent": "^9.0.1"
},
"devDependencies": {
"@bitgo/public-types": "6.48.0",
"@bitgo/public-types": "6.50.0",
"@bitgo/sdk-opensslbytes": "^2.1.0",
"@bitgo/sdk-test": "^9.1.61",
"@openpgp/web-stream-tools": "0.0.14",
Expand Down
2 changes: 1 addition & 1 deletion modules/express/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"superagent": "^9.0.1"
},
"devDependencies": {
"@bitgo/public-types": "6.48.0",
"@bitgo/public-types": "6.50.0",
"@bitgo/sdk-lib-mpc": "^10.15.0",
"@bitgo/sdk-test": "^9.1.61",
"@types/argparse": "^1.0.36",
Expand Down
2 changes: 1 addition & 1 deletion modules/sdk-coin-flrp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"nock": "^13.3.1"
},
"dependencies": {
"@bitgo/public-types": "6.48.0",
"@bitgo/public-types": "6.50.0",
"@bitgo/sdk-core": "^38.4.0",
"@bitgo/secp256k1": "^1.11.0",
"@bitgo/statics": "^59.0.0",
Expand Down
2 changes: 1 addition & 1 deletion modules/sdk-coin-sol/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
},
"dependencies": {
"@bitgo/logger": "^1.4.0",
"@bitgo/public-types": "6.48.0",
"@bitgo/public-types": "6.50.0",
"@bitgo/sdk-core": "^38.4.0",
"@bitgo/sdk-lib-mpc": "^10.15.0",
"@bitgo/statics": "^59.0.0",
Expand Down
2 changes: 1 addition & 1 deletion modules/sdk-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
]
},
"dependencies": {
"@bitgo/public-types": "6.48.0",
"@bitgo/public-types": "6.50.0",
"@bitgo/sdk-lib-mpc": "^10.15.0",
"@bitgo/secp256k1": "^1.11.0",
"@bitgo/sjcl": "^1.1.0",
Expand Down
4 changes: 4 additions & 0 deletions modules/sdk-core/src/bitgo/safe/iSafes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@ export interface CreateSafeOptions {

/**
* Handle returned by `initializeSafe`, threaded into the key ceremonies and finalize.
*
* `enabledRootSlots` is the server-decided (Flipt, evaluated once at initialize) set of root-key
* slots to generate; absent (older WP) falls back to all 4 slots.
* @experimental
*/
export interface SafeCreationHandle {
safeId: string;
enabledRootSlots?: InitializeSafeResponse['enabledRootSlots'];
}

/**
Expand Down
26 changes: 17 additions & 9 deletions modules/sdk-core/src/bitgo/safe/safes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@ export class Safes implements ISafes {
*/
async generateSafe(params: CreateSafeOptions): Promise<Safe> {
const safe = await this.initializeSafe({ label: params.label });
const rootKeys = await this.createSafeKeys({ ...params, safeId: safe.id });
const rootKeys = await this.createSafeKeys({
...params,
safeId: safe.id,
enabledRootSlots: safe.enabledRootSlots,
});
return await this.finalizeSafe(safe.id, rootKeys);
}

Expand Down Expand Up @@ -123,20 +127,24 @@ export class Safes implements ISafes {
* @experimental
*/
async createSafeKeys(params: CreateSafeOptions & SafeCreationHandle): Promise<SafeKeys> {
const { safeId, passphrase } = params;
const { safeId, passphrase, enabledRootSlots } = params;
const enterprise = this.enterpriseId;

// Absent `enabledRootSlots` (older WP, pre-gating) ⇒ all 4, preserving current behavior.
// `slots` MUST stay index-aligned with the Promise.allSettled array below. Ordered by scheme:
// the two multisig roots first, then the two MPC roots.
const slots: RootKeyType[] = ['secp256k1Multisig', 'ed25519Multisig', 'ecdsaMpc', 'eddsaMpc'];
const results = await Promise.allSettled([
const allSlots: RootKeyType[] = ['secp256k1Multisig', 'ed25519Multisig', 'ecdsaMpc', 'eddsaMpc'];
const enabled = new Set(enabledRootSlots ?? allSlots);
const slots = allSlots.filter((slot) => enabled.has(slot));
const ceremonies: Record<RootKeyType, () => Promise<RootKeyTriplet>> = {
// Phase 2.1 — multisig roots (①④): local user/backup keypairs + BitGo key, all safeId-tagged.
this.createMultisigRoot('secp256k1Multisig', safeId, passphrase, enterprise),
this.createMultisigRoot('ed25519Multisig', safeId, passphrase, enterprise),
secp256k1Multisig: () => this.createMultisigRoot('secp256k1Multisig', safeId, passphrase, enterprise),
ed25519Multisig: () => this.createMultisigRoot('ed25519Multisig', safeId, passphrase, enterprise),
// Phase 2.2 — MPC roots (②③): the existing DKLS (②) and EdDSA (③) ceremonies, safeId threaded.
this.createMpcRoot('ecdsaMpc', safeId, passphrase, enterprise),
this.createMpcRoot('eddsaMpc', safeId, passphrase, enterprise),
]);
ecdsaMpc: () => this.createMpcRoot('ecdsaMpc', safeId, passphrase, enterprise),
eddsaMpc: () => this.createMpcRoot('eddsaMpc', safeId, passphrase, enterprise),
};
const results = await Promise.allSettled(slots.map((slot) => ceremonies[slot]()));

// Single pass over the settled results: `status === 'fulfilled'` narrows `.value` to a
// RootKeyTriplet (no cast needed), and rejections are collected per-slot for the error below.
Expand Down
35 changes: 32 additions & 3 deletions modules/sdk-core/test/unit/bitgo/safe/safes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,26 @@ describe('Safes', function () {
started.should.equal(4);
});

it('runs only the enabled ceremonies when enabledRootSlots is a subset', async function () {
const result = await safes.createSafeKeys({
label: 'my safe',
passphrase: 'pw',
safeId: 'safe-1',
enabledRootSlots: ['ecdsaMpc', 'eddsaMpc'],
});

result.should.deepEqual({
rootKeys: {
hot: {
ecdsaMpc: ['hteth-user', 'hteth-backup', 'hteth-bitgo'],
eddsaMpc: ['tsol-user', 'tsol-backup', 'tsol-bitgo'],
},
},
});
keychainsByCoin.should.not.have.property('tbtc');
keychainsByCoin.should.not.have.property('txlm');
});

it('archives the safe and throws listing every failed ceremony', async function () {
// Two ceremonies fail (an MPC and a multisig root).
keychainsByCoin['hteth'] = makeKeychains('hteth');
Expand Down Expand Up @@ -236,8 +256,12 @@ describe('Safes', function () {
});

describe('generateSafe', function () {
it('chains initialize → createSafeKeys → finalize, threading the safeId', async function () {
const initializing = { id: 'test-safe-id', status: 'initializing' as const };
it('chains initialize → createSafeKeys → finalize, threading the safeId and enabledRootSlots', async function () {
const initializing = {
id: 'test-safe-id',
status: 'initializing' as const,
enabledRootSlots: ['ecdsaMpc', 'eddsaMpc'] as ('ecdsaMpc' | 'eddsaMpc')[],
};
const rootKeys = { rootKeys: { hot: {} } } as any;
const initStub = sinon.stub(safes, 'initializeSafe').resolves(initializing);
const keysStub = sinon.stub(safes, 'createSafeKeys').resolves(rootKeys);
Expand All @@ -246,7 +270,12 @@ describe('Safes', function () {
const result = await safes.generateSafe({ label: 'my safe', passphrase: 'pw' });

sinon.assert.calledWithMatch(initStub, { label: 'my safe' });
sinon.assert.calledWithMatch(keysStub, { label: 'my safe', passphrase: 'pw', safeId: 'test-safe-id' });
sinon.assert.calledWithMatch(keysStub, {
label: 'my safe',
passphrase: 'pw',
safeId: 'test-safe-id',
enabledRootSlots: ['ecdsaMpc', 'eddsaMpc'],
});
sinon.assert.calledWith(finalizeStub, 'test-safe-id', rootKeys);
sinon.assert.callOrder(initStub, keysStub, finalizeStub);
result.status().should.equal('active');
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1032,10 +1032,10 @@
monocle-ts "^2.3.13"
newtype-ts "^0.3.5"

"@bitgo/public-types@6.48.0":
version "6.48.0"
resolved "https://registry.npmjs.org/@bitgo/public-types/-/public-types-6.48.0.tgz#acad90d78e91e92c7a31677403b77a8b2e44b40a"
integrity sha512-G39FD9Ul5TFReKN07fQ8jeKEY0vkkV0YJuu2pQMWFQ7EEdqByEF1PYr28Jly54X8J8/kxCziTQ56ogwm0VWhng==
"@bitgo/public-types@6.50.0":
version "6.50.0"
resolved "https://registry.npmjs.org/@bitgo/public-types/-/public-types-6.50.0.tgz#48268ab9dbf92e9556f7c77956c18bf39fdc9048"
integrity sha512-t7rlSqeX0b6XSCvuu5XutzcxlpNWlsOD1JBdeTSSDCVbOZvHRPJcyL0/8vkfaK2bVnbpsm31O8sssnwtiugxyA==
dependencies:
fp-ts "^2.0.0"
io-ts "npm:@bitgo-forks/io-ts@2.1.4"
Expand Down
Loading