Skip to content

Release: v2.11.0#754

Merged
kvhnuke merged 58 commits intomainfrom
develop
Sep 16, 2025
Merged

Release: v2.11.0#754
kvhnuke merged 58 commits intomainfrom
develop

Conversation

@kvhnuke
Copy link
Contributor

@kvhnuke kvhnuke commented Sep 15, 2025

Summary by CodeRabbit

  • New Features
    • Added Massa network support: accounts, balances, custom tokens (MRC20), send and verify transactions, and activity tracking.
  • Network Updates
    • Added TAC and COTI Testnet; replaced zkSync Goerli with zkSync Sepolia.
    • Removed Form (mainnet/testnet), Ham, SKALE Chaos, CAGA Ankara, and Polkadot Opal.
    • Updated Fantom explorer links; adjusted Etherscan/Blockscout endpoints.
  • UI/UX
    • New Massa token add modal and send/verify flows.
    • Truncated fiat display; improved network sorting; buy MAS link.
  • Chores
    • Bumped Node.js to 22.18.0 and updated dependencies across packages.

@coderabbitai
Copy link

coderabbitai bot commented Sep 15, 2025

Walkthrough

Adds Massa blockchain support across provider, networks, API, UI, signer, and keyring; updates types and background to register Massa. Adjusts Ethereum network registry (add TAC, zkSync Sepolia; remove several), updates Fantom explorer and configs. Removes SID resolution. Bumps Node versions, Docker base, dependencies, tooling, and minor UI/UX tweaks.

Changes

Cohort / File(s) Summary
CI and runtime Node version
/.github/workflows/test-all.yml, /.github/workflows/test-swap.yml, /.nvmrc, /Dockerfile
Bump Node to 22.18.x across CI, nvm, and Docker base image.
Tooling and dependencies bump
/package.json, /packages/extension-bridge/package.json, /packages/extension/package.json, /packages/hw-wallets/package.json, /packages/keyring/package.json, /packages/name-resolution/package.json, /packages/request/package.json, /packages/signers/*/package.json, /packages/storage/package.json, /packages/swap/package.json
Dev/runtime version updates; add vite-plugin-node-polyfills; extension to 2.11.0; add @enkryptcom/signer-massa; various library bumps.
Build/test configs
/.vscode/settings.json, /packages/extension/configs/vitest.config.mts, /packages/extension/vite.config.ts
Add VSCode inlineSuggest flag; vitest adds polyfill alias/custom resolver; BUILD_TIME stringified.
Massa provider core integration
/packages/extension/src/providers/massa/**, /packages/extension/src/providers/index.ts, /packages/extension/src/types/{provider,base-network,activity}.ts, /packages/extension/src/libs/utils/{networks,initialize-wallet}.ts, /packages/extension/src/libs/background/{index,types}.ts, /packages/extension/src/libs/tokens-state/{index,types}.ts, /packages/extension/src/ui/provider-pages/routes.ts, /packages/extension/src/ui/action/views/{send-transaction,index.vue,verify-transaction/index.vue}
New Massa provider, API, networks (mainnet/buildnet), activity handler, UI routes and pages, signer wiring, types. Register provider; include in networks and initialization; extend token types/state.
Massa UI components
/packages/extension/src/providers/massa/ui/**
Add send flow components, verify flow, routes, signer helpers, token selector, address input, custom-token modal.
Keyring and signer (Massa)
/packages/keyring/src/{index.ts,utils.ts,tests/generate.test.ts}, /packages/signers/massa/**
Add Massa signer package and HD derivation, keys, address, crypto helpers; integrate signer type ed25519mas; tests for key generation.
Ethereum networks update
/packages/extension/src/providers/ethereum/networks/{index.ts,zksepolia.ts,coti-testnet.ts,tac.ts,ftm.ts}, /packages/extension/src/providers/ethereum/networks/{zkgoerli.ts,form*.ts,ham.ts,coti-devnet.ts,skale/chaos.ts} (removed), /packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/configs.ts, /packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts
Add zkSync Sepolia, COTI Testnet, TAC; remove zkGoerli, Form main/test, Ham, Caga Ankara, Skale Chaos, COTI Devnet; update Fantom explorers; adjust Etherscan endpoints; change Sanko balance source.
Name resolution changes
/packages/name-resolution/src/index.ts, /packages/name-resolution/tests/{resolver.test.ts,sid.test.ts}
Disable SID provider; adjust resolveAddress signature; update tests and skip SID suite.
Polkadot networks
/packages/extension/src/providers/polkadot/networks/{index.ts,unique/opal.ts}
Remove Opal network and its export.
UI adjustments
/packages/extension/src/ui/action/App.vue, /packages/extension/src/ui/action/components/app-menu/index.vue, /packages/extension/src/ui/action/views/network-activity/index.vue, /packages/extension/src/providers/common/libs/new-features.ts, /packages/extension/src/providers/common/ui/send-transaction/send-input-amount.vue, /packages/extension/src/ui/action/views/network-assets/{index.vue,components/custom-massa-token.vue}
Add Massa buy link and account selection logic; sort by name_long; handle Massa activity status; mark Massa as new network; truncate fiat text; network-aware custom token UIs with Massa modal.
Swap gas estimation
/packages/swap/src/common/estimateGasList.ts
Remove Binance and Matic from supported networks.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Massa Send UI
  participant Prov as MassaProvider
  participant Net as MassaNetwork/API
  participant KR as KeyRing
  participant Req as Request Layer
  participant Act as ActivityState

  User->>UI: Enter to, amount, token
  UI->>Net: getAllTokenInfo(address)
  Net-->>UI: assets, MAS price/balances
  UI->>Net: getMinimalFee()
  Net-->>UI: fee
  User->>UI: Click Send
  UI->>Prov: request(massa_setNetwork?)
  Prov->>Req: apply middlewares
  UI->>KR: MassaTransactionSigner(sign)
  KR-->>UI: signature
  UI->>Net: submit operation (sendOperation)
  Net-->>UI: operationId
  UI->>Act: store activities (sender/receiver)
  Act-->>UI: saved
  UI-->>User: Navigate to verify/success

  rect rgb(245,248,255)
  note right of Net: New Massa integration (balances, fees, submit)
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • feat: massalabs network #741 — Implements Massa integration (provider, networks, API, UI, signer); overlaps with the added Massa files and types in this PR.
  • Prep Release: v2.11.0 #744 — v2.11.0 prep including Node/Docker bumps, dependency updates, and provider additions; mirrors the environment and package changes here.
  • Feat: space id support #704 — Alters name-resolution APIs around SID; related to disabling SID and signature changes made in this PR.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Release: v2.11.0" is a concise, single-line summary that accurately reflects the primary intent of the changeset (a release/version bump and associated package updates), so it clearly communicates the main change to reviewers scanning history.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Sep 15, 2025

💼 Build Files
chrome: enkrypt-chrome-7a648bc5.zip
firefox: enkrypt-firefox-7a648bc5.zip

💉 Virus total analysis
chrome: 7a648bc5
firefox: 7a648bc5

@kvhnuke kvhnuke changed the title Release: v2.11 Release: v2.11.0 Sep 15, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 22

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts (1)

241-243: Blockscout path may omit native token → crash risk downstream

The TB path backfills the native token when missing (Lines 257–266). The Blockscout path returns raw results and does not add a native entry. If Blockscout returns no entries or omits the native token, balances[NATIVE_TOKEN_ADDRESS] is undefined and balances[address].balance (Line 337) will throw.

Fix by backfilling the native token in the Blockscout branch:

   } else if (supportedNetworks[chain].bsEndpoint) {
-    return getBlockscoutBalances(chain, address);
+    return getBlockscoutBalances(chain, address).then(tokens => {
+      const hasNative = tokens.some(
+        (i: TokenBalance) => i.contract === NATIVE_TOKEN_ADDRESS,
+      );
+      if (!hasNative) {
+        tokens.push({
+          contract: NATIVE_TOKEN_ADDRESS,
+          balance: '0x0',
+        } as TokenBalance);
+      }
+      return tokens;
+    });
   }

Also applies to: 334-345

package.json (1)

30-31: Remove hardcoded OTP from publish script (package.json:30).
Hardcoded OTP "312003" is committed — remove it from VCS. Pass OTP via env (e.g. --otp $NPM_OTP), use an npm CI token instead, or omit and enter interactively.

-    "publish": "yarn workspaces foreach --worktree -pv --exclude @enkryptcom/extension exec 'yarn npm publish --access public --otp 312003'",
+    "publish": "yarn workspaces foreach --worktree -pv --exclude @enkryptcom/extension exec 'yarn npm publish --access public'",
packages/extension/src/libs/tokens-state/index.ts (2)

35-43: Duplicate detection ignores Massa tokens.

Currently checks only TokenType.ERC20, allowing duplicate Massa tokens by address on the same chain.

Apply:

-        if (
-          t.type === TokenType.ERC20 &&
-          (t as CustomErc20Token).address.toLowerCase() ===
-            token.address.toLowerCase()
-        ) {
+        // Prevent duplicates for any address-bearing token (ERC20/MRC20)
+        if (
+          "address" in t &&
+          (t as CustomErc20Token | CustomMassaToken).address.toLowerCase() ===
+            token.address.toLowerCase()
+        ) {
           return false;
         }

54-55: Persist write is not awaited.

addErc20Token returns before storage is flushed; removeErc20Token awaits it. Make behavior consistent to avoid race conditions.

-    this.storage.set(StorageKeys.customTokens, state);
+    await this.storage.set(StorageKeys.customTokens, state);
🧹 Nitpick comments (99)
packages/extension/src/ui/action/components/app-menu/index.vue (1)

356-357: Guard against missing name_long and sort case-insensitively.

If any network lacks name_long, localeCompare will throw. Also, case-insensitive compare improves UX consistency.

Apply this diff:

-        ? a.name_long.localeCompare(b.name_long)
-        : b.name_long.localeCompare(a.name_long);
+        ? (a.name_long ?? a.name).localeCompare(b.name_long ?? b.name, undefined, { sensitivity: 'base' })
+        : (b.name_long ?? b.name).localeCompare(a.name_long ?? a.name, undefined, { sensitivity: 'base' });
packages/extension/src/providers/common/ui/send-transaction/send-input-amount.vue (8)

147-151: Make truncation robust in flex; avoid duplicate ellipsis on the container.

Ellipsis should be applied on the text element; keeping it on the container can cause unexpected clipping. Also add min-width: 0 so the child flex item can shrink in Safari/Firefox.

   &__fiat {
     position: absolute;
     left: 16px;
     bottom: 16px;
     display: flex;
     justify-content: flex-start;
     align-items: center;
     flex-direction: row;
-    max-width: 200px;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
+    max-width: 200px;
+    min-width: 0; // allow children to shrink inside flex container
   }

165-168: Ensure the text actually truncates across browsers.

Add min-width: 0 (and optionally flex: 1 1 auto) to the span so it can shrink and show the ellipsis reliably.

   span {
     font-style: normal;
     font-weight: 400;
     font-size: 14px;
     line-height: 20px;
-    text-align: center;
+    text-align: center;
     letter-spacing: 0.25px;
     color: @tertiaryLabel;
+    min-width: 0;     // important for flex overflow handling
+    flex: 1 1 auto;   // optional: let text take remaining space within max container width
     overflow: hidden;
     text-overflow: ellipsis;
     white-space: nowrap;
   }

16-16: Optional: show full fiat value on hover.

Add a title for discoverable access to the truncated value.

-      <span>{{ $filters.parseCurrency(fiatEquivalent) }}</span>
+      <span :title="$filters.parseCurrency(fiatEquivalent)">{{ $filters.parseCurrency(fiatEquivalent) }}</span>

62-64: Guard against NaN when amount is empty/invalid.

Multiplying by an empty string yields NaN in BigNumber, which may render as “NaN”. Return "0" instead.

-const fiatEquivalent = computed(() => {
-  return new BigNumber(props.fiatValue).times(props.amount).toString();
-});
+const fiatEquivalent = computed(() => {
+  const amt = props.amount?.trim();
+  if (!amt) return '0';
+  const v = new BigNumber(props.fiatValue || 0).times(new BigNumber(amt || 0));
+  return v.isFinite() ? v.toString() : '0';
+});

74-86: Replace keypress filtering with input-based sanitization (handles paste, IME, and mobile).

keypress/keyCode are deprecated and won’t catch paste/drag. Sanitize on input instead.

-  @keypress="onlyNumber"
+  @input="sanitizeAmount"
-const onlyNumber = ($event: KeyboardEvent) => {
-  const keyCode = $event.keyCode ? $event.keyCode : $event.which;
-  // Numeric
-  if (keyCode >= /* 0 */ 48 && keyCode <= /* 9 */ 57) {
-    return;
-  }
-  // Only allow a single period
-  if (keyCode === /* '.' */ 46 && amount.value.indexOf('.') === -1) {
-    return;
-  }
-  // Alphabetical (/non-numeric) or mulitple periods. Don't propagate change
-  $event.preventDefault();
-};
+const sanitizeAmount = (e: Event) => {
+  const raw = (e.target as HTMLInputElement).value;
+  // keep digits and at most one dot
+  const cleaned = raw
+    .replace(/[^\d.]/g, '')
+    .replace(/^(\.)+/, '0.')
+    .replace(/(\..*)\./g, '$1');
+  emit('update:inputAmount', cleaned);
+};

10-11: Avoid toggle-on-both focus/blur; set explicit state.

Toggling can desync on edge cases. Set true on focus, false on blur.

-  @focus="changeFocus"
-  @blur="changeFocus"
+  @focus="setFocus(true)"
+  @blur="setFocus(false)"
-const changeFocus = () => {
-  isFocus.value = !isFocus.value;
-};
+const setFocus = (v: boolean) => {
+  isFocus.value = v;
+};

Also applies to: 87-89


8-8: Theme the error color instead of hardcoding red/black.

Bind a class and style via theme tokens for consistency with dark modes/themes.

-      :style="{ color: !hasEnoughBalance ? 'red' : 'black' }"
+      :class="{ 'is-error': !hasEnoughBalance }"
 .send-input-amount {
+  & .is-error {
+    color: @error; // or appropriate theme var
+  }
 }

130-137: Dead CSS for number inputs.

Input is type="text"; the number spin-button overrides are unused here.

-  input[type='number']::-webkit-outer-spin-button,
-  input[type='number']::-webkit-inner-spin-button {
-    -webkit-appearance: none;
-    margin: 0;
-  }
-  input[type='number'] {
-    -moz-appearance: textfield;
-  }
packages/extension/src/providers/common/libs/new-features.ts (1)

3-3: Optional: mark as readonly to prevent accidental mutation

Tiny safety/intent signal; no behavior change.

Apply:

-const newNetworks: NetworkNames[] = [NetworkNames.Massa];
+const newNetworks: readonly NetworkNames[] = [NetworkNames.Massa];
packages/signers/massa/tsconfig.json (6)

18-24: Include vs exclude conflict for tests

You include tests//*.ts but exclude tests/ at the same time, so tests won’t compile. Decide one way. If this tsconfig is for build output only, exclude tests and don’t include them; otherwise, create a separate tsconfig for tests.

Apply if “build-only”:

-  "include": ["src/**/*.ts", "tests/**/*.ts"],
+  "include": ["src/**/*.ts"],
@@
-    ".vscode/**/*",
-    "tests/**/*"
+    ".vscode/**/*"

3-17: Add rootDir to stabilize emit layout

Without rootDir, TS infers it (can widen if tests are included later). Set rootDir to src to keep dist predictable.

   "compilerOptions": {
@@
-    "outDir": "dist",
+    "outDir": "dist",
+    "rootDir": "src",

4-5: Consider modern module settings aligned with bundling

If this package is bundled for the browser extension, prefer module ESNext and moduleResolution bundler (or nodenext if consumed by Node). This improves tree-shaking and aligns with TS 5 recommendations.

Option A (bundled):

-    "moduleResolution": "node",
+    "moduleResolution": "bundler",
@@
-    "module": "commonjs",
+    "module": "ESNext",

Option B (Node consumption):

-    "moduleResolution": "node",
+    "moduleResolution": "nodenext",
-    "module": "commonjs",
+    "module": "NodeNext",

Confirm your toolchain (webpack/rollup/tsup) and consumers before changing.

Also applies to: 10-11, 16-16


4-4: Libs: DOM may be insufficient for MV3 service worker

If any code runs in a background/service worker, add WebWorker lib; if strictly UI, DOM is fine. Many extensions use both; you can include both.

-    "lib": ["ESNext", "dom"],
+    "lib": ["ESNext", "dom", "WebWorker"],

6-9: Tighten type-safety (enable strict mode)

You’ve enabled unused checks; add strict for nullability and inference.

     "noUnusedLocals": true,
     "noUnusedParameters": true,
+    "strict": true,
+    "noImplicitReturns": true,
     "removeComments": true,

3-17: Build performance: consider skipLibCheck

Large monorepos benefit from skipping lib checks to speed CI; safe if libs are trusted.

     "esModuleInterop": true,
     "declaration": true,
-    "downlevelIteration": true
+    "downlevelIteration": true,
+    "skipLibCheck": true
.github/workflows/test-all.yml (1)

12-16: Add Corepack enable and proper Yarn 4 cache to speed up CI.
actions/setup-node’s cache: yarn isn’t very effective for Yarn 4 workspaces. Cache .yarn/cache and enable Corepack.

       - uses: actions/setup-node@v4
         with:
           node-version: "22.18.0"
           cache: "yarn"
+      - run: corepack enable
+      - name: Cache Yarn artifacts
+        uses: actions/cache@v4
+        with:
+          path: |
+            .yarn/cache
+            .yarn/unplugged
+            .yarn/build-state.yml
+            .pnp.cjs
+          key: ${{ runner.os }}-yarn4-${{ hashFiles('**/yarn.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-yarn4-
       - run: yarn install
.github/workflows/test-swap.yml (1)

12-16: Mirror CI improvements: enable Corepack and cache Yarn 4 artifacts.
Same optimization as the main test workflow.

       - uses: actions/setup-node@v4
         with:
           node-version: "22.18.0"
           cache: "yarn"
+      - run: corepack enable
+      - name: Cache Yarn artifacts
+        uses: actions/cache@v4
+        with:
+          path: |
+            .yarn/cache
+            .yarn/unplugged
+            .yarn/build-state.yml
+            .pnp.cjs
+          key: ${{ runner.os }}-yarn4-${{ hashFiles('**/yarn.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-yarn4-
       - run: yarn install
Dockerfile (1)

1-3: Slim the image and enable Corepack in one pass.
Fewer layers, cleaned apt lists, and Corepack enabled for Yarn 4.

-FROM node:22.18-bookworm
-RUN apt-get update
-RUN apt-get install build-essential zip -y
+FROM node:22.18-bookworm
+RUN apt-get update \
+  && apt-get install -y --no-install-recommends build-essential zip \
+  && rm -rf /var/lib/apt/lists/*
+RUN corepack enable
packages/extension/vite.config.ts (1)

56-60: Avoid locale-dependent build timestamp; use a deterministic source.

toLocaleString() is locale/timezone dependent and can produce different values across CI/dev machines. Prefer Date.now() (digits-only) or toISOString() for reproducible builds.

Apply:

-        : JSON.stringify(new Date().toLocaleString().replace(/\D/g, '')),
+        : JSON.stringify(String(Date.now())),
packages/name-resolution/tests/sid.test.ts (1)

4-4: Top-level import still executes even when suite is skipped.

If ../src/sid is removed, this file will fail to load despite describe.skip. Move the import inside the skipped callback or remove the suite.

Example:

-import SIDResolver from "../src/sid";
-
-describe.skip("SID Name resolving", () => {
+describe.skip("SID Name resolving", () => {
+  // NOTE: kept inside skipped block to avoid resolving when SID is removed
+  const getResolver = async () => (await import("../src/sid")).default;
   // ...
packages/name-resolution/tests/resolver.test.ts (1)

23-24: Expectation updated to null — also remove stale SID config above to avoid confusion.

Now that SID is no longer used, keep the expectation as null, but also drop the sid block from the resolver config to reflect actual behavior.

Patch:

   const resolver = new NameResolver({
     ens: {
       node: "https://nodes.mewapi.io/rpc/eth",
     },
-    sid: {
-      node: {
-        bnb: "https://nodes.mewapi.io/rpc/bsc",
-        arb: "https://nodes.mewapi.io/rpc/arb",
-      },
-    },
   });
packages/signers/massa/src/crypto/interfaces/hasher.ts (1)

1-4: Clarify input encoding and broaden accepted binary types.

Specify expected encoding for string (UTF‑8 vs hex) and consider accepting ArrayBufferView to cover DataView/typed arrays uniformly.

Example:

-export default interface Hasher {
-  hash(data: Buffer | Uint8Array | string): Uint8Array
-}
+/**
+ * hash() expects:
+ *  - string: UTF-8 by default (document if hex is supported)
+ *  - binary: Uint8Array/ArrayBufferView
+ */
+export default interface Hasher {
+  hash(data: Uint8Array | ArrayBufferView | string): Uint8Array;
+}
packages/signers/kadena/package.json (1)

31-37: Dev toolchain bumped — align engines with repo Node baseline.

Repo CI/node baseline is 22.18.0. Consider updating this package’s engines.node from >=14.15.0 to >=18 (or >=22) to avoid misleading consumers.

Patch:

   "engines": {
-    "node": ">=14.15.0"
+    "node": ">=18.18.0"
   },
packages/swap/package.json (1)

42-46: Align engines with workspace Node 22.x

The repo CI and .nvmrc use Node 22.18.x. Consider updating "engines.node" to reduce install-time warnings and mismatches.

-  "engines": {
-    "node": ">=14.15.0"
-  },
+  "engines": {
+    "node": ">=18.18.0"
+  },

Also applies to: 55-56

packages/signers/ethereum/package.json (1)

35-39: Dev tooling bumps look good; consider engines update

Changes are fine. Suggest aligning "engines.node" with repo standard to avoid drift.

-  "engines": {
-    "node": ">=14.15.0"
-  },
+  "engines": {
+    "node": ">=18.18.0"
+  },

Also applies to: 48-49

packages/signers/bitcoin/package.json (1)

35-39: Dev bumps OK; engines consistency

Looks good. Consider updating "engines.node" to match repo Node 22 baseline.

-  "engines": {
-    "node": ">=14.15.0"
-  },
+  "engines": {
+    "node": ">=18.18.0"
+  },

Also applies to: 48-49

packages/signers/polkadot/package.json (2)

25-31: Move commitlint to devDependencies

@commitlint/cli is a build-time tool; keeping it in dependencies bloats consumers.

   "dependencies": {
-    "@commitlint/cli": "^19.8.1",
     "@enkryptcom/utils": "workspace:^",
     "@polkadot/util": "^13.5.6",
     "@polkadot/util-crypto": "^13.5.6",
     "@polkadot/wasm-crypto": "^7.5.1",
     "assert": "^2.1.0"
   },
   "devDependencies": {
     "@enkryptcom/types": "workspace:^",
+    "@commitlint/cli": "^19.8.1",

33-37: Engines alignment

Match workspace Node baseline to prevent install-time warnings.

-  "engines": {
-    "node": ">=14.15.0"
-  },
+  "engines": {
+    "node": ">=18.18.0"
+  },

Also applies to: 47-48

packages/signers/massa/src/crypto/blake3.ts (1)

7-11: Match interface signature explicitly

Minor: keep the method signature identical to Hasher to avoid future variance issues.

-import { blake3 as hashBlake3 } from '@noble/hashes/blake3'
-import Hasher from './interfaces/hasher'
+import { blake3 as hashBlake3 } from '@noble/hashes/blake3'
+import type { Buffer } from 'node:buffer'
+import Hasher from './interfaces/hasher'

 export default class Blake3 implements Hasher {
   // eslint-disable-next-line class-methods-use-this -- Expected by the interface.
-  hash(data: Uint8Array | string): Uint8Array {
+  hash(data: Buffer | Uint8Array | string): Uint8Array {
     return hashBlake3(data)
   }
 }
packages/extension/src/types/activity.ts (1)

9-9: Use type-only import to avoid bundling massa-web3

Prevents accidental inclusion of runtime code from @massalabs/massa-web3 in the extension bundle.

-import { OperationStatus } from '@massalabs/massa-web3';
+import type { OperationStatus } from '@massalabs/massa-web3';
packages/extension/src/providers/ethereum/networks/zksepolia.ts (1)

6-6: Rename zkgoerli identifiers to zksepolia for clarity.**

Leftover “goerli” naming is misleading in a Sepolia module.

-const zkgoerliOptions: EvmNetworkOptions = {
+const zksepoliaOptions: EvmNetworkOptions = {
 ...
-const zkgoerli = new EvmNetwork(zkgoerliOptions);
-export default zkgoerli;
+const zksepolia = new EvmNetwork(zksepoliaOptions);
+export default zksepolia;

Also applies to: 21-23

packages/hw-wallets/package.json (1)

21-23: Align Node engine with repository baseline.

Repo CI and .nvmrc target Node 22.x; this package still says ">=14.15.0". Suggest raising the floor to avoid accidental use of older Node in isolated builds.

   "engines": {
-    "node": ">=14.15.0"
+    "node": ">=18.18.0"
   },

Confirm no consumers require Node <18 before raising the floor.

packages/signers/massa/src/crypto/interfaces/sealer.ts (1)

1-7: Make Sealer generic to eliminate any and improve type safety.

You can keep a true interface while avoiding any:

-// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- True interface.
-export default interface Sealer {
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  seal(data: Uint8Array): Promise<any>
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  unseal(data: any): Promise<Uint8Array>
-}
+// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- True interface.
+export default interface Sealer<TSealed = unknown> {
+  seal(data: Uint8Array): Promise<TSealed>;
+  unseal(data: TSealed): Promise<Uint8Array>;
+}

This will require adjusting implementers (e.g., PasswordSeal) to specify TSealed.

Please confirm the intended sealed payload shape so I can patch implementations in this PR.

packages/extension/src/providers/massa/libs/activity-handlers/massa.ts (2)

21-23: Use the repo logger instead of console.error for consistency.

Switch to the shared debug logger (e.g., utils/debug-logger) to honor log levels and formats.

What’s the preferred logger import here (path/name) so I can submit a follow-up diff?


13-20: Optional: de-dup and/or sort activities if upstream may return duplicates.

If ActivityState.getAllActivities can produce duplicates or unsorted results, consider normalizing here before returning.

packages/extension/configs/vitest.config.mts (1)

20-29: import.meta.resolve usage is Node ≥20; ensure CI runs on Node 22 (it does).

Looks good given the repo baseline. If you ever need Node <20 locally, provide a small fallback using createRequire().resolve.

If desired, I can add a backward-compatible resolver shim guarded by Node version.

packages/name-resolution/src/index.ts (1)

23-28: Fully remove SID to reduce bundle size and dead code.

SID is no longer initialized or used; keep importing/instantiating it adds weight and potential side effects. Remove the field, import, and commented branches. Also update NameResolverOptions to drop sid.

-import SIDResolver from "./sid";
 ...
-  sid: SIDResolver;
 ...
-    this.sid = new SIDResolver(options.sid);
   this.initDone = Promise.all([
     this.ens.init(),
     this.rns.init(),
     this.ud.init(),
-    // this.sid.init(),
   ]);
 ...
   return this.initDone.then(() =>
     Promise.all([
       this.ens.resolveReverseName(address),
-      // this.sid.resolveReverseName(address),
       this.rns.resolveReverseName(address),
       this.ud.resolveReverseName(address),
     ]).then((results) => {
 ...
   return this.initDone.then(() => {
     if (this.rns.isSupportedName(name))
       return this.rns.resolveAddress(name, coin);
     if (this.ud.isSupportedName(name))
       return this.ud.resolveAddress(name, coin);
-    // if (this.sid.isSupportedName(name))
-    //   return this.sid.resolveAddress(name, paymentIdChain);
     if (this.ens.isSupportedName(name))
       return this.ens.resolveAddress(name, coin);

After removing SID here, I can follow through with a types update and pruning any remaining SID tests/imports.

Also applies to: 31-38, 48-60

packages/extension/src/libs/tokens-state/index.ts (1)

20-29: API/docs mismatch: method now accepts Massa tokens too.

JSDoc still says “ERC20” and param type mentions only CustomErc20Token. Update docs to reflect CustomMassaToken support (or rename method to a chain-agnostic name in a follow-up).

- * Add a new custom ERC20 token for a given network.
+ * Add a new custom token with an address (ERC20/MRC20) for a given network.
...
- * @param {CustomErc20Token} token - The token information being added.
+ * @param {CustomErc20Token | CustomMassaToken} token - The token information being added.
packages/extension/src/types/base-network.ts (1)

11-11: Use path alias for consistency.

All other provider API imports use '@/…'. Prefer the alias for maintainability.

-import MassaAPI from '../providers/massa/libs/api';
+import MassaAPI from '@/providers/massa/libs/api';
packages/signers/massa/src/libs/ed25519.ts (2)

14-23: Seed handling: accept 0x-prefixed hex and validate length.

Guard against invalid hex and odd-length strings.

-const getMasterKeyFromSeed = (seed: Hex): Keys => {
-  const hmac = createHmac("sha512", Buffer.from(ED25519_CURVE, "utf8"));
-  const I = hmac.update(Buffer.from(seed, "hex")).digest();
+const getMasterKeyFromSeed = (seed: Hex): Keys => {
+  const seedHex = seed.startsWith("0x") ? seed.slice(2) : seed;
+  if (!/^[0-9a-fA-F]+$/.test(seedHex) || seedHex.length % 2 !== 0) {
+    throw new Error("Invalid seed hex");
+  }
+  const I = hmac(sha512, utf8ToBytes(ED25519_CURVE), hexToBytes(seedHex));
   const IL = I.subarray(0, 32);
   const IR = I.subarray(32);
   return {
     key: IL,
     chainCode: IR,
   };
 };

53-69: Optional: enforce apostrophes or document hardened-by-default behavior.

You always add HARDENED_OFFSET regardless of apostrophe. Either enforce apostrophes in isValidPath or add a brief comment clarifying that all segments are treated as hardened.

-  const segments = path
+  // All segments are treated as hardened (SLIP-0010)
+  const segments = path
     .split("/")
     .slice(1)
     .map(replaceDerive)
     .map((el) => parseInt(el, 10));

Add tests for:

  • invalid paths (letters, negatives, ≥ 2^31),
  • paths without apostrophes treated as hardened,
  • seed with 0x prefix.
packages/name-resolution/package.json (1)

21-23: Align engines.node with repo standard.

Repo CI/.nvmrc moved to Node 22.18.0. Consider updating "engines": { "node": ">=22.18.0" } here to prevent accidental installs on older Node.

packages/extension/src/providers/massa/types/index.ts (1)

24-31: Consider optional fields for UX tolerance.

If fromAddressName or toTokenAddress can be absent in some flows, mark them optional to reduce casting downstream.

packages/signers/massa/package.json (2)

21-23: Match Node engines to workspace.

Consider "node": ">=22.18.0" to align with CI and avoid crypto/WebCrypto mismatches on older Node.


1-62: Optional: define package exports.

Add an "exports" map to avoid deep-imports and improve ESM/CJS resolution for consumers.

packages/signers/massa/src/crypto/cross-browser.ts (6)

24-45: Avoid require() in ESM; use dynamic import.

In TS ESM sources, require is undefined at runtime. Use await import('node:crypto') in the Node path.

Apply this diff:

-  // eslint-disable-next-line @typescript-eslint/no-var-requires
-  const crypto = require('crypto')
+  const crypto = await import('node:crypto')

47-82: Hash name normalization between Node and WebCrypto.

Node expects sha256/sha512; WebCrypto expects SHA-256/SHA-512. Current code passes opts.hash verbatim and can break cross‑env. Also, prefer Uint8Array over Buffer for browser salt type.

Apply this diff:

-async function pbkdf2Browser(
-  password: string,
-  salt: Buffer,
-  opts: PBKDF2Options
-): Promise<Uint8Array> {
+async function pbkdf2Browser(
+  password: string,
+  salt: Uint8Array,
+  opts: PBKDF2Options
+): Promise<Uint8Array> {
   const { iterations, keyLength, hash } = opts
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  const crypto = window.crypto || (window as any).msCrypto
-
-  if (!crypto) throw new Error('Your browser does not expose window.crypto.')
+  const subtle = globalThis.crypto?.subtle
+  if (!subtle) throw new Error('WebCrypto subtle API is unavailable.')
@@
-  const derivedKey = await crypto.subtle.deriveKey(
+  const derivedKey = await subtle.deriveKey(
     {
       name: 'PBKDF2',
-      salt: salt,
+      salt,
       iterations: iterations,
-      hash: { name: hash },
+      hash: { name: normalizeHash(hash).web },
     },
     keyMaterial,
     { name: 'AES-GCM', length: keyLength * U8_SIZE_BITS },
     false,
     ['encrypt', 'decrypt']
   )
@@
-  const exportedKey = await crypto.subtle.exportKey('raw', derivedKey)
-  const buffer = Buffer.from(exportedKey)
-
-  return buffer
+  const exportedKey = await subtle.exportKey('raw', derivedKey)
+  return new Uint8Array(exportedKey)

And update typings:

-export type PBKDF2Options = {
+export type PBKDF2Hash = 'sha256' | 'sha512' | 'SHA-256' | 'SHA-512'
+export type PBKDF2Options = {
   iterations: number
   keyLength: number
-  hash: string
+  hash: PBKDF2Hash
 }

Add helper:

function normalizeHash(hash: PBKDF2Hash): { node: 'sha256' | 'sha512'; web: 'SHA-256' | 'SHA-512' } {
  switch (hash) {
    case 'sha256':
    case 'SHA-256':
      return { node: 'sha256', web: 'SHA-256' }
    case 'sha512':
    case 'SHA-512':
      return { node: 'sha512', web: 'SHA-512' }
    default:
      return { node: 'sha256', web: 'SHA-256' } // safe default
  }
}

Finally, use it in pbkdf2Node:

-    crypto.pbkdf2(
+    crypto.pbkdf2(
       password,
       salt,
       iterations,
       keyLength,
-      hash,
+      normalizeHash(hash).node,
       (err, derivedKey) => {

99-109: pbkdf2: unify salt type.

Change salt: Buffer to Uint8Array in the public pbkdf2 signature for consistency with AES helpers and browser environments.

Apply this diff:

 export async function pbkdf2(
   password: string,
-  salt: Buffer,
+  salt: Uint8Array,
   opts: PBKDF2Options
 ): Promise<Uint8Array> {

123-159: Prefer globalThis.crypto; avoid Buffer in browser path.

Use globalThis.crypto.subtle and return Uint8Array to avoid relying on Buffer polyfills in browsers.

Apply this diff:

-  const keyData = await window.crypto.subtle.importKey(
+  const keyData = await globalThis.crypto!.subtle.importKey(
@@
-  const encrypted = await window.crypto.subtle.encrypt(
+  const encrypted = await globalThis.crypto!.subtle.encrypt(
@@
-  return Buffer.from(encrypted)
+  return new Uint8Array(encrypted)

176-217: Minor robustness + lint fix in decrypt (Node path).

  • Don’t reassign function params (Airbnb’s no‑param‑reassign).
  • Validate ciphertext length before slicing auth tag.

Apply this diff:

   if (isNode()) {
-    // eslint-disable-next-line @typescript-eslint/no-var-requires
-    const crypto = require('crypto')
-    encryptedData = Buffer.from(encryptedData)
+    const crypto = await import('node:crypto')
+    const data = Buffer.from(encryptedData)
+    if (data.length < AUTH_TAG_SIZE_BYTES) {
+      throw new Error('encryptedData too short to contain GCM auth tag')
+    }
     const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)
     decipher.setAuthTag(
-      encryptedData.slice(encryptedData.length - AUTH_TAG_SIZE_BYTES)
+      data.slice(data.length - AUTH_TAG_SIZE_BYTES)
     )
     const decrypted = Buffer.concat([
-      decipher.update(
-        encryptedData.slice(0, encryptedData.length - AUTH_TAG_SIZE_BYTES)
-      ),
+      decipher.update(data.slice(0, data.length - AUTH_TAG_SIZE_BYTES)),
       decipher.final(),
     ])
     return decrypted
   }

14-22: Drop legacy msCrypto mention.

IE11 isn’t a target; carrying msCrypto suggests support we don’t provide. The diffs above switch to globalThis.crypto.

packages/signers/massa/src/crypto/passwordSeal.ts (1)

14-21: Iteration count trade‑off: 600k PBKDF2 iterations may jank the UI

600,000 PBKDF2‑SHA256 iterations can cause noticeable latency on lower‑end devices. Consider making this configurable or calibrating at runtime, or switching to a memory‑hard KDF where feasible. Keep default high, but allow tuning.

Would you like a small utility to benchmark KDF latency at startup and pick an iteration count that targets ~250–500 ms on the device?

packages/extension/src/providers/massa/ui/send-transaction/components/send-address-input.vue (6)

127-130: Emit toggle:showContacts on blur as well

Currently emits only on focus. Emit both true and false to keep parent state in sync.

-const changeFocus = (val: FocusEvent) => {
-  isFocus.value = val.type === 'focus';
-  if (isFocus.value) emit('toggle:showContacts', isFocus.value);
-};
+const changeFocus = (val: FocusEvent) => {
+  const focused = val.type === 'focus';
+  isFocus.value = focused;
+  emit('toggle:showContacts', focused);
+};

79-82: Guard against missing network methods

props.network.isValidAddress may be undefined when network is {} (default). Guard before calling to avoid runtime errors.

-const isValidMassaAddress = computed(() => {
-  if (!massaAddress.value || massaAddress.value.trim() === '') return false;
-  return props.network.isValidAddress(massaAddress.value);
-});
+const isValidMassaAddress = computed(() => {
+  const v = massaAddress.value?.trim();
+  if (!v) return false;
+  return typeof props.network?.isValidAddress === 'function'
+    ? !!props.network.isValidAddress(v)
+    : false;
+});

10-16: Avoid rendering when placeholder is unavailable

Rendering an with empty src can trigger unintended requests. Only render the placeholder when a source exists; otherwise show a styled div.

-      <img
-        v-else
-        :src="placeholderIdenticonSrc"
-        alt=""
-        class="send-address-input__avatar-placeholder"
-      />
+      <img
+        v-else-if="placeholderIdenticonSrc"
+        :src="placeholderIdenticonSrc"
+        alt=""
+        class="send-address-input__avatar-placeholder"
+      />
+      <div v-else class="send-address-input__avatar-placeholder"></div>

Also applies to: 108-115


26-28: Prefer CSS classes over inline colors (theme/dark‑mode friendly)

Replace inline color toggling with a class and theme var.

-        :style="{
-          color: massaAddress && !isValidMassaAddress ? 'red' : 'black',
-        }"
+        :class="{ 'is-invalid': massaAddress && !isValidMassaAddress }"

Add to styles (inside .send-address-input__address):

 .send-address-input {
   &__address {
@@
     input {
       width: 290px;
@@
       padding: 0;
     }
+    input.is-invalid {
+      color: @error;
+    }
   }
 }

Also applies to: 189-201


97-103: Computed with side‑effects (sets state) — move to event handler/watch

identiconSrc computed mutates identiconError via nextTick; avoid side‑effects in computed. Set error only in handleIdenticonError or a dedicated watcher.

Do you want me to refactor this to a watch([massaAddress, props.network], ...) that updates a currentIdenticonSrc ref and handles errors without mutating inside a computed?


145-147: Tiny CSS nit: duplicate box-sizing

box-sizing: border-box; is declared twice.

-  box-sizing: border-box;
   border: 1px solid @gray02;
-  box-sizing: border-box;
packages/keyring/package.json (1)

38-53: Engines vs. tooling mismatch: ESLint 9 requires Node ≥18.18.
You bumped dev tooling (eslint 9, TS 5.9) but engines still allow Node 14. This can break local scripts/CI for this package.

Recommended change if the repo standard is Node 18+:

-  "engines": {
-    "node": ">=14.15.0"
-  },
+  "engines": {
+    "node": ">=18.18.0"
+  },
packages/extension/src/libs/background/types.ts (1)

20-27: Avoid typeof on type-only imports (consistency).
If you see TS errors like “typeof references a type-only import,” convert the ethereum/polkadot/kadena imports to value imports for consistency with Solana/Massa.

Apply if needed:

-import type EthereumProvider from '@/providers/ethereum';
-import type PolkadotProvider from '@/providers/polkadot';
-import type KadenaProvider from '@/providers/kadena';
+import EthereumProvider from '@/providers/ethereum';
+import PolkadotProvider from '@/providers/polkadot';
+import KadenaProvider from '@/providers/kadena';
packages/extension/src/ui/action/views/network-activity/index.vue (1)

222-245: Refine Massa status mapping to avoid false failures and keep polling non‑terminal states.
Right now, any status other than explicit success defaults to failed. Safer to mark as failed/dropped only for terminal negatives; keep polling otherwise.

Apply:

-  } else if (props.network.provider === ProviderName.massa) {
-    if (!info) return;
-    const massaInfo = info as MassaRawInfo;
-    if (isActivityUpdating || massaInfo === OperationStatus.PendingInclusion)
-      return;
-
-    let status = ActivityStatus.failed;
-    // if the transaction is not found, and it's been less than 1 minute, wait for it to be processed
-    if (
-      massaInfo === OperationStatus.NotFound &&
-      Date.now() < activity.timestamp + 60_000
-    ) {
-      return;
-    } else if (
-      massaInfo === OperationStatus.Success ||
-      massaInfo === OperationStatus.SpeculativeSuccess
-    ) {
-      status = ActivityStatus.success;
-    }
-
-    activity.status = status;
-    activity.rawInfo = massaInfo;
-    updateActivitySync(activity).then(() => updateVisibleActivity(activity));
+  } else if (props.network.provider === ProviderName.massa) {
+    if (!info) return;
+    const massaInfo = info as MassaRawInfo;
+    if (isActivityUpdating || massaInfo === OperationStatus.PendingInclusion) return;
+
+    // Give NotFound up to 1 minute to appear
+    if (
+      massaInfo === OperationStatus.NotFound &&
+      Date.now() < activity.timestamp + 60_000
+    ) {
+      return;
+    }
+
+    let status: ActivityStatus | null = null;
+    if (
+      massaInfo === OperationStatus.Success ||
+      massaInfo === OperationStatus.SpeculativeSuccess
+    ) {
+      status = ActivityStatus.success;
+    } else if (massaInfo === OperationStatus.NotFound) {
+      status = ActivityStatus.dropped;
+    } else {
+      // non-terminal/unknown -> keep polling
+      return;
+    }
+
+    activity.status = status;
+    activity.rawInfo = massaInfo;
+    updateActivitySync(activity).then(() => updateVisibleActivity(activity));
   }
packages/extension/src/providers/massa/networks/index.ts (1)

5-8: Type the registry for clarity and IDE help.

Annotate the export as a typed Partial<Record<NetworkNames, BaseNetwork>> to make intent explicit and avoid widening.

-import { NetworkNames } from '@enkryptcom/types';
+import { NetworkNames } from '@enkryptcom/types';
+import { BaseNetwork } from '@/types/base-network';
 
-export default {
+const networks: Partial<Record<NetworkNames, BaseNetwork>> = {
   [NetworkNames.Massa]: mainnet,
   [NetworkNames.MassaBuildnet]: buildnet,
-};
+} as const;
+
+export default networks;
packages/extension/src/providers/massa/methods/index.ts (1)

7-19: Drop the ESLint disable and consume the param; also name the passthrough middleware.

Keeps the signature stable for call sites while staying lint-clean and easier to grep.

-export default (
-  // eslint-disable-next-line @typescript-eslint/no-unused-vars
-  _provider: BackgroundProviderInterface,
-): MiddlewareFunction[] => {
-  return [
+export default (_provider: BackgroundProviderInterface): MiddlewareFunction[] => {
+  void _provider;
+  const massa_passthrough: MiddlewareFunction = async (_req, _res, next) => next();
+  return [
     massa_getBalance,
     massa_getNetwork,
     massa_setNetwork,
-    async (request, response, next) => {
-      // Add any additional Massa-specific middleware logic here
-      return next();
-    },
+    massa_passthrough,
   ];
 };
packages/extension/src/ui/action/App.vue (2)

214-222: Optional: avoid hard-coded buy URL and guard when no selected account.

  • Consider moving the Massa buy link into the network config (like others) for consistency.
  • The default branch assumes a selected account; add a safe fallback to prevent a runtime NPE when no accounts exist.
       case NetworkNames.Massa:
-        return 'https://www.massa.net/get-mas';
+        return 'https://www.massa.net/get-mas'; // consider sourcing from network.options.buyLink
       default:
-        return `https://ccswap.myetherwallet.com/?to=${currentNetwork.value.displayAddress(
-          accountHeaderData.value.selectedAccount!.address,
-        )}&network=${currentNetwork.value.name}&crypto=${
-          currentNetwork.value.currencyName
-        }&platform=enkrypt`;
+        if (accountHeaderData.value.selectedAccount) {
+          return `https://ccswap.myetherwallet.com/?to=${currentNetwork.value.displayAddress(
+            accountHeaderData.value.selectedAccount.address,
+          )}&network=${currentNetwork.value.name}&crypto=${currentNetwork.value.currencyName}&platform=enkrypt`;
+        }
+        return 'https://ccswap.myetherwallet.com/?platform=enkrypt';

325-337: Fix: ensure selectedAccount is null when no active accounts.

Avoids assigning undefined to a field typed as EnkryptAccount | null and prevents downstream non-null assertions from breaking.

-const selectedAddress = await domainState.getSelectedAddress();
-
-let selectedAccount = activeAccounts[0];
+const selectedAddress = await domainState.getSelectedAddress();
+
+let selectedAccount: EnkryptAccount | null = activeAccounts[0] ?? null;
 if (selectedAddress) {
   const found = activeAccounts.find(acc => acc.address === selectedAddress);
   if (found) selectedAccount = found;
 }
 
 accountHeaderData.value = {
   activeAccounts,
   inactiveAccounts,
   selectedAccount,
packages/extension/src/providers/massa/methods/massa_getNetwork.ts (1)

12-19: Tighten control flow; try/catch seems unnecessary.

this.network.name should be defined; remove try/catch and return after responding to avoid accidental fallthrough.

-  if (payload.method !== 'massa_getNetwork') return next();
-  else {
-    try {
-      res(null, this.network.name);
-    } catch {
-      res(null, NetworkNames.Massa);
-    }
-  }
+  if (payload.method !== 'massa_getNetwork') return next();
+  res(null, this.network.name ?? NetworkNames.Massa);
+  return;
packages/signers/massa/src/crypto/base58.ts (1)

4-6: Nit: Clarify it's Base58Check, not plain Base58.

The implementation uses bs58check. Update the docstring to avoid confusion.

-/**
- * Base58 implementation of the Serializer interface.
- */
+/**
+ * Base58Check implementation of the Serializer interface.
+ */
packages/keyring/tests/generate.test.ts (2)

256-279: Optional: Lock keyring after assertions for consistency with other tests.

Keeps patterns uniform and avoids residual state in future edits.

       expect(pair.address).equals(
         "AU12XkXdPKYBwuy3NANX44dR3cL7WMobsYcj1fWMv1mxkkHU9qBWB",
       );
+      keyring.lock();

280-305: Optional: Lock keyring after assertions.

       expect(pair.address).equals(
         "AU12M9c9LwomXh7sEuK779RnV8QbzFfQRZ1qpKhwWzXPpShhrBfz2",
       );
+      keyring.lock();
packages/extension/src/providers/massa/methods/massa_setNetwork.ts (2)

16-33: Make params parsing robust and match case-insensitively.

Handle object/array params and case differences; return a clearer error if not found.

-      const networkName = payload.params?.[0];
+      const raw = payload.params as unknown;
+      const requested =
+        Array.isArray(raw) ? raw[0] : (raw as any)?.name ?? raw;
+      const networkName =
+        typeof requested === 'string' ? requested : undefined;

       if (!networkName) {
         res(getCustomError('Network name is required'));
         return;
       }

-      // Check if the network exists
-      const availableNetworks = Object.keys(massaNetworks);
-
-      if (!availableNetworks.includes(networkName)) {
+      const keys = Object.keys(massaNetworks);
+      const matchedKey = keys.find(
+        k => k.toLowerCase() === networkName.toLowerCase(),
+      );
+      if (!matchedKey) {
         res(
           getCustomError(
-            `Invalid network name. Available networks: ${availableNetworks.join(', ')}`,
+            `Invalid network name. Available networks: ${keys.join(', ')}`,
           ),
         );
         return;
       }

-      // Get the network object
-      const network = massaNetworks[networkName as keyof typeof massaNetworks];
+      // Get the network object
+      const network = massaNetworks[matchedKey as keyof typeof massaNetworks];

39-44: Minor: setRequestProvider exists; no need for guard.

You can call it directly; the class always defines it.

-      if (this.setRequestProvider) {
-        this.setRequestProvider(network);
-        res(null, { success: true, network: network.name });
-      } else {
-        res(getCustomError('Network switching not supported'));
-      }
+      this.setRequestProvider(network);
+      res(null, { success: true, network: network.name });
packages/extension/src/ui/action/views/network-assets/index.vue (1)

62-68: Use computed selectedAddress instead of non‑null assertion.

Avoids potential undefined at runtime and keeps template consistent.

-    <custom-evm-token v-if="showAddCustomTokens && isEvmNetwork" :address="props.accountInfo.selectedAccount?.address!"
+    <custom-evm-token v-if="showAddCustomTokens && isEvmNetwork" :address="selectedAddress"
       :network="(props.network as EvmNetwork)" @update:token-added="addCustomAsset"
       @update:close="toggleShowAddCustomTokens"></custom-evm-token>
@@
-    <custom-massa-token v-if="showAddCustomTokens && isMassaNetwork" :address="props.accountInfo.selectedAccount?.address!"
+    <custom-massa-token v-if="showAddCustomTokens && isMassaNetwork" :address="selectedAddress"
       :network="props.network" @update:token-added="addCustomAsset"
       @update:close="toggleShowAddCustomTokens"></custom-massa-token>
packages/extension/src/providers/massa/ui/send-transaction/components/send-token-select.vue (4)

2-2: Add keyboard accessibility to the clickable row

Anchor without href is not keyboard-activatable. Add role and key handlers (or switch to a button) to meet a11y basics.

-  <a class="send-token-select" @click="emit('update:toggleTokenSelect')">
+  <a
+    class="send-token-select"
+    role="button"
+    tabindex="0"
+    @click="emit('update:toggleTokenSelect')"
+    @keydown.enter.prevent="emit('update:toggleTokenSelect')"
+    @keydown.space.prevent="emit('update:toggleTokenSelect')"
+  >

4-11: Harden null/undefined fields; improve alt text

token.icon/name/symbol can be undefined (Partial). Avoid broken UI and improve accessibility.

-      <img :src="token.icon" alt="" />
+      <img :src="token.icon" :alt="token.symbol || token.name || 'token'" />
-      <h5>{{ token.name }}</h5>
+      <h5>{{ token.name || 'Unknown' }}</h5>
-        <span>{{ token.symbol }}</span>
+        <span>{{ token.symbol || '' }}</span>

53-56: Duplicate CSS declaration

box-sizing is set twice. Remove the duplicate.

   box-sizing: border-box;
-  border: 1px solid @gray02;
-  box-sizing: border-box;
+  border: 1px solid @gray02;

84-93: Avoid fixed widths for text blocks

Fixed 290px widths will truncate in narrow layouts and hurt i18n. Let flex handle it.

-      width: 290px;
+      width: auto;
+      max-width: 100%;
-      width: 290px;
+      width: auto;
+      max-width: 100%;

Also applies to: 94-107

packages/extension/src/providers/massa/methods/massa_getBalance.ts (1)

16-21: Validate type/whitespace and use JSON‑RPC error code -32602 for invalid params

Current check allows non-string inputs and returns a non-standard error code. Trim input and return -32602 for invalid params.

-      const address = payload.params?.[0];
+      const raw = payload.params?.[0];
       const network = this.network as MassaNetwork;
-      if (!address || !network.isValidAddress(address)) {
-        res(getCustomError('Please enter a valid Massa address'));
+      if (typeof raw !== 'string') {
+        res(getCustomError('Please enter a valid Massa address', -32602));
+        return;
+      }
+      const address = raw.trim();
+      if (!address || !network.isValidAddress(address)) {
+        res(getCustomError('Please enter a valid Massa address', -32602));
         return;
       }
packages/signers/massa/src/crypto/varintVersioner.ts (1)

17-20: Avoid spread to construct Uint8Array

Spreading allocates intermediate arrays. Use pre-sized buffer for a tiny perf win.

-    const versionArray = varint.encode(version);
-    return new Uint8Array([...versionArray, ...data]);
+    const versionArray = varint.encode(version);
+    const out = new Uint8Array(versionArray.length + data.length);
+    out.set(versionArray, 0);
+    out.set(data, versionArray.length);
+    return out;
packages/signers/massa/tests/sign.test.ts (2)

14-15: Make hex prefix explicit for robustness

Pass true to bufferToHex to guarantee 0x prefix regardless of defaults.

-  const msgHash = bufferToHex(blake2AsU8a(msg));
+  const msgHash = bufferToHex(blake2AsU8a(msg), true);

18-26: Consider full BIP44 path

Optional: include the address index (e.g., .../0/0) for clarity and future wallet interoperability.

If you decide to change it, update both occurrences:

-    const keypair = await signer.generate(MNEMONIC, "m/44'/632'/0'/0'");
+    const keypair = await signer.generate(MNEMONIC, "m/44'/632'/0'/0/0");

Verify no consumers assume the shorter path.

packages/extension/src/providers/massa/libs/api.ts (1)

27-31: Optional: normalize empty responses in getBalance

If provider returns undefined or malformed entry, ensure a string is always returned.

-    if (!account) return '0';
-    return account.balance.toString();
+    if (!account || account.balance == null) return '0';
+    return String(account.balance);
packages/extension/src/providers/massa/ui/send-transaction/index.vue (3)

549-549: Use numeric price, not formatted pricef, in payload.

toToken.price should be the raw numeric-string (value), not the formatted display string (valuef).

-        price: selectedAsset.value.valuef || '0',
+        price: selectedAsset.value.value || '0',

567-571: Avoid Node Buffer in browser UI for base64.

Buffer may be undefined in the web extension build. Use Web APIs or import a polyfill.

Minimal swap:

-        txData: Buffer.from(JSON.stringify(txVerifyInfo), 'utf8').toString(
-          'base64',
-        ),
+        txData: btoa(unescape(encodeURIComponent(JSON.stringify(txVerifyInfo)))),

Alternatively import a polyfill once: import { Buffer } from 'buffer' and keep current code. Please confirm which approach your build supports.


310-351: Enforce minimal fee at runtime (not just via input min).

Input min isn’t sufficient. Guard in validation to prevent sending below network minimal fee.

   const amountBN = new BigNumber(sendAmount.value);
   if (amountBN.lte(0)) {
     return false;
   }

-  return hasEnoughBalance.value;
+  // Fee guard
+  const feeBN = new BigNumber(fee.value || '0');
+  const minFeeBN = new BigNumber(minimalFee.value || '0');
+  if (feeBN.lt(minFeeBN)) return false;
+  return hasEnoughBalance.value;
packages/extension/src/providers/massa/index.ts (1)

78-82: Don’t JSON.stringify message string in error.

JSON.stringify(e.message) produces quoted JSON strings. Return a plain string.

-        return {
-          error: JSON.stringify(e.message),
-        };
+        return { error: String(e?.message ?? e) };
packages/signers/massa/src/index.ts (1)

39-51: Await verify to properly catch async errors.

Keeps try/catch effective if the inner verify throws.

-      return massaPublicKey.verify(hexToBuffer(msgHash), signature);
+      return await massaPublicKey.verify(hexToBuffer(msgHash), signature);
packages/extension/src/ui/action/views/network-assets/components/custom-massa-token.vue (1)

171-178: Token type consistency check.

You’re setting type: TokenType.ERC20 for an MRC‑20 token. If a Massa‑specific enum exists, use it; otherwise confirm addErc20Token expects this value for Massa.

packages/extension/src/providers/massa/ui/libs/signer.ts (4)

80-86: Avoid non‑null assertion on chainId; fail fast with clear error

chainId! will crash obscurely if misconfigured. Add an explicit guard.

Apply this diff:

-  const chainId = (network as MassaNetworkOptions).chainId;
-  const publicKey = PublicKey.fromString(account.publicKey);
-  const serialized = OperationManager.canonicalize(
-    chainId!,
-    operationDetails,
-    publicKey,
-  );
+  const chainId = (network as MassaNetworkOptions).chainId;
+  if (chainId === undefined || chainId === null) {
+    throw new Error('Missing Massa chainId in network config');
+  }
+  const publicKey = PublicKey.fromString(account.publicKey);
+  const serialized = OperationManager.canonicalize(chainId, operationDetails, publicKey);

87-92: Nit: rename local variable for clarity

Minor readability tweak.

-  const bufferTosign = bufferToHex(serialized);
+  const bufferToSign = bufferToHex(serialized);
   return sendUsingInternalMessengers({
     method: InternalMethods.sign,
-    params: [bufferTosign, account],
+    params: [bufferToSign, account],

115-121: Broaden message payload type; don’t assume Node Buffer in browser builds

Browser builds may lack global Buffer. Accept Uint8Array | string and handle accordingly.

Apply this diff:

-export const MassaMessageSigner = (options: {
+export const MassaMessageSigner = (options: {
   account: EnkryptAccount;
   network: BaseNetwork;
-  payload: Buffer;
+  payload: Uint8Array | Buffer | string;
 }): Promise<InternalOnMessageResponse> => {
   const { account, payload } = options;

-  const msgHash = bufferToHex(payload);
+  const msgHash =
+    typeof payload === 'string' ? payload : bufferToHex(payload as Uint8Array);

Also applies to: 122-126


89-109: Consistent error surface from internal signer

.then(res => res.error ? Promise.reject(res) : …) mixes shapes. Consider throwing new Error(message) to unify catch handling at call sites.

packages/extension/src/providers/massa/ui/send-transaction/verify-transaction/index.vue (4)

151-153: isWindowPopup is set from hardware flag; likely wrong source

isWindowPopup should reflect window context, not hardware. Use computed isPopup.

Apply this diff:

-  isWindowPopup.value = account.value.isHardware;
+  isWindowPopup.value = isPopup;

15-21: Show error paragraph only when there’s an error

Avoid empty red line in UI.

Apply this diff:

-        <p
-          class="verify-transaction__description"
-          style="color: red"
-          :class="{ popup: isPopup }"
-        >
+        <p
+          v-if="errorMsg"
+          class="verify-transaction__description"
+          style="color: red"
+          :class="{ popup: isPopup }"
+        >
           {{ errorMsg }}
         </p>

137-139: Ensure Buffer polyfill/import in the SFC

Buffer.from(...) requires a polyfill/import in many bundlers. Import explicitly.

Apply this diff:

 <script setup lang="ts">
+import { Buffer } from 'buffer';

Also applies to: 88-111


278-283: Don’t auto-hide Operation ID; let the user dismiss

Auto‑hiding after 4s can frustrate copying/sharing.

Apply this diff to remove the timeout:

-    setTimeout(() => {
-      showOperationId.value = false;
-      isProcessing.value = false;
-      callToggleRate();
-      router.push({ name: 'activity', params: { id: network.value.name } });
-    }, 4000);
+    isProcessing.value = false;

Optionally navigate only after Close.

packages/extension/src/providers/massa/networks/massa-base.ts (2)

40-105: Price/sparkline fetch is best‑effort; add minimal telemetry when it fails

The catch {} fully hides failures, complicating support. Log once at debug level.

Apply this minimal diff:

-      } catch {
-        // Price data not available, continue with default values
-      }
+      } catch (e) {
+        // Price data not available, continue with default values
+        console.debug('Massa price data unavailable:', e);
+      }

22-35: Constructor assumes chainId; validate inputs

Add a sanity check to fail fast if misconfigured networks slip in.

Apply this diff:

   constructor(options: MassaNetworkOptions) {
     super(options);
-    this.chainId = options.chainId!;
+    if (options.chainId === undefined || options.chainId === null) {
+      throw new Error('MassaNetwork: chainId is required');
+    }
+    this.chainId = options.chainId as unknown as bigint;
packages/signers/massa/src/libs/address.ts (1)

162-165: Consistently varint‑encode the type byte

Functionally equivalent for 0/1, but encoding via varint mirrors fromString and avoids footguns if types expand.

Apply this diff:

-    address.bytes = Uint8Array.from([
-      AddressType.EOA,
-      ...address.versioner.attach(Version.V0, rawBytes),
-    ]);
+    address.bytes = Uint8Array.from([
+      ...varint.encode(AddressType.EOA),
+      ...address.versioner.attach(Version.V0, rawBytes),
+    ]);

@kvhnuke kvhnuke merged commit b4a2ada into main Sep 16, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants