From c828e7b67f76bdce4e422ecc8d751ade99da8650 Mon Sep 17 00:00:00 2001 From: Peterjah Date: Tue, 11 Feb 2025 16:20:25 +0100 Subject: [PATCH] refactor MS wallet api error handling --- src/massaStation/MassaStationAccount.ts | 95 +++++++++++------------ src/massaStation/MassaStationDiscovery.ts | 27 ++++--- src/massaStation/MassaStationWallet.ts | 46 +++-------- src/massaStation/RequestHandler.ts | 64 +++++++-------- src/massaStation/utils/network.ts | 9 +-- src/metamaskSnap/snap.ts | 3 +- src/walletsManager/walletList.ts | 1 + src/walletsManager/walletsListener.ts | 1 + test-e2e/massaStation/utils/utils.ts | 1 + test-e2e/massaStation/wallet.spec.ts | 1 + 10 files changed, 110 insertions(+), 138 deletions(-) diff --git a/src/massaStation/MassaStationAccount.ts b/src/massaStation/MassaStationAccount.ts index e5485625..ec478a5f 100644 --- a/src/massaStation/MassaStationAccount.ts +++ b/src/massaStation/MassaStationAccount.ts @@ -65,13 +65,11 @@ export class MassaStationAccount implements Provider { } public async balance(final = false): Promise { - const res = await getRequest( + const { result } = await getRequest( `${MASSA_STATION_URL}massa/addresses?attributes=balance&addresses=${this.address}`, ); - if (res.isError) throw res.error; - - const balances = res.result.addressesAttributes[this.address].balance; + const balances = result.addressesAttributes[this.address].balance; return Mas.fromString(final ? balances.final : balances.pending); } @@ -87,14 +85,12 @@ export class MassaStationAccount implements Provider { queryParams.append('addresses', address); }); - const res = await getRequest( + const { result } = await getRequest( `${MASSA_STATION_URL}massa/addresses?${queryParams.toString()}`, ); - if (res.isError) throw res.error; - return addresses.map((address) => { - const balance = res.result.addressesAttributes[address].balance; + const balance = result.addressesAttributes[address].balance; return { address, @@ -113,24 +109,24 @@ export class MassaStationAccount implements Provider { DisplayData: opts?.displayData ?? true, }; - const res = await postRequest( - `${walletApiUrl()}/accounts/${this.accountName}/signMessage`, - signData, - ); - - if (res.isError) { - throw errorHandler(operationType.Sign, res.error); - } + try { + const { result } = await postRequest( + `${walletApiUrl()}/accounts/${this.accountName}/signMessage`, + signData, + ); - // MS Wallet encodes signature in base64... so we need to decode it en re-encode it in base58 - const signature = bs58check.encode( - await base64ToByteArray(res.result.signature), - ); + // MS Wallet encodes signature in base64... so we need to decode it en re-encode it in base58 + const signature = bs58check.encode( + await base64ToByteArray(result.signature), + ); - return { - publicKey: res.result.publicKey, - signature, - }; + return { + publicKey: result.publicKey, + signature, + }; + } catch (error) { + throw errorHandler(operationType.Sign, error); + } } private async minimalFee(): Promise { @@ -150,16 +146,16 @@ export class MassaStationAccount implements Provider { amount: amount.toString(), side: type === operationType.BuyRolls ? 'buy' : 'sell', }; + try { + const { result } = await postRequest( + `${walletApiUrl()}/accounts/${this.accountName}/rolls`, + body, + ); - const res = await postRequest( - `${walletApiUrl()}/accounts/${this.accountName}/rolls`, - body, - ); - - if (res.isError) { - throw errorHandler(type, res.error); + return new Operation(this, result.operationId); + } catch (error) { + throw errorHandler(type, error); } - return new Operation(this, res.result.operationId); } public async buyRolls( @@ -189,16 +185,16 @@ export class MassaStationAccount implements Provider { recipientAddress: to.toString(), }; - const res = await postRequest( - `${walletApiUrl()}/accounts/${this.accountName}/transfer`, - body, - ); + try { + const { result } = await postRequest( + `${walletApiUrl()}/accounts/${this.accountName}/transfer`, + body, + ); - if (res.isError) { - throw errorHandler(operationType.SendTransaction, res.error); + return new Operation(this, result.operationId); + } catch (error) { + throw errorHandler(operationType.SendTransaction, error); } - - return new Operation(this, res.result.operationId); } public async callSC(params: CallSCParams): Promise { @@ -224,15 +220,16 @@ export class MassaStationAccount implements Provider { async: true, }; - const res = await postRequest( - `${MASSA_STATION_URL}cmd/executeFunction`, - body, - ); + try { + const { result } = await postRequest( + `${MASSA_STATION_URL}cmd/executeFunction`, + body, + ); - if (res.isError) { - throw errorHandler('callSmartContract', res.error); + return new Operation(this, result.operationId); + } catch (error) { + throw errorHandler('callSmartContract', error); } - return new Operation(this, res.result.operationId); } public async networkInfos(): Promise { @@ -290,12 +287,12 @@ export class MassaStationAccount implements Provider { )} $MAS fee for operation`, }; - const res = await postRequest( + const { result } = await postRequest( `${MASSA_STATION_URL}cmd/deploySC`, body, ); - const operationId = res.result?.operationId; + const operationId = result?.operationId; if (!operationId) throw new Error('Operation ID not found'); diff --git a/src/massaStation/MassaStationDiscovery.ts b/src/massaStation/MassaStationDiscovery.ts index a2d151f9..9f27b905 100644 --- a/src/massaStation/MassaStationDiscovery.ts +++ b/src/massaStation/MassaStationDiscovery.ts @@ -1,14 +1,17 @@ +import { MASSA_STATION_URL } from './MassaStationWallet'; import { JsonRpcResponseData, getRequest } from './RequestHandler'; import { PluginInfo } from './types'; // Constants for URLs and plugin information -const MASSA_STATION_URL = 'https://station.massa/plugin-manager'; const PLUGIN_NAME = 'Massa Wallet'; const PLUGIN_AUTHOR = 'Massa Labs'; const TIMEOUT = 4000; async function fetchPluginData(): Promise> { - return getRequest(MASSA_STATION_URL, TIMEOUT); + return getRequest( + MASSA_STATION_URL + 'plugin-manager', + TIMEOUT, + ); } function findWalletPlugin(plugins: PluginInfo[]): PluginInfo | undefined { @@ -18,18 +21,20 @@ function findWalletPlugin(plugins: PluginInfo[]): PluginInfo | undefined { } export async function isMassaStationAvailable(): Promise { - const response = await fetchPluginData(); - return !response.isError; + try { + await fetchPluginData(); + return true; + } catch (_) { + return false; + } } export async function isMassaWalletEnabled(): Promise { - const response = await fetchPluginData(); - - if (response.isError) { - console.warn('Error fetching plugin data:', response.error); + try { + const { result } = await fetchPluginData(); + const walletPlugin = findWalletPlugin(result); + return walletPlugin && walletPlugin.status === 'Up'; + } catch (_) { return false; } - - const walletPlugin = findWalletPlugin(response.result); - return walletPlugin && walletPlugin.status === 'Up'; } diff --git a/src/massaStation/MassaStationWallet.ts b/src/massaStation/MassaStationWallet.ts index bce25c9f..1617bba0 100644 --- a/src/massaStation/MassaStationWallet.ts +++ b/src/massaStation/MassaStationWallet.ts @@ -67,9 +67,6 @@ export class MassaStationWallet implements Wallet { public async accounts(): Promise { const res = await getRequest(walletApiUrl() + '/accounts'); - if (res.isError) { - throw res.error; - } return res.result .filter((account) => { return account.status === MassaStationAccountStatus.OK; @@ -83,13 +80,10 @@ export class MassaStationWallet implements Wallet { publicKey: string, privateKey: string, ): Promise { - const res = await putRequest(walletApiUrl() + '/accounts', { + await putRequest(walletApiUrl() + '/accounts', { publicKey, privateKey, }); - if (res.isError) { - throw res.error; - } } public async deleteAccount(address: string): Promise { @@ -98,8 +92,6 @@ export class MassaStationWallet implements Wallet { walletApiUrl() + '/accounts', ); - if (allAccounts.isError) throw allAccounts.error; - const accountToDelete = allAccounts.result.find( (account) => account.address === address, ); @@ -108,13 +100,9 @@ export class MassaStationWallet implements Wallet { throw new Error('Account not found'); } - const res = await deleteRequest( + await deleteRequest( `${walletApiUrl()}/accounts/${accountToDelete.nickname}`, ); - - if (res.isError) { - throw res.error; - } } public async networkInfos(): Promise { @@ -139,8 +127,6 @@ export class MassaStationWallet implements Wallet { {}, ); - if (response.isError) throw response.error; - return new MassaStationAccount( response.result.address, response.result.nickname, @@ -222,11 +208,8 @@ export class MassaStationWallet implements Wallet { * @returns The configuration of MS wallet. */ public async getConfig(): Promise { - const res = await getRequest(walletApiUrl() + '/config'); - if (res.isError) { - throw res.error; - } - return res.result; + const { result } = await getRequest(walletApiUrl() + '/config'); + return result; } /** @@ -242,7 +225,7 @@ export class MassaStationWallet implements Wallet { rule: SignRule, desc?: string, ): Promise { - const res = await postRequest( + const { result } = await postRequest( walletApiUrl() + '/accounts/' + accountName + '/signrules', { description: desc, @@ -252,10 +235,7 @@ export class MassaStationWallet implements Wallet { enabled: rule.enabled, }, ); - if (res.isError) { - throw res.error; - } - return res.result; + return result; } /** @@ -272,7 +252,7 @@ export class MassaStationWallet implements Wallet { rule: SignRule, desc?: string, ): Promise { - const res = await putRequest( + const { result } = await putRequest( walletApiUrl() + '/accounts/' + accountName + '/signrules/' + rule.id, { description: desc, @@ -282,11 +262,8 @@ export class MassaStationWallet implements Wallet { enabled: rule.enabled, }, ); - if (res.isError) { - console.log('error', res); - throw res.error; - } - return res.result; + + return result; } /** @@ -300,11 +277,8 @@ export class MassaStationWallet implements Wallet { accountName: string, ruleId: string, ): Promise { - const res = await deleteRequest( + await deleteRequest( walletApiUrl() + '/accounts/' + accountName + '/signrules/' + ruleId, ); - if (res.isError) { - throw res.error; - } } } diff --git a/src/massaStation/RequestHandler.ts b/src/massaStation/RequestHandler.ts index 5afb3fc0..60eb1479 100644 --- a/src/massaStation/RequestHandler.ts +++ b/src/massaStation/RequestHandler.ts @@ -17,17 +17,23 @@ const requestHeaders = { /** * This interface represents a payload returned by making an http call */ -export type JsonRpcResponseData = - | { - isError: false; - result: T; - error?: never; - } - | { - isError: true; - result?: never; - error: Error; - }; +export type JsonRpcResponseData = { + result: T; +}; + +/** + * Handles errors from Axios requests. + * + * @param error - The error object thrown by Axios. + * @throws a formatted error message. + */ +function handleAxiosError(error: any): never { + const err = error.response?.data?.message + ? new Error(String(error.response.data.message)) + : new Error('Axios error: ' + String(error)); + throw err; +} + /** * This method makes a GET request to an http rest point. * @@ -46,12 +52,9 @@ export async function getRequest( headers: requestHeaders, timeout, }); - return { isError: false, result: resp.data }; - } catch (ex) { - return { - isError: true, - error: new Error('Axios Error: ' + String(ex)), - }; + return { result: resp.data }; + } catch (error) { + handleAxiosError(error); } } @@ -73,14 +76,9 @@ export async function postRequest( headers: requestHeaders, }); - return { isError: false, result: resp.data }; + return { result: resp.data }; } catch (error) { - return { - isError: true, - error: error.response?.data?.message - ? new Error(String(error.response.data.message)) - : new Error('Axios error: ' + String(error)), - }; + handleAxiosError(error); } } @@ -101,12 +99,9 @@ export async function deleteRequest( headers: requestHeaders, }); - return { isError: false, result: resp.data }; - } catch (ex) { - return { - isError: true, - error: new Error('Axios Error: ' + String(ex)), - }; + return { result: resp.data }; + } catch (error) { + handleAxiosError(error); } } @@ -129,11 +124,8 @@ export async function putRequest( headers: requestHeaders, }); - return { isError: false, result: resp.data }; - } catch (ex) { - return { - isError: true, - error: new Error('Axios error: ' + String(ex)), - }; + return { result: resp.data }; + } catch (error) { + handleAxiosError(error); } } diff --git a/src/massaStation/utils/network.ts b/src/massaStation/utils/network.ts index 903041da..7f05f931 100644 --- a/src/massaStation/utils/network.ts +++ b/src/massaStation/utils/network.ts @@ -27,21 +27,20 @@ export async function networkInfos(): Promise { }; } - const nodesResponse = await getRequest( + const { result } = await getRequest( `${MASSA_STATION_URL}massa/node`, ); - if (nodesResponse.isError) throw nodesResponse.error.message; - const url = nodesResponse.result.url; + const url = result.url; if (!client || rpcUrl !== url) { client = new JsonRPCClient(url); rpcUrl = url; } return { - name: nodesResponse.result.network, + name: result.network, url, - chainId: BigInt(nodesResponse.result.chainId), + chainId: BigInt(result.chainId), minimalFee: await client.getMinimalFee(), }; } diff --git a/src/metamaskSnap/snap.ts b/src/metamaskSnap/snap.ts index 3e0a04da..b5568b4c 100644 --- a/src/metamaskSnap/snap.ts +++ b/src/metamaskSnap/snap.ts @@ -22,7 +22,8 @@ export const getMassaSnapInfo = async ( snap.id === MASSA_SNAP_ID && (!version || snap.version === version), ); } catch (error) { - console.error('Failed to obtain installed snap', error); + // eslint-disable-next-line no-console + console.error('Failed to get installed snap', error); return undefined; } }; diff --git a/src/walletsManager/walletList.ts b/src/walletsManager/walletList.ts index 67353b2f..92e5b5fb 100644 --- a/src/walletsManager/walletList.ts +++ b/src/walletsManager/walletList.ts @@ -19,6 +19,7 @@ export async function getWallets(delay = 200): Promise { try { return await WalletClass.createIfInstalled(); } catch (error) { + // eslint-disable-next-line no-console console.error(`Error initializing wallet ${WalletClass.name}:`, error); } return null; diff --git a/src/walletsManager/walletsListener.ts b/src/walletsManager/walletsListener.ts index 7865e87b..a6edd4d6 100644 --- a/src/walletsManager/walletsListener.ts +++ b/src/walletsManager/walletsListener.ts @@ -17,6 +17,7 @@ export class WalletsListener { callback(newWallets); } } catch (error) { + // eslint-disable-next-line no-console console.error('Error checking wallet list changes:', error); } } diff --git a/test-e2e/massaStation/utils/utils.ts b/test-e2e/massaStation/utils/utils.ts index 583d3cae..824f3518 100644 --- a/test-e2e/massaStation/utils/utils.ts +++ b/test-e2e/massaStation/utils/utils.ts @@ -27,6 +27,7 @@ export async function deleteStationAccountFromNickname( let account = accounts.find((account) => account.accountName === nickname); if (!account) { + // eslint-disable-next-line no-console console.log(`Account with nickname ${nickname} not found`); return; } diff --git a/test-e2e/massaStation/wallet.spec.ts b/test-e2e/massaStation/wallet.spec.ts index c8627754..2ca173b0 100644 --- a/test-e2e/massaStation/wallet.spec.ts +++ b/test-e2e/massaStation/wallet.spec.ts @@ -22,6 +22,7 @@ describe('MassaStation wallet tests', () => { } account = acc; const balance = await account.balance(); + // eslint-disable-next-line no-console console.log( `Using account ${account.accountName} with address ${ account.address