Skip to content

Feat/rf 2840 migrating tonconnect to hub#4

Open
RyukTheCoder wants to merge 7 commits intonextfrom
feat/rf-2840-migrating-tonconnect-to-hub
Open

Feat/rf 2840 migrating tonconnect to hub#4
RyukTheCoder wants to merge 7 commits intonextfrom
feat/rf-2840-migrating-tonconnect-to-hub

Conversation

@RyukTheCoder
Copy link
Copy Markdown
Owner

@RyukTheCoder RyukTheCoder commented Apr 19, 2026

Summary

Added Ton builders, utils and types to the wallets core.

Migrated TonConnect to use the new hub APIs for ton namespaces and updated documentation:

  • updated resolving namespace for ton wallets to legacy networks
  • created an initialization function to be called with TonConnect configs before using TonConnect

How did you test this change?

TonConnect was tested end-to-end within the Hub environment:

  • Connecting to Ton Wallets
  • Reconnecting on page reload if previously connected
  • Disconnecting when user disconnects from the wallet or directly from the app
  • Executing transactions from Ton namespace

Checklist:

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • Implemented a user interface (UI) change, referencing our Figma design to ensure pixel-perfect precision.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added TonConnect wallet provider with full integration support.
    • Introduced TON blockchain support across the wallet infrastructure.
    • Enabled TON wallet connection, disconnection, and eager connection capabilities.
  • Documentation

    • Added TonConnect provider documentation including implementation notes and known limitations.
    • Updated wallet API status tables to reflect TON support.

llawliet-l-l and others added 7 commits December 31, 2025 08:18
# Conflicts:
#	wallets/core/package.json
#	wallets/core/src/hub/provider/types.ts
#	wallets/react/src/hub/helpers.ts
#	wallets/readme.md

# Conflicts:
#	wallets/provider-all/src/index.ts
#	wallets/readme.md
@kody-ai
Copy link
Copy Markdown

kody-ai Bot commented Apr 19, 2026

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Cross File
Business Logic

Access your configuration settings here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 19, 2026

📝 Walkthrough

Walkthrough

Adding comprehensive TON blockchain support to the wallet management system. A new TON namespace module is created in wallets/core with types, utilities, and builders. The Hub is extended to accept and pass per-provider configuration arguments. The TonConnect provider is refactored from a monolithic structure into a modular architecture using versioned exports. React integration is updated to configure wallet-specific options.

Changes

Cohort / File(s) Summary
TON Namespace Core
wallets/core/src/namespaces/ton/types.ts, wallets/core/src/namespaces/ton/constants.ts, wallets/core/src/namespaces/ton/utils.ts, wallets/core/src/namespaces/ton/builders.ts, wallets/core/src/namespaces/ton/mod.ts
New TON namespace module exports types (TonActions, ProviderAPI), CAIP constants ('tvm', '-239'), utilities for CAIP account formatting, and action builders for connect and canEagerConnect flows.
Hub Configuration
wallets/core/src/hub/hub.ts, wallets/core/src/hub/provider/provider.ts, wallets/core/src/hub/provider/types.ts
Hub init() and runAll() methods now accept optional per-provider configuration arguments. Provider init() accepts args passed to initialization callbacks. CommonNamespaces interface extended to include ton namespace.
Package Exports
wallets/core/package.json, wallets/core/namespaces/ton/package.json
New @rango-dev/wallets-core/namespaces/ton package export added to core package.json. Separate package.json created for TON namespace with ESM type and dist output paths configured.
TonConnect Provider Refactor
wallets/provider-tonconnect/src/provider.ts, wallets/provider-tonconnect/src/tonConnect.ts, wallets/provider-tonconnect/src/utils.ts, wallets/provider-tonconnect/src/types.ts, wallets/provider-tonconnect/src/constants.ts, wallets/provider-tonconnect/src/mod.ts
TonConnect provider refactored into modular architecture. New TonConnect class handles lazy loading of UI library. buildProvider constructs versioned provider via ProviderBuilder. Utilities export shared instance and connection wait logic. Package entry points shifted from index.js to mod.js.
TonConnect Actions & Hooks
wallets/provider-tonconnect/src/actions/ton.ts, wallets/provider-tonconnect/src/hooks/ton.ts, wallets/provider-tonconnect/src/namespaces/ton.ts
Three new action functions (connect, disconnect, canEagerConnect) implement TON wallet operations. Disconnect hook manages status change subscriptions. Namespace builder wires actions with lifecycle handlers and error standardization.
TonConnect Signer
wallets/provider-tonconnect/src/signer.ts
Signer import path updated from ./ton-signer.js to ./signers/ton.js. Input type changed from TonConnectUI to derived Provider type with network-specific instance resolution.
Deleted TonConnect Files
wallets/provider-tonconnect/src/index.ts, wallets/provider-tonconnect/src/helpers.ts
Original monolithic index module and dynamic import helpers removed. Functionality redistributed across new modular files (provider.ts, tonConnect.ts, utils.ts).
TonConnect Package Configuration
wallets/provider-tonconnect/package.json, wallets/provider-tonconnect/readme.md
Entry points redirected to mod.js/mod.ts. Build script updated with --inputs src/mod.ts. Documentation expanded with initialization config, switch account limitations, disconnect behavior notes, and init error semantics.
TonConnect Provider Wiring
wallets/provider-all/src/index.ts
TON Connect provider import changed from namespace import to named versions export. Removed conditional initialization check and legacy provider wrapping. Direct tonconnect inclusion in provider list.
React Integration
wallets/react/src/hub/useHubAdapter.ts, wallets/react/src/hub/helpers.ts, wallets/react/src/legacy/types.ts
Hub initialization now passes params.configs?.walletOptions to getHub().init(). CAIP namespace mapping extended for TON. Provider props config extended with optional walletOptions object supporting provider-specific and namespace-specific configuration.
Widget Configuration
widget/embedded/src/containers/Wallets/Wallets.tsx
Provider component extended with walletOptions config for WalletTypes.TON_CONNECT providing manifestUrl from top-level config.
Documentation
wallets/readme.md
Wallets API status tables updated to include TonConnect with TON support marked (), Auto Connect supported, Switch Account and Switch Network marked unsupported ().

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 In networks new, the TON does gleam,
With namespaces and builders—a modular dream!
Args flow free through hub's refrain,
Config and hooks in sweet campaign,
TonConnect springs to structured life,
Clean and versioned, free of strife!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: migrating TonConnect to the Hub architecture. It is specific and directly reflects the primary change across the substantial changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rf-2840-migrating-tonconnect-to-hub
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/rf-2840-migrating-tonconnect-to-hub

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

Comment on lines +24 to +25
We set **'installed'** to `true` on initialization even if we can't initialize the TonConnect instance.
Instead, we throw an error when the user tries to connect and we haven't initialized the TonConnect instance.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

kody code-review Bug high

Logic error: The 'installed' property is hardcoded to true regardless of whether the TonConnect instance is successfully initialized. This violates the provider's availability invariant, causing the UI to display the wallet as available even when it is in an unusable state (e.g., due to missing or invalid configuration). Consequently, users will encounter unexpected errors when attempting to connect to a wallet that incorrectly claimed to be installed.

We set **'installed'** to `true` only after the TonConnect instance is successfully initialized with the provided configuration.
If initialization fails or configuration is missing, **'installed'** remains `false` to prevent the UI from offering an unusable connection option.
Prompt for LLM

File wallets/provider-tonconnect/readme.md:

Line 24 to 25:

Identify and suggest improvements for the logic error in the TonConnect initialization process.

Suggested Code:

We set **'installed'** to `true` only after the TonConnect instance is successfully initialized with the provided configuration.
If initialization fails or configuration is missing, **'installed'** remains `false` to prevent the UI from offering an unusable connection option.

Talk to Kody by mentioning @kody

Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.

Copy link
Copy Markdown

@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: 8

🧹 Nitpick comments (5)
wallets/core/src/namespaces/ton/types.ts (1)

14-15: Prefer unknown over any for ProviderAPI.

Record<string, unknown> keeps flexibility while avoiding unsafe propagation of any.

♻️ Proposed refactor
-// eslint-disable-next-line `@typescript-eslint/no-explicit-any`
-export type ProviderAPI = Record<string, any>;
+export type ProviderAPI = Record<string, unknown>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/core/src/namespaces/ton/types.ts` around lines 14 - 15, Replace the
unsafe any-based type alias ProviderAPI with a safer unknown-based type: change
export type ProviderAPI = Record<string, any> to export type ProviderAPI =
Record<string, unknown>, and update any downstream places that rely on implicit
any (e.g., functions or methods that index into ProviderAPI or pass it to other
APIs) to perform proper type guards or casts before accessing properties or
assigning to narrower types; ensure symbols referencing ProviderAPI (the
ProviderAPI type itself, and any functions accepting or returning ProviderAPI)
compile after the change by adding explicit casts or runtime checks where
necessary.
wallets/core/src/namespaces/ton/utils.ts (1)

7-17: Remove redundant .toString() call.

Since account is already typed as string (from accounts: string[]), the .toString() call on line 11 is unnecessary.

♻️ Suggested simplification
 export function formatAccountsToCAIP(accounts: string[]) {
   return accounts.map(
     (account) =>
       AccountId.format({
-        address: account.toString(),
+        address: account,
         chainId: {
           namespace: CAIP_NAMESPACE,
           reference: CAIP_TON_CHAIN_ID,
         },
       }) as CaipAccount
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/core/src/namespaces/ton/utils.ts` around lines 7 - 17, The function
formatAccountsToCAIP unnecessarily calls .toString() on each account string;
remove the redundant .toString() and pass account directly into AccountId.format
in formatAccountsToCAIP so it uses the string value (replace account.toString()
with account) while keeping the existing AccountId.format payload (namespace/
reference) intact.
wallets/react/src/legacy/types.ts (1)

83-90: Index signature vs mapped type syntax.

If WalletType is a string literal union (e.g., 'metamask' | 'tonconnect' | ...), the current [key: WalletType] syntax creates an index signature that accepts any WalletType as a key but doesn't enforce that only valid wallet types can be used. Consider using a mapped type with Partial for stricter typing:

♻️ Suggested type refinement
    walletOptions?: {
-     [key: WalletType]: {
+     [key in WalletType]?: {
        provider?: unknown;
        namespaces?: {
          [namespaceId: string]: unknown;
        };
-     };
+     };
    };

Or alternatively:

walletOptions?: Partial<Record<WalletType, {
  provider?: unknown;
  namespaces?: Record<string, unknown>;
}>>;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/react/src/legacy/types.ts` around lines 83 - 90, The walletOptions
type uses an index signature "[key: WalletType]" which doesn't enforce that only
the union members of WalletType are allowed as keys; change it to a
mapped/utility type so keys are limited to WalletType (e.g., use
Partial<Record<WalletType, { provider?: unknown; namespaces?: Record<string,
unknown> }>> or an equivalent mapped type like { [K in WalletType]?: {
provider?: unknown; namespaces?: Record<string, unknown> } }). Update the
namespaces inner type from the ad-hoc index signature to Record<string, unknown>
for clarity.
wallets/provider-tonconnect/src/provider.ts (1)

19-21: Don’t silently swallow initialization failures.

The empty catch makes TonConnect init failures invisible in logs and harder to diagnose in production.

🔧 Proposed improvement
-        } catch (_) {
-          /* empty */
+        } catch (error) {
+          console.warn('[ton] initialization failed.', error);
         } finally {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/provider-tonconnect/src/provider.ts` around lines 19 - 21, The catch
block in provider.ts that swallows errors during TonConnect initialization (the
catch (_) { /* empty */ } around the TonConnect init) hides failures; change it
to capture the error (e) and surface it by logging the error with context (e.g.,
"Failed to initialize TonConnect" plus error.stack/message) using the existing
logger or console.error, and either rethrow the error or set a visible
initialization-failed state/flag so callers can handle it instead of silently
continuing.
wallets/provider-tonconnect/src/actions/ton.ts (1)

46-52: Narrow getInstance type to eliminate unsafe cast.

Line 50 casts getInstance() to TonConnectUI despite the parameter type being () => TonProviderAPI. Since TonConnect.getInstance() already returns TonConnectUI and the sole call site passes tonConnect.getInstance, narrowing the parameter type is safe and aligns with the pattern used in the connect() function in the same file.

Proposed refactor
 export function canEagerConnect(
-  getInstance: () => TonProviderAPI
+  getInstance: () => TonConnectUI
 ): FunctionWithContext<TonActions['canEagerConnect'], Context> {
   return async () => {
-    const tonConnectUI = getInstance() as TonConnectUI;
+    const tonConnectUI = getInstance();
     const connectionRestored = await tonConnectUI.connectionRestored;
     return connectionRestored;
   };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/provider-tonconnect/src/actions/ton.ts` around lines 46 - 52, The
parameter getInstance for canEagerConnect is typed as () => TonProviderAPI but
the implementation casts its result to TonConnectUI; change the parameter type
to () => TonConnectUI (matching the actual caller tonConnect.getInstance and the
pattern used in connect()) and remove the unsafe cast inside canEagerConnect so
you call getInstance() directly as a TonConnectUI to access connectionRestored.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wallets/core/src/hub/hub.ts`:
- Around line 77-79: The per-namespace init arguments passed from hub (where
namespaceMethod is invoked with
args?.[provider.id]?.namespaces?.[namespace.namespaceId]) are dropped because
Namespace.init is defined without parameters; update the Namespace API to accept
and forward those args: change the signature of init in
wallets/core/src/hub/namespaces/namespace.ts (and its implementations) to accept
an optional parameter (e.g., init(initArgs?: unknown)) and ensure each concrete
namespace implementation consumes or forwards initArgs appropriately so the
hub-provided per-namespace args are honored.
- Around line 77-79: The namespace methods (e.g., Namespace.init(),
Namespace.state() and other instance methods) are being invoked detached via
namespaceMethod(...) so their `this` is lost and private fields/methods like
`this.#initiated`, `this.#store` and `this.#storeId()` fail; fix by invoking the
method with the namespace instance as its context (call the function with
.call(namespace, ...) or otherwise bind namespaceMethod to the namespace) when
calling namespaceMethod in hub.ts so the method runs with the correct `this`.

In `@wallets/provider-tonconnect/readme.md`:
- Around line 5-10: Change the vague link text "More about implementation
status" to a descriptive label such as "Implementation status in the project
README" (so screen readers know destination) and update the link target as in
the diff; also fix the heading-level jump by using a consistent heading level
(e.g., change "#### ⚠️ Initialization" to "### ⚠️ Initialization" or adjust
surrounding headings to avoid skipping from H2 to H4), and ensure the config
keys mentioned remain code-formatted exactly as
configs.walletOptions[WalletTypes.TON_CONNECT] (alias
configs.walletOptions.tonconnect) for clarity and accessibility.

In `@wallets/provider-tonconnect/src/hooks/ton.ts`:
- Around line 17-36: The handler (context, err) => { ... } currently checks
instance() before rethrowing an upstream error, which can mask the original
error; modify the logic so that if err is truthy and instanceof Error the
function rethrows err immediately before calling instance(), so the original
error is preserved; keep the subsequent logic that creates eventCallback, calls
instance(), assigns unsubscribe = tonInstance.onStatusChange(eventCallback), and
only then handles missing instance errors.

In `@wallets/provider-tonconnect/src/tonConnect.ts`:
- Around line 16-19: The initialization guard in initialize() is inverted: after
assigning this.#env the code uses "if (this.#env) throw new Error('Environments
are not set')", which always throws; change the condition to check for missing
env (e.g., if (!this.#env) throw ...) so initialize() only throws when the
environment value is falsy; update the guard around this.#env in the
initialize() method of the TonConnect-related class accordingly.

In `@wallets/provider-tonconnect/src/types.ts`:
- Line 1: The import of LegacyNetworks must be a runtime import (not a type-only
import) because the enum LegacyNetworks is used as a value in a computed
property key (LegacyNetworks.TON); change the line that currently uses "import
type { LegacyNetworks }" to a normal import so LegacyNetworks is emitted at
runtime and can be accessed by the computed key in this file (types.ts),
ensuring any usage like LegacyNetworks.TON works as intended.

In `@wallets/react/src/hub/useHubAdapter.ts`:
- Line 89: The init call getHub().init(params.configs?.walletOptions) can use a
stale first-render walletOptions; update the logic so init uses the latest
walletOptions snapshot (not just the initial params) — e.g., store walletOptions
in the shared dataRef used by the readystatechange handler and ensure dataRef is
updated whenever params.configs?.walletOptions changes so the delayed
readystatechange/init uses the current config; specifically, update the place
that sets dataRef (and any related useEffect or subscription) to include
walletOptions and change the readystatechange/init code to read walletOptions
from dataRef instead of the original params variable.

In `@widget/embedded/src/containers/Wallets/Wallets.tsx`:
- Around line 108-112: walletOptions currently always includes a
WalletTypes.TON_CONNECT entry with provider.manifestUrl set from
config.tonConnect?.manifestUrl which can be undefined; change the construction
of walletOptions so the TON_CONNECT entry is only added when
config.tonConnect?.manifestUrl is truthy (e.g., compute manifestUrl =
config.tonConnect?.manifestUrl and conditionally spread or assign the
[WalletTypes.TON_CONNECT] object only if manifestUrl exists) to avoid emitting
an invalid manifestUrl into provider options.

---

Nitpick comments:
In `@wallets/core/src/namespaces/ton/types.ts`:
- Around line 14-15: Replace the unsafe any-based type alias ProviderAPI with a
safer unknown-based type: change export type ProviderAPI = Record<string, any>
to export type ProviderAPI = Record<string, unknown>, and update any downstream
places that rely on implicit any (e.g., functions or methods that index into
ProviderAPI or pass it to other APIs) to perform proper type guards or casts
before accessing properties or assigning to narrower types; ensure symbols
referencing ProviderAPI (the ProviderAPI type itself, and any functions
accepting or returning ProviderAPI) compile after the change by adding explicit
casts or runtime checks where necessary.

In `@wallets/core/src/namespaces/ton/utils.ts`:
- Around line 7-17: The function formatAccountsToCAIP unnecessarily calls
.toString() on each account string; remove the redundant .toString() and pass
account directly into AccountId.format in formatAccountsToCAIP so it uses the
string value (replace account.toString() with account) while keeping the
existing AccountId.format payload (namespace/ reference) intact.

In `@wallets/provider-tonconnect/src/actions/ton.ts`:
- Around line 46-52: The parameter getInstance for canEagerConnect is typed as
() => TonProviderAPI but the implementation casts its result to TonConnectUI;
change the parameter type to () => TonConnectUI (matching the actual caller
tonConnect.getInstance and the pattern used in connect()) and remove the unsafe
cast inside canEagerConnect so you call getInstance() directly as a TonConnectUI
to access connectionRestored.

In `@wallets/provider-tonconnect/src/provider.ts`:
- Around line 19-21: The catch block in provider.ts that swallows errors during
TonConnect initialization (the catch (_) { /* empty */ } around the TonConnect
init) hides failures; change it to capture the error (e) and surface it by
logging the error with context (e.g., "Failed to initialize TonConnect" plus
error.stack/message) using the existing logger or console.error, and either
rethrow the error or set a visible initialization-failed state/flag so callers
can handle it instead of silently continuing.

In `@wallets/react/src/legacy/types.ts`:
- Around line 83-90: The walletOptions type uses an index signature "[key:
WalletType]" which doesn't enforce that only the union members of WalletType are
allowed as keys; change it to a mapped/utility type so keys are limited to
WalletType (e.g., use Partial<Record<WalletType, { provider?: unknown;
namespaces?: Record<string, unknown> }>> or an equivalent mapped type like { [K
in WalletType]?: { provider?: unknown; namespaces?: Record<string, unknown> }
}). Update the namespaces inner type from the ad-hoc index signature to
Record<string, unknown> for clarity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 83e50fb1-f760-4849-8f2b-e483fbb7d0b2

📥 Commits

Reviewing files that changed from the base of the PR and between d6622c2 and 64f5f2b.

📒 Files selected for processing (31)
  • wallets/core/namespaces/ton/package.json
  • wallets/core/package.json
  • wallets/core/src/hub/hub.ts
  • wallets/core/src/hub/provider/provider.ts
  • wallets/core/src/hub/provider/types.ts
  • wallets/core/src/namespaces/ton/builders.ts
  • wallets/core/src/namespaces/ton/constants.ts
  • wallets/core/src/namespaces/ton/mod.ts
  • wallets/core/src/namespaces/ton/types.ts
  • wallets/core/src/namespaces/ton/utils.ts
  • wallets/provider-all/src/index.ts
  • wallets/provider-tonconnect/package.json
  • wallets/provider-tonconnect/readme.md
  • wallets/provider-tonconnect/src/actions/ton.ts
  • wallets/provider-tonconnect/src/constants.ts
  • wallets/provider-tonconnect/src/helpers.ts
  • wallets/provider-tonconnect/src/hooks/ton.ts
  • wallets/provider-tonconnect/src/index.ts
  • wallets/provider-tonconnect/src/mod.ts
  • wallets/provider-tonconnect/src/namespaces/ton.ts
  • wallets/provider-tonconnect/src/provider.ts
  • wallets/provider-tonconnect/src/signer.ts
  • wallets/provider-tonconnect/src/signers/ton.ts
  • wallets/provider-tonconnect/src/tonConnect.ts
  • wallets/provider-tonconnect/src/types.ts
  • wallets/provider-tonconnect/src/utils.ts
  • wallets/react/src/hub/helpers.ts
  • wallets/react/src/hub/useHubAdapter.ts
  • wallets/react/src/legacy/types.ts
  • wallets/readme.md
  • widget/embedded/src/containers/Wallets/Wallets.tsx
💤 Files with no reviewable changes (2)
  • wallets/provider-tonconnect/src/index.ts
  • wallets/provider-tonconnect/src/helpers.ts

Comment on lines +77 to +79
const result = namespaceMethod(
args?.[provider.id]?.namespaces?.[namespace.namespaceId]
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Namespace init args are forwarded but currently not consumed.

runAll('init', args) passes per-namespace args, but wallets/core/src/hub/namespaces/namespace.ts defines init() without parameters, so namespace init args are effectively dropped.

🔧 Suggested follow-up change (outside this file)
- public init(): void {
+ public init(args?: unknown): void {
    if (this.#initiated) {
      return;
    }

    const definedInitByUser = this.#actions.get('init');

    if (definedInitByUser) {
-     definedInitByUser(this.#context());
+     definedInitByUser(this.#context(), args);
    }

    this.#initiated = true;
  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/core/src/hub/hub.ts` around lines 77 - 79, The per-namespace init
arguments passed from hub (where namespaceMethod is invoked with
args?.[provider.id]?.namespaces?.[namespace.namespaceId]) are dropped because
Namespace.init is defined without parameters; update the Namespace API to accept
and forward those args: change the signature of init in
wallets/core/src/hub/namespaces/namespace.ts (and its implementations) to accept
an optional parameter (e.g., init(initArgs?: unknown)) and ensure each concrete
namespace implementation consumes or forwards initArgs appropriately so the
hub-provided per-namespace args are honored.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify detached namespace method invocation and `this` usage in namespace methods.
rg -n -C3 'const namespaceMethod = namespace\[action\]|namespaceMethod\(' wallets/core/src/hub/hub.ts
rg -n -C4 'public (init|state)\(' wallets/core/src/hub/namespaces/namespace.ts
rg -n -C2 'this\.\#' wallets/core/src/hub/namespaces/namespace.ts

Repository: RyukTheCoder/rango-client

Length of output: 7057


Bind namespace methods to preserve this context.

Namespace methods are invoked detached from their instance. The init(), state(), and all other methods in the Namespace class access private fields (e.g., this.#initiated, this.#store) or call private methods (e.g., this.#storeId(), this.#context()). Without proper binding, this will be undefined, causing runtime errors. Invoke with .call(namespace, ...).

🔧 Proposed fix
-          const result = namespaceMethod(
-            args?.[provider.id]?.namespaces?.[namespace.namespaceId]
-          );
+          const result = namespaceMethod.call(
+            namespace,
+            args?.[provider.id]?.namespaces?.[namespace.namespaceId]
+          );
📝 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
const result = namespaceMethod(
args?.[provider.id]?.namespaces?.[namespace.namespaceId]
);
const result = namespaceMethod.call(
namespace,
args?.[provider.id]?.namespaces?.[namespace.namespaceId]
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/core/src/hub/hub.ts` around lines 77 - 79, The namespace methods
(e.g., Namespace.init(), Namespace.state() and other instance methods) are being
invoked detached via namespaceMethod(...) so their `this` is lost and private
fields/methods like `this.#initiated`, `this.#store` and `this.#storeId()` fail;
fix by invoking the method with the namespace instance as its context (call the
function with .call(namespace, ...) or otherwise bind namespaceMethod to the
namespace) when calling namespaceMethod in hub.ts so the method runs with the
correct `this`.

Comment on lines +5 to +10
More about implementation status can be found [here](../readme.md).

## Implementation notes/limitations

#### ⚠️ Initialization
You should provide TonConnect configs in configs.walletOptions[WalletTypes.TON_CONNECT] (which equals configs.walletOptions.tonconnect)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix markdown accessibility/readability lint issues.

Use descriptive link text (Line 5) and avoid heading-level jumps (Line 9).

🔧 Proposed doc fix
-More about implementation status can be found [here](../readme.md).
+More about implementation status can be found in the [wallet providers README](../readme.md).

-#### ⚠️ Initialization
+### ⚠️ Initialization
📝 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
More about implementation status can be found [here](../readme.md).
## Implementation notes/limitations
#### ⚠️ Initialization
You should provide TonConnect configs in configs.walletOptions[WalletTypes.TON_CONNECT] (which equals configs.walletOptions.tonconnect)
More about implementation status can be found in the [wallet providers README](../readme.md).
## Implementation notes/limitations
### ⚠️ Initialization
You should provide TonConnect configs in configs.walletOptions[WalletTypes.TON_CONNECT] (which equals configs.walletOptions.tonconnect)
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 5-5: Link text should be descriptive

(MD059, descriptive-link-text)


[warning] 9-9: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4

(MD001, heading-increment)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/provider-tonconnect/readme.md` around lines 5 - 10, Change the vague
link text "More about implementation status" to a descriptive label such as
"Implementation status in the project README" (so screen readers know
destination) and update the link target as in the diff; also fix the
heading-level jump by using a consistent heading level (e.g., change "#### ⚠️
Initialization" to "### ⚠️ Initialization" or adjust surrounding headings to
avoid skipping from H2 to H4), and ensure the config keys mentioned remain
code-formatted exactly as configs.walletOptions[WalletTypes.TON_CONNECT] (alias
configs.walletOptions.tonconnect) for clarity and accessibility.

Comment on lines +17 to +36
(context, err) => {
const tonInstance = instance();

if (!tonInstance) {
throw new Error(
'Trying to subscribe to your Ton wallet, but seems its instance is not available.'
);
}

eventCallback = (event) => {
if (!event.payload) {
context.action('disconnect');
}
};

unsubscribe = tonInstance.onStatusChange(eventCallback);

if (err instanceof Error) {
throw err;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Preserve upstream errors before trying to subscribe.

When err exists, this block should rethrow immediately. Current ordering can replace the original failure with a secondary “instance not available” error.

🔧 Proposed fix
     (context, err) => {
+      if (err instanceof Error) {
+        throw err;
+      }
+
       const tonInstance = instance();

       if (!tonInstance) {
         throw new Error(
           'Trying to subscribe to your Ton wallet, but seems its instance is not available.'
         );
       }
@@
-      if (err instanceof Error) {
-        throw 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
(context, err) => {
const tonInstance = instance();
if (!tonInstance) {
throw new Error(
'Trying to subscribe to your Ton wallet, but seems its instance is not available.'
);
}
eventCallback = (event) => {
if (!event.payload) {
context.action('disconnect');
}
};
unsubscribe = tonInstance.onStatusChange(eventCallback);
if (err instanceof Error) {
throw err;
}
(context, err) => {
if (err instanceof Error) {
throw err;
}
const tonInstance = instance();
if (!tonInstance) {
throw new Error(
'Trying to subscribe to your Ton wallet, but seems its instance is not available.'
);
}
eventCallback = (event) => {
if (!event.payload) {
context.action('disconnect');
}
};
unsubscribe = tonInstance.onStatusChange(eventCallback);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/provider-tonconnect/src/hooks/ton.ts` around lines 17 - 36, The
handler (context, err) => { ... } currently checks instance() before rethrowing
an upstream error, which can mask the original error; modify the logic so that
if err is truthy and instanceof Error the function rethrows err immediately
before calling instance(), so the original error is preserved; keep the
subsequent logic that creates eventCallback, calls instance(), assigns
unsubscribe = tonInstance.onStatusChange(eventCallback), and only then handles
missing instance errors.

Comment on lines +16 to +19
this.#env = env;
if (this.#env) {
throw new Error('Environments are not set');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Initialization always fails due to inverted guard logic.

After Line 16 assigns this.#env, Line 17 always evaluates true and throws, so initialize() can never succeed.

Proposed fix
   async initialize(env?: Environments) {
     if (!env) {
       throw new Error('Environments are not set');
     }
-    this.#env = env;
-    if (this.#env) {
-      throw new Error('Environments are not set');
+    if (this.#env) {
+      throw new Error('TonConnect is already initialized');
     }
+    this.#env = env;
 
     this.#tonModule = await dynamicImportWithRefinedError(
       async () => await import('@tonconnect/ui')
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/provider-tonconnect/src/tonConnect.ts` around lines 16 - 19, The
initialization guard in initialize() is inverted: after assigning this.#env the
code uses "if (this.#env) throw new Error('Environments are not set')", which
always throws; change the condition to check for missing env (e.g., if
(!this.#env) throw ...) so initialize() only throws when the environment value
is falsy; update the guard around this.#env in the initialize() method of the
TonConnect-related class accordingly.

export interface Environments extends Record<string, string | undefined> {
manifestUrl: string;
}
import type { LegacyNetworks } from '@rango-dev/wallets-core/legacy';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find the file and check its content
find . -name "types.ts" -path "*/provider-tonconnect/src/*" -type f

Repository: RyukTheCoder/rango-client

Length of output: 111


🏁 Script executed:

# Read the first 20 lines of the types.ts file to see the import and usage
head -20 wallets/provider-tonconnect/src/types.ts | cat -n

Repository: RyukTheCoder/rango-client

Length of output: 562


🏁 Script executed:

# Search for LegacyNetworks usage in the file
rg -n "LegacyNetworks" wallets/provider-tonconnect/src/types.ts -A 2 -B 1

Repository: RyukTheCoder/rango-client

Length of output: 254


🏁 Script executed:

# Check the LegacyNetworks declaration in the core package
find . -path "*wallets-core*" -name "*.ts" -o -name "*.tsx" | head -20

Repository: RyukTheCoder/rango-client

Length of output: 937


🏁 Script executed:

# Search for LegacyNetworks definition
rg -n "export.*LegacyNetworks" --type ts --type tsx

Repository: RyukTheCoder/rango-client

Length of output: 96


🏁 Script executed:

# Search for LegacyNetworks export definition
rg -n "export.*LegacyNetworks" -t ts

Repository: RyukTheCoder/rango-client

Length of output: 183


🏁 Script executed:

# Try searching in the wallets-core package
find . -path "*wallets-core*" -name "*.ts" | head -30

Repository: RyukTheCoder/rango-client

Length of output: 51


🏁 Script executed:

# Look for LegacyNetworks in legacy file
fd -e ts -e js | xargs rg -l "LegacyNetworks" | grep legacy

Repository: RyukTheCoder/rango-client

Length of output: 279


🏁 Script executed:

# Search for the export directly
rg "LegacyNetworks\s*=" -t ts

Repository: RyukTheCoder/rango-client

Length of output: 51


🏁 Script executed:

# Check the Networks definition in the types file
cat -n wallets/core/src/legacy/types.ts | head -50

Repository: RyukTheCoder/rango-client

Length of output: 1556


🏁 Script executed:

# Search for Networks enum or const in the legacy types
rg -n "export.*Networks" wallets/core/src/legacy/types.ts -A 5

Repository: RyukTheCoder/rango-client

Length of output: 375


🏁 Script executed:

# Check if TON exists in the Networks enum
rg -n "TON\s*=" wallets/core/src/legacy/types.ts

Repository: RyukTheCoder/rango-client

Length of output: 86


🏁 Script executed:

# Get the full Networks enum to see all members
sed -n '5,100p' wallets/core/src/legacy/types.ts | cat -n

Repository: RyukTheCoder/rango-client

Length of output: 2694


LegacyNetworks should not be imported with import type here.

Line 1 uses a type-only import, but line 10 uses LegacyNetworks.TON as a computed property key. LegacyNetworks is an enum, which requires value-space access at runtime. Type-only imports are erased and cannot be accessed in computed keys.

🐛 Proposed fix
-import type { LegacyNetworks } from '@rango-dev/wallets-core/legacy';
+import { LegacyNetworks } from '@rango-dev/wallets-core/legacy';

Also applies to: 10-10

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/provider-tonconnect/src/types.ts` at line 1, The import of
LegacyNetworks must be a runtime import (not a type-only import) because the
enum LegacyNetworks is used as a value in a computed property key
(LegacyNetworks.TON); change the line that currently uses "import type {
LegacyNetworks }" to a normal import so LegacyNetworks is emitted at runtime and
can be accessed by the computed key in this file (types.ts), ensuring any usage
like LegacyNetworks.TON works as intended.

useEffect(() => {
const runOnInit = () => {
getHub().init();
getHub().init(params.configs?.walletOptions);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hub init is using potentially stale wallet options.

Because this effect runs once, Line 89 reads the first-render params.configs?.walletOptions. If wallet configs are populated/updated after mount, init may run without TON options.

💡 Suggested direction
-      getHub().init(params.configs?.walletOptions);
+      getHub().init(dataRef.current.walletOptions);

And include walletOptions in dataRef updates so delayed readystatechange init uses the latest config snapshot.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wallets/react/src/hub/useHubAdapter.ts` at line 89, The init call
getHub().init(params.configs?.walletOptions) can use a stale first-render
walletOptions; update the logic so init uses the latest walletOptions snapshot
(not just the initial params) — e.g., store walletOptions in the shared dataRef
used by the readystatechange handler and ensure dataRef is updated whenever
params.configs?.walletOptions changes so the delayed readystatechange/init uses
the current config; specifically, update the place that sets dataRef (and any
related useEffect or subscription) to include walletOptions and change the
readystatechange/init code to read walletOptions from dataRef instead of the
original params variable.

Comment on lines +108 to +112
walletOptions: {
[WalletTypes.TON_CONNECT]: {
provider: { manifestUrl: config.tonConnect?.manifestUrl },
},
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard TON walletOptions to avoid emitting an invalid manifestUrl.

Line 110 can pass undefined into provider options. Build this entry conditionally so TON config is only sent when manifestUrl exists.

🐛 Proposed fix
-          walletOptions: {
-            [WalletTypes.TON_CONNECT]: {
-              provider: { manifestUrl: config.tonConnect?.manifestUrl },
-            },
-          },
+          walletOptions: config.tonConnect?.manifestUrl
+            ? {
+                [WalletTypes.TON_CONNECT]: {
+                  provider: { manifestUrl: config.tonConnect.manifestUrl },
+                },
+              }
+            : undefined,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@widget/embedded/src/containers/Wallets/Wallets.tsx` around lines 108 - 112,
walletOptions currently always includes a WalletTypes.TON_CONNECT entry with
provider.manifestUrl set from config.tonConnect?.manifestUrl which can be
undefined; change the construction of walletOptions so the TON_CONNECT entry is
only added when config.tonConnect?.manifestUrl is truthy (e.g., compute
manifestUrl = config.tonConnect?.manifestUrl and conditionally spread or assign
the [WalletTypes.TON_CONNECT] object only if manifestUrl exists) to avoid
emitting an invalid manifestUrl into provider options.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Migrate TonConnect to hub architecture with TON namespace support

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Migrated TonConnect wallet to hub architecture with new namespace support
• Added TON blockchain namespace with builders, utils, and types
• Implemented Hub initialization with provider-specific configuration arguments
• Refactored TonConnect provider to use new hub provider pattern
• Updated documentation with TON wallet support status and implementation notes
Diagram
flowchart LR
  A["Hub Init System"] -->|"accepts RunAllArgs"| B["Provider Init"]
  B -->|"passes config"| C["TonConnect Provider"]
  C -->|"initializes"| D["TonConnect Instance"]
  E["TON Namespace"] -->|"connect/disconnect"| D
  E -->|"uses builders & utils"| F["CAIP Account Formatting"]
Loading

Grey Divider

File Changes

1. wallets/core/src/hub/hub.ts ✨ Enhancement +19/-5

Add RunAllArgs type and pass args through init

wallets/core/src/hub/hub.ts


2. wallets/core/src/hub/provider/provider.ts ✨ Enhancement +2/-2

Accept optional args parameter in init method

wallets/core/src/hub/provider/provider.ts


3. wallets/core/src/hub/provider/types.ts ✨ Enhancement +2/-0

Add TonActions to CommonNamespaces interface

wallets/core/src/hub/provider/types.ts


View more (28)
4. wallets/core/src/namespaces/ton/builders.ts ✨ Enhancement +15/-0

Create connect and canEagerConnect action builders

wallets/core/src/namespaces/ton/builders.ts


5. wallets/core/src/namespaces/ton/constants.ts ✨ Enhancement +2/-0

Define TON CAIP namespace and chain ID constants

wallets/core/src/namespaces/ton/constants.ts


6. wallets/core/src/namespaces/ton/mod.ts ✨ Enhancement +5/-0

Export TON namespace utilities and types

wallets/core/src/namespaces/ton/mod.ts


7. wallets/core/src/namespaces/ton/types.ts ✨ Enhancement +15/-0

Define TonActions interface and ProviderAPI type

wallets/core/src/namespaces/ton/types.ts


8. wallets/core/src/namespaces/ton/utils.ts ✨ Enhancement +18/-0

Format TON accounts to CAIP standard format

wallets/core/src/namespaces/ton/utils.ts


9. wallets/core/namespaces/ton/package.json ⚙️ Configuration changes +8/-0

Add package.json for TON namespace exports

wallets/core/namespaces/ton/package.json


10. wallets/core/package.json ⚙️ Configuration changes +5/-1

Add TON namespace export and build input

wallets/core/package.json


11. wallets/provider-tonconnect/src/mod.ts ✨ Enhancement +10/-0

Create new entry point with versioned provider

wallets/provider-tonconnect/src/mod.ts


12. wallets/provider-tonconnect/src/provider.ts ✨ Enhancement +35/-0

Build TonConnect provider with initialization logic

wallets/provider-tonconnect/src/provider.ts


13. wallets/provider-tonconnect/src/namespaces/ton.ts ✨ Enhancement +39/-0

Build TON namespace with actions and hooks

wallets/provider-tonconnect/src/namespaces/ton.ts


14. wallets/provider-tonconnect/src/actions/ton.ts ✨ Enhancement +56/-0

Implement connect, disconnect, canEagerConnect actions

wallets/provider-tonconnect/src/actions/ton.ts


15. wallets/provider-tonconnect/src/hooks/ton.ts ✨ Enhancement +47/-0

Create disconnect subscriber for TON wallet events

wallets/provider-tonconnect/src/hooks/ton.ts


16. wallets/provider-tonconnect/src/tonConnect.ts ✨ Enhancement +43/-0

Create TonConnect class for instance management

wallets/provider-tonconnect/src/tonConnect.ts


17. wallets/provider-tonconnect/src/utils.ts ✨ Enhancement +50/-0

Add utility functions for TonConnect instance handling

wallets/provider-tonconnect/src/utils.ts


18. wallets/provider-tonconnect/src/constants.ts ✨ Enhancement +38/-0

Define TON wallet metadata and configuration

wallets/provider-tonconnect/src/constants.ts


19. wallets/provider-tonconnect/src/types.ts ✨ Enhancement +16/-3

Update types for hub provider pattern

wallets/provider-tonconnect/src/types.ts


20. wallets/provider-tonconnect/src/signer.ts ✨ Enhancement +10/-5

Update signer to use new provider type structure

wallets/provider-tonconnect/src/signer.ts


21. wallets/provider-tonconnect/src/helpers.ts Miscellaneous +0/-53

Remove legacy helper functions

wallets/provider-tonconnect/src/helpers.ts


22. wallets/provider-tonconnect/src/index.ts Miscellaneous +0/-97

Remove legacy provider implementation

wallets/provider-tonconnect/src/index.ts


23. wallets/provider-tonconnect/package.json ⚙️ Configuration changes +6/-9

Update entry point and build configuration

wallets/provider-tonconnect/package.json


24. wallets/provider-tonconnect/readme.md 📝 Documentation +27/-1

Add implementation notes and feature status

wallets/provider-tonconnect/readme.md


25. wallets/provider-all/src/index.ts ✨ Enhancement +2/-13

Update TonConnect import and remove legacy init

wallets/provider-all/src/index.ts


26. wallets/react/src/hub/helpers.ts ✨ Enhancement +4/-0

Add TON namespace CAIP mapping support

wallets/react/src/hub/helpers.ts


27. wallets/react/src/hub/useHubAdapter.ts ✨ Enhancement +1/-1

Pass wallet options to hub initialization

wallets/react/src/hub/useHubAdapter.ts


28. wallets/react/src/legacy/types.ts ✨ Enhancement +8/-0

Add walletOptions configuration type

wallets/react/src/legacy/types.ts


29. wallets/readme.md 📝 Documentation +2/-0

Add TonConnect to wallet support matrix

wallets/readme.md


30. widget/embedded/src/containers/Wallets/Wallets.tsx ✨ Enhancement +6/-0

Pass TonConnect manifest URL in wallet options

widget/embedded/src/containers/Wallets/Wallets.tsx


31. wallets/provider-tonconnect/src/signers/ton.ts Additional files +0/-0

...

wallets/provider-tonconnect/src/signers/ton.ts


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 19, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. TonConnect init always fails 🐞 Bug ≡ Correctness
Description
TonConnect.initialize() assigns this.#env = env and then immediately throws when this.#env is
truthy, so the TonConnect module/instance never gets created. As a result, provider init silently
fails and later getInstance() calls will throw, breaking connect/canEagerConnect.
Code

wallets/provider-tonconnect/src/tonConnect.ts[R12-26]

+  async initialize(env?: Environments) {
+    if (!env) {
+      throw new Error('Environments are not set');
+    }
+    this.#env = env;
+    if (this.#env) {
+      throw new Error('Environments are not set');
+    }
+
+    this.#tonModule = await dynamicImportWithRefinedError(
+      async () => await import('@tonconnect/ui')
+    );
+    const { TonConnectUI } = this.#tonModule;
+    this.#tonConnectInstance = new TonConnectUI(this.#env);
+  }
Evidence
initialize() throws unconditionally after setting #env because it checks if (this.#env) right
after this.#env = env, making the rest of initialization unreachable. The provider’s init calls
tonConnect.initialize(environments) but swallows any thrown error and still marks the wallet
installed, so the wallet can appear available while getInstance() remains uninitialized and will
throw when actions run.

wallets/provider-tonconnect/src/tonConnect.ts[12-26]
wallets/provider-tonconnect/src/tonConnect.ts[28-35]
wallets/provider-tonconnect/src/provider.ts[9-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`TonConnect.initialize()` always throws after assigning `this.#env`, preventing TonConnect UI module import and instance creation.

### Issue Context
This makes the TonConnect provider appear installed (provider init sets `installed=true` in `finally`) but unusable because `getInstance()` later throws.

### Fix Focus Areas
- wallets/provider-tonconnect/src/tonConnect.ts[12-26]
- wallets/provider-tonconnect/src/provider.ts[14-30]

### Suggested fix
- Remove the second guard entirely, or change it to the intended condition (e.g. `if (!this.#env) throw ...`).
- Optionally add a clearer error for missing/invalid `manifestUrl` if that’s required by `TonConnectUI`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Unsubscribe before initialization 🐞 Bug ☼ Reliability
Description
waitForConnection() calls unsubscribe() inside subscription callbacks before unsubscribe is
initialized, which can throw if a callback fires before the assignment and can leave listeners
attached. This can break the connection flow and cause leaks.
Code

wallets/provider-tonconnect/src/utils.ts[R20-48]

+  return new Promise((resolve, reject) => {
+    const unsubscribeStatusChange = tonConnectUI.onStatusChange(
+      (state) => {
+        const walletConnected = !!state?.account.address;
+
+        if (walletConnected) {
+          unsubscribe();
+          resolve(state.account.address);
+        }
+      },
+      (error) => {
+        unsubscribe();
+        reject(error);
+      }
+    );
+
+    const unsubscribeModalStateChange = tonConnectUI.onModalStateChange(
+      (modalState) => {
+        if (modalState.closeReason === 'action-cancelled') {
+          unsubscribe();
+          reject(new Error('The action was canceled by the user'));
+        }
+      }
+    );
+
+    const unsubscribe = () => {
+      unsubscribeStatusChange();
+      unsubscribeModalStateChange();
+    };
Evidence
In waitForConnection, both onStatusChange and error/cancel handlers invoke unsubscribe(), but
unsubscribe is declared later as a const. If any callback executes before the `const unsubscribe
= () => { ... } line runs, accessing unsubscribe` is a temporal-dead-zone error and cleanup won’t
happen.

wallets/provider-tonconnect/src/utils.ts[20-49]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`waitForConnection()` uses `unsubscribe()` in callbacks before `unsubscribe` is initialized, which can throw and prevent proper cleanup.

### Issue Context
The callbacks passed into `onStatusChange`/`onModalStateChange` can run at any time; the current implementation assumes they won’t run until after `unsubscribe` is assigned.

### Fix Focus Areas
- wallets/provider-tonconnect/src/utils.ts[20-48]

### Suggested fix
- Declare `let unsubscribe = () => {};` before registering listeners.
- After obtaining `unsubscribeStatusChange` and `unsubscribeModalStateChange`, reassign `unsubscribe = () => { unsubscribeStatusChange(); unsubscribeModalStateChange(); }`.
- (Optional) Guard cleanup calls so calling unsubscribe twice is safe.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +12 to +26
async initialize(env?: Environments) {
if (!env) {
throw new Error('Environments are not set');
}
this.#env = env;
if (this.#env) {
throw new Error('Environments are not set');
}

this.#tonModule = await dynamicImportWithRefinedError(
async () => await import('@tonconnect/ui')
);
const { TonConnectUI } = this.#tonModule;
this.#tonConnectInstance = new TonConnectUI(this.#env);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Tonconnect init always fails 🐞 Bug ≡ Correctness

TonConnect.initialize() assigns this.#env = env and then immediately throws when this.#env is
truthy, so the TonConnect module/instance never gets created. As a result, provider init silently
fails and later getInstance() calls will throw, breaking connect/canEagerConnect.
Agent Prompt
### Issue description
`TonConnect.initialize()` always throws after assigning `this.#env`, preventing TonConnect UI module import and instance creation.

### Issue Context
This makes the TonConnect provider appear installed (provider init sets `installed=true` in `finally`) but unusable because `getInstance()` later throws.

### Fix Focus Areas
- wallets/provider-tonconnect/src/tonConnect.ts[12-26]
- wallets/provider-tonconnect/src/provider.ts[14-30]

### Suggested fix
- Remove the second guard entirely, or change it to the intended condition (e.g. `if (!this.#env) throw ...`).
- Optionally add a clearer error for missing/invalid `manifestUrl` if that’s required by `TonConnectUI`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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.

2 participants