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
1 change: 1 addition & 0 deletions packages/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@kadena/client": "^1.18.0",
"@kadena/pactjs-cli": "^1.18.0",
"@ledgerhq/hw-transport-webusb": "^6.29.8",
"@massalabs/massa-web3": "5.2.1-dev.20250730141858",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify Massa Web3 dev version consistency and stability.

The extension uses the same dev version 5.2.1-dev.20250730141858 as the signer package. This development version should be verified for stability and consistency across the codebase.


🏁 Script executed:

#!/bin/bash
# Description: Check if the Massa Web3 version is used consistently across packages

# Search for all references to massa-web3 dependency
rg -A 2 -B 2 "@massalabs/massa-web3" --type json

# Check if there are any version mismatches
fd "package.json" --exec grep -l "massa-web3" {} \; | xargs grep "massa-web3"

Length of output: 1416


Standardize @massalabs/massa-web3 dev version across all packages

The extension is pinned to 5.2.1-dev.20250730141858, while both the types and signer packages use ^5.2.1-dev. This mismatch can lead to drift or unexpected behavior when newer dev builds are released.

Action items:

  • Decide on your desired workflow for dev builds:
    • If you want automatic updates to the latest dev build, use ^5.2.1-dev everywhere.
    • If you require a reproducible timestamped build, pin all three packages to 5.2.1-dev.20250730141858.
  • Verify that the chosen dev release is sufficiently stable for your release cadence.

Affected files:

  • packages/extension/package.json
  • packages/types/package.json
  • packages/signers/massa/package.json
🤖 Prompt for AI Agents
In packages/extension/package.json around line 42, the @massalabs/massa-web3 dev
version is pinned to 5.2.1-dev.20250730141858 while other packages use
^5.2.1-dev; standardize them by choosing one workflow and applying it to all
three files (packages/extension/package.json, packages/types/package.json,
packages/signers/massa/package.json): either replace the pinned timestamp with
^5.2.1-dev in extension to allow automatic dev updates, or update the versions
in types and signers to the exact timestamp 5.2.1-dev.20250730141858 to lock a
reproducible build; after changing, run your package manager to update the
lockfile (npm/yarn/pnpm install) and run the test/build suite to verify
stability.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we set this to a prod version?

"@metamask/eth-sig-util": "^8.2.0",
"@metaplex-foundation/mpl-bubblegum": "^5.0.2",
"@metaplex-foundation/umi": "^1.2.0",
Expand Down
1 change: 1 addition & 0 deletions packages/extension/src/libs/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class BackgroundHandler {
[ProviderName.bitcoin]: {},
[ProviderName.kadena]: {},
[ProviderName.solana]: {},
[ProviderName.massa]: {},
};
this.#providers = Providers;
}
Expand Down
5 changes: 4 additions & 1 deletion packages/extension/src/libs/background/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type EthereumProvider from '@/providers/ethereum';
import type PolkadotProvider from '@/providers/polkadot';
import type KadenaProvider from '@/providers/kadena';
import SolanaProvider from '@/providers/solana';
import MassaProvider from '@/providers/massa';

export interface TabProviderType {
[key: string]: Record<
Expand All @@ -12,6 +13,7 @@ export interface TabProviderType {
| BitcoinProvider
| KadenaProvider
| SolanaProvider
| MassaProvider
>;
}
export interface ProviderType {
Expand All @@ -20,7 +22,8 @@ export interface ProviderType {
| typeof PolkadotProvider
| typeof BitcoinProvider
| typeof KadenaProvider
| typeof SolanaProvider;
| typeof SolanaProvider
| typeof MassaProvider;
}
export interface ExternalMessageOptions {
savePersistentEvents: boolean;
Expand Down
3 changes: 2 additions & 1 deletion packages/extension/src/libs/tokens-state/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CustomToken,
CustomErc20Token,
TokenType,
CustomMassaToken,
} from './types';
import { NetworkNames } from '@enkryptcom/types';

Expand All @@ -24,7 +25,7 @@ export class TokensState {
*/
async addErc20Token(
chainName: NetworkNames,
token: CustomErc20Token,
token: CustomErc20Token | CustomMassaToken,
): Promise<boolean> {
let state: IState | null = await this.storage.get(StorageKeys.customTokens);

Expand Down
4 changes: 4 additions & 0 deletions packages/extension/src/libs/tokens-state/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ export interface CustomErc20Token extends CustomToken {
address: `0x${string}`;
}

export interface CustomMassaToken extends CustomToken {
address: `AS${string}`;
}

export type IState = Partial<Record<NetworkNames, CustomToken[]>>;
11 changes: 11 additions & 0 deletions packages/extension/src/libs/utils/initialize-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import PolkadotNetworks from '@/providers/polkadot/networks';
import BitcoinNetworks from '@/providers/bitcoin/networks';
import KadenaNetworks from '@/providers/kadena/networks';
import SolanaNetworks from '@/providers/solana/networks';
import MassaNetworks from '@/providers/massa/networks';
import { NetworkNames, WalletType } from '@enkryptcom/types';
import { getAccountsByNetworkName } from '@/libs/utils/accounts';
import BackupState from '../backup-state';
Expand All @@ -23,6 +24,9 @@ export const initAccounts = async (keyring: KeyRing) => {
const ed25519sol = (
await getAccountsByNetworkName(NetworkNames.Solana)
).filter(acc => !acc.isTestWallet);
const ed25519massa = (
await getAccountsByNetworkName(NetworkNames.Massa)
).filter(acc => !acc.isTestWallet);
if (secp256k1.length == 0)
await keyring.saveNewAccount({
basePath: EthereumNetworks.ethereum.basePath,
Expand Down Expand Up @@ -58,6 +62,13 @@ export const initAccounts = async (keyring: KeyRing) => {
signerType: SolanaNetworks.solana.signer[0],
walletType: WalletType.mnemonic,
});
if (ed25519massa.length == 0)
await keyring.saveNewAccount({
basePath: MassaNetworks.mainnet.basePath,
name: 'Massa Account 1',
signerType: MassaNetworks.mainnet.signer[0],
walletType: WalletType.mnemonic,
});
};
export const onboardInitializeWallets = async (options: {
mnemonic: string;
Expand Down
12 changes: 11 additions & 1 deletion packages/extension/src/libs/utils/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ import Polkadot from '@/providers/polkadot/networks/polkadot';
import Bitcoin from '@/providers/bitcoin/networks/bitcoin';
import Kadena from '@/providers/kadena/networks/kadena';
import Solana from '@/providers/solana/networks/solana';
import MassaNetworks from '@/providers/massa/networks';
import Massa from '@/providers/massa/networks/mainnet';

const providerNetworks: Record<ProviderName, Record<string, BaseNetwork>> = {
[ProviderName.ethereum]: EthereumNetworks,
[ProviderName.polkadot]: PolkadotNetworks,
[ProviderName.bitcoin]: BitcoinNetworks,
[ProviderName.kadena]: KadenaNetworks,
[ProviderName.solana]: SolanaNetworks,
[ProviderName.massa]: MassaNetworks,
[ProviderName.enkrypt]: {},
};
const getAllNetworks = async (
Expand All @@ -34,7 +37,9 @@ const getAllNetworks = async (
.concat(Object.values(PolkadotNetworks) as BaseNetwork[])
.concat(Object.values(BitcoinNetworks) as BaseNetwork[])
.concat(Object.values(KadenaNetworks) as BaseNetwork[])
.concat(Object.values(SolanaNetworks) as BaseNetwork[]);
.concat(Object.values(SolanaNetworks) as BaseNetwork[])
.concat(Object.values(MassaNetworks) as BaseNetwork[]);

if (!includeCustom) {
return allNetworks;
}
Expand Down Expand Up @@ -67,17 +72,20 @@ const DEFAULT_SUBSTRATE_NETWORK_NAME = NetworkNames.Polkadot;
const DEFAULT_BTC_NETWORK_NAME = NetworkNames.Bitcoin;
const DEFAULT_KADENA_NETWORK_NAME = NetworkNames.Kadena;
const DEFAULT_SOLANA_NETWORK_NAME = NetworkNames.Solana;
const DEFAULT_MASSA_NETWORK_NAME = NetworkNames.Massa;

const DEFAULT_EVM_NETWORK = Ethereum;
const DEFAULT_SUBSTRATE_NETWORK = Polkadot;
const DEFAULT_BTC_NETWORK = Bitcoin;
const DEFAULT_KADENA_NETWORK = Kadena;
const DEFAULT_SOLANA_NETWORK = Solana;
const DEFAULT_MASSA_NETWORK = Massa;

const POPULAR_NAMES = [
NetworkNames.Bitcoin,
NetworkNames.Ethereum,
NetworkNames.Solana,
NetworkNames.Massa,
NetworkNames.Matic,
NetworkNames.Polkadot,
NetworkNames.Binance,
Expand All @@ -100,4 +108,6 @@ export {
DEFAULT_KADENA_NETWORK_NAME,
DEFAULT_SOLANA_NETWORK,
DEFAULT_SOLANA_NETWORK_NAME,
DEFAULT_MASSA_NETWORK,
DEFAULT_MASSA_NETWORK_NAME,
};
2 changes: 2 additions & 0 deletions packages/extension/src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PolkadotProvider from '@/providers/polkadot';
import BitcoinProvider from '@/providers/bitcoin';
import KadenaProvider from '@/providers/kadena';
import SolanaProvider from '@/providers/solana';
import MassaProvider from '@/providers/massa';
import { ProviderName } from '@/types/provider';

export default {
Expand All @@ -11,4 +12,5 @@ export default {
[ProviderName.bitcoin]: BitcoinProvider,
[ProviderName.kadena]: KadenaProvider,
[ProviderName.solana]: SolanaProvider,
[ProviderName.massa]: MassaProvider,
};
92 changes: 92 additions & 0 deletions packages/extension/src/providers/massa/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { BaseNetwork } from '@/types/base-network';
import getRequestProvider, { RequestClass } from '@enkryptcom/request';
import { MiddlewareFunction, OnMessageResponse } from '@enkryptcom/types';
import Middlewares from './methods';
import EventEmitter from 'eventemitter3';
import {
BackgroundProviderInterface,
ProviderName,
ProviderRPCRequest,
} from '@/types/provider';
import GetUIPath from '@/libs/utils/get-ui-path';
import PublicKeyRing from '@/libs/keyring/public-keyring';
import UIRoutes from './ui/routes/names';
import { RoutesType } from '@/types/ui';
import massaNetworks from './networks';
import { NetworkNames } from '@enkryptcom/types';

export default class MassaProvider
extends EventEmitter
implements BackgroundProviderInterface
{
public network: BaseNetwork;
requestProvider: RequestClass;
middlewares: MiddlewareFunction[] = [];
namespace: string;
KeyRing: PublicKeyRing;
UIRoutes: RoutesType;
toWindow: (message: string) => void;

constructor(
toWindow: (message: string) => void,
network: BaseNetwork = massaNetworks[NetworkNames.Massa],
) {
super();
this.network = network;
this.toWindow = toWindow;
this.setMiddleWares();
this.requestProvider = getRequestProvider('', this.middlewares);
this.requestProvider.on('notification', (notif: any) => {
this.sendNotification(JSON.stringify(notif));
});
Comment on lines +38 to +41
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Bug: requestProvider is initialized with an empty URL, breaking first requests

Initializing with '' means early calls to request() will target an invalid endpoint until setRequestProvider() is invoked elsewhere. Also, notification wiring is duplicated here and will be lost on provider replacement.

Apply this diff to initialize with the actual network URL and centralize wiring via a helper (see next comment for the helper):

-    this.requestProvider = getRequestProvider('', this.middlewares);
-    this.requestProvider.on('notification', (notif: any) => {
-      this.sendNotification(JSON.stringify(notif));
-    });
+    this.initRequestProvider(this.network.node);

Committable suggestion skipped: line range outside the PR's diff.

this.namespace = ProviderName.massa;
this.KeyRing = new PublicKeyRing();

this.UIRoutes = UIRoutes;
}

private setMiddleWares(): void {
Comment on lines +47 to +48
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add a helper to consistently initialize and wire the request provider (incl. notifications)

This keeps constructor and network changes DRY and prevents missing event subscriptions when replacing the provider.

+  private initRequestProvider(node: string): void {
+    this.requestProvider = getRequestProvider(node, this.middlewares);
+    this.requestProvider.on('notification', (notif: unknown) => {
+      void this.sendNotification(JSON.stringify(notif));
+    });
+  }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/extension/src/providers/massa/index.ts around lines 47-48, add a
private helper (e.g. initializeRequestProvider(provider: RequestProvider)) that
centralizes assigning this.requestProvider, wiring its notification/event
handlers, and attaching any network-change listeners; ensure the helper first
unsubscribes or cleans up the previous provider's listeners if present, then
sets this.requestProvider = provider, registers all required
onNotification/onEvent callbacks and ties provider lifecycle to the
provider/network change logic, and replace direct wiring in the constructor and
any provider-replacement code to call this helper so event subscriptions are
never missed when swapping providers.

this.middlewares = Middlewares(this).map(mw => mw.bind(this));
}

setRequestProvider(network: BaseNetwork): void {
const prevURL = new URL(this.network.node);
const newURL = new URL(network.node);
this.network = network;
Comment on lines +52 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Harden URL parsing; new URL() will throw if network.node lacks a protocol

If any Massa network config provides a node without an explicit protocol, this will throw and leave the provider in a bad state. Guard it and fall back to re-init.

Proposed hardening:

-    const prevURL = new URL(this.network.node);
-    const newURL = new URL(network.node);
+    let prevURL: URL;
+    let newURL: URL;
+    try {
+      prevURL = new URL(this.network.node);
+      newURL = new URL(network.node);
+    } catch {
+      this.network = network;
+      this.initRequestProvider(network.node);
+      return;
+    }

To verify configs contain absolute URLs with protocols, run:


🏁 Script executed:

#!/bin/bash
# Inspect Massa network configs to ensure node URLs include protocol (http/https/ws/wss)
set -euo pipefail

echo "Searching Massa networks definitions..."
fd -a --extension ts networks packages/extension/src/providers/massa | while read -r f; do
  echo "=== File: $f ==="
  rg -n "node\s*:" -A1 -B1 "$f"
done

echo
echo "Heuristic check for protocols:"
rg -n "node\s*:\s*['\"](http|https|ws|wss)://" packages/extension/src/providers/massa || {
  echo "WARNING: No nodes with explicit protocols found by heuristic. Please confirm definitions."
}

Length of output: 549


Harden URL parsing in setRequestProvider

Our Massa network definitions currently don’t include explicit protocols (scan found no http://, https://, ws:// or wss://), so calling new URL(network.node) will throw and leave the provider uninitialized. Wrap these calls in a try/catch and fall back to re-initializing the request provider:

• File: packages/extension/src/providers/massa/index.ts, method setRequestProvider

   setRequestProvider(network: BaseNetwork): void {
-    const prevURL = new URL(this.network.node);
-    const newURL = new URL(network.node);
+    let prevURL: URL;
+    let newURL: URL;
+    try {
+      prevURL = new URL(this.network.node);
+      newURL = new URL(network.node);
+    } catch {
+      this.network = network;
+      this.initRequestProvider(network.node);
+      return;
+    }
    this.network = network;

This ensures that if a node URL is missing its protocol, we safely re-init rather than crash the provider.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setRequestProvider(network: BaseNetwork): void {
const prevURL = new URL(this.network.node);
const newURL = new URL(network.node);
this.network = network;
setRequestProvider(network: BaseNetwork): void {
let prevURL: URL;
let newURL: URL;
try {
prevURL = new URL(this.network.node);
newURL = new URL(network.node);
} catch {
this.network = network;
this.initRequestProvider(network.node);
return;
}
this.network = network;
🤖 Prompt for AI Agents
In packages/extension/src/providers/massa/index.ts around lines 52 to 55, the
code calls new URL(...) on network.node which can throw if the string lacks a
protocol; wrap the URL parsing in a try/catch and on any error fallback to
re-initializing the request provider (e.g., leave this.network set to the
incoming network and call the existing provider init routine) so the provider
does not remain uninitialized—catch the exception, log or ignore the parse
error, and perform the safe re-init path instead of allowing the throw to
propagate.

if (prevURL.protocol === newURL.protocol)
this.requestProvider.changeNetwork(network.node);
else
this.requestProvider = getRequestProvider(network.node, this.middlewares);
}
Comment on lines +52 to +60
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Notifications lost after protocol change; reinitialize provider to re-subscribe listeners

In the else branch you replace the provider instance but don’t re-attach the 'notification' handler, so notifications will stop after switching protocol (e.g., http → https).

   setRequestProvider(network: BaseNetwork): void {
-    const prevURL = new URL(this.network.node);
-    const newURL = new URL(network.node);
+    const prevURL = new URL(this.network.node);
+    const newURL = new URL(network.node);
     this.network = network;
     if (prevURL.protocol === newURL.protocol)
       this.requestProvider.changeNetwork(network.node);
     else
-      this.requestProvider = getRequestProvider(network.node, this.middlewares);
+      this.initRequestProvider(network.node);
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setRequestProvider(network: BaseNetwork): void {
const prevURL = new URL(this.network.node);
const newURL = new URL(network.node);
this.network = network;
if (prevURL.protocol === newURL.protocol)
this.requestProvider.changeNetwork(network.node);
else
this.requestProvider = getRequestProvider(network.node, this.middlewares);
}
setRequestProvider(network: BaseNetwork): void {
const prevURL = new URL(this.network.node);
const newURL = new URL(network.node);
this.network = network;
if (prevURL.protocol === newURL.protocol)
this.requestProvider.changeNetwork(network.node);
else
this.initRequestProvider(network.node);
}
🤖 Prompt for AI Agents
packages/extension/src/providers/massa/index.ts around lines 52 to 60: when
switching protocol you replace this.requestProvider but don’t re-attach the
provider’s 'notification' handler so notifications stop after protocol change;
after creating the new provider call the same subscription setup used for the
old provider to re-register the 'notification' listener (and any other listeners
you rely on) — i.e., capture or reuse the existing handler reference(s) and
attach them to the new provider instance immediately after
getRequestProvider(...) so notifications continue after protocol changes.


async isPersistentEvent(): Promise<boolean> {
return false;
}

async sendNotification(notif: string): Promise<void> {
return this.toWindow(notif);
}

request(request: ProviderRPCRequest): Promise<OnMessageResponse> {
return this.requestProvider
.request(request)
.then(res => {
return {
result: JSON.stringify(res),
};
})
.catch(e => {
return {
error: JSON.stringify(e.message),
};
});
}
Comment on lines +70 to +83
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Preserve structured error info instead of stringifying only e.message

Only sending e.message loses error code/data and may hinder UI handling (e.g., EIP-1193-like error codes). Serialize a structured error payload.

   request(request: ProviderRPCRequest): Promise<OnMessageResponse> {
     return this.requestProvider
       .request(request)
       .then(res => {
         return {
           result: JSON.stringify(res),
         };
       })
-      .catch(e => {
-        return {
-          error: JSON.stringify(e.message),
-        };
-      });
+      .catch((e: unknown) => {
+        const err =
+          e && typeof e === 'object'
+            ? { message: (e as any).message ?? String(e), code: (e as any).code }
+            : { message: String(e) };
+        return { error: JSON.stringify(err) };
+      });
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
request(request: ProviderRPCRequest): Promise<OnMessageResponse> {
return this.requestProvider
.request(request)
.then(res => {
return {
result: JSON.stringify(res),
};
})
.catch(e => {
return {
error: JSON.stringify(e.message),
};
});
}
request(request: ProviderRPCRequest): Promise<OnMessageResponse> {
return this.requestProvider
.request(request)
.then(res => {
return {
result: JSON.stringify(res),
};
})
.catch((e: unknown) => {
const err =
e && typeof e === 'object'
? { message: (e as any).message ?? String(e), code: (e as any).code }
: { message: String(e) };
return { error: JSON.stringify(err) };
});
}
🤖 Prompt for AI Agents
In packages/extension/src/providers/massa/index.ts around lines 70 to 83, the
catch handler currently returns only JSON.stringify(e.message) which discards
structured error properties (code, data, stack) needed by the UI; modify the
catch to return a structured error payload instead (e.g., JSON.stringify the
full error object or build { message: e.message, code: e.code, data: e.data,
stack: e.stack }), ensuring the returned shape matches OnMessageResponse.error
expectations and avoiding double-stringifying already-serializable objects.


getUIPath(page: string): string {
return GetUIPath(page, this.namespace);
}

getCurrentNetwork(): BaseNetwork {
return this.network;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import MassaActivity from './massa';

export { MassaActivity };
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { BaseNetwork } from '@/types/base-network';
import { Activity, ActivityStatus, ActivityType } from '@/types/activity';
import { ActivityHandlerType } from '@/libs/activity-state/types';
import ActivityState from '@/libs/activity-state';

const MassaActivity: ActivityHandlerType = async (
network: BaseNetwork,
address: string,
): Promise<Activity[]> => {
try {
// Get activities from local storage
const activityState = new ActivityState();
const activities = await activityState.getAllActivities({
address,
network: network.name,
});

// For now, return local activities
// In the future, this can be extended to fetch from Massa explorer API
return activities;
} catch (error) {
console.error('Error fetching Massa activities:', error);
return [];
}
};

export default MassaActivity;
60 changes: 60 additions & 0 deletions packages/extension/src/providers/massa/libs/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ProviderAPIInterface } from '@/types/provider';
import {
JsonRpcPublicProvider,
MRC20,
NodeStatusInfo,
OperationStatus,
} from '@massalabs/massa-web3';

export default class MassaAPI extends ProviderAPIInterface {
public provider: JsonRpcPublicProvider;
public node: string;

constructor(node: string) {
super(node);
this.node = node;
this.provider = JsonRpcPublicProvider.fromRPCUrl(
node,
) as JsonRpcPublicProvider;
}

public get api() {
return this;
}

async init(): Promise<void> {}

async getBalance(address: string): Promise<string> {
const [account] = await this.provider.balanceOf([address], false);
if (!account) return '0';
return account.balance.toString();
}
Comment on lines +28 to +31
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for address parameter

The getBalance method should validate the address parameter before making the API call to prevent potential errors.

 async getBalance(address: string): Promise<string> {
+  if (!address || !address.trim()) {
+    return '0';
+  }
   const [account] = await this.provider.balanceOf([address], false);
   if (!account) return '0';
   return account.balance.toString();
 }
🤖 Prompt for AI Agents
In packages/extension/src/providers/massa/libs/api.ts around lines 28 to 31, the
getBalance implementation calls this.provider.balanceOf without validating the
address; add input validation at the top of the method to ensure address is a
non-empty string (and optionally matches Massa address format/regex), return '0'
or throw a clear error for invalid input, and only call this.provider.balanceOf
when the address passes validation (trim the input before validation to avoid
whitespace issues).


async getBalanceMRC20(address: string, contract: string): Promise<string> {
const mrc20 = new MRC20(this.provider, contract);
const balance = await mrc20.balanceOf(address);
return balance.toString();
}

async getMinimalFee(): Promise<string> {
try {
const networkInfo = await this.provider.networkInfos();
return networkInfo.minimalFee.toString();
} catch (error) {
// Return a default minimal fee if network info is not available
return '10000000'; // 0.01 MAS in base units (9 decimals)
}
}

async getTransactionStatus(opId: string): Promise<OperationStatus | null> {
try {
return this.provider.getOperationStatus(opId);
} catch (error) {
return null;
}
}

async getNodeStatus(): Promise<NodeStatusInfo> {
return this.provider.getNodeStatus();
}
}
19 changes: 19 additions & 0 deletions packages/extension/src/providers/massa/methods/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MiddlewareFunction } from '@enkryptcom/types';
import { BackgroundProviderInterface } from '@/types/provider';
import massa_getBalance from './massa_getBalance';
import massa_getNetwork from './massa_getNetwork';
import massa_setNetwork from './massa_setNetwork';

export default (
provider: BackgroundProviderInterface,
): MiddlewareFunction[] => {
return [
massa_getBalance,
massa_getNetwork,
massa_setNetwork,
async (request, response, next) => {
// Add any additional Massa-specific middleware logic here
return next();
},
];
};
Loading