Skip to content

Conversation

@yasin-ce
Copy link
Collaborator

Summary

  • Add JointAccountTransactionSignHelper for proposing sign requests
  • Add LocalAccountSigningHelper for local account signing
  • Update TransactionSignManager to handle TransactionSigner.Joint
  • Update ExternalTransactionSignManager for joint account support
  • Add TransactionSigner.Joint case handling across the app
  • Refactor AccountRecoveryTypeSelectionFragment to Compose
  • Add ContactIcon composable and PeraToolbar improvements

Test Plan

  • Verify transaction signing works for standard accounts
  • Verify joint account transactions trigger sign request flow
  • Test account recovery type selection screen

@yasin-ce yasin-ce self-assigned this Jan 20, 2026
@yasin-ce yasin-ce force-pushed the multisig/03-tests-and-deeplink branch from b98a876 to 5211943 Compare January 20, 2026 09:31
@yasin-ce yasin-ce force-pushed the multisig/04-misc-updates branch 2 times, most recently from 8602ae8 to cfd09c6 Compare January 20, 2026 09:47
- Fix duplicate DI bindings for joint account repository
- Add missing interface implementations
- Update transaction signer handling for joint accounts
- Fix import statements and code organization
@yasin-ce yasin-ce force-pushed the multisig/04-misc-updates branch from cfd09c6 to 252f8ea Compare January 20, 2026 13:49
- Replace GetJointAccountParticipantCount with GetLocalAccount
- Update JointSignRequestDTO to JointSignRequest
- Get participant count from LocalAccount.Joint.participantAddresses
Convert TODO() to comment-style TODOs and remove duplicate when cases
to fix detekt UnreachableCode violations.

Files fixed:
- GetAccountOriginalStateIconDrawablePreviewUseCase
- AccountStatusDetailPreviewDecider
- CreateWalletConnectArbitraryDataSignerUseCase
- GetAccountIconDrawablePreviewUseCase
Comment on lines 31 to 33
suspend fun getLocalAccount(address: String): LocalAccount? {
return getLocalAccount.invoke(address)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unnecessary function. We can remove this and inject use case to class which uses this function


class JointAccountTransactionSignHelper @Inject constructor(
private val getLocalAccount: GetLocalAccount,
private val getLocalAccounts: GetLocalAccounts,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unused parameter

}
}

private suspend fun signWithAlgo25Account(transactionBytes: ByteArray, signerAddress: String): ByteArray? {
Copy link
Collaborator

Choose a reason for hiding this comment

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

LocalAccountSignHelper can be used instead

}
}

private suspend fun signWithHdKeyAccount(transactionBytes: ByteArray, hdKey: LocalAccount.HdKey): ByteArray? {
Copy link
Collaborator

Choose a reason for hiding this comment

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

LocalAccountSignHelper can be used instead

Comment on lines 188 to 189
val signedTransaction = Encoder.decodeFromMsgPack(signedTransactionBytes, SignedTransaction::class.java)
signedTransaction.sig?.bytes?.takeIf { it.isNotEmpty() }
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move this into AlgoSdk


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomSheetContent(
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be private

@OptIn(ExperimentalMaterial3Api::class)
@Suppress("MagicNumber")
@Composable
fun BottomSheetHeader(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be private

Comment on lines 126 to 137
val accountAddresses = transactions.transactions
.flatMap { it.getTransactionsThatNeedsToBeSigned() }
.map { it.accountAddress }
.distinct()

for (address in accountAddresses) {
val accountType = getAccountType(address)
if (accountType == AccountType.Joint) {
displayError(Local(AnnotatedString(R.string.joint_accounts_are_not_supported)))
return
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move this logic into its on usecase that checks if a transaction requires a Joint account or not.

}
val accountErrorItems = localAccounts
.mapNotNull { localAccount ->
val registrationType = getAccountRegistrationType(localAccount)
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can use local account type instead of registration type

)
}

private fun shouldIncludeAccount(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should do this filtering before returning local accounts. Since this feature affects whole app, we shouldn't do individual filter

- Do NOT change data class to sealed interface
- Do NOT remove wrapper/delegation functions
- Do NOT change filter+map to mapNotNull
- Do NOT remove TODO placeholders
- Do NOT move data classes or companion objects
- Do NOT inject use cases directly when helper exists
- Do NOT change existing class dependencies
- Do NOT rename existing identifiers without explicit request
- Do NOT remove string resources
- Do NOT simplify when expressions

Also add clarifying comment to TODO in AssetTransferPreviewFragment
- Remove unnecessary getLocalAccount wrapper from LocalAccountSigningHelper
- Refactor JointAccountTransactionSignHelper:
  - Use LocalAccountSigningHelper for signing
  - Change JointSignResult from data class to sealed interface
  - Move data classes and companion object to bottom of file
  - Add TODO comment for extractSignatureFromSignedTransaction
- Use mapNotNull instead of filter+map in AccountPreviewProcessor
- Remove duplicate TransactionSigner.Joint branch in TransactionSignManager
- Update TransactionSignManager to use sealed interface pattern
1. AccountRecoveryTypeSelectionScreen.kt:
   - Make BottomSheetContent private
   - Make BottomSheetHeader private
   - Fix scrolling title - title no longer scrolls with content

2. SwapConfirmationViewModel.kt:
   - Extract joint account check to IsJointAccountInAddresses use case
   - Add IsJointAccountInAddressesUseCase implementation
   - Add DI binding in SwapUiModule

3. AccountPreviewProcessor.kt:
   - Use local account type instead of registration type
   - Add getLocalAccountType helper function

4. GroupChoiceWidget.kt:
   - Replace showNewBadge boolean with badge composable slot
   - Add GroupChoiceNewBadge composable for reusable badge

5. PeraToolbar.kt:
   - Remove rightLabel parameter, use endContainer instead
   - Add PeraToolbarLinkText for link-styled text
   - Add PeraToolbarTitle for default title text
   - Add PeraToolbarLargeTitle for large title text
   - Add PeraToolbarTitleWithSubtitle for title with subtitle
   - Keep textStyle for backward compatibility
1. TransactionManagerResult - Use sealed Success class:
   - Convert Success from data class to sealed class
   - Add Success.SignedTransaction for completed transactions
   - Add Success.TransactionRequestSigned for joint account requests
   - Update all usages in TransactionSignManager, TransactionSignBaseFragment, MainActivity

2. GetLocalAccounts - Filter joint accounts at use case level:
   - GetLocalAccountsUseCase now filters joint accounts when feature toggle is off
   - GetLocalAccountsFlowUseCase now filters joint accounts when feature toggle is off
   - Remove redundant shouldIncludeAccount filtering from AccountPreviewProcessor
   - Joint account filtering is now consistent across the entire app
- Add signWithAlgo25AccountReturnSignature using Sdk.signTransactionReturnSignature
- Add signWithHdKeyAccountReturnSignature using existing HD wallet API
- Rename signWithAlgo25 -> signWithAlgo25Account
- Rename signWithHdKey -> signWithHdKeyAccount
- Rename signTransactionSignatureOnly -> signTransactionReturnSignature
- Update Go mobile SDK version to 1.0.9
- Clean and organize cursor rules file
- Fix MaxLineLength in AccountPreviewProcessor
- Suppress TooManyFunctions in SwapUiModule (pre-existing)
- Suppress LongParameterList in TransactionSignManager (pre-existing)
- Split SwapUiModule into SwapUiModule and SwapTrackingModule
- Create AccountBalanceProvider to group balance-related use cases
- Reduce TransactionSignManager constructor parameters from 10 to 8
- Add cursor rule: never use @Suppress without approval
yasin-ce added a commit that referenced this pull request Jan 23, 2026
* multisig/04-misc-updates:
  Fix detekt issues without @Suppress
  Fix pre-existing detekt issues
  Use Go SDK for transaction signing and return signature directly
  fix: Address remaining PR #514 review comments
  fix: Address PR #514 review comments
  fix: Address PR #514 feedback
  docs: Add refactoring restrictions to prevent unwanted changes
yasin-ce added a commit that referenced this pull request Jan 23, 2026
…-support

* multisig/05-data-models:
  Address PR #515 comments for data models
  Fix detekt issues without @Suppress
  Fix pre-existing detekt issues
  Use Go SDK for transaction signing and return signature directly
  fix: Address remaining PR #514 review comments
  fix: Address PR #514 review comments
  fix: Address PR #514 feedback
  docs: Add refactoring restrictions to prevent unwanted changes
@yasin-ce yasin-ce requested a review from mitsinsar January 23, 2026 19:29
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.

3 participants