Skip to content

Commit d52012e

Browse files
4.2.1
1 parent d249c56 commit d52012e

File tree

159 files changed

+3248
-921
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

159 files changed

+3248
-921
lines changed

changelogs/4.2.0.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
· Handy Widgets · Track balances and view NFTs right from your home screen.
22
· Live Fiat Previews · See the total balance in multiple fiat currencies at once.
3-
· New Welcome Flow · Easier onboarding with confetti.
3+
· New Welcome Flow · Easier onboarding with confetti 🎉

changelogs/4.2.1.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
· Handy Widgets · Track balances and view NFTs right from your home screen.
2+
· Live Fiat Previews · See the total balance in multiple fiat currencies at once.
3+
· New Welcome Flow · Easier onboarding with confetti.

docs/add-chain.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Adding a New Blockchain (Chain) Guide
2+
3+
This short guide lists the minimum required code touch-points to register a new chain in the project.
4+
For deeper architectural rules (stubs, UI gating, import boundaries, etc.) please see [the multichain Cursor rule](../.cursor/rules/multichain.mdc).
5+
6+
## Required Code Changes (Single Source Spots)
7+
8+
Update all of the following in one PR:
9+
10+
1. Add the chain literal to `ApiChain` in `src/api/types/misc.ts`.
11+
2. Extend `ApiWalletByChain` (and add a wallet type) in `src/api/types/storage.ts`.
12+
3. Add a config entry to `CHAIN_CONFIG` in `src/util/chain.ts` (title, flags, regexes, native token, explorer, optional `formatTransferUrl`, etc.).
13+
4. Add per‑chain style variables in `$byChain` inside `src/styles/scssVariables.scss` (colors, accents, etc.).
14+
5. Create the SDK folder `src/api/chains/<chain>/` and export `const <chain>Sdk: ChainSdk<'<chain>'>` from its `index.ts` (all interface methods present; unsupported ones throw `Not supported in <ChainName>`, see `src/api/chains/tron/index.ts` as example).
15+
6. Register the SDK in the map `chains` in `src/api/chains/index.ts`.
16+
7. Add a font icon: `src/assets/font-icons/chain-<chain>.svg` (match size & baseline of existing chain icons).
17+
8. (Optional) Map the native token icon in `TOKEN_FONT_ICONS` in `src/config.ts` if a custom glyph is needed.
18+
19+
## Minimum Viable Feature Set (Recommended Order)
20+
21+
Implement these first so the chain is actually usable.
22+
23+
### Authentication (Importing / Viewing Wallets)
24+
25+
- Importing from a BIP39 mnemonic
26+
- Importing from an address (view-only)
27+
28+
Nice to have later:
29+
- Importing from a Ledger hardware wallet
30+
31+
### Token List
32+
33+
- Native token is required
34+
- Prices
35+
- Jettons can be added later
36+
37+
### Balances
38+
39+
- The SDK chain polling methods must update the balance of the supported tokens
40+
41+
### Activity History
42+
43+
- Fetching activity history slices
44+
- Fetching activity fee
45+
- The SDK chain polling methods must check for new transactions and add them to the start of the list
46+
47+
Nice to have later:
48+
- Comment decryption (if applicable)
49+
50+
### Sending Tokens
51+
52+
- Fetching the fee in the Send form
53+
- Sending
54+
55+
Nice to have later:
56+
- Comment
57+
- Encrypted comment (if applicable)
58+
- Sending with a Ledger hardware wallet
59+
60+
## UI Gating Basics
61+
62+
Only surface features that are actually supported:
63+
- If your chain has no `formatTransferUrl`, it must not appear in Deposit Link flows.
64+
- Use flags from `CHAIN_CONFIG` (e.g. `isTransferCommentSupported`, `isLedgerSupported`) instead of hard-coded `if (chain === ...)`.
65+
66+
## Stubs & Unsupported Features
67+
68+
Provide throwing stubs (`function notSupported(): never`) for every `ChainSdk` method you cannot implement yet.
69+
70+
## Backend & Infrastructure Coordination
71+
72+
A new chain is not only a client concern. It also requires backend support:
73+
74+
What you need from backend:
75+
- Access to a reliable node / RPC endpoint (or cluster) for the new chain
76+
- Indexing & enrichment for activity
77+
- Real-time activity notifications via our backend socket (set by `CHAIN_CONFIG[chain].doesBackendSocketSupport`)
78+
79+
`doesBackendSocketSupport` flag:
80+
- Set to `false` only temporarily while backend adds socket activity support.
81+
- Once backend provides notifications, switch it to `true` so the client receives push updates instead of relying solely on polling.
82+
- Do not leave it `false` long-term; stale value means unnecessary latency and extra battery consumption from polling.
83+
84+
Reach out to the backend team early (ideally before starting client implementation) with the chain’s requirements: activity feed shape, fee estimation endpoints (if any), token metadata plans, and any staking / NFT / domain features you plan to enable soon.
85+
Clearly mark in the PR description whether backend socket support is already live or pending.
86+
87+
If in doubt about what backend exposes, ask — do *not* guess or scrape public explorers.
88+
89+
## Common Pitfalls
90+
91+
| Pitfall | Fix |
92+
|---------|-----|
93+
| Added chain but missed `$byChain` styles | Add style map entry before shipping |
94+
| Added special-case UI `if (chain === '<name>')` | Replace with a config flag in `CHAIN_CONFIG` |
95+
| Method missing in one chain SDK | Add stub throwing `Not supported in <ChainName>` |
96+
| Catching stub error to hide feature | Gate the feature in UI instead |
97+
| Left `doesBackendSocketSupport` = false after backend enabled | Set it to true and remove temporary polling-only logic |

mobile/android/air/SubModules/AirAsFramework/src/main/java/org/mytonwallet/app_air/airasframework/AirAsFrameworkApplication.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ import org.mytonwallet.app_air.uicomponents.helpers.FontManager
99
import org.mytonwallet.app_air.walletbasecontext.WBaseStorage
1010
import org.mytonwallet.app_air.walletbasecontext.localization.LocaleController
1111
import org.mytonwallet.app_air.walletbasecontext.logger.Logger
12+
import org.mytonwallet.app_air.walletbasecontext.theme.ThemeManager
13+
import org.mytonwallet.app_air.walletbasecontext.theme.ThemeManager.setAccentColor
14+
import org.mytonwallet.app_air.walletbasecontext.theme.ThemeManager.setNftAccentColor
15+
import org.mytonwallet.app_air.walletbasecontext.utils.ApplicationContextHolder
1216
import org.mytonwallet.app_air.walletcontext.cacheStorage.WCacheStorage
1317
import org.mytonwallet.app_air.walletcontext.globalStorage.IGlobalStorageProvider
1418
import org.mytonwallet.app_air.walletcontext.globalStorage.WGlobalStorage
15-
import org.mytonwallet.app_air.walletcontext.helpers.ApplicationContextHolder
1619
import org.mytonwallet.app_air.walletcontext.helpers.DevicePerformanceClassifier
1720
import org.mytonwallet.app_air.walletcontext.helpers.LauncherIconController
1821
import org.mytonwallet.app_air.walletcontext.secureStorage.WSecureStorage
19-
import org.mytonwallet.app_air.walletbasecontext.theme.ThemeManager
20-
import org.mytonwallet.app_air.walletbasecontext.theme.ThemeManager.setAccentColor
21-
import org.mytonwallet.app_air.walletbasecontext.theme.ThemeManager.setNftAccentColor
2222
import org.mytonwallet.app_air.walletcore.WalletCore
2323
import org.mytonwallet.app_air.walletcore.stores.AccountStore
2424
import org.mytonwallet.app_air.walletcore.stores.ActivityStore
@@ -68,6 +68,8 @@ class AirAsFrameworkApplication {
6868

6969
t = System.currentTimeMillis()
7070
WBaseStorage.init(applicationContext)
71+
WBaseStorage.setActiveLanguage(WGlobalStorage.getLangCode())
72+
WBaseStorage.setBaseCurrency(WGlobalStorage.getBaseCurrency())
7173
Logger.i(
7274
Logger.LogTag.AIR_APPLICATION,
7375
"WBaseStorage.init: ${System.currentTimeMillis() - t}ms"

mobile/android/air/SubModules/AirAsFramework/src/main/java/org/mytonwallet/app_air/airasframework/MainWindow.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ import androidx.core.content.ContextCompat
1010
import org.mytonwallet.app_air.airasframework.splash.SplashVC
1111
import org.mytonwallet.app_air.uicomponents.base.WNavigationController
1212
import org.mytonwallet.app_air.uicomponents.base.WWindow
13+
import org.mytonwallet.app_air.uiwidgets.configurations.WidgetsConfigurations
14+
import org.mytonwallet.app_air.walletbasecontext.logger.Logger
1315
import org.mytonwallet.app_air.walletcontext.WalletContextManager
1416
import org.mytonwallet.app_air.walletcontext.globalStorage.WGlobalStorage
1517
import org.mytonwallet.app_air.walletcontext.helpers.AutoLockHelper
1618
import org.mytonwallet.app_air.walletcore.WalletCore
1719
import org.mytonwallet.app_air.walletcore.pushNotifications.AirPushNotifications
18-
import org.mytonwallet.app_air.walletbasecontext.logger.Logger
1920

2021
class MainWindow : WWindow() {
2122
private val splashVC by lazy {
@@ -86,6 +87,16 @@ class MainWindow : WWindow() {
8687
AutoLockHelper.appResumed()
8788
}
8889

90+
var lastWidgetUpdate: Long = 0
91+
override fun onPause() {
92+
super.onPause()
93+
val currentDt = System.currentTimeMillis()
94+
if (currentDt - lastWidgetUpdate > 60 * 1000) {
95+
lastWidgetUpdate = currentDt
96+
WidgetsConfigurations.reloadWidgets(applicationContext)
97+
}
98+
}
99+
89100
override fun onDestroy() {
90101
super.onDestroy()
91102
destroyBridge()

mobile/android/air/SubModules/AirAsFramework/src/main/java/org/mytonwallet/app_air/airasframework/WidgetConfigurationWindow.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class WidgetConfigurationWindow : WWindow() {
3232
ActionsWidgetConfigurationVC(this, appWidgetId, onResult)
3333
}
3434

35-
"org.mytonwallet.app_air.widgets.actionsWidget.PriceWidget" -> {
35+
"org.mytonwallet.app_air.widgets.priceWidget.PriceWidget" -> {
3636
PriceWidgetConfigurationVC(this, appWidgetId, onResult)
3737
}
3838

mobile/android/air/SubModules/Ledger/src/main/java/org/mytonwallet/app_air/ledger/connectionManagers/LedgerUsbManager.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import org.mytonwallet.app_air.ledger.LedgerManager.ConnectionState
77
import org.mytonwallet.app_air.ledger.usb.HIDDevice
88
import org.mytonwallet.app_air.ledger.usb.USBManager
99
import org.mytonwallet.app_air.walletcore.WalletCore
10-
import org.mytonwallet.app_air.walletcore.models.LedgerAppInfo
1110
import org.mytonwallet.app_air.walletcore.models.MBlockchain
1211
import org.mytonwallet.app_air.walletcore.moshi.api.ApiMethod
1312

@@ -107,15 +106,15 @@ object LedgerUsbManager : ILedgerConnectionManager {
107106
ApiMethod.Other.WaitForLedgerApp(chain = MBlockchain.ton),
108107
callback = { res, error ->
109108
if (res != true || error != null) {
110-
onUpdate(ConnectionState.Done(LedgerDevice.Usb(device)))
109+
onUpdate(
110+
ConnectionState.Error(
111+
step = ConnectionState.Error.Step.TON_APP,
112+
shortMessage = null
113+
)
114+
)
111115
return@call
112116
}
113-
onUpdate(
114-
ConnectionState.Error(
115-
step = ConnectionState.Error.Step.TON_APP,
116-
shortMessage = null
117-
)
118-
)
117+
onUpdate(ConnectionState.Done(LedgerDevice.Usb(device)))
119118
}
120119
)
121120
}

mobile/android/air/SubModules/Ledger/src/main/java/org/mytonwallet/app_air/ledger/screens/ledgerConnect/LedgerConnectVC.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,8 @@ class LedgerConnectVC(
831831
super.viewWillAppear()
832832
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
833833
configureTryAgainButton(
834-
toOpenSettings = !LedgerBleManager.isPermissionGranted() &&
834+
toOpenSettings = LedgerManager.activeMode == LedgerManager.ConnectionMode.BLE &&
835+
!LedgerBleManager.isPermissionGranted() &&
835836
!ActivityCompat.shouldShowRequestPermissionRationale(
836837
window!!,
837838
Manifest.permission.BLUETOOTH_SCAN

mobile/android/air/SubModules/Ledger/src/main/java/org/mytonwallet/app_air/ledger/screens/ledgerWallets/LedgerWalletsVC.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ class LedgerWalletsVC(
255255
else -> {
256256
LedgerLoadMoreCell(context).apply {
257257
onTap = {
258-
homeVM.loadMore(items.size - 1)
258+
homeVM.loadMore(items.size)
259259
}
260260
}
261261
}

mobile/android/air/SubModules/UIAssets/src/main/java/org/mytonwallet/app_air/uiassets/viewControllers/renew/RenewVC.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import org.mytonwallet.app_air.walletbasecontext.localization.LocaleController
3030
import org.mytonwallet.app_air.walletbasecontext.theme.ViewConstants
3131
import org.mytonwallet.app_air.walletbasecontext.theme.WColor
3232
import org.mytonwallet.app_air.walletbasecontext.theme.color
33-
import org.mytonwallet.app_air.walletcontext.utils.formatDateAndTime
33+
import org.mytonwallet.app_air.walletbasecontext.utils.formatDateAndTime
3434
import org.mytonwallet.app_air.walletbasecontext.utils.smartDecimalsCount
3535
import org.mytonwallet.app_air.walletbasecontext.utils.toString
3636
import org.mytonwallet.app_air.walletcore.TONCOIN_SLUG

0 commit comments

Comments
 (0)