Skip to content

Release 1.0.1 - #82

Merged
ProudOfZiggy merged 23 commits into
mainfrom
dev
Jun 23, 2026
Merged

Release 1.0.1#82
ProudOfZiggy merged 23 commits into
mainfrom
dev

Conversation

@ProudOfZiggy

@ProudOfZiggy ProudOfZiggy commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

  • New Features

    • Added QR code scanner for wallet connections
    • Introduced gasless transaction support for select tokens
    • Added crypto onramp functionality for purchasing assets
    • Enhanced token selection with fee asset picker for gasless transactions
  • Improvements

    • Rebranded native currency from TON to GRAM across the app
    • Redesigned home screen with new Send, Swap, and Stake actions
    • Enhanced balance display with numeric animations
    • Improved token/jetton metadata resolution and display
    • Added new design icons for scanning, settings, sorting, and currencies
    • Updated wallet header with compact switcher in navigation bar
  • Documentation

    • Significantly expanded README with comprehensive integration guide, DeFi manager setup, and code examples

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds gasless and jetton SDK APIs, updates the demo send flow and wallet home with QR scanning and UI refreshes, converts several SDK failures to typed errors, makes storage async, expands generated models and docs, and updates tests, assets, and GRAM labeling.

Changes

Demo app and SDK refresh

Layer / File(s) Summary
Demo UI refresh and scan flow
Demo/TONWalletApp/Wallet/Home/*, Demo/TONWalletApp/Wallet/Scan/*, Demo/TONWalletApp/UIKit/DesignSystem/*, Demo/TONWalletApp/Assets.xcassets/*, Demo/TONWalletApp/Debug/*, Demo/TONWalletApp/Swap/*, Demo/TONWalletApp/Staking/*, Demo/TONWalletApp/Wallet/...
Adds a QR scanner and scan handling on wallet home, refreshes home/design-system presentation, adds icon assets and styles, introduces a numeric text debug screen, improves swap balance display, and renames displayed TON units to GRAM in demo surfaces.
Demo gasless send flow
Demo/TONWalletApp/Sending/*, Demo/TONWalletApp/TONWalletApp.swift, Demo/TONWalletApp/Env.swift.example
Adds gasless sending state, fee-asset loading and pickers, updated token contracts, sheet-based asset selection, and shared app registration of a TonAPI gasless provider.
Gasless and jetton SDK APIs
Sources/TONWalletKit/API/DeFi/Gasless/*, Sources/TONWalletKit/API/Jettons/*, Sources/TONWalletKit/API/Models/WalletKit/TONGasless*, Sources/TONWalletKit/API/Models/WalletKit/TONJetton*, Sources/TONWalletKit/API/TONWalletKit.swift, README.md
Adds gasless provider and manager APIs, TonAPI gasless provider types, jetton manager access, related Codable models, jetton transfer response destinations, and README coverage for the expanded SDK surface.
Generated models and codegen support
Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnramp*, Sources/TONWalletKit/API/Models/WalletKit/TONDefiProviderType.swift, Scripts/generate-api/*, Sources/TONWalletKit/API/Wallet/Parameters/*, Sources/TONWalletKit/API/Models/WalletKit/TON*
Adds generated crypto-onramp and generic fixture models, extends generic model template rendering, expands wallet parameter structs, and updates multiple model comments from TON wording to GRAM.
Typed errors and async contract updates
Sources/TONWalletKit/API/Storage/*, Sources/TONWalletKit/API/Wallet/*, Sources/TONWalletKit/API/TONWalletKitError.swift, Sources/TONWalletKit/JSAdapters/*, Sources/TONWalletKit/JSWalletKit/*, Sources/TONWalletKit/JSCore/*
Converts storage methods to async contracts through the JS adapter layer, switches wallet signing calls to options objects, and replaces several string-based failures with typed SDK, bridge, resource, conversion, and crypto polyfill errors.
Tests and mocks for new contracts
Tests/TONWalletKitTests/API/DeFi/Gasless/*, Tests/TONWalletKitTests/JSAdapters/*, Tests/TONWalletKitTests/JSWalletKit/*, Tests/TONWalletKitTests/API/*, Tests/TONWalletKitTests/Mocks/*
Adds gasless API and adapter coverage, updates mocks for async storage and signing options, and strengthens existing tests to assert specific typed error cases and promise-based behavior.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~100 minutes

Poem

🐇 I found new paths through QR light,
And gasless hops now feel just right.
GRAM signs bloom where TON once grew,
With typed errors crisp as morning dew.
I thump my paws: “Fine work to do!”

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Release 1.0.1' is too vague and generic; it does not clearly convey the specific changes or primary purpose of this large changeset. Replace with a more descriptive title summarizing the main changes, such as 'Add gasless provider support, jettons manager, and TON/GRAM rebranding' or 'Implement gasless transactions and improve DeFi integrations'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 dev

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Demo/TONWalletApp/Sending/SendTokensViewModel.swift`:
- Around line 250-262: In the requoteIfNeeded() function, after canceling
quoteTask and before any early returns from the guard statements, reset the
quote UI state by clearing isQuoting and any fee-related data properties. This
ensures that when the function exits early due to missing required conditions
(gaslessEnabled, jettonAddress, feeAsset, relay, recipientAddress, or amount),
the UI immediately reflects that no quote is in progress rather than leaving
stale quote state visible. Apply the same clearing logic to the similar code
block mentioned at lines 296-307.

In `@Demo/TONWalletApp/Staking/StakingView.swift`:
- Line 217: The StakingView displays mixed denomination terminology with "GRAM"
in the infoRow call for "Instant Unstake Available" while other parts of the
same view use "TON" (such as in unstake method descriptions). To fix this,
locate all denomination references throughout the StakingView component and
choose one consistent unit label, then replace all occurrences to match that
standard. This includes the infoRow function call and any other text strings
that reference the token denomination to ensure uniform terminology throughout
the entire staking screen.

In `@Demo/TONWalletApp/UIKit/DesignSystem/Icons/TONIcon.swift`:
- Around line 55-59: The nav icon cases iconScan, iconSettings, iconSort, and
iconCurrency are currently referencing top-level asset names, but they should
use DesignSystem asset groups to maintain consistency with the icon catalog
contract. Move these icon assets into the appropriate DesignSystem group in
Assets.xcassets (likely Icons24 based on the 24px home navigation context),
update the case values to reference the properly organized asset names within
the DesignSystem groups (following the naming pattern used by other DesignSystem
icons), and ensure the TONIcon.image computed property uses these named assets
as the primary source with SF Symbol as a fallback.

In `@Demo/TONWalletApp/UIKit/DesignSystem/Tokens/TONTypography.swift`:
- Line 6: The inline documentation comment at the beginning of
TONTypography.swift is outdated and states there are only three SF Pro Bold
"Price" sizes (40 / 44 / 64), but the file now defines five price sizes
(64/50/44/40/30). Update this comment to accurately reflect the current set of
five price sizes and ensure the "SF Pro Bold" terminology is consistent with the
new price style definitions throughout the file.

In
`@Demo/TONWalletApp/Wallet/Requests/SignMessage/WalletSignMessageRequestView.swift`:
- Around line 431-439: The code currently has inconsistent TON/GRAM terminology
in WalletSignMessageRequestView where the methods around lines 431-439 return
"GRAM" for the .ton case, but other parts of the same view still render "TON"
labels, causing mixed units to appear in the confirmation flow. Search through
the entire WalletSignMessageRequestView for all places where TON amount labels
are displayed (including the methods shown in the diff and any other
label-generating methods or text assignments), and ensure they all use the same
terminology consistently - either change all instances to "GRAM" to match the
recent changes in the unitLabel method, or revert the changes to use "TON"
throughout the view so users see uniform labeling.

In
`@Demo/TONWalletApp/Wallet/Requests/Transaction/WalletTransactionRequestView.swift`:
- Around line 431-439: The assetLabel method in WalletTransactionRequestView has
been updated to return "GRAM" for the `.ton` case, but the transaction
confirmation view still displays titles with "Send TON #..." which creates
inconsistency. Find where the transaction title or header is being constructed
(likely in a method that builds the confirmation view text or labels) and update
any hardcoded references from "TON" to "GRAM" to match the assetLabel changes
and ensure the entire transaction sheet uses consistent terminology throughout.

In `@README.md`:
- Around line 36-38: The fenced code block containing the GitHub URL
https://github.com/ton-connect/kit-ios.git is missing a language identifier
after the opening triple backticks, which violates markdownlint rule MD040. Add
the language identifier "text" immediately after the opening triple backticks
(changing ``` to ```text) to specify the code block language and resolve the
linting violation.

In `@Sources/TONWalletKit/API/DeFi/Gasless/TONGaslessManager.swift`:
- Around line 104-109: The provider(with:) method returns an optional
TONGaslessProvider but always constructs and returns a provider instance when
getProvider does not throw, making it impossible to return nil as the optional
return type suggests. Check if the jsObject returned from getProvider represents
a valid/found provider (likely by verifying it is not nil or checking a boolean
property indicating the provider exists), and return nil when the provider is
not found instead of unconditionally constructing TONGaslessProvider with the
jsObject.

In `@Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampStatus.swift`:
- Line 30: The docstring for the TONCryptoOnrampStatus enum incorrectly
documents deposit transfer details rather than describing the status enum
itself. Replace the current comment with one that accurately describes the
enum's purpose as representing the status of a crypto onramp operation, such as
the possible states of success, pending, or failed that indicate the outcome or
current state of an onramp transaction.

In `@Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampStatusParams.swift`:
- Line 30: The comment for the TONCryptoOnrampStatusParams struct incorrectly
describes deposit details that are returned by a provider, when this struct
actually contains request parameters (depositId, providerId) used to look up the
status of a deposit. Update the comment to accurately reflect that this struct
represents status lookup parameters rather than deposit response details, making
it clear that these parameters are sent to query the status of an existing
deposit.

In `@Sources/TONWalletKit/JSAdapters/TONGaslessProviderJSAdapter.swift`:
- Around line 53-56: When self is deallocated during async execution in the
promise blocks, the early return guards (guard let self else { return }) leave
JS promises pending indefinitely instead of settling them. For all four
locations at lines 55, 91, 116, and 141 across the config, quote, and
sendTransaction methods, replace the early return with a call to reject with an
appropriate error describing that the adapter was deallocated, ensuring every
promise path is properly settled whether success, failure, or deallocation
occurs.

In `@Sources/TONWalletKit/JSAdapters/TONWalletKitStorageJSAdapter.swift`:
- Around line 49-60: The resolve and reject callbacks are being executed within
an unstructured Task that may run on any thread, but JSContext and JSValue
require main thread access. Wrap the resolve?.call() and reject?.call()
invocations within a DispatchQueue.main.async call to ensure the JSContext
callbacks execute on the main thread where the context was created.
Alternatively, apply the `@MainActor` annotation to the entire
TONWalletKitStorageJSAdapter class or specific methods to enforce main thread
execution at compile time, which would be consistent with the threading pattern
already used in WKWebView+Injection.swift.

In `@Tests/TONWalletKitTests/JSAdapters/TONGaslessProviderJSAdapterTests.swift`:
- Around line 114-126: The test metadataRejectsWhenDeallocated (and the similar
tests at lines 153-165, 191-203, 229-241) currently asserts that any Error is
thrown when the context is deallocated, which is too loose and can miss
regressions. Replace the generic (any Error).self assertion with the specific
concrete error type or case that is actually expected to be thrown when the
JSContext is deallocated. This ensures the test validates the intended
deallocation failure path rather than passing for any error condition.
🪄 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

Run ID: 6f1de143-4bc6-4426-aa2a-78f9e9e07f39

📥 Commits

Reviewing files that changed from the base of the PR and between 1a7737a and a1d313b.

⛔ Files ignored due to path filters (8)
  • Demo/TONWalletApp/Assets.xcassets/DesignSystem/Icons24/TON.imageset/TON.svg is excluded by !**/*.svg
  • Demo/TONWalletApp/Assets.xcassets/DesignSystem/Icons24/TON.imageset/icon_gram.svg is excluded by !**/*.svg
  • Demo/TONWalletApp/Assets.xcassets/DesignSystem/Icons24/TonFill.imageset/TonFill.svg is excluded by !**/*.svg
  • Demo/TONWalletApp/Assets.xcassets/DesignSystem/Icons24/TonFill.imageset/icon_gram.svg is excluded by !**/*.svg
  • Demo/TONWalletApp/Assets.xcassets/icon_currency.imageset/icon_currency.svg is excluded by !**/*.svg
  • Demo/TONWalletApp/Assets.xcassets/icon_scan.imageset/icon_scan.svg is excluded by !**/*.svg
  • Demo/TONWalletApp/Assets.xcassets/icon_settings.imageset/icon_settings.svg is excluded by !**/*.svg
  • Demo/TONWalletApp/Assets.xcassets/icon_sort.imageset/icon_sort.svg is excluded by !**/*.svg
📒 Files selected for processing (134)
  • Demo/TONWalletApp/Assets.xcassets/DesignSystem/Icons24/TON.imageset/Contents.json
  • Demo/TONWalletApp/Assets.xcassets/DesignSystem/Icons24/TonFill.imageset/Contents.json
  • Demo/TONWalletApp/Assets.xcassets/icon_currency.imageset/Contents.json
  • Demo/TONWalletApp/Assets.xcassets/icon_scan.imageset/Contents.json
  • Demo/TONWalletApp/Assets.xcassets/icon_settings.imageset/Contents.json
  • Demo/TONWalletApp/Assets.xcassets/icon_sort.imageset/Contents.json
  • Demo/TONWalletApp/Debug/DebugMenuView.swift
  • Demo/TONWalletApp/Debug/NumericTextDebugView.swift
  • Demo/TONWalletApp/Env.swift.example
  • Demo/TONWalletApp/Info.plist
  • Demo/TONWalletApp/Sending/FeeAssetViewModel.swift
  • Demo/TONWalletApp/Sending/SendAssetPickerBottomSheet.swift
  • Demo/TONWalletApp/Sending/SendTokensView.swift
  • Demo/TONWalletApp/Sending/SendTokensViewModel.swift
  • Demo/TONWalletApp/Sending/SendableJettonViewModel.swift
  • Demo/TONWalletApp/Sending/SendableTONViewModel.swift
  • Demo/TONWalletApp/Sending/SendableTokenViewModel.swift
  • Demo/TONWalletApp/Staking/StakingView.swift
  • Demo/TONWalletApp/Staking/StakingViewModel.swift
  • Demo/TONWalletApp/Swap/SwapView.swift
  • Demo/TONWalletApp/Swap/SwapViewModel.swift
  • Demo/TONWalletApp/TONWalletApp.swift
  • Demo/TONWalletApp/UIKit/DesignSystem/Components/Button/TONActionButton.swift
  • Demo/TONWalletApp/UIKit/DesignSystem/Icons/TONIcon.swift
  • Demo/TONWalletApp/UIKit/DesignSystem/Tokens/TONColors+Semantic.swift
  • Demo/TONWalletApp/UIKit/DesignSystem/Tokens/TONTypography.swift
  • Demo/TONWalletApp/Wallet/Home/Actions/WalletHomeActionsRow.swift
  • Demo/TONWalletApp/Wallet/Home/Assets/WalletHomeAssetRowView.swift
  • Demo/TONWalletApp/Wallet/Home/Header/WalletHomeHeaderView.swift
  • Demo/TONWalletApp/Wallet/Home/NFTs/WalletHomeNFTsCarousel.swift
  • Demo/TONWalletApp/Wallet/Home/WalletHomeView.swift
  • Demo/TONWalletApp/Wallet/Home/WalletHomeViewModel.swift
  • Demo/TONWalletApp/Wallet/Jettons/List/WalletJettonsListItem.swift
  • Demo/TONWalletApp/Wallet/List/WalletsListView.swift
  • Demo/TONWalletApp/Wallet/Requests/SignMessage/WalletSignMessageRequestView.swift
  • Demo/TONWalletApp/Wallet/Requests/Transaction/WalletTransactionRequestView.swift
  • Demo/TONWalletApp/Wallet/Scan/QRScannerView.swift
  • README.md
  • Scripts/generate-api/fixtures/TONGenericInstanceContainer.swift
  • Scripts/generate-api/fixtures/TONGenericInstanceMultiArg.swift
  • Scripts/generate-api/fixtures/TONGenericInstanceSubsetArg.swift
  • Scripts/generate-api/templates/modelGeneric.mustache
  • Sources/TONWalletKit/API/Base/TONProviderType.swift
  • Sources/TONWalletKit/API/DeFi/Gasless/AnyTONGaslessProviderIdentifier.swift
  • Sources/TONWalletKit/API/DeFi/Gasless/Encoding/TONEncodableGaslessProvider.swift
  • Sources/TONWalletKit/API/DeFi/Gasless/TONGaslessManager.swift
  • Sources/TONWalletKit/API/DeFi/Gasless/TONGaslessProvider.swift
  • Sources/TONWalletKit/API/DeFi/Gasless/TONGaslessProviderIdentifier.swift
  • Sources/TONWalletKit/API/DeFi/Gasless/TonApi/TONTonApiGaslessProvider.swift
  • Sources/TONWalletKit/API/DeFi/Gasless/TonApi/TONTonApiGaslessProviderIdentifier.swift
  • Sources/TONWalletKit/API/Jettons/TONJettonsManager.swift
  • Sources/TONWalletKit/API/Models/Core/TONBase64.swift
  • Sources/TONWalletKit/API/Models/Core/TONHex.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONAccountState.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampDeposit.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampDepositParams.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampDestinationCurrency.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampProviderMetadata.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampProviderMetadataOverride.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampQuote.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampQuoteParams.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampSourceCurrency.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampStatus.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampStatusParams.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampSupportedCurrencies.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONDefiProviderType.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONGaslessConfig.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONGaslessProviderMetadata.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONGaslessProviderMetadataOverride.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONGaslessQuote.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONGaslessQuoteParams.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONGaslessSendParams.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONGaslessSendResponse.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONGaslessSupportedAsset.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONJettonInfo.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONJettonVerification.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONJettonsTransferRequest.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONOmnistonSwapProviderConfig.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONStakingProviderInfo.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONStakingProviderMetadata.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONStakingQuoteParams.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONStakingTokenInfo.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONStructuredItemType.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONTokenInfo.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONTonApiGaslessChainConfig.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONTonApiGaslessProviderConfig.swift
  • Sources/TONWalletKit/API/Models/WalletKit/TONTransferRequest.swift
  • Sources/TONWalletKit/API/Storage/TONWalletKitKeychainStorage.swift
  • Sources/TONWalletKit/API/Storage/TONWalletKitStorage.swift
  • Sources/TONWalletKit/API/Streaming/TONStreamingProvider.swift
  • Sources/TONWalletKit/API/TONWalletKit.swift
  • Sources/TONWalletKit/API/TONWalletKitError.swift
  • Sources/TONWalletKit/API/Wallet/Adapters/TONWalletAdapter.swift
  • Sources/TONWalletKit/API/Wallet/Encoding/TONEncodableWallet.swift
  • Sources/TONWalletKit/API/Wallet/Parameters/TONV4R2WalletParameters.swift
  • Sources/TONWalletKit/API/Wallet/Parameters/TONV5R1WalletParameters.swift
  • Sources/TONWalletKit/API/Wallet/TONWalletProtocol.swift
  • Sources/TONWalletKit/API/WebView/WKWebView+Injection.swift
  • Sources/TONWalletKit/JSAdapters/TONBridgeEventsHandlerJSAdapter.swift
  • Sources/TONWalletKit/JSAdapters/TONGaslessProviderJSAdapter.swift
  • Sources/TONWalletKit/JSAdapters/TONWalletAdapterJSAdapter.swift
  • Sources/TONWalletKit/JSAdapters/TONWalletKitStorageJSAdapter.swift
  • Sources/TONWalletKit/JSCore/Convertion/JSValueConversionError.swift
  • Sources/TONWalletKit/JSCore/JSDynamic.swift
  • Sources/TONWalletKit/JSWalletKit/Bridge/JSBridgeRawEventsHandler.swift
  • Sources/TONWalletKit/JSWalletKit/Bridge/TONBridgeEventError.swift
  • Sources/TONWalletKit/JSWalletKit/DeFi/Gasless/JSGaslessProvider.swift
  • Sources/TONWalletKit/JSWalletKit/JSWalletKitFile.swift
  • Sources/TONWalletKit/JSWalletKit/JSWalletKitResourceError.swift
  • Sources/TONWalletKit/JSWalletKit/Polyfilling/JSCryptoPolyfillError.swift
  • Sources/TONWalletKit/JSWalletKit/Polyfilling/JSPBKDF2Polyfill.swift
  • Sources/TONWalletKit/JSWalletKit/Polyfilling/JSSecureRandomBytesPolyfill.swift
  • Sources/TONWalletKit/JSWalletKit/Scripts/JSWalletKitInjectionScript.swift
  • Sources/TONWalletKit/Resources/JS/walletkit-ios-bridge.mjs
  • Tests/TONWalletKitTests/API/DeFi/Gasless/Encoding/TONEncodableGaslessProviderTests.swift
  • Tests/TONWalletKitTests/API/DeFi/Gasless/TONGaslessManagerTests.swift
  • Tests/TONWalletKitTests/API/DeFi/Gasless/TONGaslessProviderIdentifierTests.swift
  • Tests/TONWalletKitTests/API/DeFi/Gasless/TONGaslessProviderTests.swift
  • Tests/TONWalletKitTests/API/Models/Core/TONBase64Tests.swift
  • Tests/TONWalletKitTests/API/Models/Core/TONHexTests.swift
  • Tests/TONWalletKitTests/API/Streaming/TONStreamingProviderTests.swift
  • Tests/TONWalletKitTests/API/TONWalletKitTests.swift
  • Tests/TONWalletKitTests/API/Wallet/Adapters/TONWalletAdapterTests.swift
  • Tests/TONWalletKitTests/API/Wallet/Encoding/TONEncodableWalletTests.swift
  • Tests/TONWalletKitTests/Foundation/StringError+Testing.swift
  • Tests/TONWalletKitTests/JSAdapters/TONBridgeEventsHandlerJSAdapterTests.swift
  • Tests/TONWalletKitTests/JSAdapters/TONGaslessProviderJSAdapterTests.swift
  • Tests/TONWalletKitTests/JSAdapters/TONWalletKitStorageJSAdapterTests.swift
  • Tests/TONWalletKitTests/JSWalletKit/Bridge/JSBridgeRawEventsHandlerTests.swift
  • Tests/TONWalletKitTests/JSWalletKit/Polyfilling/JSPBKDF2PolyfillTests.swift
  • Tests/TONWalletKitTests/JSWalletKit/Polyfilling/JSSecureRandomBytesPolyfillTests.swift
  • Tests/TONWalletKitTests/Mocks/MockGaslessProvider.swift
  • Tests/TONWalletKitTests/Mocks/MockStorage.swift
  • Tests/TONWalletKitTests/Mocks/MockWalletAdapter.swift

Comment on lines +250 to +262
private func requoteIfNeeded() {
quoteTask?.cancel()

guard
gaslessEnabled,
let jettonAddress = selectedToken.jettonAddress,
let feeAsset = selectedFeeAsset,
let relay = relayAddress,
!recipientAddress.isEmpty,
!amount.isEmpty
else {
return
}

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 | ⚡ Quick win

Clear quote UI state immediately after task cancellation/early exit.

Line 251 cancels the current quote task, but early returns in this flow can leave stale quote state (isQuoting/fee data) visible until another successful quote pass.

💡 Suggested fix
 private func requoteIfNeeded() {
     quoteTask?.cancel()
+    isQuoting = false

     guard
         gaslessEnabled,
         let jettonAddress = selectedToken.jettonAddress,
         let feeAsset = selectedFeeAsset,
         let relay = relayAddress,
         !recipientAddress.isEmpty,
         !amount.isEmpty
     else {
+        currentQuote = nil
+        gaslessFeeText = nil
         return
     }

@@
         quoteTask = Task { [weak self] in
             guard let self else { return }
             do {
@@
             } catch {
                 if Task.isCancelled { return }
                 self.currentQuote = nil
                 self.gaslessFeeText = nil
                 self.gaslessError = "Failed to get gasless quote"
                 self.isQuoting = false
                 debugPrint(error)
             }
         }
 }

Also applies to: 296-307

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Demo/TONWalletApp/Sending/SendTokensViewModel.swift` around lines 250 - 262,
In the requoteIfNeeded() function, after canceling quoteTask and before any
early returns from the guard statements, reset the quote UI state by clearing
isQuoting and any fee-related data properties. This ensures that when the
function exits early due to missing required conditions (gaslessEnabled,
jettonAddress, feeAsset, relay, recipientAddress, or amount), the UI immediately
reflects that no quote is in progress rather than leaving stale quote state
visible. Apply the same clearing logic to the similar code block mentioned at
lines 296-307.

}
if let available = viewModel.formattedInstantUnstakeAvailable {
infoRow(label: "Instant Unstake Available", value: "\(available) TON")
infoRow(label: "Instant Unstake Available", value: "\(available) GRAM")

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 | ⚡ Quick win

Unify denomination wording across the staking screen

Line 217 switches to GRAM, but the same view still contains TON copy (e.g., unstake method descriptions), which creates mixed terminology in one flow. Please align all visible denomination strings to one unit label.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Demo/TONWalletApp/Staking/StakingView.swift` at line 217, The StakingView
displays mixed denomination terminology with "GRAM" in the infoRow call for
"Instant Unstake Available" while other parts of the same view use "TON" (such
as in unstake method descriptions). To fix this, locate all denomination
references throughout the StakingView component and choose one consistent unit
label, then replace all occurrences to match that standard. This includes the
infoRow function call and any other text strings that reference the token
denomination to ensure uniform terminology throughout the entire staking screen.

Comment on lines +55 to +59
// MARK: - 24 Home / nav (top-level imagesets)
case iconScan = "icon_scan"
case iconSettings = "icon_settings"
case iconSort = "icon_sort"
case iconCurrency = "icon_currency"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Move these nav icon assets into DesignSystem icon groups.

These new cases are tied to top-level asset names (icon_scan, icon_settings, etc.), but this file’s icon additions should use the DesignSystem asset groups to keep the icon catalog contract consistent.

As per coding guidelines, Demo/TONWalletApp/UIKit/DesignSystem/**/Icons/TONIcon.swift must “Drop Figma-exported icon assets into Demo/TONWalletApp/Assets.xcassets/DesignSystem/ (Tabbar, Icons24, Icons40 groups) and update TONIcon.image to prefer named assets with SF Symbol as fallback”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Demo/TONWalletApp/UIKit/DesignSystem/Icons/TONIcon.swift` around lines 55 -
59, The nav icon cases iconScan, iconSettings, iconSort, and iconCurrency are
currently referencing top-level asset names, but they should use DesignSystem
asset groups to maintain consistency with the icon catalog contract. Move these
icon assets into the appropriate DesignSystem group in Assets.xcassets (likely
Icons24 based on the 24px home navigation context), update the case values to
reference the properly organized asset names within the DesignSystem groups
(following the naming pattern used by other DesignSystem icons), and ensure the
TONIcon.image computed property uses these named assets as the primary source
with SF Symbol as a fallback.

Source: Coding guidelines

// All 23 SF Pro styles enumerated from the Figma "Typography" section via MCP.
// Names mirror Apple HIG (Title 1/2/3, Body, Callout, Subheadline 1/2, Footnote, Caption 1/2)
// plus the three SF Pro Rounded Bold "Price" sizes (40 / 44 / 64) used for amounts.
// plus the three SF Pro Bold "Price" sizes (40 / 44 / 64) used for amounts (non-rounded).

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 | ⚡ Quick win

Update stale inline docs for the new price style set.

Line 6 still says there are three price sizes, but this file now defines five (64/50/44/40/30). The section label should also match “SF Pro Bold” terminology.

✏️ Suggested doc fix
-// plus the three SF Pro Bold "Price" sizes (40 / 44 / 64) used for amounts (non-rounded).
+// plus five SF Pro Bold "Price" sizes (30 / 40 / 44 / 50 / 64) used for amounts (non-rounded).

-        // MARK: - Price (SF Pro Rounded Bold)
+        // MARK: - Price (SF Pro Bold)

Also applies to: 20-45

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Demo/TONWalletApp/UIKit/DesignSystem/Tokens/TONTypography.swift` at line 6,
The inline documentation comment at the beginning of TONTypography.swift is
outdated and states there are only three SF Pro Bold "Price" sizes (40 / 44 /
64), but the file now defines five price sizes (64/50/44/40/30). Update this
comment to accurately reflect the current set of five price sizes and ensure the
"SF Pro Bold" terminology is consistent with the new price style definitions
throughout the file.

Comment on lines +431 to +439
case .ton: return "GRAM"
case .jetton: return transfer.tokenAddress.map { shortAddress($0.value) } ?? "Jetton"
case .nft: return transfer.tokenAddress.map { shortAddress($0.value) } ?? "NFT"
}
}

private func unitLabel(for transfer: TONTransactionTraceMoneyFlowItem) -> String {
switch transfer.assetType {
case .ton: return "TON"
case .ton: return "GRAM"

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 | ⚡ Quick win

Keep TON/GRAM terminology consistent within this view.

Line 431 and Line 439 now emit GRAM, but the same screen still renders TON in other amount/title paths, so users can see mixed units in one confirmation flow. Please align all TON-denominated strings in this view to one label.

Suggested alignment patch
-                title: "Send TON #\(index + 1)",
+                title: "Send GRAM #\(index + 1)",

-    private func tonAmountText(_ amount: TONTokenAmount) -> String? {
-        Self.tonFormatter.string(from: amount).map { "\($0) TON" }
-    }
+    private func tonAmountText(_ amount: TONTokenAmount) -> String? {
+        Self.tonFormatter.string(from: amount).map { "\($0) GRAM" }
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@Demo/TONWalletApp/Wallet/Requests/SignMessage/WalletSignMessageRequestView.swift`
around lines 431 - 439, The code currently has inconsistent TON/GRAM terminology
in WalletSignMessageRequestView where the methods around lines 431-439 return
"GRAM" for the .ton case, but other parts of the same view still render "TON"
labels, causing mixed units to appear in the confirmation flow. Search through
the entire WalletSignMessageRequestView for all places where TON amount labels
are displayed (including the methods shown in the diff and any other
label-generating methods or text assignments), and ensure they all use the same
terminology consistently - either change all instances to "GRAM" to match the
recent changes in the unitLabel method, or revert the changes to use "TON"
throughout the view so users see uniform labeling.

import Foundation
import _BigInt

/** Deposit details returned by a crypto onramp provider. The user must send `amount` of `sourceCurrencyAddress` to `address` on `sourceChain` to complete the onramp; the provider then delivers the target crypto to the user's TON address. */

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 | ⚡ Quick win

Fix the enum docstring to match the type purpose.

Line 30 documents deposit transfer details, but this type is an onramp status enum. Please align the comment with success/pending/failed semantics.

💡 Proposed fix
-/** Deposit details returned by a crypto onramp provider.  The user must send &`#x60`;amount&`#x60`; of &`#x60`;sourceCurrencyAddress&`#x60`; to &`#x60`;address&`#x60`; on &`#x60`;sourceChain&`#x60`; to complete the onramp; the provider then delivers the target crypto to the user&`#39`;s TON address. */
+/** Current processing status of a crypto onramp deposit. */
📝 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
/** Deposit details returned by a crypto onramp provider. The user must send `amount` of `sourceCurrencyAddress` to `address` on `sourceChain` to complete the onramp; the provider then delivers the target crypto to the user's TON address. */
/** Current processing status of a crypto onramp deposit. */
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampStatus.swift` at
line 30, The docstring for the TONCryptoOnrampStatus enum incorrectly documents
deposit transfer details rather than describing the status enum itself. Replace
the current comment with one that accurately describes the enum's purpose as
representing the status of a crypto onramp operation, such as the possible
states of success, pending, or failed that indicate the outcome or current state
of an onramp transaction.

import Foundation
import _BigInt

/** Deposit details returned by a crypto onramp provider. The user must send `amount` of `sourceCurrencyAddress` to `address` on `sourceChain` to complete the onramp; the provider then delivers the target crypto to the user's TON address. */

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 | ⚡ Quick win

Correct the type-level comment for status params.

Line 30 describes deposit details, but this struct represents request parameters (depositId, providerId) for status lookup.

💡 Proposed fix
-/** Deposit details returned by a crypto onramp provider.  The user must send &`#x60`;amount&`#x60`; of &`#x60`;sourceCurrencyAddress&`#x60`; to &`#x60`;address&`#x60`; on &`#x60`;sourceChain&`#x60`; to complete the onramp; the provider then delivers the target crypto to the user&`#39`;s TON address. */
+/** Parameters required to query a crypto onramp deposit status. */
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/TONWalletKit/API/Models/WalletKit/TONCryptoOnrampStatusParams.swift`
at line 30, The comment for the TONCryptoOnrampStatusParams struct incorrectly
describes deposit details that are returned by a provider, when this struct
actually contains request parameters (depositId, providerId) used to look up the
status of a deposit. Update the comment to accurately reflect that this struct
represents status lookup parameters rather than deposit response details, making
it clear that these parameters are sent to query the status of an existing
deposit.

Comment on lines +53 to +56
return JSValue(newPromiseIn: context) { [weak self] resolve, reject in
Task {
guard let self else { return }

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify unresolved-promise pattern exists in this adapter
rg -nP --type=swift -U 'JSValue\(newPromiseIn:\s*context\)\s*\{\s*\[weak self\]\s*resolve,\s*reject\s*in[\s\S]*?guard let self else \{ return \}' Sources/TONWalletKit/JSAdapters/TONGaslessProviderJSAdapter.swift

Repository: ton-org/kit-ios

Length of output: 681


🏁 Script executed:

cat -n Sources/TONWalletKit/JSAdapters/TONGaslessProviderJSAdapter.swift | head -160

Repository: ton-org/kit-ios

Length of output: 6790


Always settle promises when self is deallocated.

Lines 55, 91, 116, and 141 return early on self == nil without calling resolve or reject, leaving the JS promise pending indefinitely. When the adapter is deallocated during async execution, JS-side callers hang waiting on unresolved promises.

Suggested fix
 return JSValue(newPromiseIn: context) { [weak self] resolve, reject in
     Task {
-        guard let self else { return }
+        guard let self else {
+            reject?.call(withArguments: ["Adapter deallocated before completing request"])
+            return
+        }

         do {
             let result = try await self.gaslessProvider.metadata()
             let jsResult = try result.encode(in: context)
             resolve?.call(withArguments: [jsResult])
         } catch {
             reject?.call(withArguments: [error.localizedDescription])
         }
     }
 }

Apply the same guard pattern to config, quote, and sendTransaction.

📝 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
return JSValue(newPromiseIn: context) { [weak self] resolve, reject in
Task {
guard let self else { return }
return JSValue(newPromiseIn: context) { [weak self] resolve, reject in
Task {
guard let self else {
reject?.call(withArguments: ["Adapter deallocated before completing request"])
return
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/TONWalletKit/JSAdapters/TONGaslessProviderJSAdapter.swift` around
lines 53 - 56, When self is deallocated during async execution in the promise
blocks, the early return guards (guard let self else { return }) leave JS
promises pending indefinitely instead of settling them. For all four locations
at lines 55, 91, 116, and 141 across the config, quote, and sendTransaction
methods, replace the early return with a call to reject with an appropriate
error describing that the adapter was deallocated, ensuring every promise path
is properly settled whether success, failure, or deallocation occurs.

Comment on lines +49 to 60
return JSValue(newPromiseIn: context) { [weak self] resolve, reject in
Task {
guard let self else { return }

do {
try await self.storage.set(key: key, value: value)
resolve?.call(withArguments: [JSValue(undefinedIn: context)])
} catch {
reject?.call(withArguments: [error.localizedDescription])
}
}
}

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if there's existing thread handling for JSContext in the codebase
rg -n "`@MainActor`|DispatchQueue\.main" --type swift Sources/TONWalletKit/JSAdapters/
rg -n "JSContext" --type swift -A 2 -B 2 Sources/TONWalletKit/JSAdapters/ | head -50

Repository: ton-org/kit-ios

Length of output: 4357


🏁 Script executed:

# Read the full TONWalletKitStorageJSAdapter.swift file
cat -n Sources/TONWalletKit/JSAdapters/TONWalletKitStorageJSAdapter.swift

Repository: ton-org/kit-ios

Length of output: 5655


🏁 Script executed:

# Search for TONWalletKitStorage protocol definition
fd -t f "\.swift$" Sources/TONWalletKit/ | xargs rg -l "protocol TONWalletKitStorage" | head -5

Repository: ton-org/kit-ios

Length of output: 118


🏁 Script executed:

# Check how storage is used and if it has `@MainActor`
rg -n "`@MainActor`" --type swift Sources/TONWalletKit/ | grep -i storage

Repository: ton-org/kit-ios

Length of output: 41


🏁 Script executed:

# Read the TONWalletKitStorage protocol definition
cat -n Sources/TONWalletKit/API/Storage/TONWalletKitStorage.swift

Repository: ton-org/kit-ios

Length of output: 1775


🏁 Script executed:

# Check for `@MainActor` in the protocol and any implementations
rg -n "`@MainActor`|nonisolated" --type swift Sources/TONWalletKit/API/Storage/

Repository: ton-org/kit-ios

Length of output: 41


🏁 Script executed:

# Look at how the adapter is instantiated and used - check for any `@MainActor` context
rg -n "TONWalletKitStorageJSAdapter" --type swift -B 3 -A 3 Sources/TONWalletKit/ | head -100

Repository: ton-org/kit-ios

Length of output: 2217


🏁 Script executed:

# Check how JSContext is created and managed - look for WebView or JS bridge setup
rg -n "JSContext" --type swift Sources/TONWalletKit/API/ -B 2 -A 2 | head -80

Repository: ton-org/kit-ios

Length of output: 7180


🏁 Script executed:

# Search for WKWebView usage which typically requires main thread
rg -n "WKWebView" --type swift Sources/TONWalletKit/ -B 2 -A 2

Repository: ton-org/kit-ios

Length of output: 735


🏁 Script executed:

# Check if there are any tests or examples showing how this is used
fd -t f "\.swift$" Sources/ | xargs rg -l "TONWalletKitStorageJSAdapter\|JSContext" | xargs rg -n "DispatchQueue\|MainActor\|Thread" | head -40

Repository: ton-org/kit-ios

Length of output: 1076


🏁 Script executed:

# Look at the WKWebView injection to understand how JSContext is set up
cat -n Sources/TONWalletKit/API/WebView/WKWebView+Injection.swift

Repository: ton-org/kit-ios

Length of output: 6881


🏁 Script executed:

# Search for how JSContext is created in the codebase
rg -n "JSContext\(\)" --type swift Sources/TONWalletKit/ -B 2 -A 2 | head -60

Repository: ton-org/kit-ios

Length of output: 5267


🏁 Script executed:

# Check if there's any concurrency/threading handling in similar promise patterns
rg -n "newPromiseIn|resolve\?\.|reject\?\." --type swift Sources/TONWalletKit/JSAdapters/ -B 1 -A 1

Repository: ton-org/kit-ios

Length of output: 35300


JSContext access from unstructured Task lacks thread safety guarantees.

JSContext and JSValue are not thread-safe. The resolve?.call() and reject?.call() callbacks execute from an unstructured Task which may run on any cooperative thread pool thread, while the JSContext expects to be accessed from the thread where it was created (typically main thread for WKWebView contexts).

This pattern appears across all JSAdapter implementations (storage, signer, wallet adapter, providers, API client, sessions manager). While it hasn't caused visible issues yet, it violates JSCore's threading constraints and could cause crashes or undefined behavior under certain scheduling conditions.

Dispatch resolve/reject callbacks to the main thread:

🔧 Suggested approach
 return JSValue(newPromiseIn: context) { [weak self] resolve, reject in
     Task {
         guard let self else { return }

         do {
             try await self.storage.set(key: key, value: value)
-            resolve?.call(withArguments: [JSValue(undefinedIn: context)])
+            DispatchQueue.main.async {
+                resolve?.call(withArguments: [JSValue(undefinedIn: context)])
+            }
         } catch {
-            reject?.call(withArguments: [error.localizedDescription])
+            DispatchQueue.main.async {
+                reject?.call(withArguments: [error.localizedDescription])
+            }
         }
     }
 }

Alternatively, apply @MainActor to the adapter class or individual methods (consistent with how JS message handling is already implemented in WKWebView+Injection.swift).

📝 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
return JSValue(newPromiseIn: context) { [weak self] resolve, reject in
Task {
guard let self else { return }
do {
try await self.storage.set(key: key, value: value)
resolve?.call(withArguments: [JSValue(undefinedIn: context)])
} catch {
reject?.call(withArguments: [error.localizedDescription])
}
}
}
return JSValue(newPromiseIn: context) { [weak self] resolve, reject in
Task {
guard let self else { return }
do {
try await self.storage.set(key: key, value: value)
DispatchQueue.main.async {
resolve?.call(withArguments: [JSValue(undefinedIn: context)])
}
} catch {
DispatchQueue.main.async {
reject?.call(withArguments: [error.localizedDescription])
}
}
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/TONWalletKit/JSAdapters/TONWalletKitStorageJSAdapter.swift` around
lines 49 - 60, The resolve and reject callbacks are being executed within an
unstructured Task that may run on any thread, but JSContext and JSValue require
main thread access. Wrap the resolve?.call() and reject?.call() invocations
within a DispatchQueue.main.async call to ensure the JSContext callbacks execute
on the main thread where the context was created. Alternatively, apply the
`@MainActor` annotation to the entire TONWalletKitStorageJSAdapter class or
specific methods to enforce main thread execution at compile time, which would
be consistent with the threading pattern already used in
WKWebView+Injection.swift.

Comment on lines +114 to +126
@Test("metadata rejects when context is deallocated")
func metadataRejectsWhenDeallocated() async {
var jsContext: JSContext? = JSContext()!
let provider = MockGaslessProvider(identifier: TONTonApiGaslessProviderIdentifier())
let sut = TONGaslessProviderJSAdapter(context: jsContext!, gaslessProvider: provider)
jsContext = nil

let result = sut.metadata()

await #expect(throws: (any Error).self) {
try await result.then()
}
}

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 | ⚡ Quick win

Assert the specific deallocated-context failure instead of any Error.

These tests currently pass on any thrown error, so they can miss regressions in the intended deallocation path. Please assert the concrete error case/message expected from context deallocation.

Suggested tightening
-        await `#expect`(throws: (any Error).self) {
-            try await result.then()
-        }
+        await `#expect`(throws: TONWalletKitError.self) { // replace with exact expected error type
+            try await result.then()
+        }
+        // Optionally assert the exact case/message for context deallocation.

Also applies to: 153-165, 191-203, 229-241

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/TONWalletKitTests/JSAdapters/TONGaslessProviderJSAdapterTests.swift`
around lines 114 - 126, The test metadataRejectsWhenDeallocated (and the similar
tests at lines 153-165, 191-203, 229-241) currently asserts that any Error is
thrown when the context is deallocated, which is too loose and can miss
regressions. Replace the generic (any Error).self assertion with the specific
concrete error type or case that is actually expected to be thrown when the
JSContext is deallocated. This ensures the test validates the intended
deallocation failure path rather than passing for any error condition.

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
@ProudOfZiggy
ProudOfZiggy merged commit d954cec into main Jun 23, 2026
3 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.

2 participants