diff --git a/src/api-client.ts b/src/api-client.ts index cfd8915d..7afbad42 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -50,35 +50,26 @@ export class ApiClient { }; } - public async issueGetRequest(path: string): Promise { + public async issueGetRequest(path: string, requestOptions?: RequestOptions): Promise { const token = this.authProvider.signJwt(path); const res = await this.axiosInstance.get(path, { - headers: {"Authorization": `Bearer ${token}`} + headers: this.getHeaders(token, requestOptions) }); return res.data; } public async issuePostRequest(path: string, body: any, requestOptions?: RequestOptions): Promise { const token = this.authProvider.signJwt(path, body); - const headers: any = {"Authorization": `Bearer ${token}`}; - const idempotencyKey = requestOptions?.idempotencyKey; - if (idempotencyKey) { - headers["Idempotency-Key"] = idempotencyKey; - } - - const ncwWalletId = requestOptions?.ncw?.walletId; - if (ncwWalletId) { - headers["X-End-User-Wallet-Id"] = ncwWalletId; - } - - const response = await this.axiosInstance.post(path, body, {headers}); + const response = await this.axiosInstance.post(path, body, { + headers: this.getHeaders(token, requestOptions) + }); return response.data; } - public async issuePutRequest(path: string, body: any): Promise { + public async issuePutRequest(path: string, body: any, requestOptions?: RequestOptions): Promise { const token = this.authProvider.signJwt(path, body); const res = (await this.axiosInstance.put(path, body, { - headers: {"Authorization": `Bearer ${token}`} + headers: this.getHeaders(token, requestOptions) })); return res.data; } @@ -86,7 +77,7 @@ export class ApiClient { public async issuePatchRequest(path: string, body: any): Promise { const token = this.authProvider.signJwt(path, body); const res = (await this.axiosInstance.patch(path, body, { - headers: {"Authorization": `Bearer ${token}`} + headers: this.getHeaders(token) })); return res.data; } @@ -94,8 +85,25 @@ export class ApiClient { public async issueDeleteRequest(path: string): Promise { const token = this.authProvider.signJwt(path); const res = (await this.axiosInstance.delete(path, { - headers: {"Authorization": `Bearer ${token}`} + headers: this.getHeaders(token), })); return res.data; } + + private getHeaders(token: string, requestOptions?: RequestOptions) { + const headers: any = { + "Authorization": `Bearer ${token}`, + }; + + const idempotencyKey = requestOptions?.idempotencyKey; + if (idempotencyKey) { + headers["Idempotency-Key"] = idempotencyKey; + } + const ncwWalletId = requestOptions?.ncw?.walletId; + if (ncwWalletId) { + headers["X-End-User-Wallet-Id"] = ncwWalletId; + } + + return headers; + } } diff --git a/src/fireblocks-sdk.ts b/src/fireblocks-sdk.ts index 9ff805be..7c2c7ad9 100644 --- a/src/fireblocks-sdk.ts +++ b/src/fireblocks-sdk.ts @@ -106,10 +106,10 @@ import { } from "./types"; import { AxiosProxyConfig, AxiosResponse } from "axios"; import { PIIEncryption } from "./pii-client"; -import { NcwApiClient } from "./ncw-api-client"; -import { NcwSdk } from "./ncw-sdk"; +import { NcwApiClient } from "./ncw/ncw-api-client"; export * from "./types"; +export * from "./ncw/types"; export interface SDKOptions { /** HTTP request timeout */ @@ -178,9 +178,9 @@ export class FireblocksSDK { * NCW API Namespace * * @readonly - * @type {NcwSdk} + * @type {NcwApiClient} */ - public get NCW(): NcwSdk { + public get NCW(): NcwApiClient { return this.apiNcw; } diff --git a/src/ncw-api-client.ts b/src/ncw/api-client-admin.ts similarity index 63% rename from src/ncw-api-client.ts rename to src/ncw/api-client-admin.ts index a45755a4..350ecfa3 100644 --- a/src/ncw-api-client.ts +++ b/src/ncw/api-client-admin.ts @@ -1,48 +1,35 @@ -import { ApiClient } from "./api-client"; -import { - AssetResponse, - Web3PagedResponse, - NCW, -} from "./types"; -import { NcwSdk } from "./ncw-sdk"; +import { ApiClient } from "../api-client"; +import { AssetResponse, NCW, Web3PagedResponse } from "../types"; +import { INcwAdminSdk } from "./types"; -export class NcwApiClient implements NcwSdk { - private readonly NCW_BASE_PATH = "/v1/ncw/wallets"; +export class NcwAdminSdk implements INcwAdminSdk { - constructor(private readonly apiClient: ApiClient) { } + constructor(private readonly apiClient: ApiClient, private readonly BASE_PATH: string) { } public async createWallet(): Promise<{ walletId: string; enabled: boolean; }> { return await this.apiClient.issuePostRequest( - `${this.NCW_BASE_PATH}`, - {}); + `${this.BASE_PATH}`, + {}, + ); } public async getWallet(walletId: string): Promise<{ walletId: string; enabled: boolean; }> { return await this.apiClient.issueGetRequest( - `${this.NCW_BASE_PATH}/${walletId}`); - } - - public async enableWallet(walletId: string, enabled: boolean): Promise { - return await this.apiClient.issuePutRequest( - `${this.NCW_BASE_PATH}/${walletId}/enable`, - { enabled }); + `${this.BASE_PATH}/${walletId}`, + ); } public async getWalletDevices(walletId: string): Promise { return await this.apiClient.issueGetRequest( - `${this.NCW_BASE_PATH}/${walletId}/devices/`); + `${this.BASE_PATH}/${walletId}/devices/`, + ); } public async enableWalletDevice(walletId: string, deviceId: string, enabled: boolean): Promise { return await this.apiClient.issuePutRequest( - `${this.NCW_BASE_PATH}/${walletId}/devices/${deviceId}/enable`, - { enabled }); - } - - public async invokeWalletRpc(walletId: string, deviceId: string, payload: string): Promise<{ result: string; } | { error: { message: string; code?: number; }; }> { - return await this.apiClient.issuePostRequest( - `${this.NCW_BASE_PATH}/${walletId}/devices/${deviceId}/invoke`, - { payload }); + `${this.BASE_PATH}/${walletId}/devices/${deviceId}/enable`, + { enabled }, + ); } public async createWalletAccount(walletId: string): Promise<{ @@ -50,8 +37,9 @@ export class NcwApiClient implements NcwSdk { accountId: number; }> { return await this.apiClient.issuePostRequest( - `${this.NCW_BASE_PATH}/${walletId}/accounts`, - {}); + `${this.BASE_PATH}/${walletId}/accounts`, + {}, + ); } public async getWallets({ pageCursor, pageSize, sort, order }: NCW.GetWalletsPayload = {}): Promise> { @@ -62,7 +50,7 @@ export class NcwApiClient implements NcwSdk { ...(order && { order }), }); - return await this.apiClient.issueGetRequest(`${this.NCW_BASE_PATH}?${params.toString()}`); + return await this.apiClient.issueGetRequest(`${this.BASE_PATH}?${params.toString()}`); } public async getWalletAccounts(walletId: string, { pageCursor, pageSize, sort, order }: NCW.GetWalletsPayload = {}): Promise { return await this.apiClient.issueGetRequest( - `${this.NCW_BASE_PATH}/${walletId}/accounts/${accountId}`); + `${this.BASE_PATH}/${walletId}/accounts/${accountId}`, + ); } public async getWalletAssets(walletId: string, accountId: number, { pageCursor, pageSize, sort, order }: NCW.GetWalletAssetsPayload = {}): Promise> { @@ -97,17 +87,21 @@ export class NcwApiClient implements NcwSdk { }); return await this.apiClient.issueGetRequest( - `${this.NCW_BASE_PATH}/${walletId}/accounts/${accountId}/assets?${params.toString()}`); + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets?${params.toString()}`, + ); } public async getWalletAsset(walletId: string, accountId: number, assetId: string): Promise { return await this.apiClient.issueGetRequest( - `${this.NCW_BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}`); + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}`, + ); } public async activateWalletAsset(walletId: string, accountId: number, assetId: string): Promise { return await this.apiClient.issuePostRequest( - `${this.NCW_BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}`, {}); + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}`, + {}, + ); } public async getWalletAssetAddresses(walletId: string, accountId: number, assetId: string, { pageCursor, pageSize, sort, order }: NCW.GetWalletAddressesPayload = {}): Promise> { @@ -119,17 +113,20 @@ export class NcwApiClient implements NcwSdk { }); return await this.apiClient.issueGetRequest( - `${this.NCW_BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/addresses?${params.toString()}`); + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/addresses?${params.toString()}`, + ); } public async getWalletAssetBalance(walletId: string, accountId: number, assetId: string): Promise { return await this.apiClient.issueGetRequest( - `${this.NCW_BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/balance`); + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/balance`, + ); } public async refreshWalletAssetBalance(walletId: string, accountId: number, assetId: string): Promise { return await this.apiClient.issuePutRequest( - `${this.NCW_BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/balance`, - {}); + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/balance`, + {}, + ); } } diff --git a/src/ncw/api-client-signer.ts b/src/ncw/api-client-signer.ts new file mode 100644 index 00000000..25325496 --- /dev/null +++ b/src/ncw/api-client-signer.ts @@ -0,0 +1,150 @@ +import { ApiClient } from "../api-client"; +import { AssetResponse, NCW, RequestOptions, Web3PagedResponse } from "../types"; +import { INcwSignerSdk } from "./types"; + +export class NcwSignerSdk implements INcwSignerSdk { + + constructor(private readonly apiClient: ApiClient, private readonly BASE_PATH: string) { } + + public async getWallet(walletId: string): Promise<{ walletId: string; enabled: boolean; }> { + return await this.apiClient.issueGetRequest( + `${this.BASE_PATH}/${walletId}`, + this.getRequestOptions(walletId), + ); + } + + public async enableWallet(walletId: string, enabled: boolean): Promise { + return await this.apiClient.issuePutRequest( + `${this.BASE_PATH}/${walletId}/enable`, + { enabled }, + this.getRequestOptions(walletId), + ); + } + + public async getWalletDevices(walletId: string): Promise { + return await this.apiClient.issueGetRequest( + `${this.BASE_PATH}/${walletId}/devices/`, + this.getRequestOptions(walletId), + ); + } + + public async enableWalletDevice(walletId: string, deviceId: string, enabled: boolean): Promise { + return await this.apiClient.issuePutRequest( + `${this.BASE_PATH}/${walletId}/devices/${deviceId}/enable`, + { enabled }, + this.getRequestOptions(walletId), + ); + } + + public async invokeWalletRpc(walletId: string, deviceId: string, payload: string): Promise<{ result: string; } | { error: { message: string; code?: number; }; }> { + return await this.apiClient.issuePostRequest( + `${this.BASE_PATH}/${walletId}/devices/${deviceId}/invoke`, + { payload }, + this.getRequestOptions(walletId), + ); + } + + public async createWalletAccount(walletId: string): Promise<{ + walletId: string; + accountId: number; + }> { + return await this.apiClient.issuePostRequest( + `${this.BASE_PATH}/${walletId}/accounts`, + {}, + this.getRequestOptions(walletId), + ); + } + + public async getWalletAccounts(walletId: string, { pageCursor, pageSize, sort, order }: NCW.GetWalletsPayload = {}): Promise> { + const params = new URLSearchParams({ + ...(pageCursor && { pageCursor }), + ...(pageSize && { pageSize: pageSize.toString() }), + ...(sort && { sort }), + ...(order && { order }), + }); + + return await this.apiClient.issueGetRequest( + `${this.BASE_PATH}/${walletId}/accounts?${params.toString()}`, + this.getRequestOptions(walletId), + ); + } + + public async getWalletAccount(walletId: string, accountId: number): Promise<{ + walletId: string; + accountId: number; + }> { + return await this.apiClient.issueGetRequest( + `${this.BASE_PATH}/${walletId}/accounts/${accountId}`, + this.getRequestOptions(walletId), + ); + } + + public async getWalletAssets(walletId: string, accountId: number, { pageCursor, pageSize, sort, order }: NCW.GetWalletAssetsPayload = {}): Promise> { + const params = new URLSearchParams({ + ...(pageCursor && { pageCursor }), + ...(pageSize && { pageSize: pageSize.toString() }), + ...(sort && { sort }), + ...(order && { order }), + }); + + return await this.apiClient.issueGetRequest( + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets?${params.toString()}`, + this.getRequestOptions(walletId), + ); + } + + public async getWalletAsset(walletId: string, accountId: number, assetId: string): Promise { + return await this.apiClient.issueGetRequest( + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}`, + this.getRequestOptions(walletId), + ); + } + + public async activateWalletAsset(walletId: string, accountId: number, assetId: string): Promise { + return await this.apiClient.issuePostRequest( + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}`, + {}, + this.getRequestOptions(walletId), + ); + } + + public async getWalletAssetAddresses(walletId: string, accountId: number, assetId: string, { pageCursor, pageSize, sort, order }: NCW.GetWalletAddressesPayload = {}): Promise> { + const params = new URLSearchParams({ + ...(pageCursor && { pageCursor }), + ...(pageSize && { pageSize: pageSize.toString() }), + ...(sort && { sort }), + ...(order && { order }), + }); + + return await this.apiClient.issueGetRequest( + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/addresses?${params.toString()}`, + this.getRequestOptions(walletId), + ); + } + + public async getWalletAssetBalance(walletId: string, accountId: number, assetId: string): Promise { + return await this.apiClient.issueGetRequest( + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/balance`, + this.getRequestOptions(walletId), + ); + } + + public async refreshWalletAssetBalance(walletId: string, accountId: number, assetId: string): Promise { + return await this.apiClient.issuePutRequest( + `${this.BASE_PATH}/${walletId}/accounts/${accountId}/assets/${assetId}/balance`, + {}, + this.getRequestOptions(walletId), + ); + } + + private getRequestOptions(walletId: string): RequestOptions { + return { + ncw: { + walletId, + }, + }; + } +} diff --git a/src/ncw/ncw-api-client.ts b/src/ncw/ncw-api-client.ts new file mode 100644 index 00000000..0cb4497c --- /dev/null +++ b/src/ncw/ncw-api-client.ts @@ -0,0 +1,23 @@ +import { ApiClient } from "../api-client"; +import { NcwAdminSdk } from "./api-client-admin"; +import { NcwSignerSdk } from "./api-client-signer"; + +export class NcwApiClient { + private readonly _admin: NcwAdminSdk; + private readonly _signer: NcwSignerSdk; + + private readonly NCW_BASE_PATH = "/v1/ncw/wallets"; + + constructor(readonly apiClient: ApiClient) { + this._admin = new NcwAdminSdk(apiClient, this.NCW_BASE_PATH); + this._signer = new NcwSignerSdk(apiClient, this.NCW_BASE_PATH); + } + + public get admin(): NcwAdminSdk { + return this._admin; + } + public get signer(): NcwSignerSdk { + return this._signer; + } + +} diff --git a/src/ncw-sdk.ts b/src/ncw/types.ts similarity index 95% rename from src/ncw-sdk.ts rename to src/ncw/types.ts index c6b7a658..4e64d170 100644 --- a/src/ncw-sdk.ts +++ b/src/ncw/types.ts @@ -1,13 +1,8 @@ import { AssetResponse, Web3PagedResponse, NCW, -} from "./types"; - -export interface NcwSdk { - /** - * Create a new NCW wallet - */ - createWallet(): Promise<{ walletId: string; enabled: boolean; }>; +} from "../types"; +interface NcwSdk { /** * Get a NCW wallet * @@ -15,15 +10,6 @@ export interface NcwSdk { */ getWallet(walletId: string): Promise<{ walletId: string; enabled: boolean; }>; - /** - * Enable a NCW wallet - * - * @param {string} walletId - * @param {boolean} enabled - */ - enableWallet(walletId: string, enabled: boolean): Promise; - - /** * Get NCW wallet devices * @@ -42,16 +28,6 @@ export interface NcwSdk { */ enableWalletDevice(walletId: string, deviceId: string, enabled: boolean): Promise; - /** - * Invoke NCW wallet RPC call - * - * @param {string} walletId - * @param {string} deviceId - * @param {string} payload - * @return {*} {(Promise<{ result: string } | { error: { message: string, code?: number } }>)} - */ - invokeWalletRpc(walletId: string, deviceId: string, payload: string): Promise<{ result: string; } | { error: { message: string; code?: number; }; }>; - /** * Create a new NCW wallet account * @@ -62,14 +38,6 @@ export interface NcwSdk { accountId: number; }>; - /** - * Get NCW wallets - * - * @param {GetWalletsPayload} { pageCursor, pageSize, sort, order } - * @return {*} {Promise>} - */ - getWallets({ pageCursor, pageSize, sort, order }: NCW.GetWalletsPayload): Promise>; - /** * Get NCW accounts * @@ -153,3 +121,43 @@ export interface NcwSdk { */ refreshWalletAssetBalance(walletId: string, accountId: number, assetId: string): Promise; } + +export interface INcwAdminSdk extends NcwSdk { + /** + * Create a new NCW wallet + */ + createWallet(): Promise<{ walletId: string; enabled: boolean; }>; + + /** + * Get NCW wallets + * + * @param {GetWalletsPayload} { pageCursor, pageSize, sort, order } + * @return {*} {Promise>} + */ + getWallets({ pageCursor, pageSize, sort, order }: NCW.GetWalletsPayload): Promise>; + +} + +export interface INcwSignerSdk extends NcwSdk { + /** + * Enable a NCW wallet + * + * @param {string} walletId + * @param {boolean} enabled + */ + + enableWallet(walletId: string, enabled: boolean): Promise; + /** + * Invoke NCW wallet RPC call + * + * @param {string} walletId + * @param {string} deviceId + * @param {string} payload + * @return {*} {(Promise<{ result: string } | { error: { message: string, code?: number } }>)} + */ + invokeWalletRpc(walletId: string, deviceId: string, payload: string): Promise<{ result: string; } | { error: { message: string; code?: number; }; }>; +} + +export * from "./ncw-api-client"; +export * from "./api-client-admin"; +export * from "./api-client-signer";