Skip to content

Commit

Permalink
Add operation errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben-Rey committed Mar 4, 2024
1 parent 2f7985a commit 5f45635
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 80 deletions.
87 changes: 52 additions & 35 deletions src/bearbyWallet/BearbyAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { IAccount } from '../account/IAccount';
import { AddressInfo, web3 } from '@hicaru/bearby.js';
import { postRequest } from '../massaStation/RequestHandler';
import { IAccountSignOutput } from '../account/AccountSign';
import { operationErrorMapping } from '../errors/utils/errorMapping';
/**
* The maximum allowed gas for a read operation
*/
Expand Down Expand Up @@ -103,29 +104,40 @@ export class BearbyAccount implements IAccount {
if (data instanceof Buffer) {
strData = data.toString();
}
const signature = await web3.wallet.signMessage(strData);
return {
publicKey: signature.publicKey,
base58Encoded: signature.signature,
};
try {
const signature = await web3.wallet.signMessage(strData);

return {
publicKey: signature.publicKey,
base58Encoded: signature.signature,
};
} catch (error) {
throw operationErrorMapping('sign', error);
}
}

public async buyRolls(amount: bigint): Promise<ITransactionDetails> {
await this.connect();
const operationId = await web3.massa.buyRolls(amount.toString());

return {
operationId,
} as ITransactionDetails;
try {
const operationId = await web3.massa.buyRolls(amount.toString());
return {
operationId,
};
} catch (error) {
throw operationErrorMapping('buyRolls', error);
}
}

public async sellRolls(amount: bigint): Promise<ITransactionDetails> {
await this.connect();
const operationId = await web3.massa.sellRolls(amount.toString());

return {
operationId,
} as ITransactionDetails;
try {
const operationId = await web3.massa.sellRolls(amount.toString());
return {
operationId,
};
} catch (error) {
throw operationErrorMapping('sellRolls', error);
}
}

public async sendTransaction(
Expand All @@ -134,12 +146,16 @@ export class BearbyAccount implements IAccount {
): Promise<ITransactionDetails> {
await this.connect();

const operationId = await web3.massa.payment(
amount.toString(),
recipientAddress,
);
try {
const operationId = await web3.massa.payment(
amount.toString(),
recipientAddress,
);

return { operationId };
return { operationId };
} catch (error) {
throw operationErrorMapping('sendTransaction', error);
}
}

public async callSC(
Expand All @@ -164,22 +180,23 @@ export class BearbyAccount implements IAccount {
);
}

let unsafeParameters: Uint8Array;
if (parameter instanceof Uint8Array) {
unsafeParameters = parameter;
} else {
unsafeParameters = Uint8Array.from(parameter.serialize());
const unsafeParameters =
parameter instanceof Uint8Array
? parameter
: Uint8Array.from(parameter.serialize());
let operationId;
try {
operationId = await web3.contract.call({
maxGas: Number(maxGas),
coins: Number(amount),
fee: Number(fee),
targetAddress: contractAddress,
functionName: functionName,
unsafeParameters,
});
} catch (error) {
throw operationErrorMapping('callSC', error);
}

const operationId = await web3.contract.call({
maxGas: Number(maxGas),
coins: Number(amount),
fee: Number(fee),
targetAddress: contractAddress,
functionName: functionName,
unsafeParameters,
});

return { operationId };
}

Expand Down
2 changes: 1 addition & 1 deletion src/errors/BaseError.spec.ts → src/errors/base.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BaseError from './BaseError';
import { BaseError } from './base';

test('BaseError', () => {
expect(new BaseError('An error occurred.').message).toBe(
Expand Down
6 changes: 4 additions & 2 deletions src/errors/BaseError.ts → src/errors/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type BaseErrorParameters = {
export type BaseErrorParameters = {
docsPath?: string;
metaMessages?: string[];
} & (
Expand All @@ -12,7 +12,9 @@ type BaseErrorParameters = {
}
);

export default class BaseError extends Error {
export type BaseErrorType = BaseError & { name: 'WalletProviderError' };

export class BaseError extends Error {
metaMessages: string[];
docsPath?: string;
override name = 'WalletProviderError';
Expand Down
5 changes: 5 additions & 0 deletions src/errors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { BaseError, type BaseErrorType } from './base';
export {
UserRejectionError,
type UserRejectionErrorType,
} from './userRejection';
10 changes: 10 additions & 0 deletions src/errors/userRejection.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { UserRejectionError } from './userRejection';

test('userRejection', () => {
const operationName = 'operation';
expect(
new UserRejectionError({
operationName: operationName,
}).message,
).toBe(`The operation ${operationName} was rejected by the user.`);
});
13 changes: 13 additions & 0 deletions src/errors/userRejection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BaseError } from './base';

export type UserRejectionErrorType = UserRejectionError & {
name: 'UserRejectionError';
};

export class UserRejectionError extends BaseError {
override name = 'UserRejectionError';

constructor({ operationName }) {
super(`The operation ${operationName} was rejected by the user.`);
}
}
40 changes: 40 additions & 0 deletions src/errors/utils/errorMapping.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { UserRejectionError } from '../userRejection';
import { isUserRejectionError, operationErrorMapping } from './errorMapping';

const massaUserRejectionErrorMessage = 'Action canceled by user';
const bearbyUserRejectionErrorMessage = 'User rejected';
const someOtherErrorMessage = 'Some other error';

describe('isUserRejectionError', () => {
it('should return true if error message includes "User rejected"', () => {
const error = new Error(massaUserRejectionErrorMessage);
expect(isUserRejectionError(error)).toBe(true);
});

it('should return true if error message includes "Action canceled by user"', () => {
const error = new Error(bearbyUserRejectionErrorMessage);
expect(isUserRejectionError(error)).toBe(true);
});

it('should return false if error message does not include specific rejection messages', () => {
const error = new Error(someOtherErrorMessage);
expect(isUserRejectionError(error)).toBe(false);
});
});

describe('operationErrorMapping', () => {
it('should return a UserRejectionError if the error is a user rejection error', () => {
const error = new Error('User rejected');
const mappedError = operationErrorMapping('someOperation', error);
expect(mappedError).toBeInstanceOf(UserRejectionError);
expect(mappedError.message).toBe(
'The operation someOperation was rejected by the user.',
);
});

it('should return the original error if the error is not a user rejection error', () => {
const error = new Error(someOtherErrorMessage);
const mappedError = operationErrorMapping('someOperation', error);
expect(mappedError).toBe(error);
});
});
24 changes: 24 additions & 0 deletions src/errors/utils/errorMapping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { UserRejectionError } from '../userRejection';

export function isUserRejectionError(error: Error): boolean {
const bearbyUserRejectionErrorMessage = 'User rejected';
const massaUserRejectionErrorMessage = 'Action canceled by user';
return (
error.message &&
(error.message.includes(bearbyUserRejectionErrorMessage) ||
error.message.includes(massaUserRejectionErrorMessage))
);
}

export function operationErrorMapping(
operationName: string,
error: Error,
): Error {
if (isUserRejectionError(error)) {
return new UserRejectionError({
operationName: operationName,
});
} else {
return error;
}
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export {
Provider,
} from './provider';

export * from './errors';

export { IMassaStationWallet } from './massaStation/MassaStationProvider';

export { MassaStationAccount } from './massaStation/MassaStationAccount';
Expand Down
64 changes: 22 additions & 42 deletions src/massaStation/MassaStationAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { argsToBase64, uint8ArrayToBase64 } from '../utils/argsToBase64';
import { IAccountSignOutput, ISignMessage } from '../account/AccountSign';
import { encode as base58Encode } from 'bs58check';
import { ExecuteFunctionBody } from './types';
import { operationErrorMapping } from '../errors/utils/errorMapping';

/**
* This interface represents the the individual wallet's final and pending balances returned by MassaStation
Expand Down Expand Up @@ -138,18 +139,13 @@ export class MassaStationAccount implements IAccount {
DisplayData: true,
};

try {
signOpResponse = await postRequest<IAccountSignResponse>(
`${MASSA_STATION_ACCOUNTS_URL}/${this._name}/signMessage`,
signData,
);
} catch (ex) {
console.error(`MassaStation account signing error`);
throw ex;
}
signOpResponse = await postRequest<IAccountSignResponse>(
`${MASSA_STATION_ACCOUNTS_URL}/${this._name}/signMessage`,
signData,
);

if (signOpResponse.isError || signOpResponse.error) {
throw signOpResponse.error;
throw operationErrorMapping('sign', signOpResponse.error);
}

const signature = base58Encode(
Expand Down Expand Up @@ -180,14 +176,11 @@ export class MassaStationAccount implements IAccount {
amount: amount.toString(),
side: 'buy',
};
try {
buyRollsOpResponse = await postRequest<ITransactionDetails>(url, body);
} catch (ex) {
console.error(`MassaStation account: error while buying rolls: ${ex}`);
throw ex;
}

buyRollsOpResponse = await postRequest<ITransactionDetails>(url, body);

if (buyRollsOpResponse.isError || buyRollsOpResponse.error) {
throw buyRollsOpResponse.error;
operationErrorMapping('buyRolls', buyRollsOpResponse.error);
}
return buyRollsOpResponse.result;
}
Expand All @@ -210,14 +203,11 @@ export class MassaStationAccount implements IAccount {
amount: amount.toString(),
side: 'sell',
};
try {
sellRollsOpResponse = await postRequest<ITransactionDetails>(url, body);
} catch (ex) {
console.error(`MassaStation account: error while selling rolls: ${ex}`);
throw ex;
}

sellRollsOpResponse = await postRequest<ITransactionDetails>(url, body);

if (sellRollsOpResponse.isError || sellRollsOpResponse.error) {
throw sellRollsOpResponse.error;
operationErrorMapping('sellRolls', sellRollsOpResponse.error);
}
return sellRollsOpResponse.result;
}
Expand All @@ -242,17 +232,12 @@ export class MassaStationAccount implements IAccount {
recipientAddress: recipientAddress,
};

try {
sendTxOpResponse = await postRequest<ITransactionDetails>(url, body);
} catch (ex) {
console.error(
`MassaStation account: error while sending transaction: ${ex}`,
);
throw ex;
}
sendTxOpResponse = await postRequest<ITransactionDetails>(url, body);

if (sendTxOpResponse.isError || sendTxOpResponse.error) {
throw sendTxOpResponse.error;
throw operationErrorMapping('sendTransaction', sendTxOpResponse.error);
}

return sendTxOpResponse.result;
}

Expand Down Expand Up @@ -313,16 +298,11 @@ export class MassaStationAccount implements IAccount {
maxGas: maxGas ? maxGas.toString() : '',
async: true,
};
try {
CallSCOpResponse = await postRequest<ITransactionDetails>(url, body);
} catch (ex) {
console.log(
`MassaStation account: error while interacting with smart contract: ${ex}`,
);
throw ex;
}

CallSCOpResponse = await postRequest<ITransactionDetails>(url, body);

if (CallSCOpResponse.isError || CallSCOpResponse.error) {
throw CallSCOpResponse.error;
throw operationErrorMapping('callSmartContract', CallSCOpResponse.error);
}
return CallSCOpResponse.result;
}
Expand Down

0 comments on commit 5f45635

Please sign in to comment.