Skip to content

Conversation

@yasin-ce
Copy link
Collaborator

Summary

  • Add LocalAccount.Joint domain model with participant addresses and threshold
  • Add JointDao and JointEntity for local database storage
  • Add JointAccountRepository interface and implementation
  • Add joint account mappers (entity ↔ domain model)
  • Add GetJointAccount, GetJointAccountProposerAddress use cases
  • Add database migration for joint account table
  • Add unit tests for repository and mappers

Test Plan

  • Verify joint account can be saved to local database
  • Verify joint account can be retrieved from database
  • Verify mappers correctly transform data
  • Run unit tests: ./gradlew :common-sdk:testDebugUnitTest

@yasin-ce yasin-ce self-assigned this Jan 20, 2026
@yasin-ce yasin-ce force-pushed the multisig/01-resources branch from ee276ea to 1e4e4e2 Compare January 20, 2026 09:30
- Add JointAccountRepository with API integration
- Add JointSignRequest API use cases
- Add JointAccountInbox API use cases
- Add domain models for joint accounts (LocalAccount.Joint)
- Add DTOs for API communication
- Implement account type detection for joint accounts
@yasin-ce yasin-ce force-pushed the multisig/02-data-layer branch from e196a43 to 72c4117 Compare January 20, 2026 09:31
data object Joint : AccountType

companion object {
fun AccountType.canSignTransaction(): Boolean {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems like it is time to move this function in AccountType interface, and let subclasses to implement

@ColumnInfo("algo_address")
val algoAddress: String,
@ColumnInfo("participant_addresses")
val participantAddresses: String,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we consider creating new table for participant addresses? Right now we won't be able to query. This will cause us to fetch every joint account. For example displaying error when user wants to remove one of the participant accounts from the device etc.

operator fun invoke(localAccount: LocalAccount.Joint): JointEntity
}

internal class JointEntityMapperImpl @Inject constructor(
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 implementation class into new file

import com.algorand.wallet.jointaccount.creation.domain.model.CreateJointAccountDTO
import javax.inject.Inject

class CreateJointAccountDTOMapper @Inject constructor() {
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 make this internal and create an interface for it.

import com.algorand.wallet.jointaccount.creation.domain.model.JointAccountDTO
import javax.inject.Inject

class JointAccountDTOMapper @Inject constructor() {
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 make this internal and create an interface for it.

import com.algorand.wallet.account.local.domain.usecase.GetLocalAccount
import javax.inject.Inject

internal class GetJointAccountUseCase @Inject constructor(
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 remove this usecase and use joint account repository to return local account object

import com.algorand.wallet.account.local.domain.usecase.GetLocalAccount
import javax.inject.Inject

internal class GetJointAccountParticipantCountUseCase @Inject constructor(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can be removed and handled by repository


package com.algorand.wallet.jointaccount.creation.domain.model

data class JointAccountDTO(
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 remove DTO


package com.algorand.wallet.jointaccount.creation.domain.model

data class CreateJointAccountDTO(
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 remove DTO

operator fun invoke(entity: JointEntity): LocalAccount.Joint
}

internal class JointMapperImpl @Inject constructor(
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should move this into its own file

Per PR review comments:
- Split JointEntityMapper interface and impl into separate files
- Split JointMapper interface and impl into separate files
- Make CreateJointAccountDTOMapper internal with interface+impl pattern
- Make JointAccountDTOMapper internal with interface+impl pattern
- Make CreateJointAccountRequest internal
- Make JointAccountResponse internal
- Add DI bindings for new mapper interfaces
- Update tests to use Impl classes
Per PR review: Move canSignTransaction() function from companion
object to interface method with subclass implementations.

- Each AccountType subtype now overrides canSignTransaction()
- Removed companion object with extension function
- Updated all call sites to remove companion import
Per PR review comments:
- Remove GetJointAccount/GetJointAccountUseCase (use repository directly)
- Remove GetJointAccountParticipantCount/GetJointAccountParticipantCountUseCase
- Remove JointAccountDTO and CreateJointAccountDTO
- Remove JointAccountDTOMapper and CreateJointAccountDTOMapper
- Remove related tests
- Update DI module
version = dto.version
)
}
internal interface CreateJointAccountDTOMapper {
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 rename mapper same as class it maps

import com.algorand.wallet.jointaccount.creation.domain.model.CreateJointAccountDTO
import javax.inject.Inject

internal class CreateJointAccountDTOMapperImpl @Inject constructor() : CreateJointAccountDTOMapper {
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 rename mapper same as class it maps

)
}
}
internal interface JointAccountDTOMapper {
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 rename mapper same as class it maps

import com.algorand.wallet.jointaccount.creation.domain.model.JointAccountDTO
import javax.inject.Inject

internal class JointAccountDTOMapperImpl @Inject constructor() : JointAccountDTOMapper {
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 rename mapper same as class it maps

): GetJointAccountProposerAddress = useCase

@Provides
fun provideCreateJointAccountDTOMapper(
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 rename provider same as class provides

): CreateJointAccountDTOMapper = impl

@Provides
fun provideJointAccountDTOMapper(
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 rename provider same as class provides

@mitsinsar mitsinsar self-requested a review January 22, 2026 11:39
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