Thorchain integration#9403
Conversation
Implement end-to-end THORChain support in multiswap sending flow. This adds THORChain-specific send data/settings/result types, a dedicated send transaction service, and adapter `deposit()` support for native THOR swaps (with MsgDeposit when no inbound vault, or MsgSend when inbound exists). It also updates quote parsing for nullable inbound/gas fields, improves THOR asset mapping (including RUNE and cache version bump), wires THOR tx hash into swap confirmation, and updates marketkit/thorchainkit versions.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
🚧 Files skipped from review as they are similar to previous changes (10)
📝 WalkthroughWalkthroughAdds Thorchain support across dependency configuration, blockchain metadata, kit lifecycle management, wallet and transaction adapters, multiswap flows, send screens, transaction presentation, app status, balance handling, and address derivation validation. ChangesThorchain integration
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant SendPage
participant SendThorchainViewModel
participant ThorchainAdapter
participant ThorchainKit
SendPage->>SendThorchainViewModel: collect amount and address state
SendThorchainViewModel->>ThorchainAdapter: send(amount, address, memo)
ThorchainAdapter->>ThorchainKit: submit Thorchain transaction
ThorchainKit-->>ThorchainAdapter: transaction id
ThorchainAdapter-->>SendThorchainViewModel: transaction id
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Pull request overview
Adds THORChain (RUNE + THORChain assets) support across walletkit, including address handling, send flow, transaction parsing/display, and multiswap integration; also includes a couple of concurrency/race-condition fixes in adapter/balance update flows.
Changes:
- Introduce THORChain kit manager + adapters (balance/receive/send + transactions) and wire them into
App, adapter factories/managers, and UI. - Add THORChain send screens + confirmation flow, address validation/handling, and transaction record/view-item support (list + details).
- Update multiswap Thorchain-provider logic for THORChain-native inputs, plus dependency bumps to bring in
thorchain-kit-android.
Reviewed changes
Copilot reviewed 54 out of 54 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| walletkit/src/test/java/io/horizontalsystems/walletkit/ThorchainAddressDerivationTest.kt | Adds deterministic THORChain address derivation test. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/ui/compose/components/TransactionInfoCells.kt | Enables transaction options UI for THORChain. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/watchaddress/WatchAddressViewModel.kt | Marks THORChain as unsupported for watch-address flow. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactions/TransactionViewItemFactory.kt | Adds list-item mapping for THORChain incoming/outgoing records. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactions/TransactionRecordRepository.kt | Includes THORChain in supported transaction repository blockchains. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactionInfo/TransactionViewItemFactoryHelper.kt | Adds THORChain fee section handling for outgoing tx info. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactionInfo/TransactionInfoViewItemFactory.kt | Adds THORChain transaction info sections + memo item. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactionInfo/TransactionInfoService.kt | Includes THORChain coin UIDs for rate lookups in tx info. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/settings/appstatus/AppStatusViewModel.kt | Displays THORChain kit status in app status screen. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/settings/appstatus/AppStatusModule.kt | Injects THORChain manager into app status VM. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainViewModel.kt | Implements THORChain send ViewModel + confirmation data + send action. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainScreen.kt | Adds THORChain send Compose screen UI. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainModule.kt | Adds DI factory/wiring for THORChain send flow. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainConfirmationScreen.kt | Adds THORChain send confirmation Compose screen. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainAddressService.kt | Adds THORChain send address validation service. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/SendPage.kt | Routes THORChain to new send screen/module. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/SendConfirmationPage.kt | Adds THORChain confirmation page type and routing. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/address/EnterAddressValidator.kt | Adds THORChain address validator using ISendThorchainAdapter. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/SwapConfirmViewModel.kt | Supports THORChain tx hash extraction from send results. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionSettings.kt | Adds THORChain send-transaction settings type. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionServiceThorchain.kt | Implements THORChain send-transaction service (swap/deposit/send). |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionServiceFactory.kt | Creates THORChain send-transaction service via Thorchain adapter. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionResult.kt | Adds THORChain send-transaction result type. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionData.kt | Adds THORChain send data models (Deposit/Send). |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/USwapProvider.kt | Adds THORChain-native token asset mapping for provider assets map. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/SwapHelper.kt | Resolves THORChain receive address via THORChain kit manager. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/MayaProvider.kt | Tightens null handling for inbound address in Maya quote conversion. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/BaseThorChainProvider.kt | Adds THORChain-native swap send-data path + versioned cache for asset mapping. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/history/SwapInfoViewModel.kt | Adds RuneScan tx explorer URL for THORChain. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/configuredtoken/ConfiguredTokenInfoViewModel.kt | Displays THORChain asset denom in configured token info. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/coin/overview/CoinOverviewViewModel.kt | Adds THORChain asset variants for coin overview. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/balance/BalanceViewItemFactory.kt | Assigns sorting weight for THORChain balances. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/balance/BalanceService.kt | Fixes race by avoiding writing sorted results back to shared list. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/address/IAddressHandler.kt | Adds THORChain address handler + UDN code mapping. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/address/AddressInputModule.kt | Registers THORChain handler in address parser chain. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/modules/address/AddressHandlerFactory.kt | Adds THORChain handler to handler factory. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/entities/transactionrecords/thorchain/ThorchainTransactionRecord.kt | Introduces base THORChain transaction record. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/entities/transactionrecords/thorchain/ThorchainOutgoingTransactionRecord.kt | Adds THORChain outgoing record model. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/entities/transactionrecords/thorchain/ThorchainIncomingTransactionRecord.kt | Adds THORChain incoming record model. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/entities/Address.kt | Adds THORChain support in address→tokenType mapping. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/providers/FeeTokenProvider.kt | Ensures THORChain assets use native fee token query. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/MarketKitExtensions.kt | Adds THORChain support metadata (supported token types, titles, ordering, etc.). |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/TransactionAdapterManager.kt | Wires THORChain transactions adapter creation. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/ThorchainKitManager.kt | Adds THORChain kit lifecycle manager + signer/address helpers. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/AdapterManager.kt | Adds THORChain refresh + fixes init adapter-map rebuild race. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/Interfaces.kt | Adds ISendThorchainAdapter interface. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AddressValidatorFactory.kt | Registers THORChain validator in factory. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AdapterFactory.kt | Creates THORChain adapters + THORChain transactions adapter. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/App.kt | Adds THORChain kit manager wiring into app singleton graph. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainTransactionsAdapter.kt | Implements THORChain ITransactionsAdapter. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainTransactionConverter.kt | Converts Midgard transactions into wallet transaction records. |
| walletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainAdapter.kt | Implements THORChain balance/receive/send adapter. |
| walletkit/build.gradle.kts | Adds thorchain kit dependency to walletkit module. |
| gradle/libs.versions.toml | Adds thorchainKit version + bumps marketKit version. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 13
🧹 Nitpick comments (1)
walletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AdapterFactory.kt (1)
188-190: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated
ThorchainAdapterconstruction.The exact same
ThorchainAdapter(thorchainKitManager.getThorchainKitWrapper(wallet.account), wallet)expression appears at both theTokenType.Native/BlockchainType.Thorchainbranch and theTokenType.ThorchainAssetbranch. Extracting a small private helper (e.g.getThorchainAdapter(wallet)) avoids the two call sites drifting apart later.♻️ Proposed refactor
+ private fun getThorchainAdapter(wallet: Wallet): IAdapter = + ThorchainAdapter(thorchainKitManager.getThorchainKitWrapper(wallet.account), wallet) + BlockchainType.Thorchain -> { - ThorchainAdapter(thorchainKitManager.getThorchainKitWrapper(wallet.account), wallet) + getThorchainAdapter(wallet) } ... is TokenType.ThorchainAsset -> when (wallet.token.blockchainType) { - BlockchainType.Thorchain -> ThorchainAdapter(thorchainKitManager.getThorchainKitWrapper(wallet.account), wallet) + BlockchainType.Thorchain -> getThorchainAdapter(wallet) else -> null }Also applies to: 226-229
🤖 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 `@walletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AdapterFactory.kt` around lines 188 - 190, Extract the duplicated ThorchainAdapter construction from the TokenType.Native/BlockchainType.Thorchain and TokenType.ThorchainAsset branches into a private helper such as getThorchainAdapter(wallet). Replace both call sites with the helper while preserving the existing thorchainKitManager.getThorchainKitWrapper(wallet.account) and wallet arguments.
🤖 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
`@walletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainAdapter.kt`:
- Line 34: Update the coroutine collectors launched from ThorchainAdapter around
coroutineScope, including the getDenomBalanceFlow(denom) and syncStateFlow
collectors, to handle uncaught flow exceptions with catch or surrounding
try-catch. Ensure one collector’s failure does not cancel sibling coroutines or
silently stop balance and sync updates, while preserving the existing
estimateFee handling.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainTransactionConverter.kt`:
- Around line 39-54: Update the transaction conversion loop around userSpends
and ThorchainOutgoingTransactionRecord so to is resolved from the current
transfer’s asset-specific counterparty rather than
transaction.outgoing.firstOrNull(). Preserve first-entry fallback only if the
model guarantees one counterparty per asset, and ensure each generated record is
attributed to the correct address in multi-transfer actions.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/ThorchainKitManager.kt`:
- Around line 22-29: Update ThorchainKitManager to implement the Clearable
interface and add an override clear() method that cancels the manager’s scope
using coroutineScope.cancel(). Preserve the existing job cancellation behavior
in stop(), and ensure the scope property is the one cleaned up.
- Around line 102-123: Protect the backgroundManager.stateFlow collector in
start() with exception handling so failures from thorchainKit.pause(), the
delayed resume path, or related state handling do not silently terminate the
launch coroutine. Catch and visibly report exceptions using the project’s
established logging mechanism while preserving the existing
background/foreground transition behavior.
- Around line 44-82: Update ThorchainKitManager’s getThorchainKitWrapper,
getSigner, and getAddress seed-derived operations so cryptographic work executes
on Dispatchers.IO within runCatching (or equivalent manager-level background
dispatch), while preserving their existing results and
UnsupportedAccountException behavior.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/balance/BalanceService.kt`:
- Around line 99-109: Update the balance refresh flow around ensureActive() and
_balanceItemsFlow.update so cancellation validation and emission are serialized
with the source update. Use the existing mutex or generation/token mechanism to
revalidate the sort job while holding the synchronization guard immediately
before publishing, preventing a cancelled job from emitting stale sorted rows.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/USwapProvider.kt`:
- Around line 223-229: Update the provider’s blockchainTypes registration to
include Thorchain so discovery reaches the existing BlockchainType.Thorchain
branch. In start(), version the cached provider identifier and invalidate or
replace the unversioned cache entry so existing clients refresh stale or missing
data while preserving current discovery behavior.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionServiceThorchain.kt`:
- Around line 60-68: Update SendTransactionServiceThorchain.sendTransaction so
the adapter.deposit and adapter.send calls execute inside
withContext(Dispatchers.IO), including the surrounding signing and broadcast
operations while preserving the existing transaction-result flow.
- Around line 23-57: Serialize access to sendData and cautions in
SendTransactionServiceThorchain using the existing mutex withLock, including
updates in setSendTransactionData and the snapshot read in createState. Ensure
the confirmation/quote refresh flow cannot observe partially updated state,
while preserving the current caution calculation and emitted state behavior.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/SendPage.kt`:
- Around line 187-200: Propagate the prefilled input.memo through the Thorchain
send flow: pass it from SendPage’s SendThorchainModule.Factory and
SendThorchainScreen construction, add the corresponding Factory/ViewModel
parameters, and initialize the Thorchain memo field with it. Preserve existing
behavior when no memo is provided.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainAddressService.kt`:
- Around line 12-62: Refactor SendThorchainAddressService to extend ServiceState
and replace the hand-rolled MutableStateFlow/State setup with override fun
createState(). Move address validation and updates into mutex.withLock, derive
all state from the state passed to the update operation, and call emitState()
after mutations; preserve the existing validAddress, invalid-address error, and
canBeSend behavior.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainViewModel.kt`:
- Around line 64-87: Wrap each of the four collectors in
init—amountService.stateFlow, addressService.stateFlow, and both
xRateService.getRateFlow calls—with the project’s established coroutine
exception-handling pattern, using try-catch or a Flow catch operator. Ensure
exceptions from handleUpdatedAmountState, handleUpdatedAddressState, and rate
updates are handled without silently terminating the viewModelScope launches.
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/settings/appstatus/AppStatusViewModel.kt`:
- Around line 229-231: Update getBlockchainStatusBlock() to add a Thorchain
branch that reads thorchainKitManager.statusInfo and includes it in the
block-based App Status UI, matching the existing getBlockchainStatus() behavior
and formatting used for other blockchains.
---
Nitpick comments:
In
`@walletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AdapterFactory.kt`:
- Around line 188-190: Extract the duplicated ThorchainAdapter construction from
the TokenType.Native/BlockchainType.Thorchain and TokenType.ThorchainAsset
branches into a private helper such as getThorchainAdapter(wallet). Replace both
call sites with the helper while preserving the existing
thorchainKitManager.getThorchainKitWrapper(wallet.account) and wallet arguments.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5dad10aa-38d4-4bc5-8315-a64e3df289a0
📒 Files selected for processing (54)
gradle/libs.versions.tomlwalletkit/build.gradle.ktswalletkit/src/main/java/io/horizontalsystems/walletkit/core/App.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/Interfaces.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/MarketKitExtensions.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainAdapter.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainTransactionConverter.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainTransactionsAdapter.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AdapterFactory.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AddressValidatorFactory.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/AdapterManager.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/ThorchainKitManager.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/TransactionAdapterManager.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/core/providers/FeeTokenProvider.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/entities/Address.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/entities/transactionrecords/thorchain/ThorchainIncomingTransactionRecord.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/entities/transactionrecords/thorchain/ThorchainOutgoingTransactionRecord.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/entities/transactionrecords/thorchain/ThorchainTransactionRecord.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/address/AddressHandlerFactory.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/address/AddressInputModule.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/address/IAddressHandler.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/balance/BalanceService.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/balance/BalanceViewItemFactory.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/coin/overview/CoinOverviewViewModel.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/configuredtoken/ConfiguredTokenInfoViewModel.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/SwapConfirmViewModel.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/history/SwapInfoViewModel.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/BaseThorChainProvider.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/MayaProvider.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/SwapHelper.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/USwapProvider.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionData.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionResult.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionServiceFactory.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionServiceThorchain.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionSettings.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/SendConfirmationPage.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/SendPage.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/address/EnterAddressValidator.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainAddressService.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainConfirmationScreen.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainModule.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainScreen.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainViewModel.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/settings/appstatus/AppStatusModule.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/settings/appstatus/AppStatusViewModel.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactionInfo/TransactionInfoService.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactionInfo/TransactionInfoViewItemFactory.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactionInfo/TransactionViewItemFactoryHelper.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactions/TransactionRecordRepository.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/transactions/TransactionViewItemFactory.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/modules/watchaddress/WatchAddressViewModel.ktwalletkit/src/main/java/io/horizontalsystems/walletkit/ui/compose/components/TransactionInfoCells.ktwalletkit/src/test/java/io/horizontalsystems/walletkit/ThorchainAddressDerivationTest.kt
| @Synchronized | ||
| fun getThorchainKitWrapper(account: Account): ThorchainKitWrapper { | ||
| if (this.thorchainKitWrapper != null && currentAccount != account) { | ||
| stop() | ||
| } | ||
|
|
||
| if (this.thorchainKitWrapper == null) { | ||
| val accountType = account.type | ||
| this.thorchainKitWrapper = when (accountType) { | ||
| is AccountType.Mnemonic -> { | ||
| createKitInstance(accountType, account) | ||
| } | ||
|
|
||
| else -> throw UnsupportedAccountException() | ||
| } | ||
| start() | ||
| useCount = 0 | ||
| currentAccount = account | ||
| } | ||
|
|
||
| useCount++ | ||
| return this.thorchainKitWrapper!! | ||
| } | ||
|
|
||
| private fun createKitInstance(accountType: AccountType.Mnemonic, account: Account): ThorchainKitWrapper { | ||
| val kit = ThorchainKit.getInstance(App.instance, accountType.seed, Network.Mainnet, account.id) | ||
|
|
||
| return ThorchainKitWrapper(kit) | ||
| } | ||
|
|
||
| fun getSigner(accountType: AccountType): Signer = when (accountType) { | ||
| is AccountType.Mnemonic -> Signer.getInstance(accountType.seed, Network.Mainnet) | ||
| else -> throw UnsupportedAccountException() | ||
| } | ||
|
|
||
| fun getAddress(accountType: AccountType): String = when (accountType) { | ||
| is AccountType.Mnemonic -> ThorchainKit.getAddress(accountType.seed, Network.Mainnet).toString() | ||
| else -> throw UnsupportedAccountException() | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm all call sites of these ThorchainKitManager methods run on Dispatchers.IO (or a background context) rather than Main.
rg -n --type=kt 'thorchainKitManager\.(getThorchainKitWrapper|getSigner|getAddress)' -B5 -A2Repository: horizontalsystems/unstoppable-wallet-android
Length of output: 209
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Kotlin files matching ThorchainKitManager/Adapter:"
git ls-files | rg '(^|/)Thorchain|ThorchainKitManager\.kt|ThorchainAdapter\.kt|WalletKit' || true
echo
echo "Direct method references:"
rg -n 'thorchainKitManager\.(getThorchainKitWrapper|getSigner|getAddress)' || true
echo
echo "Manager declarations/imports/usages:"
rg -n 'ThorchainKitManager|ThorchainAdapter|getThorchainKitWrapper|getSigner\(|getAddress\(' .Repository: horizontalsystems/unstoppable-wallet-android
Length of output: 1118
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re, subprocess
files = subprocess.check_output(['git','ls-files','--', '*.kt'], text=True).splitlines()
queries = ['getThorchainKitWrapper', 'getSigner', 'getAddress']
# also include ThorchainKitManager.getThorchainKitWrapper for direct qualifier form
queries += ['ThorchainKitManager']
target_pat = re.compile(r'ThorchainKitManager\.(?:getThorchainKitWrapper|getSigner|getAddress)\b|thorchainKitManager\.(?:getThorchainKitWrapper|getSigner|getAddress)\b|getThorchainKitWrapper\s*\(|getSigner\s*\(|getAddress\s*\(')
for fpath in files:
if fpath.startswith('walletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/ThorchainKitManager.kt'):
continue
try:
txt = Path(fpath).read_text(errors='ignore')
except Exception:
continue
if target_pat.search(txt):
print(f'--- {fpath}')
lines = txt.splitlines()
for i,l in enumerate(lines,1):
if target_pat.search(l):
lo=max(1,i-8); hi=min(len(lines),i+6)
for j in range(lo,hi+1):
marker='>> ' if j==i else ' '
print(f'{marker}{j:4}\t{lines[j-1]}')
PYRepository: horizontalsystems/unstoppable-wallet-android
Length of output: 14917
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Repository root:"
pwd
echo
git ls-files | wc -l
echo
echo "Top-level files:"
git ls-files | sed 's#/.*##' | sort -u | head -100
echo
echo "Root tree-ish entries (tree equivalent):"
git ls-tree --name-only -d HEAD | sort -u | head -200Repository: horizontalsystems/unstoppable-wallet-android
Length of output: 892
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "All Kotlin files matching ThorchainKitManager/thorchainKitManager/address:"
git ls-files '*.kt' '\*.kt' | xargs rg -n 'ThorchainKitManager|thorchainKitManager|App\.thorchainKitManager|getThorchainKitWrapper\(|getSigner\(|getAddress\(' -g '*.kt' || true
echo
echo "Search all files for Thorchain address/signing method references:"
rg -n 'ThorchainKit\.getAddress|ThorchainKit\.getInstance|Signer\.(getInstance|address)|ThorchainAdapter|ThorchainTransactionsAdapter|thorchainKitManager' . || true
echo
echo "Candidate adapter contexts:"
for f in \
walletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainAdapter.kt \
walletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AdapterFactory.kt \
walletkit/src/main/java/io/horizontalsystems/walletkit/modules/address/IAddressHandler.kt \
walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/SwapHelper.kt \
walletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/ThorchainKitManager.kt
do
if [ -f "$f" ]; then
echo "===== $f ====="
wc -l "$f"
ast-grep outline "$f" || true
fi
doneRepository: horizontalsystems/unstoppable-wallet-android
Length of output: 22476
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "All matches using git-tracked .kt files:"
git ls-files '*.kt' | while IFS= read -r f; do
rg -n 'ThorchainKitManager|thorchainKitManager|App\.thorchainKitManager|getThorchainKitWrapper\(|getSigner\(|getAddress\(' "$f" || true
done
echo
echo "Search all checked-out files for related Thorchain references:"
rg -n 'ThorchainKit\.getAddress|ThorchainKit\.getInstance|Signer\.(getInstance|address)|ThorchainAdapter|ThorchainTransactionsAdapter|thorchainKitManager' --glob '*.kt' --glob '*.java' --glob '*.kts' --glob '*.gradle' --glob '*.xml' . || true
echo
echo "Candidate file contexts:"
for f in \
walletkit/src/main/java/io/horizontalsystems/walletkit/core/adapters/ThorchainAdapter.kt \
walletkit/src/main/java/io/horizontalsystems/walletkit/core/factories/AdapterFactory.kt \
walletkit/src/main/java/io/horizontalsystems/walletkit/modules/address/IAddressHandler.kt \
walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/providers/SwapHelper.kt \
walletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/ThorchainKitManager.kt
do
if [ -f "$f" ]; then
echo "===== $f ====="
wc -l "$f"
ast-grep outline "$f" || true
fi
doneRepository: horizontalsystems/unstoppable-wallet-android
Length of output: 18679
Dispatch Thorchain seed operations off the main thread.
getThorchainKitWrapper, getSigner, and getAddress derive from the raw seed synchronously. Current Kotlin call sites include AdapterFactory and SwapHelper, but those caller contexts don’t establish a background dispatcher; move the seed operations into runCatching { withContext(Dispatchers.IO) { ... } } or otherwise ensure the manager itself runs the cryptographic work off the main thread.
🤖 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
`@walletkit/src/main/java/io/horizontalsystems/walletkit/core/managers/ThorchainKitManager.kt`
around lines 44 - 82, Update ThorchainKitManager’s getThorchainKitWrapper,
getSigner, and getAddress seed-derived operations so cryptographic work executes
on Dispatchers.IO within runCatching (or equivalent manager-level background
dispatch), while preserving their existing results and
UnsupportedAccountException behavior.
Source: Path instructions
| override suspend fun sendTransaction(mevProtectionEnabled: Boolean): SendTransactionResult { | ||
| val txHash = when (val data = sendData!!) { | ||
| is SendTransactionData.Thorchain.Deposit -> { | ||
| adapter.deposit(data.asset, data.amount, data.memo) | ||
| } | ||
|
|
||
| is SendTransactionData.Thorchain.Send -> { | ||
| adapter.send(data.amount, data.address, data.memo) | ||
| } |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win
Confine signing and broadcast to Dispatchers.IO.
SwapConfirmViewModel.swap() invokes this path from Dispatchers.Default; this service does not switch dispatchers before adapter.deposit() or adapter.send(). Enforce withContext(Dispatchers.IO) around those operations.
As per path instructions, “Cryptographic operations must run on Dispatchers.IO or a dedicated executor, never Dispatchers.Main.”
🤖 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
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/multiswap/sendtransaction/SendTransactionServiceThorchain.kt`
around lines 60 - 68, Update SendTransactionServiceThorchain.sendTransaction so
the adapter.deposit and adapter.send calls execute inside
withContext(Dispatchers.IO), including the surrounding signing and broadcast
operations while preserving the existing transaction-result flow.
Source: Path instructions
| class SendThorchainAddressService { | ||
| private var address: Address? = null | ||
| private var addressError: Throwable? = null | ||
|
|
||
| private val _stateFlow = MutableStateFlow( | ||
| State( | ||
| address = address, | ||
| addressError = addressError, | ||
| canBeSend = addressError == null, | ||
| ) | ||
| ) | ||
| val stateFlow = _stateFlow.asStateFlow() | ||
|
|
||
| fun setAddress(address: Address?) { | ||
| this.address = address | ||
|
|
||
| validateAddress() | ||
|
|
||
| emitState() | ||
| } | ||
|
|
||
| private fun validateAddress() { | ||
| addressError = null | ||
| val address = this.address ?: return | ||
|
|
||
| try { | ||
| ThorchainAddress.fromString(address.hex, Network.Mainnet) | ||
| } catch (e: Exception) { | ||
| addressError = Throwable(Translator.getString(R.string.SwapSettings_Error_InvalidAddress)) | ||
| } | ||
| } | ||
|
|
||
| private fun emitState() { | ||
| _stateFlow.update { | ||
| State( | ||
| address = address, | ||
| addressError = addressError, | ||
| canBeSend = addressError == null | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| data class State( | ||
| val address: Address?, | ||
| val addressError: Throwable?, | ||
| val canBeSend: Boolean | ||
| ) { | ||
| val validAddress: Address? | ||
| get() = if (addressError == null) address else null | ||
| } | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Doesn't follow the required Service pattern (ServiceState + mutex-guarded updates).
Per repo guidelines for **/*Service.kt, Services should extend a ServiceState base class with override fun createState() and guard state mutations with mutex.withLock. This class instead manages a hand-rolled data class State and mutates plain address/addressError vars directly, then rebuilds state in emitState() from those external vars rather than from the it passed into _stateFlow.update, which defeats the atomicity update provides.
As per coding guidelines, "Use ServiceState base class for Services with override fun createState() and call emitState() after state changes" and "Use mutex.withLock for thread-safe state updates in Services."
🤖 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
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainAddressService.kt`
around lines 12 - 62, Refactor SendThorchainAddressService to extend
ServiceState and replace the hand-rolled MutableStateFlow/State setup with
override fun createState(). Move address validation and updates into
mutex.withLock, derive all state from the state passed to the update operation,
and call emitState() after mutations; preserve the existing validAddress,
invalid-address error, and canBeSend behavior.
Source: Coding guidelines
| init { | ||
| viewModelScope.launch(Dispatchers.Default) { | ||
| amountService.stateFlow.collect { | ||
| handleUpdatedAmountState(it) | ||
| } | ||
| } | ||
| viewModelScope.launch(Dispatchers.Default) { | ||
| addressService.stateFlow.collect { | ||
| handleUpdatedAddressState(it) | ||
| } | ||
| } | ||
| viewModelScope.launch(Dispatchers.Default) { | ||
| xRateService.getRateFlow(sendToken.coin.uid).collect { | ||
| coinRate = it | ||
| } | ||
| } | ||
| viewModelScope.launch(Dispatchers.Default) { | ||
| xRateService.getRateFlow(feeToken.coin.uid).collect { | ||
| feeCoinRate = it | ||
| } | ||
| } | ||
|
|
||
| addressService.setAddress(address) | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Unguarded launch blocks in init can silently crash on an uncaught exception.
The four viewModelScope.launch(Dispatchers.Default) { ... } collectors (amount state, address state, two rate flows) have no try-catch/catch operator. An exception inside any collector (e.g. from handleUpdatedAmountState/handleUpdatedAddressState) propagates uncaught.
As per coding guidelines, "Wrap uncaught exceptions in launch blocks with try-catch or use the catch operator to prevent silent termination."
🛡️ Example fix pattern
viewModelScope.launch(Dispatchers.Default) {
- amountService.stateFlow.collect {
- handleUpdatedAmountState(it)
- }
+ amountService.stateFlow
+ .catch { logger.warning("amount state collection failed", it) }
+ .collect { handleUpdatedAmountState(it) }
}Apply the same pattern to the other three collectors.
🤖 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
`@walletkit/src/main/java/io/horizontalsystems/walletkit/modules/send/thorchain/SendThorchainViewModel.kt`
around lines 64 - 87, Wrap each of the four collectors in
init—amountService.stateFlow, addressService.stateFlow, and both
xRateService.getRateFlow calls—with the project’s established coroutine
exception-handling pattern, using try-catch or a Flow catch operator. Ensure
exceptions from handleUpdatedAmountState, handleUpdatedAddressState, and rate
updates are handled without silently terminating the viewModelScope launches.
Source: Coding guidelines
#9402
Summary by CodeRabbit