diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/confirm/BuildConfirmPropertiesImpl.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/confirm/BuildConfirmPropertiesImpl.kt index 8f54a4d7b..504c443db 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/confirm/BuildConfirmPropertiesImpl.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/confirm/BuildConfirmPropertiesImpl.kt @@ -1,6 +1,7 @@ package com.gemwallet.android.data.coordinators.confirm import com.gemwallet.android.application.confirm.coordinators.BuildConfirmProperties +import com.gemwallet.android.cases.addresses.GetAddressName import com.gemwallet.android.cases.nodes.GetCurrentBlockExplorer import com.gemwallet.android.data.repositories.stake.StakeRepository import com.gemwallet.android.domains.asset.chain @@ -19,6 +20,7 @@ import uniffi.gemstone.Explorer class BuildConfirmPropertiesImpl( private val stakeRepository: StakeRepository, private val getCurrentBlockExplorer: GetCurrentBlockExplorer, + private val getAddressName: GetAddressName, ) : BuildConfirmProperties { override suspend fun invoke( @@ -31,7 +33,10 @@ class BuildConfirmPropertiesImpl( val chainExplorer = Explorer(chain.string) return mutableListOf().apply { add(ConfirmProperty.Source(assetInfo.walletName)) - val destination = ConfirmProperty.Destination.map(request, getValidator(request)) + val addressName = request.destination()?.address + ?.takeIf { it.isNotEmpty() } + ?.let { getAddressName.getAddressName(chain, it) } + val destination = ConfirmProperty.Destination.map(request, getValidator(request), addressName) add( when (destination) { is ConfirmProperty.Destination.Transfer -> ConfirmProperty.Destination.Transfer( diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/ConfirmModule.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/ConfirmModule.kt index 7fa0b21af..b322b4d25 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/ConfirmModule.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/ConfirmModule.kt @@ -7,6 +7,7 @@ import com.gemwallet.android.application.confirm.coordinators.ValidateBalance import com.gemwallet.android.blockchain.operators.LoadPrivateKeyOperator import com.gemwallet.android.blockchain.services.BroadcastService import com.gemwallet.android.blockchain.services.SignClientProxy +import com.gemwallet.android.cases.addresses.GetAddressName import com.gemwallet.android.cases.nodes.GetCurrentBlockExplorer import com.gemwallet.android.cases.transactions.CreateTransaction import com.gemwallet.android.data.coordinators.confirm.BuildConfirmPropertiesImpl @@ -51,8 +52,10 @@ object ConfirmModule { fun provideBuildConfirmProperties( stakeRepository: StakeRepository, getCurrentBlockExplorer: GetCurrentBlockExplorer, + getAddressName: GetAddressName, ): BuildConfirmProperties = BuildConfirmPropertiesImpl( stakeRepository, getCurrentBlockExplorer, + getAddressName, ) } diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/TransactionModule.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/TransactionModule.kt index da01f008d..a24294308 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/TransactionModule.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/TransactionModule.kt @@ -5,6 +5,7 @@ import com.gemwallet.android.application.assets.coordinators.PrefetchAssets import com.gemwallet.android.application.transactions.coordinators.GetTransactionDetails import com.gemwallet.android.application.transactions.coordinators.GetTransactions import com.gemwallet.android.application.transactions.coordinators.SyncTransactions +import com.gemwallet.android.cases.addresses.SaveAddressNames import com.gemwallet.android.cases.nodes.GetCurrentBlockExplorer import com.gemwallet.android.cases.transactions.SaveTransactions import com.gemwallet.android.data.coordinators.transaction.GetTransactionDetailsImpl @@ -38,6 +39,7 @@ object TransactionModule { walletPreferencesFactory: WalletPreferencesFactory, gemDeviceApiClient: GemDeviceApiClient, saveTransactions: SaveTransactions, + saveAddressNames: SaveAddressNames, prefetchAssets: PrefetchAssets, ensureWalletAssets: EnsureWalletAssets, ): SyncTransactions { @@ -45,6 +47,7 @@ object TransactionModule { walletPreferencesFactory = walletPreferencesFactory, gemDeviceApiClient = gemDeviceApiClient, saveTransactions = saveTransactions, + saveAddressNames = saveAddressNames, prefetchAssets = prefetchAssets, ensureWalletAssets = ensureWalletAssets, ) diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/WalletModule.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/WalletModule.kt index b29981210..8fba05503 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/WalletModule.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/di/WalletModule.kt @@ -11,6 +11,7 @@ import com.gemwallet.android.application.wallet.coordinators.ToggleWalletPin import com.gemwallet.android.application.wallet.coordinators.WalletIdGenerator import com.gemwallet.android.blockchain.operators.DeleteKeyStoreOperator import com.gemwallet.android.blockchain.operators.LoadPrivateDataOperator +import com.gemwallet.android.cases.addresses.RenameWalletAddresses import com.gemwallet.android.cases.device.SyncSubscription import com.gemwallet.android.data.coordinators.wallet.DeleteWalletImpl import com.gemwallet.android.data.coordinators.wallet.GetAllWalletsImpl @@ -58,8 +59,9 @@ object WalletModule { @Singleton fun provideSetWalletName( walletsRepository: WalletsRepository, + renameWalletAddresses: RenameWalletAddresses, ): SetWalletName { - return SetWalletNameImpl(walletsRepository) + return SetWalletNameImpl(walletsRepository, renameWalletAddresses) } @Provides diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/GetTransactionDetailsImpl.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/GetTransactionDetailsImpl.kt index 567d5aab3..9589fb3dd 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/GetTransactionDetailsImpl.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/GetTransactionDetailsImpl.kt @@ -19,6 +19,7 @@ import com.gemwallet.android.model.Crypto import com.gemwallet.android.model.TransactionExtended import com.gemwallet.android.model.format import com.gemwallet.android.domains.asset.chain +import com.wallet.core.primitives.AddressType import com.wallet.core.primitives.Asset import com.wallet.core.primitives.BlockExplorerLink import com.wallet.core.primitives.Currency @@ -190,29 +191,39 @@ class TransactionDetailsAggregateImpl( TransactionType.StakeUnfreeze, TransactionType.PerpetualModifyPosition, TransactionType.StakeWithdraw -> null - TransactionType.TokenApproval -> destinationAddress { address, explorerLink -> - TransactionDetailsValue.Destination.Contract(address, explorerLink) + TransactionType.TokenApproval -> destinationAddress { address, name, explorerLink -> + TransactionDetailsValue.Destination.Contract(address, name, explorerLink) } - TransactionType.StakeDelegate -> destinationAddress { address, explorerLink -> - TransactionDetailsValue.Destination.Validator(address, explorerLink) + TransactionType.StakeDelegate -> destinationAddress { address, name, explorerLink -> + TransactionDetailsValue.Destination.Validator(address, name, explorerLink) } - TransactionType.SmartContractCall -> destinationAddress { address, explorerLink -> + TransactionType.SmartContractCall -> destinationAddress { address, name, explorerLink -> when (data.transaction.getWalletConnectOutputAction()) { - TransferDataOutputAction.Send -> TransactionDetailsValue.Destination.Recipient(address, explorerLink) + TransferDataOutputAction.Send -> TransactionDetailsValue.Destination.Recipient(data = address, name = name, explorerLink = explorerLink) TransferDataOutputAction.Sign, - null -> TransactionDetailsValue.Destination.Contract(address, explorerLink) + null -> TransactionDetailsValue.Destination.Contract(address, name, explorerLink) } } TransactionType.EarnWithdraw, - TransactionType.EarnDeposit -> destinationAddress { address, explorerLink -> - TransactionDetailsValue.Destination.ProviderAddress(address, explorerLink) + TransactionType.EarnDeposit -> destinationAddress { address, name, explorerLink -> + TransactionDetailsValue.Destination.ProviderAddress(address, name, explorerLink) } TransactionType.Swap -> this@TransactionDetailsAggregateImpl.swapProvider?.let { TransactionDetailsValue.Destination.Provider(it) } TransactionType.Transfer, TransactionType.TransferNFT -> when (data.transaction.direction) { TransactionDirection.SelfTransfer, - TransactionDirection.Outgoing -> TransactionDetailsValue.Destination.Recipient(data.transaction.to, recipientExplorerLink) - TransactionDirection.Incoming -> TransactionDetailsValue.Destination.Sender(data.transaction.from, senderExplorerLink) + TransactionDirection.Outgoing -> TransactionDetailsValue.Destination.Recipient( + data = data.transaction.to, + name = data.toAddress?.name, + addressType = data.toAddress?.type, + explorerLink = recipientExplorerLink, + ) + TransactionDirection.Incoming -> TransactionDetailsValue.Destination.Sender( + data = data.transaction.from, + name = data.fromAddress?.name, + addressType = data.fromAddress?.type, + explorerLink = senderExplorerLink, + ) } } @@ -238,6 +249,13 @@ class TransactionDetailsAggregateImpl( TransactionDirection.SelfTransfer -> data.transaction.to } + private val participantAddressName: String? + get() = when (data.transaction.direction) { + TransactionDirection.Incoming -> data.fromAddress?.name + TransactionDirection.Outgoing, + TransactionDirection.SelfTransfer -> data.toAddress?.name + } + private val participantExplorerLink: BlockExplorerLink? get() = when (participantAddress) { data.transaction.from -> senderExplorerLink @@ -246,8 +264,8 @@ class TransactionDetailsAggregateImpl( } private inline fun destinationAddress( - build: (address: String, explorerLink: BlockExplorerLink?) -> TransactionDetailsValue.Destination, + build: (address: String, name: String?, explorerLink: BlockExplorerLink?) -> TransactionDetailsValue.Destination, ): TransactionDetailsValue.Destination? = participantAddress .takeIf { it.isNotEmpty() } - ?.let { build(it, participantExplorerLink) } + ?.let { build(it, participantAddressName, participantExplorerLink) } } diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/GetTransactionsImpl.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/GetTransactionsImpl.kt index fe0584ef4..c53f64890 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/GetTransactionsImpl.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/GetTransactionsImpl.kt @@ -49,31 +49,44 @@ class GetTransactionsImpl( @Stable class TransactionDataAggregateImpl( - private val data: TransactionExtended + private val data: TransactionExtended, ) : TransactionDataAggregate { override val id: TransactionId = data.transaction.id override val asset: Asset = data.asset + override val addressName: String? = when (data.transaction.type) { + TransactionType.StakeDelegate, + TransactionType.StakeUndelegate, + TransactionType.StakeRedelegate, + TransactionType.EarnDeposit, + TransactionType.EarnWithdraw -> data.toAddress + else -> when (data.transaction.direction) { + TransactionDirection.Incoming -> data.fromAddress + TransactionDirection.Outgoing, + TransactionDirection.SelfTransfer -> data.toAddress + } + }?.name + override val address: String get() = when (data.transaction.type) { TransactionType.TransferNFT, - TransactionType.Transfer -> when (data.transaction.direction) { + TransactionType.Transfer, + TransactionType.TokenApproval, + TransactionType.SmartContractCall -> when (data.transaction.direction) { TransactionDirection.SelfTransfer, TransactionDirection.Outgoing -> AddressFormatter(data.transaction.to, chain = data.transaction.assetId.chain).value() TransactionDirection.Incoming -> AddressFormatter(data.transaction.from, chain = data.transaction.assetId.chain).value() } - TransactionType.Swap, - TransactionType.TokenApproval, TransactionType.StakeDelegate, TransactionType.StakeUndelegate, TransactionType.StakeRedelegate, - TransactionType.StakeWithdraw, - TransactionType.EarnWithdraw, TransactionType.EarnDeposit, + TransactionType.EarnWithdraw -> AddressFormatter(data.transaction.to, chain = data.transaction.assetId.chain).value() + TransactionType.Swap, + TransactionType.StakeWithdraw, TransactionType.AssetActivation, TransactionType.StakeRewards, - TransactionType.SmartContractCall, TransactionType.PerpetualOpenPosition, TransactionType.StakeFreeze, TransactionType.StakeUnfreeze, @@ -152,5 +165,4 @@ class TransactionDataAggregateImpl( decimalPlace = 2, dynamicPlace = true, ) - } diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/SyncTransactionsImpl.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/SyncTransactionsImpl.kt index c25bc8ae5..7a2325993 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/SyncTransactionsImpl.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/transaction/SyncTransactionsImpl.kt @@ -3,32 +3,33 @@ package com.gemwallet.android.data.coordinators.transaction import com.gemwallet.android.application.assets.coordinators.EnsureWalletAssets import com.gemwallet.android.application.assets.coordinators.PrefetchAssets import com.gemwallet.android.application.transactions.coordinators.SyncTransactions +import com.gemwallet.android.cases.addresses.SaveAddressNames import com.gemwallet.android.cases.transactions.SaveTransactions import com.gemwallet.android.data.service.store.WalletPreferencesFactory import com.gemwallet.android.data.services.gemapi.GemDeviceApiClient import com.gemwallet.android.ext.getAssociatedAssetIds import com.gemwallet.android.ext.identifier import com.gemwallet.android.ext.walletId -import com.wallet.core.primitives.Transaction import com.wallet.core.primitives.AssetId +import com.wallet.core.primitives.TransactionsResponse import com.wallet.core.primitives.Wallet class SyncTransactionsImpl( private val walletPreferencesFactory: WalletPreferencesFactory, private val gemDeviceApiClient: GemDeviceApiClient, private val saveTransactions: SaveTransactions, + private val saveAddressNames: SaveAddressNames, private val prefetchAssets: PrefetchAssets, private val ensureWalletAssets: EnsureWalletAssets, ) : SyncTransactions { override suspend fun syncTransactions(wallet: Wallet) { val preferences = walletPreferencesFactory.create(wallet.id) - val transactions = runCatching { - gemDeviceApiClient.getTransactions(wallet.id, preferences.transactionsTimestamp)?.transactions + val response = runCatching { + gemDeviceApiClient.getTransactions(wallet.id, preferences.transactionsTimestamp) }.getOrNull() ?: return - syncAssets(wallet, transactions) - saveTransactions.saveTransactions(walletId = wallet.walletId, transactions) + sync(wallet, response) preferences.transactionsTimestamp = currentTimestamp() } @@ -36,23 +37,24 @@ class SyncTransactionsImpl( val preferences = walletPreferencesFactory.create(wallet.id) val assetId = assetId.identifier val timestamp = preferences.transactionsForAssetTimestamp(assetId) - val transactions = runCatching { - gemDeviceApiClient.getTransactions(wallet.id, assetId, timestamp)?.transactions + val response = runCatching { + gemDeviceApiClient.getTransactions(wallet.id, assetId, timestamp) }.getOrNull() ?: return - syncAssets(wallet, transactions) - saveTransactions.saveTransactions(walletId = wallet.walletId, transactions) + sync(wallet, response) preferences.setTransactionsForAssetTimestamp(assetId, currentTimestamp()) } - private fun currentTimestamp(): Long = System.currentTimeMillis() / 1000 - - private suspend fun syncAssets(wallet: Wallet, transactions: List) { - val assetIds = transactions + private suspend fun sync(wallet: Wallet, response: TransactionsResponse) { + val assetIds = response.transactions .flatMap { it.getAssociatedAssetIds() } .distinct() - prefetchAssets.prefetchAssets(assetIds) ensureWalletAssets.ensureWalletAssets(wallet, assetIds) + + saveTransactions.saveTransactions(walletId = wallet.walletId, response.transactions) + saveAddressNames.saveAddressNames(response.addressNames) } + + private fun currentTimestamp(): Long = System.currentTimeMillis() / 1000 } diff --git a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/wallet/SetWalletNameImpl.kt b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/wallet/SetWalletNameImpl.kt index 597c0623a..9e8cfc291 100644 --- a/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/wallet/SetWalletNameImpl.kt +++ b/android/data/coordinators/src/main/kotlin/com/gemwallet/android/data/coordinators/wallet/SetWalletNameImpl.kt @@ -1,16 +1,19 @@ package com.gemwallet.android.data.coordinators.wallet import com.gemwallet.android.application.wallet.coordinators.SetWalletName +import com.gemwallet.android.cases.addresses.RenameWalletAddresses import com.gemwallet.android.data.repositories.wallets.WalletsRepository +import com.wallet.core.primitives.WalletId import kotlinx.coroutines.flow.firstOrNull class SetWalletNameImpl( - private val walletsRepository: WalletsRepository + private val walletsRepository: WalletsRepository, + private val renameWalletAddresses: RenameWalletAddresses, ) : SetWalletName { override suspend fun setWalletName(walletId: String, name: String) { val wallet = walletsRepository.getWallet(walletId).firstOrNull() ?: return walletsRepository.updateWallet(wallet.copy(name = name)) + renameWalletAddresses.rename(WalletId(walletId), name) } - -} \ No newline at end of file +} diff --git a/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/addresses/AddressesRepository.kt b/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/addresses/AddressesRepository.kt new file mode 100644 index 000000000..88a9c6f13 --- /dev/null +++ b/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/addresses/AddressesRepository.kt @@ -0,0 +1,36 @@ +package com.gemwallet.android.data.repositories.addresses + +import com.gemwallet.android.cases.addresses.GetAddressName +import com.gemwallet.android.cases.addresses.RenameWalletAddresses +import com.gemwallet.android.cases.addresses.SaveAddressNames +import com.gemwallet.android.data.service.store.database.AddressesDao +import com.gemwallet.android.data.service.store.database.entities.toAddressRecords +import com.gemwallet.android.data.service.store.database.entities.toDTO +import com.gemwallet.android.data.service.store.database.entities.toRecord +import com.wallet.core.primitives.AddressName +import com.wallet.core.primitives.Chain +import com.wallet.core.primitives.Wallet +import com.wallet.core.primitives.WalletId + +class AddressesRepository( + private val addressesDao: AddressesDao, +) : SaveAddressNames, GetAddressName, RenameWalletAddresses { + + override suspend fun saveAddressNames(addressNames: List) { + if (addressNames.isEmpty()) return + addressesDao.insert(addressNames.toRecord()) + } + + override suspend fun getAddressName(chain: Chain, address: String): AddressName? { + if (address.isEmpty()) return null + return addressesDao.get(chain, address)?.toDTO() + } + + override suspend fun rename(walletId: WalletId, name: String) { + addressesDao.updateName(walletId.id, name) + } + + suspend fun saveWalletAddresses(wallet: Wallet) { + addressesDao.insert(wallet.toAddressRecords()) + } +} diff --git a/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/di/AddressesModule.kt b/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/di/AddressesModule.kt new file mode 100644 index 000000000..906287c7c --- /dev/null +++ b/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/di/AddressesModule.kt @@ -0,0 +1,37 @@ +package com.gemwallet.android.data.repositories.di + +import com.gemwallet.android.cases.addresses.GetAddressName +import com.gemwallet.android.cases.addresses.RenameWalletAddresses +import com.gemwallet.android.cases.addresses.SaveAddressNames +import com.gemwallet.android.data.repositories.addresses.AddressesRepository +import com.gemwallet.android.data.service.store.database.AddressesDao +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@InstallIn(SingletonComponent::class) +@Module +object AddressesModule { + + @Singleton + @Provides + fun provideAddressesRepository(addressesDao: AddressesDao): AddressesRepository = + AddressesRepository(addressesDao) + + @Singleton + @Provides + fun provideSaveAddressNames(addressesRepository: AddressesRepository): SaveAddressNames = + addressesRepository + + @Singleton + @Provides + fun provideGetAddressName(addressesRepository: AddressesRepository): GetAddressName = + addressesRepository + + @Singleton + @Provides + fun provideRenameWalletAddresses(addressesRepository: AddressesRepository): RenameWalletAddresses = + addressesRepository +} diff --git a/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/di/WalletsModule.kt b/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/di/WalletsModule.kt index e25235a55..ad8944081 100644 --- a/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/di/WalletsModule.kt +++ b/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/di/WalletsModule.kt @@ -2,6 +2,7 @@ package com.gemwallet.android.data.repositories.di import com.gemwallet.android.application.wallet.coordinators.WalletIdGenerator import com.gemwallet.android.blockchain.operators.CreateAccountOperator +import com.gemwallet.android.data.repositories.addresses.AddressesRepository import com.gemwallet.android.data.repositories.wallets.WalletsRepository import com.gemwallet.android.data.repositories.wallets.WalletsRepositoryImpl import com.gemwallet.android.data.service.store.database.AccountsDao @@ -21,6 +22,7 @@ object WalletsModule { fun provideWalletsRepository( walletsDao: WalletsDao, accountsDao: AccountsDao, + addressesRepository: AddressesRepository, assetsDao: AssetsDao, createAccountOperator: CreateAccountOperator, walletIdGenerator: WalletIdGenerator, @@ -29,6 +31,7 @@ object WalletsModule { return WalletsRepositoryImpl( walletsDao = walletsDao, accountsDao = accountsDao, + addressesRepository = addressesRepository, assetsDao = assetsDao, createAccount = createAccountOperator, walletIdGenerator = walletIdGenerator, diff --git a/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/wallets/WalletsRepositoryImpl.kt b/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/wallets/WalletsRepositoryImpl.kt index 59cc2031f..19a2c8a2e 100644 --- a/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/wallets/WalletsRepositoryImpl.kt +++ b/android/data/repositories/src/main/kotlin/com/gemwallet/android/data/repositories/wallets/WalletsRepositoryImpl.kt @@ -3,6 +3,7 @@ package com.gemwallet.android.data.repositories.wallets import com.gemwallet.android.application.wallet.coordinators.WalletIdGenerator import com.gemwallet.android.blockchain.operators.CreateAccountOperator import com.gemwallet.android.cases.wallet.ImportError +import com.gemwallet.android.data.repositories.addresses.AddressesRepository import com.gemwallet.android.data.service.store.database.AccountsDao import com.gemwallet.android.data.service.store.database.AssetsDao import com.gemwallet.android.data.service.store.database.StoreTransactionRunner @@ -29,6 +30,7 @@ import javax.inject.Singleton class WalletsRepositoryImpl @Inject constructor( private val walletsDao: WalletsDao, private val accountsDao: AccountsDao, + private val addressesRepository: AddressesRepository, private val assetsDao: AssetsDao, private val createAccount: CreateAccountOperator, private val walletIdGenerator: WalletIdGenerator, @@ -138,6 +140,7 @@ class WalletsRepositoryImpl @Inject constructor( transactionRunner.run { walletsDao.insert(wallet.toRecord()) insertAccountsWithNativeAssets(wallet) + addressesRepository.saveWalletAddresses(wallet) wallet } } diff --git a/android/data/services/store/schemas/com.gemwallet.android.data.service.store.database.GemDatabase/73.json b/android/data/services/store/schemas/com.gemwallet.android.data.service.store.database.GemDatabase/73.json new file mode 100644 index 000000000..28ed708dc --- /dev/null +++ b/android/data/services/store/schemas/com.gemwallet.android.data.service.store.database.GemDatabase/73.json @@ -0,0 +1,2243 @@ +{ + "formatVersion": 1, + "database": { + "version": 73, + "identityHash": "8b8ecdaf771936e0ffd5daf16b017709", + "entities": [ + { + "tableName": "wallets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `domain_name` TEXT, `type` TEXT NOT NULL, `position` INTEGER NOT NULL, `pinned` INTEGER NOT NULL, `index` INTEGER NOT NULL, `source` TEXT NOT NULL DEFAULT 'Import', PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "domainName", + "columnName": "domain_name", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "pinned", + "columnName": "pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "source", + "columnName": "source", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'Import'" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "accounts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`wallet_id` TEXT NOT NULL, `derivation_path` TEXT NOT NULL, `address` TEXT NOT NULL, `chain` TEXT NOT NULL, `extendedPublicKey` TEXT, PRIMARY KEY(`wallet_id`, `chain`), FOREIGN KEY(`chain`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`wallet_id`) REFERENCES `wallets`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "walletId", + "columnName": "wallet_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "derivationPath", + "columnName": "derivation_path", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chain", + "columnName": "chain", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "extendedPublicKey", + "columnName": "extendedPublicKey", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "wallet_id", + "chain" + ] + }, + "indices": [ + { + "name": "index_accounts_chain", + "unique": false, + "columnNames": [ + "chain" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_accounts_chain` ON `${TABLE_NAME}` (`chain`)" + } + ], + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "chain" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "wallets", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "wallet_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "addresses", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`chain` TEXT NOT NULL, `address` TEXT NOT NULL, `walletId` TEXT, `name` TEXT NOT NULL, `type` TEXT NOT NULL, `status` TEXT NOT NULL, PRIMARY KEY(`chain`, `address`), FOREIGN KEY(`chain`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`walletId`) REFERENCES `wallets`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "chain", + "columnName": "chain", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "walletId", + "columnName": "walletId", + "affinity": "TEXT" + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "chain", + "address" + ] + }, + "indices": [ + { + "name": "index_addresses_chain", + "unique": false, + "columnNames": [ + "chain" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_addresses_chain` ON `${TABLE_NAME}` (`chain`)" + }, + { + "name": "index_addresses_walletId", + "unique": false, + "columnNames": [ + "walletId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_addresses_walletId` ON `${TABLE_NAME}` (`walletId`)" + } + ], + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "chain" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "wallets", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "walletId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "asset", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `symbol` TEXT NOT NULL, `decimals` INTEGER NOT NULL, `type` TEXT NOT NULL, `chain` TEXT NOT NULL, `is_enabled` INTEGER NOT NULL, `is_buy_enabled` INTEGER NOT NULL, `is_sell_enabled` INTEGER NOT NULL, `is_swap_enabled` INTEGER NOT NULL, `is_stake_enabled` INTEGER NOT NULL, `staking_apr` REAL, `rank` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "decimals", + "columnName": "decimals", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chain", + "columnName": "chain", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isEnabled", + "columnName": "is_enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isBuyEnabled", + "columnName": "is_buy_enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isSellEnabled", + "columnName": "is_sell_enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isSwapEnabled", + "columnName": "is_swap_enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isStakeEnabled", + "columnName": "is_stake_enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "stakingApr", + "columnName": "staking_apr", + "affinity": "REAL" + }, + { + "fieldPath": "rank", + "columnName": "rank", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "balances", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `wallet_id` TEXT NOT NULL, `available` TEXT NOT NULL, `available_amount` REAL NOT NULL, `frozen` TEXT NOT NULL, `frozen_amount` REAL NOT NULL, `locked` TEXT NOT NULL, `locked_amount` REAL NOT NULL, `staked` TEXT NOT NULL, `staked_amount` REAL NOT NULL, `pending` TEXT NOT NULL, `pending_amount` REAL NOT NULL, `rewards` TEXT NOT NULL, `rewards_amount` REAL NOT NULL, `reserved` TEXT NOT NULL, `reserved_amount` REAL NOT NULL, `total_amount` REAL NOT NULL, `is_active` INTEGER NOT NULL, `is_pinned` INTEGER NOT NULL, `is_visible` INTEGER NOT NULL, `list_position` INTEGER NOT NULL, `votes` INTEGER NOT NULL DEFAULT 0, `energy_available` INTEGER NOT NULL DEFAULT 0, `energy_total` INTEGER NOT NULL DEFAULT 0, `bandwidth_available` INTEGER NOT NULL DEFAULT 0, `bandwidth_total` INTEGER NOT NULL DEFAULT 0, `updated_at` INTEGER, PRIMARY KEY(`asset_id`, `wallet_id`), FOREIGN KEY(`asset_id`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`wallet_id`) REFERENCES `wallets`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "walletId", + "columnName": "wallet_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "available", + "columnName": "available", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "availableAmount", + "columnName": "available_amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "frozen", + "columnName": "frozen", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "frozenAmount", + "columnName": "frozen_amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "locked", + "columnName": "locked", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "lockedAmount", + "columnName": "locked_amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "staked", + "columnName": "staked", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "stakedAmount", + "columnName": "staked_amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "pending", + "columnName": "pending", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pendingAmount", + "columnName": "pending_amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "rewards", + "columnName": "rewards", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rewardsAmount", + "columnName": "rewards_amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "reserved", + "columnName": "reserved", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "reservedAmount", + "columnName": "reserved_amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "totalAmount", + "columnName": "total_amount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "isActive", + "columnName": "is_active", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPinned", + "columnName": "is_pinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isVisible", + "columnName": "is_visible", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "listPosition", + "columnName": "list_position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "votes", + "columnName": "votes", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "energyAvailable", + "columnName": "energy_available", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "energyTotal", + "columnName": "energy_total", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "bandwidthAvailable", + "columnName": "bandwidth_available", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "bandwidthTotal", + "columnName": "bandwidth_total", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "updatedAt", + "columnName": "updated_at", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id", + "wallet_id" + ] + }, + "indices": [ + { + "name": "index_balances_wallet_id", + "unique": false, + "columnNames": [ + "wallet_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_balances_wallet_id` ON `${TABLE_NAME}` (`wallet_id`)" + } + ], + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "asset_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "wallets", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "wallet_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "prices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `value` REAL, `usd_value` REAL, `day_changed` REAL, `currency` TEXT NOT NULL, PRIMARY KEY(`asset_id`))", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL" + }, + { + "fieldPath": "usdValue", + "columnName": "usd_value", + "affinity": "REAL" + }, + { + "fieldPath": "dayChanged", + "columnName": "day_changed", + "affinity": "REAL" + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id" + ] + } + }, + { + "tableName": "transactions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `walletId` TEXT NOT NULL, `hash` TEXT NOT NULL, `assetId` TEXT NOT NULL, `feeAssetId` TEXT NOT NULL, `owner` TEXT NOT NULL, `recipient` TEXT NOT NULL, `contract` TEXT, `metadata` TEXT, `state` TEXT NOT NULL, `type` TEXT NOT NULL, `blockNumber` TEXT NOT NULL, `sequence` TEXT NOT NULL, `fee` TEXT NOT NULL, `value` TEXT NOT NULL, `payload` TEXT, `direction` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`id`, `walletId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "walletId", + "columnName": "walletId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "assetId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "feeAssetId", + "columnName": "feeAssetId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "owner", + "columnName": "owner", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contract", + "columnName": "contract", + "affinity": "TEXT" + }, + { + "fieldPath": "metadata", + "columnName": "metadata", + "affinity": "TEXT" + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "blockNumber", + "columnName": "blockNumber", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sequence", + "columnName": "sequence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fee", + "columnName": "fee", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "payload", + "columnName": "payload", + "affinity": "TEXT" + }, + { + "fieldPath": "direction", + "columnName": "direction", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "walletId" + ] + } + }, + { + "tableName": "tx_swap_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tx_id` TEXT NOT NULL, `from_asset_id` TEXT NOT NULL, `to_asset_id` TEXT NOT NULL, `from_amount` TEXT NOT NULL, `to_amount` TEXT NOT NULL, PRIMARY KEY(`tx_id`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "tx_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fromAssetId", + "columnName": "from_asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "toAssetId", + "columnName": "to_asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fromAmount", + "columnName": "from_amount", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "toAmount", + "columnName": "to_amount", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "tx_id" + ] + } + }, + { + "tableName": "room_connection", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `wallet_id` TEXT NOT NULL, `session_id` TEXT NOT NULL, `state` TEXT NOT NULL, `created_at` INTEGER NOT NULL, `expire_at` INTEGER NOT NULL, `app_name` TEXT NOT NULL, `app_description` TEXT NOT NULL, `app_url` TEXT NOT NULL, `app_icon` TEXT NOT NULL, `redirect_native` TEXT, `redirect_universal` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "walletId", + "columnName": "wallet_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sessionId", + "columnName": "session_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "created_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "expireAt", + "columnName": "expire_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "appName", + "columnName": "app_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "appDescription", + "columnName": "app_description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "appUrl", + "columnName": "app_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "appIcon", + "columnName": "app_icon", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "redirectNative", + "columnName": "redirect_native", + "affinity": "TEXT" + }, + { + "fieldPath": "redirectUniversal", + "columnName": "redirect_universal", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "stake_delegation_validator", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `chain` TEXT NOT NULL, `name` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `commission` REAL NOT NULL, `apr` REAL NOT NULL, `providerType` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`chain`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chain", + "columnName": "chain", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isActive", + "columnName": "isActive", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "commission", + "columnName": "commission", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "apr", + "columnName": "apr", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "providerType", + "columnName": "providerType", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_stake_delegation_validator_chain", + "unique": false, + "columnNames": [ + "chain" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_stake_delegation_validator_chain` ON `${TABLE_NAME}` (`chain`)" + } + ], + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "chain" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "stake_delegation_base", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `address` TEXT NOT NULL, `delegation_id` TEXT NOT NULL, `validator_id` TEXT NOT NULL, `asset_id` TEXT NOT NULL, `state` TEXT NOT NULL, `balance` TEXT NOT NULL, `rewards` TEXT NOT NULL, `completion_date` INTEGER, `price` REAL, `price_change` REAL, `shares` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "delegationId", + "columnName": "delegation_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "validatorId", + "columnName": "validator_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "balance", + "columnName": "balance", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rewards", + "columnName": "rewards", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "completionDate", + "columnName": "completion_date", + "affinity": "INTEGER" + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "REAL" + }, + { + "fieldPath": "priceChange", + "columnName": "price_change", + "affinity": "REAL" + }, + { + "fieldPath": "shares", + "columnName": "shares", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "nodes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `status` TEXT NOT NULL, `priority` INTEGER NOT NULL, `chain` TEXT NOT NULL, PRIMARY KEY(`url`), FOREIGN KEY(`chain`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priority", + "columnName": "priority", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "chain", + "columnName": "chain", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "url" + ] + }, + "indices": [ + { + "name": "index_nodes_chain", + "unique": false, + "columnNames": [ + "chain" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_nodes_chain` ON `${TABLE_NAME}` (`chain`)" + } + ], + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "chain" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "session", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `wallet_id` TEXT NOT NULL, `currency` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "walletId", + "columnName": "wallet_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "banners", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`wallet_id` TEXT NOT NULL, `asset_id` TEXT NOT NULL, `chain` TEXT, `state` TEXT NOT NULL, `event` TEXT NOT NULL, PRIMARY KEY(`wallet_id`, `asset_id`), FOREIGN KEY(`chain`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "walletId", + "columnName": "wallet_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chain", + "columnName": "chain", + "affinity": "TEXT" + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "event", + "columnName": "event", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "wallet_id", + "asset_id" + ] + }, + "indices": [ + { + "name": "index_banners_event", + "unique": false, + "columnNames": [ + "event" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_banners_event` ON `${TABLE_NAME}` (`event`)" + }, + { + "name": "index_banners_wallet_id", + "unique": false, + "columnNames": [ + "wallet_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_banners_wallet_id` ON `${TABLE_NAME}` (`wallet_id`)" + }, + { + "name": "index_banners_chain", + "unique": false, + "columnNames": [ + "chain" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_banners_chain` ON `${TABLE_NAME}` (`chain`)" + } + ], + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "chain" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "price_alerts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `assetId` TEXT NOT NULL, `currency` TEXT NOT NULL, `price` REAL, `pricePercentChange` REAL, `priceDirection` TEXT, `lastNotifiedAt` INTEGER, `enabled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "assetId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "REAL" + }, + { + "fieldPath": "pricePercentChange", + "columnName": "pricePercentChange", + "affinity": "REAL" + }, + { + "fieldPath": "priceDirection", + "columnName": "priceDirection", + "affinity": "TEXT" + }, + { + "fieldPath": "lastNotifiedAt", + "columnName": "lastNotifiedAt", + "affinity": "INTEGER" + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "nft_collections", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `description` TEXT, `chain` TEXT NOT NULL, `contractAddress` TEXT NOT NULL, `imageUrl` TEXT NOT NULL, `previewImageUrl` TEXT NOT NULL, `originalSourceUrl` TEXT NOT NULL, `status` TEXT, `links` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`chain`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "chain", + "columnName": "chain", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contractAddress", + "columnName": "contractAddress", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "imageUrl", + "columnName": "imageUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "previewImageUrl", + "columnName": "previewImageUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "originalSourceUrl", + "columnName": "originalSourceUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT" + }, + { + "fieldPath": "links", + "columnName": "links", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_nft_collections_chain", + "unique": false, + "columnNames": [ + "chain" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_nft_collections_chain` ON `${TABLE_NAME}` (`chain`)" + } + ], + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "chain" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "nft_assets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `collection_id` TEXT NOT NULL, `token_id` TEXT NOT NULL, `token_type` TEXT NOT NULL, `name` TEXT NOT NULL, `description` TEXT, `chain` TEXT NOT NULL, `contract_address` TEXT, `image_url` TEXT NOT NULL, `preview_image_url` TEXT NOT NULL, `original_image_url` TEXT NOT NULL, `attributes` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`collection_id`) REFERENCES `nft_collections`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`chain`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "collectionId", + "columnName": "collection_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tokenId", + "columnName": "token_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "tokenType", + "columnName": "token_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT" + }, + { + "fieldPath": "chain", + "columnName": "chain", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contractAddress", + "columnName": "contract_address", + "affinity": "TEXT" + }, + { + "fieldPath": "imageUrl", + "columnName": "image_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "previewImageUrl", + "columnName": "preview_image_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "originalSourceUrl", + "columnName": "original_image_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attributes", + "columnName": "attributes", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_nft_assets_collection_id", + "unique": false, + "columnNames": [ + "collection_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_nft_assets_collection_id` ON `${TABLE_NAME}` (`collection_id`)" + }, + { + "name": "index_nft_assets_chain", + "unique": false, + "columnNames": [ + "chain" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_nft_assets_chain` ON `${TABLE_NAME}` (`chain`)" + } + ], + "foreignKeys": [ + { + "table": "nft_collections", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "collection_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "chain" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "nft_assets_associations", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`wallet_id` TEXT NOT NULL, `asset_id` TEXT NOT NULL, PRIMARY KEY(`wallet_id`, `asset_id`), FOREIGN KEY(`asset_id`) REFERENCES `nft_assets`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`wallet_id`) REFERENCES `wallets`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "walletId", + "columnName": "wallet_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "wallet_id", + "asset_id" + ] + }, + "indices": [ + { + "name": "index_nft_assets_associations_asset_id", + "unique": false, + "columnNames": [ + "asset_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_nft_assets_associations_asset_id` ON `${TABLE_NAME}` (`asset_id`)" + } + ], + "foreignKeys": [ + { + "table": "nft_assets", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "asset_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "wallets", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "wallet_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "asset_links", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, PRIMARY KEY(`asset_id`, `name`), FOREIGN KEY(`asset_id`) REFERENCES `asset`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id", + "name" + ] + }, + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "asset_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "asset_market", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `marketCap` REAL, `marketCapFdv` REAL, `marketCapRank` INTEGER, `totalVolume` REAL, `circulatingSupply` REAL, `totalSupply` REAL, `maxSupply` REAL, `allTimeHigh` REAL, `allTimeHighDate` INTEGER, `allTimeHighChangePercentage` REAL, `allTimeLow` REAL, `allTimeLowDate` INTEGER, `allTimeLowChangePercentage` REAL, PRIMARY KEY(`asset_id`), FOREIGN KEY(`asset_id`) REFERENCES `asset`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "marketCap", + "columnName": "marketCap", + "affinity": "REAL" + }, + { + "fieldPath": "marketCapFdv", + "columnName": "marketCapFdv", + "affinity": "REAL" + }, + { + "fieldPath": "marketCapRank", + "columnName": "marketCapRank", + "affinity": "INTEGER" + }, + { + "fieldPath": "totalVolume", + "columnName": "totalVolume", + "affinity": "REAL" + }, + { + "fieldPath": "circulatingSupply", + "columnName": "circulatingSupply", + "affinity": "REAL" + }, + { + "fieldPath": "totalSupply", + "columnName": "totalSupply", + "affinity": "REAL" + }, + { + "fieldPath": "maxSupply", + "columnName": "maxSupply", + "affinity": "REAL" + }, + { + "fieldPath": "allTimeHigh", + "columnName": "allTimeHigh", + "affinity": "REAL" + }, + { + "fieldPath": "allTimeHighDate", + "columnName": "allTimeHighDate", + "affinity": "INTEGER" + }, + { + "fieldPath": "allTimeHighChangePercentage", + "columnName": "allTimeHighChangePercentage", + "affinity": "REAL" + }, + { + "fieldPath": "allTimeLow", + "columnName": "allTimeLow", + "affinity": "REAL" + }, + { + "fieldPath": "allTimeLowDate", + "columnName": "allTimeLowDate", + "affinity": "INTEGER" + }, + { + "fieldPath": "allTimeLowChangePercentage", + "columnName": "allTimeLowChangePercentage", + "affinity": "REAL" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id" + ] + }, + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "asset_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "assets_priority", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`query` TEXT NOT NULL, `asset_id` TEXT NOT NULL, `priority` INTEGER NOT NULL, PRIMARY KEY(`query`, `asset_id`))", + "fields": [ + { + "fieldPath": "query", + "columnName": "query", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "priority", + "columnName": "priority", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "query", + "asset_id" + ] + } + }, + { + "tableName": "currency_rates", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`currency` TEXT NOT NULL, `rate` REAL NOT NULL, PRIMARY KEY(`currency`))", + "fields": [ + { + "fieldPath": "currency", + "columnName": "currency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "currency" + ] + } + }, + { + "tableName": "fiat_transactions", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `walletId` TEXT NOT NULL, `assetId` TEXT NOT NULL, `transactionType` TEXT NOT NULL, `provider` TEXT NOT NULL, `status` TEXT NOT NULL, `fiatAmount` REAL NOT NULL, `fiatCurrency` TEXT NOT NULL, `value` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `detailsUrl` TEXT, PRIMARY KEY(`id`, `walletId`), FOREIGN KEY(`walletId`) REFERENCES `wallets`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`assetId`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "walletId", + "columnName": "walletId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "assetId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "transactionType", + "columnName": "transactionType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "provider", + "columnName": "provider", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "fiatAmount", + "columnName": "fiatAmount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "fiatCurrency", + "columnName": "fiatCurrency", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "detailsUrl", + "columnName": "detailsUrl", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "walletId" + ] + }, + "indices": [ + { + "name": "index_fiat_transactions_walletId", + "unique": false, + "columnNames": [ + "walletId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_fiat_transactions_walletId` ON `${TABLE_NAME}` (`walletId`)" + }, + { + "name": "index_fiat_transactions_assetId", + "unique": false, + "columnNames": [ + "assetId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_fiat_transactions_assetId` ON `${TABLE_NAME}` (`assetId`)" + } + ], + "foreignKeys": [ + { + "table": "wallets", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "walletId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "assetId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "recent_assets", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `wallet_id` TEXT NOT NULL, `to_asset_id` TEXT, `type` TEXT NOT NULL, `addedAt` INTEGER NOT NULL, PRIMARY KEY(`asset_id`, `wallet_id`, `type`), FOREIGN KEY(`asset_id`) REFERENCES `asset`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`wallet_id`) REFERENCES `wallets`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "assetId", + "columnName": "asset_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "walletId", + "columnName": "wallet_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "toAssetId", + "columnName": "to_asset_id", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "addedAt", + "columnName": "addedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "asset_id", + "wallet_id", + "type" + ] + }, + "indices": [ + { + "name": "index_recent_assets_wallet_id", + "unique": false, + "columnNames": [ + "wallet_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_recent_assets_wallet_id` ON `${TABLE_NAME}` (`wallet_id`)" + } + ], + "foreignKeys": [ + { + "table": "asset", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "asset_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "wallets", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "wallet_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "perpetual", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `provider` TEXT NOT NULL, `assetId` TEXT NOT NULL, `identifier` TEXT NOT NULL, `price` REAL NOT NULL, `pricePercentChange24h` REAL NOT NULL, `openInterest` REAL NOT NULL, `volume24h` REAL NOT NULL, `funding` REAL NOT NULL, `maxLeverage` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "provider", + "columnName": "provider", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "assetId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "identifier", + "columnName": "identifier", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "pricePercentChange24h", + "columnName": "pricePercentChange24h", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "openInterest", + "columnName": "openInterest", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "volume24h", + "columnName": "volume24h", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "funding", + "columnName": "funding", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "maxLeverage", + "columnName": "maxLeverage", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "perpetual_asset_id_idx", + "unique": false, + "columnNames": [ + "assetId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `perpetual_asset_id_idx` ON `${TABLE_NAME}` (`assetId`)" + } + ] + }, + { + "tableName": "perpetual_asset", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `symbol` TEXT NOT NULL, `decimals` INTEGER NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "decimals", + "columnName": "decimals", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "perpetual_balance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountAddress` TEXT NOT NULL, `available` REAL NOT NULL, `reserved` REAL NOT NULL, `withdrawable` REAL NOT NULL, PRIMARY KEY(`accountAddress`))", + "fields": [ + { + "fieldPath": "accountAddress", + "columnName": "accountAddress", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "available", + "columnName": "available", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "reserved", + "columnName": "reserved", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "withdrawable", + "columnName": "withdrawable", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "accountAddress" + ] + } + }, + { + "tableName": "perpetual_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`perpetualId` TEXT NOT NULL, `isPinned` INTEGER NOT NULL, PRIMARY KEY(`perpetualId`))", + "fields": [ + { + "fieldPath": "perpetualId", + "columnName": "perpetualId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isPinned", + "columnName": "isPinned", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "perpetualId" + ] + } + }, + { + "tableName": "perpetual_position", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `perpetualId` TEXT NOT NULL, `accountAddress` TEXT NOT NULL, `assetId` TEXT NOT NULL, `size` REAL NOT NULL, `sizeValue` REAL NOT NULL, `leverage` INTEGER NOT NULL, `entryPrice` REAL, `liquidationPrice` REAL, `marginType` TEXT NOT NULL, `direction` TEXT NOT NULL, `marginAmount` REAL NOT NULL, `takeProfitPrice` REAL, `takeProfitType` TEXT, `takeProfitOrderId` TEXT, `stopLossPrice` REAL, `stopLossType` TEXT, `stopLossOrderId` TEXT, `pnl` REAL NOT NULL, `funding` REAL, PRIMARY KEY(`id`, `perpetualId`, `accountAddress`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "perpetualId", + "columnName": "perpetualId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountAddress", + "columnName": "accountAddress", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "assetId", + "columnName": "assetId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "sizeValue", + "columnName": "sizeValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "leverage", + "columnName": "leverage", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryPrice", + "columnName": "entryPrice", + "affinity": "REAL" + }, + { + "fieldPath": "liquidationPrice", + "columnName": "liquidationPrice", + "affinity": "REAL" + }, + { + "fieldPath": "marginType", + "columnName": "marginType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "direction", + "columnName": "direction", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "marginAmount", + "columnName": "marginAmount", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "takeProfitPrice", + "columnName": "takeProfitPrice", + "affinity": "REAL" + }, + { + "fieldPath": "takeProfitType", + "columnName": "takeProfitType", + "affinity": "TEXT" + }, + { + "fieldPath": "takeProfitOrderId", + "columnName": "takeProfitOrderId", + "affinity": "TEXT" + }, + { + "fieldPath": "stopLossPrice", + "columnName": "stopLossPrice", + "affinity": "REAL" + }, + { + "fieldPath": "stopLossType", + "columnName": "stopLossType", + "affinity": "TEXT" + }, + { + "fieldPath": "stopLossOrderId", + "columnName": "stopLossOrderId", + "affinity": "TEXT" + }, + { + "fieldPath": "pnl", + "columnName": "pnl", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "funding", + "columnName": "funding", + "affinity": "REAL" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "perpetualId", + "accountAddress" + ] + }, + "indices": [ + { + "name": "perpetual_position_asset_id_idx", + "unique": false, + "columnNames": [ + "assetId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `perpetual_position_asset_id_idx` ON `${TABLE_NAME}` (`assetId`)" + }, + { + "name": "perpetual_position_perpetual_id_idx", + "unique": false, + "columnNames": [ + "perpetualId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `perpetual_position_perpetual_id_idx` ON `${TABLE_NAME}` (`perpetualId`)" + }, + { + "name": "perpetual_position_account_address_idx", + "unique": false, + "columnNames": [ + "accountAddress" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `perpetual_position_account_address_idx` ON `${TABLE_NAME}` (`accountAddress`)" + } + ] + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8b8ecdaf771936e0ffd5daf16b017709')" + ] + } +} \ No newline at end of file diff --git a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/AddressesDao.kt b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/AddressesDao.kt new file mode 100644 index 000000000..be25357a5 --- /dev/null +++ b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/AddressesDao.kt @@ -0,0 +1,21 @@ +package com.gemwallet.android.data.service.store.database + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.gemwallet.android.data.service.store.database.entities.DbAddress +import com.wallet.core.primitives.Chain + +@Dao +interface AddressesDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(addresses: List) + + @Query("SELECT * FROM addresses WHERE chain = :chain AND address = :address LIMIT 1") + suspend fun get(chain: Chain, address: String): DbAddress? + + @Query("UPDATE addresses SET name = :name WHERE walletId = :walletId") + suspend fun updateName(walletId: String, name: String) +} diff --git a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/GemDatabase.kt b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/GemDatabase.kt index 4c1884781..03eff3ea8 100644 --- a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/GemDatabase.kt +++ b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/GemDatabase.kt @@ -4,6 +4,7 @@ import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.TypeConverters import com.gemwallet.android.data.service.store.database.entities.DbAccount +import com.gemwallet.android.data.service.store.database.entities.DbAddress import com.gemwallet.android.data.service.store.database.entities.DbAsset import com.gemwallet.android.data.service.store.database.entities.DbAssetLink import com.gemwallet.android.data.service.store.database.entities.DbAssetMarket @@ -33,10 +34,11 @@ import com.gemwallet.android.data.service.store.database.entities.DbTxSwapMetada import com.gemwallet.android.data.service.store.database.entities.DbWallet @Database( - version = 72, + version = 73, entities = [ DbWallet::class, DbAccount::class, + DbAddress::class, DbAsset::class, DbBalance::class, DbPrice::class, @@ -71,6 +73,8 @@ abstract class GemDatabase : RoomDatabase() { abstract fun accountsDao(): AccountsDao + abstract fun addressesDao(): AddressesDao + abstract fun assetsDao(): AssetsDao abstract fun balancesDao(): BalancesDao diff --git a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/TransactionsDao.kt b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/TransactionsDao.kt index 1e6500f79..8557e4bb4 100644 --- a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/TransactionsDao.kt +++ b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/TransactionsDao.kt @@ -7,6 +7,7 @@ import androidx.room.Query import androidx.room.RawQuery import androidx.sqlite.db.SupportSQLiteQuery import com.gemwallet.android.application.transactions.coordinators.TransactionsRequestFilter +import com.gemwallet.android.data.service.store.database.entities.DbAddress import com.gemwallet.android.data.service.store.database.entities.DbAsset import com.gemwallet.android.data.service.store.database.entities.DbPrice import com.gemwallet.android.data.service.store.database.entities.DbTransaction @@ -42,7 +43,15 @@ const val EXTENDED_COLUMNS = """ to_asset.name AS to_asset_name, to_asset.symbol AS to_asset_symbol, to_asset.decimals AS to_asset_decimals, - to_asset.type AS to_asset_type + to_asset.type AS to_asset_type, + from_addr.chain AS from_address_chain, + from_addr.name AS from_address_name, + from_addr.type AS from_address_type, + from_addr.status AS from_address_status, + to_addr.chain AS to_address_chain, + to_addr.name AS to_address_name, + to_addr.type AS to_address_type, + to_addr.status AS to_address_status """ const val EXTENDED_SOURCE = """ @@ -54,6 +63,8 @@ const val EXTENDED_SOURCE = """ LEFT JOIN tx_swap_metadata as swap ON tx.id = swap.tx_id LEFT JOIN asset as from_asset ON swap.from_asset_id = from_asset.id LEFT JOIN asset as to_asset ON swap.to_asset_id = to_asset.id + LEFT JOIN addresses as from_addr ON from_addr.chain = asset.chain AND from_addr.address = tx.owner + LEFT JOIN addresses as to_addr ON to_addr.chain = asset.chain AND to_addr.address = tx.recipient WHERE tx.walletId = :walletId """ @@ -72,6 +83,7 @@ interface TransactionsDao { DbAsset::class, DbPrice::class, DbTxSwapMetadata::class, + DbAddress::class, ] ) fun getExtendedTransactions(query: SupportSQLiteQuery): Flow> diff --git a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/di/DatabaseModule.kt b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/di/DatabaseModule.kt index 5d12a79bc..034bcdb1d 100644 --- a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/di/DatabaseModule.kt +++ b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/di/DatabaseModule.kt @@ -4,6 +4,7 @@ import android.content.Context import androidx.room.Room import com.gemwallet.android.application.PasswordStore import com.gemwallet.android.data.service.store.database.AccountsDao +import com.gemwallet.android.data.service.store.database.AddressesDao import com.gemwallet.android.data.service.store.database.AssetsDao import com.gemwallet.android.data.service.store.database.AssetsPriorityDao import com.gemwallet.android.data.service.store.database.BalancesDao @@ -72,6 +73,7 @@ object DatabaseModule { .addMigrations(Migration_69_70) .addMigrations(Migration_70_71) .addMigrations(Migration_71_72) + .addMigrations(Migration_72_73) .build() @Singleton @@ -86,6 +88,10 @@ object DatabaseModule { @Provides fun provideAccountsDao(db: GemDatabase): AccountsDao = db.accountsDao() + @Singleton + @Provides + fun provideAddressesDao(db: GemDatabase): AddressesDao = db.addressesDao() + @Singleton @Provides fun provideAssetsDao(db: GemDatabase): AssetsDao = db.assetsDao() diff --git a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/di/Migration_72_73.kt b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/di/Migration_72_73.kt new file mode 100644 index 000000000..139daefd9 --- /dev/null +++ b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/di/Migration_72_73.kt @@ -0,0 +1,26 @@ +package com.gemwallet.android.data.service.store.database.di + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +object Migration_72_73 : Migration(72, 73) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE IF NOT EXISTS `addresses` ( + `chain` TEXT NOT NULL, + `address` TEXT NOT NULL, + `walletId` TEXT, + `name` TEXT NOT NULL, + `type` TEXT NOT NULL, + `status` TEXT NOT NULL, + PRIMARY KEY(`chain`, `address`), + FOREIGN KEY(`chain`) REFERENCES `asset`(`id`) ON UPDATE CASCADE ON DELETE CASCADE, + FOREIGN KEY(`walletId`) REFERENCES `wallets`(`id`) ON UPDATE CASCADE ON DELETE CASCADE + ) + """ + ) + db.execSQL("CREATE INDEX IF NOT EXISTS `index_addresses_chain` ON `addresses` (`chain`)") + db.execSQL("CREATE INDEX IF NOT EXISTS `index_addresses_walletId` ON `addresses` (`walletId`)") + } +} diff --git a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/entities/DbAddress.kt b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/entities/DbAddress.kt new file mode 100644 index 000000000..f2f57b48d --- /dev/null +++ b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/entities/DbAddress.kt @@ -0,0 +1,70 @@ +package com.gemwallet.android.data.service.store.database.entities + +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import com.wallet.core.primitives.AddressName +import com.wallet.core.primitives.AddressType +import com.wallet.core.primitives.Chain +import com.wallet.core.primitives.VerificationStatus +import com.wallet.core.primitives.Wallet + +@Entity( + tableName = "addresses", + primaryKeys = ["chain", "address"], + foreignKeys = [ + ForeignKey( + entity = DbAsset::class, + parentColumns = ["id"], + childColumns = ["chain"], + onDelete = ForeignKey.CASCADE, + onUpdate = ForeignKey.CASCADE, + ), + ForeignKey( + entity = DbWallet::class, + parentColumns = ["id"], + childColumns = ["walletId"], + onDelete = ForeignKey.CASCADE, + onUpdate = ForeignKey.CASCADE, + ), + ], + indices = [Index("chain"), Index("walletId")], +) +data class DbAddress( + val chain: Chain, + val address: String, + val walletId: String?, + val name: String, + val type: AddressType, + val status: VerificationStatus, +) + +fun AddressName.toRecord(): DbAddress = DbAddress( + chain = chain, + address = address, + walletId = null, + name = name, + type = type, + status = status, +) + +fun DbAddress.toDTO(): AddressName = AddressName( + chain = chain, + address = address, + name = name, + type = type, + status = status, +) + +fun List.toRecord(): List = map { it.toRecord() } + +fun Wallet.toAddressRecords(): List = accounts.map { account -> + DbAddress( + chain = account.chain, + address = account.address, + walletId = id, + name = name, + type = AddressType.InternalWallet, + status = VerificationStatus.Verified, + ) +} diff --git a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/entities/DbTransactionExtended.kt b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/entities/DbTransactionExtended.kt index 5b2eab453..f592fad65 100644 --- a/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/entities/DbTransactionExtended.kt +++ b/android/data/services/store/src/main/kotlin/com/gemwallet/android/data/service/store/database/entities/DbTransactionExtended.kt @@ -3,7 +3,11 @@ package com.gemwallet.android.data.service.store.database.entities import androidx.room.ColumnInfo import androidx.room.Embedded import com.gemwallet.android.model.TransactionExtended +import com.wallet.core.primitives.AddressName +import com.wallet.core.primitives.AddressType +import com.wallet.core.primitives.Chain import com.wallet.core.primitives.Price +import com.wallet.core.primitives.VerificationStatus data class DbTransactionExtended( @Embedded val transaction: DbTransaction, @@ -15,6 +19,15 @@ data class DbTransactionExtended( @ColumnInfo("fee_price_day_changed") val feePriceDayChanged: Double?, @Embedded(prefix = "from_asset_") val fromAsset: DbAssetProjection?, @Embedded(prefix = "to_asset_") val toAsset: DbAssetProjection?, + @Embedded(prefix = "from_address_") val fromAddress: DbAddressProjection?, + @Embedded(prefix = "to_address_") val toAddress: DbAddressProjection?, +) + +data class DbAddressProjection( + val chain: Chain, + val name: String, + val type: AddressType, + val status: VerificationStatus, ) fun DbTransactionExtended.toDTO(): TransactionExtended? { @@ -28,7 +41,17 @@ fun DbTransactionExtended.toDTO(): TransactionExtended? { fromAsset?.toDTO(), toAsset?.toDTO(), ), + fromAddress = fromAddress?.toAddressName(transaction.owner), + toAddress = toAddress?.toAddressName(transaction.recipient), ) } +private fun DbAddressProjection.toAddressName(address: String): AddressName = AddressName( + chain = chain, + address = address, + name = name, + type = type, + status = status, +) + fun List.toDTO() = mapNotNull { it.toDTO() } diff --git a/android/features/activities/presents/src/main/kotlin/com/gemwallet/android/features/activities/presents/details/components/DestinationPropertyItem.kt b/android/features/activities/presents/src/main/kotlin/com/gemwallet/android/features/activities/presents/details/components/DestinationPropertyItem.kt index 6c1a7cc95..71f798fb3 100644 --- a/android/features/activities/presents/src/main/kotlin/com/gemwallet/android/features/activities/presents/details/components/DestinationPropertyItem.kt +++ b/android/features/activities/presents/src/main/kotlin/com/gemwallet/android/features/activities/presents/details/components/DestinationPropertyItem.kt @@ -25,7 +25,7 @@ fun DestinationPropertyItem(property: TransactionDetailsValue.Destination, listP is TransactionDetailsValue.Destination.Validator -> R.string.stake_validator is TransactionDetailsValue.Destination.ProviderAddress -> R.string.common_provider }, - displayText = AddressFormatter(property.data).value(), + displayText = property.name ?: AddressFormatter(property.data).value(), copyValue = property.data, explorerLink = property.explorerLink, listPosition = listPosition, diff --git a/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/GetAddressName.kt b/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/GetAddressName.kt new file mode 100644 index 000000000..5c6b6127e --- /dev/null +++ b/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/GetAddressName.kt @@ -0,0 +1,8 @@ +package com.gemwallet.android.cases.addresses + +import com.wallet.core.primitives.AddressName +import com.wallet.core.primitives.Chain + +interface GetAddressName { + suspend fun getAddressName(chain: Chain, address: String): AddressName? +} diff --git a/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/RenameWalletAddresses.kt b/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/RenameWalletAddresses.kt new file mode 100644 index 000000000..1449e23f6 --- /dev/null +++ b/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/RenameWalletAddresses.kt @@ -0,0 +1,7 @@ +package com.gemwallet.android.cases.addresses + +import com.wallet.core.primitives.WalletId + +interface RenameWalletAddresses { + suspend fun rename(walletId: WalletId, name: String) +} diff --git a/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/SaveAddressNames.kt b/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/SaveAddressNames.kt new file mode 100644 index 000000000..71d80d64f --- /dev/null +++ b/android/gemcore/src/main/kotlin/com/gemwallet/android/cases/addresses/SaveAddressNames.kt @@ -0,0 +1,7 @@ +package com.gemwallet.android.cases.addresses + +import com.wallet.core.primitives.AddressName + +interface SaveAddressNames { + suspend fun saveAddressNames(addressNames: List) +} diff --git a/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmProperty.kt b/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmProperty.kt index a98f157be..c598a2c33 100644 --- a/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmProperty.kt +++ b/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/confirm/ConfirmProperty.kt @@ -1,6 +1,7 @@ package com.gemwallet.android.domains.confirm import com.gemwallet.android.model.ConfirmParams +import com.wallet.core.primitives.AddressName import com.wallet.core.primitives.Asset import com.wallet.core.primitives.BlockExplorerLink import com.wallet.core.primitives.DelegationValidator @@ -18,7 +19,11 @@ sealed interface ConfirmProperty { class PerpetualOper(val providerName: String) : Destination(providerName) companion object { - fun map(params: ConfirmParams, validator: DelegationValidator?): Destination? = when (params) { + fun map( + params: ConfirmParams, + validator: DelegationValidator?, + addressName: AddressName? = null, + ): Destination? = when (params) { is ConfirmParams.Activate, is ConfirmParams.Stake.Freeze, is ConfirmParams.Stake.Unfreeze, @@ -37,7 +42,7 @@ sealed interface ConfirmProperty { is ConfirmParams.NftParams, is ConfirmParams.TransferParams.Token, is ConfirmParams.TransferParams.Native -> params.destination()?.let { - Transfer(domain = it.name, address = it.address) + Transfer(domain = it.name ?: addressName?.name, address = it.address) } ?: throw ConfirmError.RecipientEmpty is ConfirmParams.TransferParams.Generic -> Generic(params.name) } diff --git a/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/transaction/aggregates/TransactionDataAggregate.kt b/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/transaction/aggregates/TransactionDataAggregate.kt index f48667e1f..7ecdf7809 100644 --- a/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/transaction/aggregates/TransactionDataAggregate.kt +++ b/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/transaction/aggregates/TransactionDataAggregate.kt @@ -10,6 +10,8 @@ interface TransactionDataAggregate { val id: TransactionId val asset: Asset val address: String + val addressName: String? + get() = null val value: String val equivalentValue: String? val type: TransactionType diff --git a/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/transaction/values/TransactionDetailsValue.kt b/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/transaction/values/TransactionDetailsValue.kt index 182915960..6caa4f84d 100644 --- a/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/transaction/values/TransactionDetailsValue.kt +++ b/android/gemcore/src/main/kotlin/com/gemwallet/android/domains/transaction/values/TransactionDetailsValue.kt @@ -1,6 +1,7 @@ package com.gemwallet.android.domains.transaction.values import com.gemwallet.android.model.AssetInfo +import com.wallet.core.primitives.AddressType import com.wallet.core.primitives.Asset import com.wallet.core.primitives.BlockExplorerLink import com.wallet.core.primitives.Currency @@ -37,12 +38,39 @@ sealed interface TransactionDetailsValue { class Date(val data: String) : TransactionDetailsValue - sealed class Destination(val data: String, open val explorerLink: BlockExplorerLink? = null) : TransactionDetailsValue { - class Sender(data: String, override val explorerLink: BlockExplorerLink? = null) : Destination(data, explorerLink) - class Recipient(data: String, override val explorerLink: BlockExplorerLink? = null) : Destination(data, explorerLink) - class Contract(data: String, override val explorerLink: BlockExplorerLink? = null) : Destination(data, explorerLink) - class Validator(data: String, override val explorerLink: BlockExplorerLink? = null) : Destination(data, explorerLink) - class ProviderAddress(data: String, override val explorerLink: BlockExplorerLink? = null) : Destination(data, explorerLink) + sealed class Destination( + val data: String, + val name: String? = null, + val addressType: AddressType? = null, + val explorerLink: BlockExplorerLink? = null, + ) : TransactionDetailsValue { + class Sender( + data: String, + name: String? = null, + addressType: AddressType? = null, + explorerLink: BlockExplorerLink? = null, + ) : Destination(data, name, addressType, explorerLink) + class Recipient( + data: String, + name: String? = null, + addressType: AddressType? = null, + explorerLink: BlockExplorerLink? = null, + ) : Destination(data, name, addressType, explorerLink) + class Contract( + data: String, + name: String? = null, + explorerLink: BlockExplorerLink? = null, + ) : Destination(data, name = name, explorerLink = explorerLink) + class Validator( + data: String, + name: String? = null, + explorerLink: BlockExplorerLink? = null, + ) : Destination(data, name = name, explorerLink = explorerLink) + class ProviderAddress( + data: String, + name: String? = null, + explorerLink: BlockExplorerLink? = null, + ) : Destination(data, name = name, explorerLink = explorerLink) class Provider(name: String) : Destination(name) } diff --git a/android/gemcore/src/main/kotlin/com/gemwallet/android/model/TransactionExtended.kt b/android/gemcore/src/main/kotlin/com/gemwallet/android/model/TransactionExtended.kt index 56952835d..12f83196a 100644 --- a/android/gemcore/src/main/kotlin/com/gemwallet/android/model/TransactionExtended.kt +++ b/android/gemcore/src/main/kotlin/com/gemwallet/android/model/TransactionExtended.kt @@ -4,6 +4,7 @@ package com.gemwallet.android.model +import com.wallet.core.primitives.AddressName import com.wallet.core.primitives.Asset import com.wallet.core.primitives.Price import com.wallet.core.primitives.Transaction @@ -16,6 +17,8 @@ data class TransactionExtended ( val feeAsset: Asset, val price: Price? = null, val feePrice: Price? = null, - val assets: List + val assets: List, + val fromAddress: AddressName? = null, + val toAddress: AddressName? = null, ) diff --git a/android/gemcore/src/main/kotlin/com/wallet/core/primitives/generated/AddressName.kt b/android/gemcore/src/main/kotlin/com/wallet/core/primitives/generated/AddressName.kt index 19bfbfe4d..f8dff6583 100644 --- a/android/gemcore/src/main/kotlin/com/wallet/core/primitives/generated/AddressName.kt +++ b/android/gemcore/src/main/kotlin/com/wallet/core/primitives/generated/AddressName.kt @@ -12,7 +12,7 @@ data class AddressName ( val chain: Chain, val address: String, val name: String, - val type: AddressType? = null, + val type: AddressType, val status: VerificationStatus ) diff --git a/android/ui/src/main/kotlin/com/gemwallet/android/ui/components/list_item/transaction/TransactionDataAggregateExt.kt b/android/ui/src/main/kotlin/com/gemwallet/android/ui/components/list_item/transaction/TransactionDataAggregateExt.kt index 00428ae30..c905a2993 100644 --- a/android/ui/src/main/kotlin/com/gemwallet/android/ui/components/list_item/transaction/TransactionDataAggregateExt.kt +++ b/android/ui/src/main/kotlin/com/gemwallet/android/ui/components/list_item/transaction/TransactionDataAggregateExt.kt @@ -34,22 +34,29 @@ fun TransactionDataAggregate.getBadgeColor(): Color = state.statusColor() @Composable fun TransactionDataAggregate.formatAddress(): String? = when (type) { TransactionType.TransferNFT, - TransactionType.Transfer -> when (direction) { - TransactionDirection.SelfTransfer, - TransactionDirection.Outgoing -> "${stringResource(id = R.string.transfer_to)} $address" - TransactionDirection.Incoming -> "${stringResource(id = R.string.transfer_from)} $address" - } - TransactionType.Swap, + TransactionType.Transfer, TransactionType.TokenApproval, + TransactionType.SmartContractCall -> { + val displayAddress = addressName ?: address + when (direction) { + TransactionDirection.SelfTransfer, + TransactionDirection.Outgoing -> "${stringResource(id = R.string.transfer_to)} $displayAddress" + TransactionDirection.Incoming -> "${stringResource(id = R.string.transfer_from)} $displayAddress" + } + } TransactionType.StakeDelegate, - TransactionType.StakeUndelegate, TransactionType.StakeRedelegate, + TransactionType.EarnDeposit -> (addressName ?: address) + .takeIf { it.isNotEmpty() } + ?.let { "${stringResource(id = R.string.transfer_to)} $it" } + TransactionType.StakeUndelegate, + TransactionType.EarnWithdraw -> (addressName ?: address) + .takeIf { it.isNotEmpty() } + ?.let { "${stringResource(id = R.string.transfer_from)} $it" } + TransactionType.Swap, TransactionType.StakeWithdraw, TransactionType.AssetActivation, TransactionType.StakeRewards, - TransactionType.EarnDeposit, - TransactionType.EarnWithdraw, - TransactionType.SmartContractCall, TransactionType.PerpetualOpenPosition, TransactionType.StakeFreeze, TransactionType.StakeUnfreeze, diff --git a/core b/core index bffb6b2a8..2df07ccf4 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit bffb6b2a83aa4dad50d59effc98a7ffd55f64689 +Subproject commit 2df07ccf4d194d2d6b3f663f8a7e9ac854e9a535 diff --git a/ios/Packages/Primitives/Sources/Generated/AddressName.swift b/ios/Packages/Primitives/Sources/Generated/AddressName.swift index dc485c6e7..577feff90 100644 --- a/ios/Packages/Primitives/Sources/Generated/AddressName.swift +++ b/ios/Packages/Primitives/Sources/Generated/AddressName.swift @@ -8,10 +8,10 @@ public struct AddressName: Codable, Equatable, Hashable, Sendable { public let chain: Chain public let address: String public let name: String - public let type: AddressType? + public let type: AddressType public let status: VerificationStatus - public init(chain: Chain, address: String, name: String, type: AddressType?, status: VerificationStatus) { + public init(chain: Chain, address: String, name: String, type: AddressType, status: VerificationStatus) { self.chain = chain self.address = address self.name = name diff --git a/ios/Packages/Primitives/TestKit/AddressName+PrimitivesTestKit.swift b/ios/Packages/Primitives/TestKit/AddressName+PrimitivesTestKit.swift index c3957b8c1..da793d17f 100644 --- a/ios/Packages/Primitives/TestKit/AddressName+PrimitivesTestKit.swift +++ b/ios/Packages/Primitives/TestKit/AddressName+PrimitivesTestKit.swift @@ -8,7 +8,7 @@ public extension AddressName { chain: Chain = .arbitrum, address: String = "0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7", name: String = "Hyperliquid", - type: AddressType? = nil, + type: AddressType = .address, status: VerificationStatus = .verified, ) -> AddressName { AddressName( diff --git a/ios/Packages/PrimitivesComponents/Sources/Components/TransactionView.swift b/ios/Packages/PrimitivesComponents/Sources/Components/TransactionView.swift index 8286593fb..c71c259af 100644 --- a/ios/Packages/PrimitivesComponents/Sources/Components/TransactionView.swift +++ b/ios/Packages/PrimitivesComponents/Sources/Components/TransactionView.swift @@ -71,8 +71,8 @@ private struct ExplorerMock: ExplorerLinkFetchable { feePrice: nil, assets: [], prices: [], - fromAddress: AddressName(chain: .smartChain, address: "0x92abCE21234D71EC443E679f3a1feAFD3Fc830fB", name: "test1", type: nil, status: .verified), - toAddress: AddressName(chain: .smartChain, address: "0x8d7460E51bCf4eD26877cb77E56f3ce7E9f5EB8F", name: "test2", type: nil, status: .verified), + fromAddress: AddressName(chain: .smartChain, address: "0x92abCE21234D71EC443E679f3a1feAFD3Fc830fB", name: "test1", type: .address, status: .verified), + toAddress: AddressName(chain: .smartChain, address: "0x8d7460E51bCf4eD26877cb77E56f3ce7E9f5EB8F", name: "test2", type: .address, status: .verified), ) let transactionVMMock = TransactionViewModel( diff --git a/ios/Packages/Store/Sources/Migrations.swift b/ios/Packages/Store/Sources/Migrations.swift index 2137fa580..75a4efd18 100644 --- a/ios/Packages/Store/Sources/Migrations.swift +++ b/ios/Packages/Store/Sources/Migrations.swift @@ -470,6 +470,13 @@ struct Migrations { try PerpetualPositionRecord.create(db: db) } + migrator.registerMigration("Backfill type in \(AddressRecord.databaseTableName)") { db in + try db.execute( + sql: "UPDATE \(AddressRecord.databaseTableName) SET \(AddressRecord.Columns.type.name) = ? WHERE \(AddressRecord.Columns.type.name) IS NULL", + arguments: [AddressType.address.rawValue], + ) + } + try migrator.migrate(dbQueue) } } diff --git a/ios/Packages/Store/Sources/Models/AddressRecord.swift b/ios/Packages/Store/Sources/Models/AddressRecord.swift index d75ab26ef..c2c81e54f 100644 --- a/ios/Packages/Store/Sources/Models/AddressRecord.swift +++ b/ios/Packages/Store/Sources/Models/AddressRecord.swift @@ -18,7 +18,7 @@ struct AddressRecord: Codable, FetchableRecord, PersistableRecord { let chain: Chain let address: String let name: String - let type: AddressType? + let type: AddressType let status: VerificationStatus } @@ -33,6 +33,7 @@ extension AddressRecord: CreateTable { $0.column(Columns.name.name, .text) .notNull() $0.column(Columns.type.name, .text) + .notNull() $0.column(Columns.status.name, .text) .notNull() .defaults(to: VerificationStatus.unverified.rawValue)