Skip to content
Merged
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
40 changes: 18 additions & 22 deletions modules/bitgo/test/v2/unit/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2070,7 +2070,7 @@ describe('V2 Wallet:', function () {
getKeyNock.isDone().should.be.True();
});

describe('OFC Multi-User-Key Wallet Sharing', function () {
describe('OFC multi-key-user-Key Wallet Sharing', function () {
const userId = '123';
const email = 'shareto@sdktest.com';
const permissions = 'view,spend';
Expand All @@ -2081,7 +2081,7 @@ describe('V2 Wallet:', function () {
before(function () {
const ofcCoin = bitgo.coin('ofc');

// Regular OFC wallet without multi-user-key feature
// Regular OFC wallet without multi-key-user-key feature
const regularOfcWalletData = {
id: '5b34252f1bf349930e3400c00000000',
coin: 'ofc',
Expand All @@ -2096,24 +2096,20 @@ describe('V2 Wallet:', function () {
} as any;
ofcWallet = new Wallet(bitgo, ofcCoin, regularOfcWalletData);

// OFC wallet with multi-user-key feature
// OFC wallet with multi-key-user-key feature
const multiUserKeyWalletData = {
id: '5b34252f1bf349930e3400d00000000',
coin: 'ofc',
keys: [
'5b3424f91bf349930e34018400000000',
'5b3424f91bf349930e34018500000000',
'5b3424f91bf349930e34018600000000',
],
keys: ['5b3424f91bf349930e34018400000000'],
coinSpecific: {
features: ['multi-user-key'],
features: ['multi-key-user-key'],
},
multisigType: 'onchain',
type: 'hot',
} as any;
ofcMultiUserKeyWallet = new Wallet(bitgo, ofcCoin, multiUserKeyWalletData);

// Non-multi-user-key wallet for backwards compatibility tests
// Non-multi-key-user-key wallet for backwards compatibility tests
const nonMultiUserKeyWalletData = {
id: '5b34252f1bf349930e34020a00000003',
coin: 'ofc',
Expand All @@ -2132,7 +2128,7 @@ describe('V2 Wallet:', function () {
});

describe('createShare method', function () {
describe('multi-user-key wallets', function () {
describe('multi-key-user-key wallets', function () {
it('should exclude keychain property from API request', async function () {
const createShareParams = {
user: userId,
Expand Down Expand Up @@ -2168,7 +2164,7 @@ describe('V2 Wallet:', function () {

await ofcMultiUserKeyWallet
.createShare(createShareParams)
.should.be.rejectedWith('keychain property must not be provided for multi-user-key wallets');
.should.be.rejectedWith('keychain property must not be provided for multi-key-user-key wallets');
});

it('should omit keychain from request even when empty object is provided', async function () {
Expand All @@ -2193,7 +2189,7 @@ describe('V2 Wallet:', function () {
});
});

describe('non-multi-user-key wallets', function () {
describe('non-multi-key-user-key wallets', function () {
it('should include keychain property in API request when provided', async function () {
const createShareParams = {
user: userId,
Expand Down Expand Up @@ -2229,7 +2225,7 @@ describe('V2 Wallet:', function () {
});

describe('shareWallet method', function () {
describe('multi-user-key wallets', function () {
describe('multi-key-user-key wallets', function () {
it('should skip keychain preparation and set skipKeychain=true in API request', async function () {
const getSharingKeyNock = nock(bgUrl)
.post('/api/v1/user/sharingkey', { email })
Expand Down Expand Up @@ -2284,7 +2280,7 @@ describe('V2 Wallet:', function () {
});
});

describe('non-multi-user-key wallets', function () {
describe('non-multi-key-user-key wallets', function () {
it('should include keychain when wallet passphrase is provided', async function () {
const toKeychain = utxoLib.bip32.fromSeed(Buffer.from('deadbeef02deadbeef02deadbeef02deadbeef02', 'hex'));
const path = 'm/999999/1/1';
Expand All @@ -2307,7 +2303,7 @@ describe('V2 Wallet:', function () {
});

const createShareStub = sinon.stub(nonMultiUserKeyWallet, 'createShare').callsFake(async (options) => {
// For non-multi-user-key wallets, keychain should be present when spend permissions are included
// For non-multi-key-user-key wallets, keychain should be present when spend permissions are included
options!.keychain!.should.not.be.undefined();
options!.keychain!.pub!.should.equal(pub);
return undefined;
Expand All @@ -2322,15 +2318,15 @@ describe('V2 Wallet:', function () {
});
});

describe('multi-user-key detection', function () {
it('should detect multi-user-key wallet via coinSpecific.features array', async function () {
describe('multi-key-user-key detection', function () {
it('should detect multi-key-user-key wallet via coinSpecific.features array', async function () {
const ofcCoin: any = bitgo.coin('ofc');
const walletWithMultiUserKeyFeature = new Wallet(bitgo, ofcCoin, {
id: '5b34252f1bf349930e34020a00000004',
coin: 'ofc',
keys: ['5b3424f91bf349930e34017500000003'],
coinSpecific: {
features: ['multi-user-key'],
features: ['multi-key-user-key'],
},
type: 'hot',
});
Expand Down Expand Up @@ -2358,7 +2354,7 @@ describe('V2 Wallet:', function () {
.times(3)
.reply(200, { userId, pubkey: 'testpubkey', path: 'm/999999/1/1' });

// Multi-user-key wallet should skip keychain
// Multi-key-user-key wallet should skip keychain
const getEncryptedUserKeychainStub1 = sinon.stub(walletWithMultiUserKeyFeature, 'getEncryptedUserKeychain');
getEncryptedUserKeychainStub1.rejects(new Error('getEncryptedUserKeychain should not be called'));
const createShareStub1 = sinon
Expand All @@ -2371,14 +2367,14 @@ describe('V2 Wallet:', function () {
getEncryptedUserKeychainStub1.called.should.be.false();
createShareStub1.calledOnce.should.be.true();

// Wallet without multi-user-key feature should respect skipKeychain flag
// Wallet without multi-key-user-key feature should respect skipKeychain flag
const createShareStub2 = sinon.stub(walletWithoutFeature, 'createShare').callsFake(async (options) => {
return undefined;
});
await walletWithoutFeature.shareWallet({ email, permissions, skipKeychain: true });
createShareStub2.calledOnce.should.be.true();

// Wallet without coinSpecific should not be detected as multi-user-key
// Wallet without coinSpecific should not be detected as multi-key-user-key
const createShareStub3 = sinon.stub(walletWithoutCoinSpecific, 'createShare').callsFake(async (options) => {
return undefined;
});
Expand Down
10 changes: 5 additions & 5 deletions modules/bitgo/test/v2/unit/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1885,7 +1885,7 @@ describe('V2 Wallets:', function () {
permissions: ['admin', 'spend', 'view'],
state: 'active',
userMultiKeyRotationRequired: true,
// No keychain - this is the key difference for multi-user-key shares
// No keychain - this is the key difference for multi-key-user-key shares
},
],
outgoing: [],
Expand Down Expand Up @@ -1957,7 +1957,7 @@ describe('V2 Wallets:', function () {
permissions: ['admin', 'spend', 'view'],
state: 'active',
userMultiKeyRotationRequired: true,
// No keychain - this is the key difference for multi-user-key shares
// No keychain - this is the key difference for multi-key-user-key shares
},
],
outgoing: [],
Expand Down Expand Up @@ -2140,10 +2140,10 @@ describe('V2 Wallets:', function () {
const encryptedPrv = bitgo.encrypt({ input: keychain.prv, password: userPassword });
sandbox.stub(bitgo, 'encrypt').returns(encryptedPrv);

// Should use the multi-user-key flow (no signature/payload/keyId)
// Should use the multi-key-user-key flow (no signature/payload/keyId)
const acceptShareNock = nock(bgUrl)
.post(`/api/v2/ofc/walletshare/${shareId}`, (body: any) => {
// Verify it's using multi-user-key flow (has pub and encryptedPrv, but no signature/payload/keyId)
// Verify it's using multi-key-user-key flow (has pub and encryptedPrv, but no signature/payload/keyId)
return (
body.walletShareId === shareId &&
body.state === 'accepted' &&
Expand All @@ -2161,7 +2161,7 @@ describe('V2 Wallets:', function () {

should.equal(res.changed, true);
should.equal(res.state, 'accepted');
// Verify reshare was NOT called (multi-user-key flow)
// Verify reshare was NOT called (multi-key-user-key flow)
should.equal(reshareStub.called, false);

walletShareNock.done();
Expand Down
8 changes: 4 additions & 4 deletions modules/sdk-core/src/bitgo/wallet/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,7 @@ export class Wallet implements IWallet {
}

private isMultiUserKeyWallet(): boolean {
return this._wallet.coinSpecific?.features?.includes('multi-user-key') ?? false;
return this._wallet.coinSpecific?.features?.includes('multi-key-user-key') ?? false;
}

/**
Expand All @@ -1609,7 +1609,7 @@ export class Wallet implements IWallet {

if (isMultiUserKeyWallet) {
if (params.keychain && !_.isEmpty(params.keychain)) {
throw new Error('keychain property must not be provided for multi-user-key wallets');
throw new Error('keychain property must not be provided for multi-key-user-key wallets');
}
// Remove keychain from params if presents
return await this.bitgo.post(this.url('/share')).send(_.omit(params, 'keychain')).result();
Expand Down Expand Up @@ -1811,8 +1811,8 @@ export class Wallet implements IWallet {
throw new Error('Expected skipKeychain to be a boolean. ');
}

// Check if this is a multi-user-key OFC wallet
// For multi-user-key wallets, skip keychain preparation regardless of other conditions
// Check if this is a multi-key-user-key OFC wallet
// For multi-key-user-key wallets, skip keychain preparation regardless of other conditions
const needsKeychain =
!this.isMultiUserKeyWallet() &&
!params.skipKeychain &&
Expand Down
2 changes: 1 addition & 1 deletion modules/sdk-core/src/bitgo/wallet/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@ export class Wallets implements IWallets {
};

// Note: Unlike keychainOverrideRequired, we do NOT reshare the wallet with spenders
// This is a key difference - multi-user-key wallets don't require reshare
// This is a key difference - multi-key-user-key wallets don't require reshare
return this.updateShare(updateParams);
}

Expand Down