Skip to content

Commit

Permalink
feat(sdk-core): add bulkShareWallet method
Browse files Browse the repository at this point in the history
Bulk wallet share sdk

Ticket: CS-3699
  • Loading branch information
SoumalyaBh committed Sep 12, 2024
1 parent 2eac2e7 commit 9f5ffba
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 42 deletions.
34 changes: 23 additions & 11 deletions modules/bitgo/test/v2/unit/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1464,23 +1464,22 @@ describe('V2 Wallets:', function () {

it('should throw an error if shareOptions is empty', async () => {
try {
await wallet.createBulkKeyShares({ shareOptions: [] });
await wallet.createBulkKeyShares([]);
assert.fail('Expected error not thrown');
} catch (error) {
assert.strictEqual(error.message, 'shareOptions cannot be empty');
}
});

it('should skip shareoption if keychain parameters are missing', async () => {
const params = {
shareOptions: [
{
user: '[email protected]',
permissions: ['spend'],
keychain: { pub: 'pubkey', encryptedPrv: '', fromPubKey: '', toPubKey: '', path: '' },
},
],
};
const params = [
{
user: '[email protected]',
permissions: ['spend'],
keychain: { pub: 'pubkey', encryptedPrv: '', fromPubKey: '', toPubKey: '', path: '' },
},
];

try {
await wallet.createBulkKeyShares(params);
assert.fail('Expected error not thrown');
Expand All @@ -1506,6 +1505,19 @@ describe('V2 Wallets:', function () {
},
],
};
const paramsToSend = [
{
user: '[email protected]',
permissions: ['spend'],
keychain: {
pub: 'pubkey',
encryptedPrv: 'encryptedPrv',
fromPubKey: 'fromPubKey',
toPubKey: 'toPubKey',
path: 'm/0/0',
},
},
];
nock(bgUrl)
.post(`/api/v2/wallet/${walletData.id}/walletshares`, params)
.reply(200, {
Expand All @@ -1527,7 +1539,7 @@ describe('V2 Wallets:', function () {
},
],
});
const result = await wallet.createBulkKeyShares(params);
const result = await wallet.createBulkKeyShares(paramsToSend);
assert.strictEqual(result.shares[0].id, 'userId', 'The share ID should match');
assert.strictEqual(result.shares[0].coin, walletData.coin, 'The coin should match');
assert.strictEqual(result.shares[0].wallet, walletData.id, 'The wallet ID should match');
Expand Down
12 changes: 5 additions & 7 deletions modules/sdk-core/src/bitgo/wallet/iWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,12 +485,10 @@ export interface ShareWalletOptions {
disableEmail?: boolean;
}

export interface BulkCreateShareOptions {
shareOptions: Array<{
user: string;
permissions: string[];
keychain: BulkWalletShareKeychain;
}>;
export interface BulkCreateShareOption {
user: string;
permissions: string[];
keychain: BulkWalletShareKeychain;
}

export interface BulkWalletShareOptions {
Expand Down Expand Up @@ -804,7 +802,7 @@ export interface IWallet {
getPrv(params?: GetPrvOptions): Promise<any>;
createShare(params?: CreateShareOptions): Promise<any>;
shareWallet(params?: ShareWalletOptions): Promise<any>;
createBulkKeyShares(params?: BulkCreateShareOptions): Promise<CreateBulkWalletShareListResponse>;
createBulkKeyShares(params?: BulkCreateShareOption[]): Promise<CreateBulkWalletShareListResponse>;
bulkWalletShare(params?: BulkWalletShareOptions): Promise<CreateBulkWalletShareListResponse>;
removeUser(params?: RemoveUserOptions): Promise<any>;
prebuildTransaction(params?: PrebuildTransactionOptions): Promise<PrebuildTransactionResult>;
Expand Down
42 changes: 18 additions & 24 deletions modules/sdk-core/src/bitgo/wallet/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
CreateAddressOptions,
CreatePolicyRuleOptions,
CreateShareOptions,
BulkCreateShareOptions,
BulkCreateShareOption,
BulkWalletShareOptions,
CrossChainUTXO,
DeployForwardersOptions,
Expand Down Expand Up @@ -1486,7 +1486,8 @@ export class Wallet implements IWallet {
if (!params.shareOptions || Object.keys(params.shareOptions).length === 0) {
throw new Error('shareOptions cannot be empty');
}
const bulkCreateShareOptions: BulkCreateShareOptions = { shareOptions: [] };
// const bulkCreateShareOptions: BulkCreateShareOptions = { shareOptions: [] };
const bulkCreateShareOptions: BulkCreateShareOption[] = [];

for (const shareOption of params.shareOptions) {
common.validateParams(shareOption, ['userId', 'pubKey', 'path'], []);
Expand Down Expand Up @@ -1537,7 +1538,7 @@ export class Wallet implements IWallet {
throw e;
}
}
bulkCreateShareOptions.shareOptions.push({
bulkCreateShareOptions.push({
user: shareOption.userId,
permissions: shareOption.permissions,
keychain: Object.keys(sharedKeychain ?? {}).length === 0 ? undefined : sharedKeychain,
Expand All @@ -1548,25 +1549,19 @@ export class Wallet implements IWallet {
}

/**
* Creates bulk key shares for the given wallet.
* Creates bulk wallet share entries for specified share options.
* Filters out share options that do not contain valid keychain information or have missing keychain fields.
* If all share options are invalid or empty, it throws an error.
* Sends a POST request to create the wallet shares for valid share options.
*
* @async
* @param {BulkCreateShareOptions} [params={ shareOptions: [] }] - The options for creating bulk key shares.
* @param {Array<ShareOption>} params.shareOptions - An array of share option objects containing keychain information.
* @param {Object} params.shareOptions[].keychain - The keychain object for each share option.
* @param {string} params.shareOptions[].keychain.pub - The public key of the keychain.
* @param {string} params.shareOptions[].keychain.encryptedPrv - The encrypted private key of the keychain.
* @param {string} params.shareOptions[].keychain.fromPubKey - The sender's public key.
* @param {string} params.shareOptions[].keychain.toPubKey - The recipient's public key.
* @param {string} params.shareOptions[].keychain.path - The derivation path of the keychain.
* @throws {Error} If `shareOptions` is empty or any required keychain parameter is missing.
* @returns {Promise<CreateBulkWalletShareListResponse>} A promise that resolves with the result of the bulk key shares creation request.
*/

async createBulkKeyShares(
params: BulkCreateShareOptions = { shareOptions: [] }
): Promise<CreateBulkWalletShareListResponse> {
const filteredShareOptions = params.shareOptions.filter((shareOption) => {
* @param {BulkCreateShareOption[]} [params=[]] - The array of share options to process.
* Keychain entries must include the following fields: `pub`, `encryptedPrv`, `fromPubKey`, `toPubKey`, and `path`.
* @returns {Promise<CreateBulkWalletShareListResponse>} A promise resolving to the result of the wallet shares creation.
* @throws {Error} Throws an error if no valid share options are provided.
*/
async createBulkKeyShares(params: BulkCreateShareOption[] = []): Promise<CreateBulkWalletShareListResponse> {
const filteredShareOptions = params.filter((shareOption) => {
try {
if (shareOption.keychain) {
// Validate that all keychain fields are present
Expand All @@ -1581,15 +1576,14 @@ export class Wallet implements IWallet {
return false;
}
});
params.shareOptions = filteredShareOptions;
params = filteredShareOptions;

if (!params.shareOptions || Object.keys(params.shareOptions).length === 0) {
if (!params || Object.keys(params).length === 0) {
throw new Error('shareOptions cannot be empty');
}

const url = this.bitgo.url(`/wallet/${this._wallet.id}/walletshares`, 2);

return this.bitgo.post(url).send(params).result();
return this.bitgo.post(url).send({ shareOptions: params }).result();
}

/**
Expand Down

0 comments on commit 9f5ffba

Please sign in to comment.