From b8ba284731da79c67744187c19ca85bfd5ace93e Mon Sep 17 00:00:00 2001 From: Marat Biryushev Date: Mon, 16 Sep 2024 16:59:35 +0300 Subject: [PATCH 01/10] test --- gradle/libs.versions.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e29bec177..1247e293e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -179,6 +179,8 @@ walletconnectBomDep = { module = "com.walletconnect:android-bom", version.ref = walletconnectCoreDep = { module = "com.walletconnect:android-core" } walletconnectWeb3WalletDep = { module = "com.walletconnect:web3wallet" } +jnr-x86asm = { module = "com.github.jnr:jnr-x86asm", version.ref = "1.0.2" } + [bundles] compose = [ "compose-runtime", "compose-ui", "compose-runtimeLiveData", "compose-compiler", From 78b3b91236912f23675c371c146469b3930f6f36 Mon Sep 17 00:00:00 2001 From: Marat Biryushev Date: Mon, 16 Sep 2024 17:03:57 +0300 Subject: [PATCH 02/10] fix --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1247e293e..c872e9d41 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -179,7 +179,7 @@ walletconnectBomDep = { module = "com.walletconnect:android-bom", version.ref = walletconnectCoreDep = { module = "com.walletconnect:android-core" } walletconnectWeb3WalletDep = { module = "com.walletconnect:web3wallet" } -jnr-x86asm = { module = "com.github.jnr:jnr-x86asm", version.ref = "1.0.2" } +jnr-x86asm = { module = "com.github.jnr:jnr-x86asm" } [bundles] compose = [ From f6e294950183db1b408d1f34dac86c6767c6370f Mon Sep 17 00:00:00 2001 From: marat-biriushev <49524488+marat-biriushev@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:10:36 +0300 Subject: [PATCH 03/10] Update libs.versions.toml --- gradle/libs.versions.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c872e9d41..37fca187e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -61,6 +61,7 @@ wsVersion = "2.14" xNetworking = "0.2.5-temp7" zxingEmbeddedVersion = "4.3.0" zxingVersion = "3.5.3" +jnr-x86asm = "1.0.2" [libraries] appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } @@ -192,4 +193,4 @@ compose = [ composeDebug = [ "compose-uiTooling", "customview", "customview-poolingcontainer" ] -coroutines = ["coroutines-core", "coroutines-android"] \ No newline at end of file +coroutines = ["coroutines-core", "coroutines-android"] From 84871ce1cd9632ace59aa888471ddfadfd603a30 Mon Sep 17 00:00:00 2001 From: marat-biriushev <49524488+marat-biriushev@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:18:23 +0300 Subject: [PATCH 04/10] Update libs.versions.toml --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 37fca187e..2b1b82c70 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -180,7 +180,7 @@ walletconnectBomDep = { module = "com.walletconnect:android-bom", version.ref = walletconnectCoreDep = { module = "com.walletconnect:android-core" } walletconnectWeb3WalletDep = { module = "com.walletconnect:web3wallet" } -jnr-x86asm = { module = "com.github.jnr:jnr-x86asm" } +jnr-x86asm = { module = "com.github.jnr:jnr-x86asm:1.0.2" } [bundles] compose = [ From ac668d10e565ec6c80c737b3ed6307eeaad8ef31 Mon Sep 17 00:00:00 2001 From: marat-biriushev <49524488+marat-biriushev@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:22:11 +0300 Subject: [PATCH 05/10] Update libs.versions.toml --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2b1b82c70..054c75361 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -180,7 +180,7 @@ walletconnectBomDep = { module = "com.walletconnect:android-bom", version.ref = walletconnectCoreDep = { module = "com.walletconnect:android-core" } walletconnectWeb3WalletDep = { module = "com.walletconnect:web3wallet" } -jnr-x86asm = { module = "com.github.jnr:jnr-x86asm:1.0.2" } +jnr-x86asm = { module = "com.github.jnr:jnr-x86asm", version.ref = "jnr-x86asm" } [bundles] compose = [ From efdfdfd8e53d8ec3c2400e2663d2d93a81b4f476 Mon Sep 17 00:00:00 2001 From: Naghme98 Date: Mon, 16 Sep 2024 18:44:54 +0300 Subject: [PATCH 06/10] test --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 054c75361..a72b628b9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -61,7 +61,7 @@ wsVersion = "2.14" xNetworking = "0.2.5-temp7" zxingEmbeddedVersion = "4.3.0" zxingVersion = "3.5.3" -jnr-x86asm = "1.0.2" +jnrVersion = "1.0.2" [libraries] appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } @@ -180,7 +180,7 @@ walletconnectBomDep = { module = "com.walletconnect:android-bom", version.ref = walletconnectCoreDep = { module = "com.walletconnect:android-core" } walletconnectWeb3WalletDep = { module = "com.walletconnect:web3wallet" } -jnr-x86asm = { module = "com.github.jnr:jnr-x86asm", version.ref = "jnr-x86asm" } +jnr-x86asm = { module = "com.github.jnr:jnr-x86asm", version.ref = "jnrVersion" } [bundles] compose = [ From 97898c6d784c37baaef6c586dc69a608cb0cf825 Mon Sep 17 00:00:00 2001 From: Naghme98 Date: Mon, 16 Sep 2024 18:56:40 +0300 Subject: [PATCH 07/10] test --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 729795b5e..d816aaaf4 100644 --- a/build.gradle +++ b/build.gradle @@ -51,8 +51,8 @@ allprojects { google() mavenLocal() maven { url "https://nexus.iroha.tech/repository/maven-soramitsu/" } - maven { url "https://jitpack.io" } mavenCentral() + maven { url "https://jitpack.io" } maven { url = readSecret("PAY_WINGS_REPOSITORY_URL") From a0c156d84eb771613d88f18e99230b91bc5fd26f Mon Sep 17 00:00:00 2001 From: Deneath Date: Wed, 25 Sep 2024 13:24:36 +0700 Subject: [PATCH 08/10] Add remote assets sync service Signed-off-by: Deneath --- .../jp/co/soramitsu/coredb/AppDatabase.kt | 4 +- .../soramitsu/coredb/migrations/Migrations.kt | 6 + .../coredb/model/chain/ChainLocal.kt | 3 +- .../runtime/di/ChainRegistryModule.kt | 8 +- .../co/soramitsu/runtime/di/RuntimeModule.kt | 11 + .../runtime/multiNetwork/ChainRegistry.kt | 4 +- .../multiNetwork/chain/ChainSyncService.kt | 242 ++++++++++-------- .../runtime/multiNetwork/chain/Mappers.kt | 13 +- .../chain/RemoteAssetsSyncService.kt | 34 +++ .../runtime/multiNetwork/chain/model/Chain.kt | 7 +- 10 files changed, 208 insertions(+), 124 deletions(-) create mode 100644 runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/RemoteAssetsSyncService.kt diff --git a/core-db/src/main/java/jp/co/soramitsu/coredb/AppDatabase.kt b/core-db/src/main/java/jp/co/soramitsu/coredb/AppDatabase.kt index c42233216..319c1c4a1 100644 --- a/core-db/src/main/java/jp/co/soramitsu/coredb/AppDatabase.kt +++ b/core-db/src/main/java/jp/co/soramitsu/coredb/AppDatabase.kt @@ -75,6 +75,7 @@ import jp.co.soramitsu.coredb.migrations.Migration_66_67 import jp.co.soramitsu.coredb.migrations.Migration_67_68 import jp.co.soramitsu.coredb.migrations.Migration_68_69 import jp.co.soramitsu.coredb.migrations.Migration_69_70 +import jp.co.soramitsu.coredb.migrations.Migration_70_71 import jp.co.soramitsu.coredb.migrations.RemoveAccountForeignKeyFromAsset_17_18 import jp.co.soramitsu.coredb.migrations.RemoveLegacyData_35_36 import jp.co.soramitsu.coredb.migrations.RemoveStakingRewardsTable_22_23 @@ -103,7 +104,7 @@ import jp.co.soramitsu.coredb.model.chain.FavoriteChainLocal import jp.co.soramitsu.coredb.model.chain.MetaAccountLocal @Database( - version = 70, + version = 71, entities = [ AccountLocal::class, AddressBookContact::class, @@ -197,6 +198,7 @@ abstract class AppDatabase : RoomDatabase() { .addMigrations(Migration_67_68) .addMigrations(Migration_68_69) .addMigrations(Migration_69_70) + .addMigrations(Migration_70_71) .build() } return instance!! diff --git a/core-db/src/main/java/jp/co/soramitsu/coredb/migrations/Migrations.kt b/core-db/src/main/java/jp/co/soramitsu/coredb/migrations/Migrations.kt index 262ae9751..a50a3631e 100644 --- a/core-db/src/main/java/jp/co/soramitsu/coredb/migrations/Migrations.kt +++ b/core-db/src/main/java/jp/co/soramitsu/coredb/migrations/Migrations.kt @@ -3,6 +3,12 @@ package jp.co.soramitsu.coredb.migrations import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase +val Migration_70_71 = object : Migration(70, 71) { + override fun migrate(db: SupportSQLiteDatabase) { + db.execSQL("ALTER TABLE chains ADD COLUMN `remoteAssetsSource` TEXT NULL DEFAULT NULL") + } +} + val Migration_69_70 = object : Migration(69, 70) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL("DELETE FROM storage") diff --git a/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainLocal.kt b/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainLocal.kt index 8741791d3..f982d8928 100644 --- a/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainLocal.kt +++ b/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainLocal.kt @@ -24,7 +24,8 @@ data class ChainLocal( val isChainlinkProvider: Boolean, val supportNft: Boolean, val isUsesAppId: Boolean, - val identityChain: String? + val identityChain: String?, + val remoteAssetsSource: String? ) { class ExternalApi( diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/di/ChainRegistryModule.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/di/ChainRegistryModule.kt index 2f2a359ef..9b857073b 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/di/ChainRegistryModule.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/di/ChainRegistryModule.kt @@ -4,8 +4,6 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import javax.inject.Provider -import javax.inject.Singleton import jp.co.soramitsu.common.data.network.NetworkApiCreator import jp.co.soramitsu.common.data.storage.Preferences import jp.co.soramitsu.common.domain.NetworkStateService @@ -20,6 +18,7 @@ import jp.co.soramitsu.coredb.dao.MetaAccountDao import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry import jp.co.soramitsu.runtime.multiNetwork.chain.ChainSyncService import jp.co.soramitsu.runtime.multiNetwork.chain.ChainsRepository +import jp.co.soramitsu.runtime.multiNetwork.chain.RemoteAssetsSyncServiceProvider import jp.co.soramitsu.runtime.multiNetwork.chain.remote.ChainFetcher import jp.co.soramitsu.runtime.multiNetwork.connection.ConnectionPool import jp.co.soramitsu.runtime.multiNetwork.connection.EthereumConnectionPool @@ -32,6 +31,8 @@ import jp.co.soramitsu.runtime.storage.NodesSettingsStorage import jp.co.soramitsu.shared_utils.wsrpc.SocketService import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.serialization.json.Json +import javax.inject.Provider +import javax.inject.Singleton @InstallIn(SingletonComponent::class) @Module @@ -49,7 +50,8 @@ class ChainRegistryModule { chainFetcher: ChainFetcher, metaAccountDao: MetaAccountDao, assetDao: AssetDao, - ) = ChainSyncService(dao, chainFetcher, metaAccountDao, assetDao) + remoteAssetsSyncServiceProvider: RemoteAssetsSyncServiceProvider + ) = ChainSyncService(dao, chainFetcher, metaAccountDao, assetDao, remoteAssetsSyncServiceProvider) @Provides @Singleton diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/di/RuntimeModule.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/di/RuntimeModule.kt index 02ad3e28e..e4ef55547 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/di/RuntimeModule.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/di/RuntimeModule.kt @@ -10,8 +10,10 @@ import jp.co.soramitsu.core.extrinsic.mortality.IChainStateRepository import jp.co.soramitsu.core.extrinsic.mortality.MortalityConstructor import jp.co.soramitsu.core.rpc.RpcCalls import jp.co.soramitsu.core.storage.StorageCache +import jp.co.soramitsu.coredb.dao.ChainDao import jp.co.soramitsu.coredb.dao.StorageDao import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry +import jp.co.soramitsu.runtime.multiNetwork.chain.RemoteAssetsSyncServiceProvider import jp.co.soramitsu.runtime.repository.ChainStateRepository import jp.co.soramitsu.runtime.storage.DbStorageCache import jp.co.soramitsu.runtime.storage.source.LocalStorageSource @@ -86,4 +88,13 @@ class RuntimeModule { fun provideSubstrateCalls( chainRegistry: ChainRegistry ) = RpcCalls(chainRegistry) + + @Provides + @Singleton + fun provideRemoteAssetsSyncServiceProvider( + //okxApiService: OkxApiService, + chainDao: ChainDao + ): RemoteAssetsSyncServiceProvider { + return RemoteAssetsSyncServiceProvider(/* okxApiService, */chainDao) + } } diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/ChainRegistry.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/ChainRegistry.kt index dc4beaa12..0803d7a61 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/ChainRegistry.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/ChainRegistry.kt @@ -1,7 +1,6 @@ package jp.co.soramitsu.runtime.multiNetwork import android.util.Log -import javax.inject.Inject import jp.co.soramitsu.common.domain.NetworkStateService import jp.co.soramitsu.common.mixin.api.UpdatesMixin import jp.co.soramitsu.common.mixin.api.UpdatesProviderUi @@ -51,6 +50,7 @@ import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import javax.inject.Inject data class ChainService( val runtimeProvider: RuntimeProvider, @@ -118,7 +118,7 @@ class ChainRegistry @Inject constructor( configsSyncDeferred.add(chainSyncDeferred) configsSyncDeferred.add(typesResultDeferred) - val chainsSyncResult = chainSyncDeferred.await() + val chainsSyncResult = kotlin.runCatching { chainSyncDeferred.await() } val typesResult = typesResultDeferred.await() return@withContext if(chainsSyncResult.isSuccess && typesResult.isSuccess) { diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSyncService.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSyncService.kt index da4426621..853db3386 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSyncService.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSyncService.kt @@ -14,142 +14,158 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.withContext class ChainSyncService( private val dao: ChainDao, private val chainFetcher: ChainFetcher, private val metaAccountDao: MetaAccountDao, - private val assetsDao: AssetDao + private val assetsDao: AssetDao, + private val remoteAssetsSyncServiceProvider: RemoteAssetsSyncServiceProvider ) { suspend fun syncUp() = withContext(Dispatchers.Default) { - runCatching { - val localChainsJoinedInfo = dao.getJoinChainInfo() - val localChainsJoinedInfoMap = dao.getJoinChainInfo().associateBy { it.chain.id } + val syncedChainsDeferred = async { configChainsSyncUp() } + val syncedChains = runCatching { syncedChainsDeferred.await() }.onFailure { it.printStackTrace() }.getOrNull() ?: return@withContext - val remoteChains = chainFetcher.getChains() - .filter { - !it.disabled && (it.assets?.isNotEmpty() == true) - } - .map { - it.toChain() + val chainsWithRemoteAssets = syncedChains.filter { it.remoteAssetsSource != null } + + supervisorScope { + chainsWithRemoteAssets.forEach { chain -> + launch { + val service = remoteAssetsSyncServiceProvider.provide(chain) + service?.sync() } - val remoteMapping = remoteChains.associateBy(Chain::id) + } + } + } - val mappedRemoteChains = remoteChains.map { mapChainToChainLocal(it) } - val chainsSyncDeferred = async { - val chainsToUpdate: MutableList = mutableListOf() - val chainsToAdd: MutableList = mutableListOf() - val chainsToRemove = - localChainsJoinedInfo.filter { it.chain.id !in remoteMapping.keys } - .map { it.chain } + private suspend fun configChainsSyncUp() = supervisorScope { + val localChainsJoinedInfo = dao.getJoinChainInfo() + val localChainsJoinedInfoMap = dao.getJoinChainInfo().associateBy { it.chain.id } - mappedRemoteChains.forEach { remoteChainInfo -> - val remoteChain = remoteChainInfo.chain - val localChain = localChainsJoinedInfoMap[remoteChain.id]?.chain + val remoteChains = chainFetcher.getChains() + .filter { + !it.disabled && (it.assets?.isNotEmpty() == true) + } + .map { + it.toChain() + } + val remoteMapping = remoteChains.associateBy(Chain::id) + + val mappedRemoteChains = remoteChains.map { mapChainToChainLocal(it) } + val chainsSyncDeferred = async { + val chainsToUpdate: MutableList = mutableListOf() + val chainsToAdd: MutableList = mutableListOf() + val chainsToRemove = + localChainsJoinedInfo.filter { it.chain.id !in remoteMapping.keys } + .map { it.chain } + + mappedRemoteChains.forEach { remoteChainInfo -> + val remoteChain = remoteChainInfo.chain + val localChain = localChainsJoinedInfoMap[remoteChain.id]?.chain + + when { + localChain == null -> chainsToAdd.add(remoteChain) // new + localChain != remoteChain -> chainsToUpdate.add(remoteChain) // updated + } + } + dao.updateChains(chainsToAdd, chainsToUpdate, chainsToRemove) + } + + chainsSyncDeferred.await() + coroutineScope { + chainsSyncDeferred.join() + launch { + val localAssets = + localChainsJoinedInfo.map { it.assets }.flatten() + val remoteAssets = + mappedRemoteChains.map { it.assets }.flatten() + + val assetsToAdd: MutableList = mutableListOf() + val assetsToUpdate: MutableList = mutableListOf() + val assetsToRemove = + localAssets.filter { local -> + val remoteAssetsIds = remoteAssets.map { it.id to it.chainId } + local.id to local.chainId !in remoteAssetsIds + }.toList() + + remoteAssets.forEach { remoteAsset -> + val localAsset = localAssets.find { it.id == remoteAsset.id && it.chainId == remoteAsset.chainId} when { - localChain == null -> chainsToAdd.add(remoteChain) // new - localChain != remoteChain -> chainsToUpdate.add(remoteChain) // updated + localAsset == null -> { + assetsToAdd.add(remoteAsset) + } // new + localAsset != remoteAsset -> { + assetsToUpdate.add(remoteAsset) + } // updated } } - dao.updateChains(chainsToAdd, chainsToUpdate, chainsToRemove) + dao.updateAssets(assetsToAdd, assetsToUpdate, assetsToRemove) + + val metaAccounts = metaAccountDao.getMetaAccounts() + if(metaAccounts.isEmpty()) return@launch + val newLocalAssets = metaAccounts.map { metaAccount -> + assetsToAdd.mapNotNull { + val chain = remoteMapping[it.chainId] + val accountId = if (chain?.isEthereumBased == true) { + metaAccount.ethereumAddress + } else { + metaAccount.substrateAccountId + } ?: return@mapNotNull null + AssetLocal( + accountId = accountId, + id = it.id, + chainId = it.chainId, + metaId = metaAccount.id, + tokenPriceId = it.priceId, + enabled = false + ) + } + }.flatten() + + assetsDao.insertAssets(newLocalAssets) + assetsDao.deleteAssets(assetsToRemove.map { it.id}) } + launch { + val remoteNodes = mappedRemoteChains.map { it.nodes }.flatten() + val localNodes = localChainsJoinedInfo.map { it.nodes }.flatten() + val nodesToUpdate: MutableList = mutableListOf() + val nodesToAdd: MutableList = mutableListOf() + val nodesToRemove = + localNodes.filter { local -> local.url !in remoteNodes.map { it.url } }.filter { it.isDefault } - chainsSyncDeferred.await() - coroutineScope { - chainsSyncDeferred.join() - launch { - val localAssets = - localChainsJoinedInfo.map { it.assets }.flatten() - val remoteAssets = - mappedRemoteChains.map { it.assets }.flatten() - - val assetsToAdd: MutableList = mutableListOf() - val assetsToUpdate: MutableList = mutableListOf() - val assetsToRemove = - localAssets.filter { local -> - val remoteAssetsIds = remoteAssets.map { it.id to it.chainId } - local.id to local.chainId !in remoteAssetsIds - }.toList() - - remoteAssets.forEach { remoteAsset -> - val localAsset = localAssets.find { it.id == remoteAsset.id && it.chainId == remoteAsset.chainId} - - when { - localAsset == null -> { - assetsToAdd.add(remoteAsset) - } // new - localAsset != remoteAsset -> { - assetsToUpdate.add(remoteAsset) - } // updated - } - } - dao.updateAssets(assetsToAdd, assetsToUpdate, assetsToRemove) - - val metaAccounts = metaAccountDao.getMetaAccounts() - if(metaAccounts.isEmpty()) return@launch - val newLocalAssets = metaAccounts.map { metaAccount -> - assetsToAdd.mapNotNull { - val chain = remoteMapping[it.chainId] - val accountId = if (chain?.isEthereumBased == true) { - metaAccount.ethereumAddress - } else { - metaAccount.substrateAccountId - } ?: return@mapNotNull null - AssetLocal( - accountId = accountId, - id = it.id, - chainId = it.chainId, - metaId = metaAccount.id, - tokenPriceId = it.priceId, - enabled = false - ) - } - }.flatten() - - assetsDao.insertAssets(newLocalAssets) - assetsDao.deleteAssets(assetsToRemove.map { it.id}) - } - launch { - val remoteNodes = mappedRemoteChains.map { it.nodes }.flatten() - val localNodes = localChainsJoinedInfo.map { it.nodes }.flatten() - val nodesToUpdate: MutableList = mutableListOf() - val nodesToAdd: MutableList = mutableListOf() - val nodesToRemove = - localNodes.filter { local -> local.url !in remoteNodes.map { it.url } }.filter { it.isDefault } - - remoteNodes.forEach { remoteNode -> - val localNode = localNodes.find { it.url == remoteNode.url } - - when { - localNode == null -> nodesToAdd.add(remoteNode) // new - localNode != remoteNode -> nodesToUpdate.add(remoteNode) // updated - } + remoteNodes.forEach { remoteNode -> + val localNode = localNodes.find { it.url == remoteNode.url } + + when { + localNode == null -> nodesToAdd.add(remoteNode) // new + localNode != remoteNode -> nodesToUpdate.add(remoteNode) // updated } - dao.updateNodes(nodesToAdd, nodesToUpdate, nodesToRemove) } - launch { - val remoteExplorers = mappedRemoteChains.map { it.explorers }.flatten() - val localExplorers = localChainsJoinedInfo.map { it.explorers }.flatten() - val explorersToUpdate: MutableList = mutableListOf() - val explorersToAdd: MutableList = mutableListOf() - val explorersToRemove = - localExplorers.filter { local -> local.type to local.chainId !in remoteExplorers.map { it.type to it.chainId } } - - remoteExplorers.forEach { remoteExplorer -> - val localExplorer = localExplorers.find { it.chainId == remoteExplorer.chainId && it.type == remoteExplorer.type } - - when { - localExplorer == null -> explorersToAdd.add(remoteExplorer) // new - localExplorer != remoteExplorer -> explorersToUpdate.add(remoteExplorer) // updated - } + dao.updateNodes(nodesToAdd, nodesToUpdate, nodesToRemove) + } + launch { + val remoteExplorers = mappedRemoteChains.map { it.explorers }.flatten() + val localExplorers = localChainsJoinedInfo.map { it.explorers }.flatten() + val explorersToUpdate: MutableList = mutableListOf() + val explorersToAdd: MutableList = mutableListOf() + val explorersToRemove = + localExplorers.filter { local -> local.type to local.chainId !in remoteExplorers.map { it.type to it.chainId } } + + remoteExplorers.forEach { remoteExplorer -> + val localExplorer = localExplorers.find { it.chainId == remoteExplorer.chainId && it.type == remoteExplorer.type } + + when { + localExplorer == null -> explorersToAdd.add(remoteExplorer) // new + localExplorer != remoteExplorer -> explorersToUpdate.add(remoteExplorer) // updated } - dao.updateExplorers(explorersToAdd, explorersToUpdate, explorersToRemove) } + dao.updateExplorers(explorersToAdd, explorersToUpdate, explorersToRemove) } - - }.onFailure { it.printStackTrace() } + remoteChains + } } } diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/Mappers.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/Mappers.kt index 4e0c60f94..8d02e46a3 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/Mappers.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/Mappers.kt @@ -23,6 +23,7 @@ private const val TESTNET_OPTION = "testnet" private const val NOMINATION_POOL_OPTION = "poolStaking" private const val NFT_OPTION = "nft" private const val USES_APP_ID_OPTION = "checkAppId" +private const val REMOTE_ASSETS_OPTION = "remoteAssets" private fun mapSectionTypeRemoteToSectionType(section: String) = when (section) { "subquery" -> Chain.ExternalApi.Section.Type.SUBQUERY @@ -162,7 +163,11 @@ fun ChainRemote.toChain(): Chain { supportNft = NFT_OPTION in optionsOrEmpty, paraId = this.paraId, isUsesAppId = USES_APP_ID_OPTION in optionsOrEmpty, - identityChain = identityChain + identityChain = identityChain, + remoteAssetsSource = when { + REMOTE_ASSETS_OPTION in optionsOrEmpty -> Chain.RemoteAssetsSource.OnChain + else -> null + } ) } @@ -272,7 +277,8 @@ fun mapChainLocalToChain(chainLocal: JoinedChainInfo): Chain { chainlinkProvider = isChainlinkProvider, supportNft = supportNft, isUsesAppId = isUsesAppId, - identityChain = identityChain + identityChain = identityChain, + remoteAssetsSource = remoteAssetsSource?.let { Chain.RemoteAssetsSource.valueOf(it) } ) } } @@ -346,7 +352,8 @@ fun mapChainToChainLocal(chain: Chain): JoinedChainInfo { isChainlinkProvider = chainlinkProvider, supportNft = supportNft, isUsesAppId = isUsesAppId, - identityChain = identityChain + identityChain = identityChain, + remoteAssetsSource = remoteAssetsSource?.name ) } diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/RemoteAssetsSyncService.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/RemoteAssetsSyncService.kt new file mode 100644 index 000000000..5cb80b68f --- /dev/null +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/RemoteAssetsSyncService.kt @@ -0,0 +1,34 @@ +package jp.co.soramitsu.runtime.multiNetwork.chain + +import jp.co.soramitsu.coredb.dao.ChainDao +import jp.co.soramitsu.runtime.multiNetwork.chain.model.Chain + +class RemoteAssetsSyncServiceProvider( + //private val okxApiService: OkxApiService, + private val chainDao: ChainDao +){ + fun provide(chain: Chain): RemoteAssetsSyncService? { + return when { + chain.isEthereumChain && chain.remoteAssetsSource == Chain.RemoteAssetsSource.OKX -> OkxRemoteAssetsSyncService(chain, chainDao) + else -> null + } + } +} + +interface RemoteAssetsSyncService { + suspend fun sync() +} + +class OkxRemoteAssetsSyncService( + //private val okxApiService: OkxApiService, + private val chain: Chain, + private val chainDao: ChainDao +): RemoteAssetsSyncService { + + override suspend fun sync() { + //val assets = okxApiService.getAvailableAssets() + //val chainAssets = assets.map { ChainAssetLocal(id = "", name = "", chainId = chain.id, ...) } + //chainDao.insertChainAssets(chainAssets) + } + +} \ No newline at end of file diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/model/Chain.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/model/Chain.kt index 2943d9816..9f9933b61 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/model/Chain.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/model/Chain.kt @@ -53,7 +53,8 @@ data class Chain( val chainlinkProvider: Boolean, val supportNft: Boolean, val isUsesAppId: Boolean, - val identityChain: String? + val identityChain: String?, + val remoteAssetsSource: RemoteAssetsSource? ) : IChain { val assetsById = assets.associateBy(CoreAsset::id) @@ -87,6 +88,10 @@ data class Chain( } } + enum class RemoteAssetsSource { + OnChain, OKX + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false From b4542f89e1cbf44b7ac31194a9d0c3bf9c99ea05 Mon Sep 17 00:00:00 2001 From: Deneath Date: Thu, 3 Oct 2024 14:14:34 +0700 Subject: [PATCH 09/10] Add new price service Signed-off-by: Deneath --- .../impl/data/repository/PricesSyncService.kt | 166 ++++++++++++++++++ .../data/repository/WalletRepositoryImpl.kt | 129 +------------- .../wallet/impl/di/WalletFeatureModule.kt | 50 +++++- 3 files changed, 217 insertions(+), 128 deletions(-) create mode 100644 feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/PricesSyncService.kt diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/PricesSyncService.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/PricesSyncService.kt new file mode 100644 index 000000000..d0a77dbea --- /dev/null +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/PricesSyncService.kt @@ -0,0 +1,166 @@ +package jp.co.soramitsu.wallet.impl.data.repository + +import android.annotation.SuppressLint +import jp.co.soramitsu.common.data.network.coingecko.CoingeckoApi +import jp.co.soramitsu.common.data.network.coingecko.FiatCurrency +import jp.co.soramitsu.common.data.network.runtime.binding.cast +import jp.co.soramitsu.common.domain.GetAvailableFiatCurrencies +import jp.co.soramitsu.common.domain.SelectedFiat +import jp.co.soramitsu.core.models.Asset.PriceProvider +import jp.co.soramitsu.core.models.Asset.PriceProviderType +import jp.co.soramitsu.coredb.dao.TokenPriceDao +import jp.co.soramitsu.coredb.model.TokenPriceLocal +import jp.co.soramitsu.runtime.multiNetwork.chain.ChainsRepository +import jp.co.soramitsu.runtime.multiNetwork.chain.model.ChainId +import jp.co.soramitsu.wallet.impl.data.network.blockchain.EthereumRemoteSource +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.job +import kotlinx.coroutines.supervisorScope +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext +import java.math.BigDecimal + +class PricesSyncService( + private val tokenPriceDao: TokenPriceDao, + private val coingeckoPricesService: CoingeckoPricesService, + private val chainlinkPricesService: ChainlinkPricesService, + private val selectedFiat: SelectedFiat, + private val availableFiatCurrencies: GetAvailableFiatCurrencies, +) { + + private val syncMutex = Mutex() + private var pricesSyncJob: Job? = null + + @SuppressLint("LogNotTimber") + suspend fun sync() = withContext(Dispatchers.Default) { + syncMutex.withLock { + if (pricesSyncJob?.isCompleted == false && pricesSyncJob?.isCancelled == false) return@withContext + pricesSyncJob?.cancel() + pricesSyncJob = coroutineScope { + val selectedFiat = selectedFiat.get() + val fiatModel = availableFiatCurrencies[selectedFiat] + ?: return@coroutineScope this.coroutineContext.job + + val coingeckoPrices = async { coingeckoPricesService.load(fiatModel) } + + val chainlinkPricesDeferred = async { + val price24hChange = + coingeckoPrices.await().associate { it.priceId to it.recentRateChange } + + .filterValues { it != null }.cast>() + chainlinkPricesService.load(fiatModel, price24hChange) + } + + val allPrices = coingeckoPrices.await() + chainlinkPricesDeferred.await() + tokenPriceDao.insertTokensPrice(allPrices) + + this.coroutineContext.job + } + } + } +} + +// priceId to [ +// currencyId to priceValue, +// currencyId_24h_change to changeValue +// ] +typealias CoingeckoResponse = Map> + +class CoingeckoPricesService( + private val coingeckoApi: CoingeckoApi, + private val chainsRepository: ChainsRepository +) { + companion object { + private const val COINGECKO_REQUEST_DELAY_MILLIS = 60 * 1000 + } + private val cache = mutableMapOf() + private val timestamps = mutableMapOf() + + suspend fun load(currency: FiatCurrency): List { + val allAssets = chainsRepository.getChains().map { it.assets }.flatten() + val priceIds = allAssets.mapNotNull { it.priceId } + + val cacheAlive = System.currentTimeMillis() < (timestamps.getOrDefault(currency.id, 0L) + COINGECKO_REQUEST_DELAY_MILLIS) + val cacheExists = cache[currency.id] != null + val shouldGetFromCache = cacheExists && cacheAlive + + val coingeckoPriceStats = if(shouldGetFromCache) { + requireNotNull(cache[currency.id]) + } else { + coingeckoApi.getAssetPrice(priceIds.joinToString(","), currency.id, true) + .also { + timestamps[currency.id] = System.currentTimeMillis() + cache[currency.id] = it + } + } + + val tokenPrices = priceIds.mapNotNull { priceId -> + val stat = coingeckoPriceStats[priceId] ?: return@mapNotNull null + + val changeKey = "${currency.id}_24h_change" + val change = stat[changeKey] + + TokenPriceLocal(priceId, stat[currency.id], currency.symbol, change) + } + + return tokenPrices + } +} + +class ChainlinkPricesService( + private val ethereumSource: EthereumRemoteSource, + private val chainsRepository: ChainsRepository +) { + suspend fun load( + currency: FiatCurrency, + prices24hChange: Map + ): List { + if (currency.id != "usd") { + return emptyList() + } + val chains = chainsRepository.getChains() + val chainlinkServiceProvider = chains.find { it.chainlinkProvider } ?: return emptyList() + val chainlinkAssets = chains.map { it.assets }.flatten() + .filter { it.priceProvider?.type == PriceProviderType.Chainlink } + + return supervisorScope { + chainlinkAssets.map { asset -> + async { + val priceProvider = asset.priceProvider ?: return@async null + val price = + getChainlinkPrices( + priceProvider = priceProvider, + chainId = chainlinkServiceProvider.id + ) + ?: return@async null + + TokenPriceLocal( + priceProvider.id, + price, + currency.symbol, + prices24hChange.getOrDefault(asset.priceId, null) + ) + } + }.awaitAll().filterNotNull() + } + } + + private suspend fun getChainlinkPrices( + priceProvider: PriceProvider, + chainId: ChainId + ): BigDecimal? { + return runCatching { + ethereumSource.fetchPriceFeed( + chainId = chainId, + receiverAddress = priceProvider.id + )?.let { price -> + BigDecimal(price, priceProvider.precision) + } + }.getOrNull() + } +} \ No newline at end of file diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/WalletRepositoryImpl.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/WalletRepositoryImpl.kt index 0f5638439..6b6643c14 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/WalletRepositoryImpl.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/WalletRepositoryImpl.kt @@ -1,8 +1,6 @@ package jp.co.soramitsu.wallet.impl.data.repository import com.opencsv.CSVReaderHeaderAware -import java.math.BigDecimal -import java.math.BigInteger import jp.co.soramitsu.account.api.domain.interfaces.AccountRepository import jp.co.soramitsu.account.api.domain.model.MetaAccount import jp.co.soramitsu.account.api.domain.model.accountId @@ -16,7 +14,6 @@ import jp.co.soramitsu.common.data.network.runtime.binding.bindString import jp.co.soramitsu.common.data.network.runtime.binding.cast import jp.co.soramitsu.common.data.secrets.v2.KeyPairSchema import jp.co.soramitsu.common.data.secrets.v2.MetaAccountSecrets -import jp.co.soramitsu.common.domain.GetAvailableFiatCurrencies import jp.co.soramitsu.common.mixin.api.UpdatesMixin import jp.co.soramitsu.common.mixin.api.UpdatesProviderUi import jp.co.soramitsu.common.utils.Modules @@ -25,7 +22,6 @@ import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.requireValue import jp.co.soramitsu.common.utils.tokens import jp.co.soramitsu.core.extrinsic.ExtrinsicService -import jp.co.soramitsu.core.models.Asset.PriceProvider import jp.co.soramitsu.core.models.IChain import jp.co.soramitsu.core.runtime.storage.returnType import jp.co.soramitsu.core.utils.utilityAsset @@ -36,7 +32,6 @@ import jp.co.soramitsu.coredb.model.AssetUpdateItem import jp.co.soramitsu.coredb.model.AssetWithToken import jp.co.soramitsu.coredb.model.OperationLocal import jp.co.soramitsu.coredb.model.PhishingLocal -import jp.co.soramitsu.coredb.model.TokenPriceLocal import jp.co.soramitsu.runtime.ext.accountIdOf import jp.co.soramitsu.runtime.ext.addressOf import jp.co.soramitsu.runtime.multiNetwork.ChainRegistry @@ -70,7 +65,6 @@ import jp.co.soramitsu.wallet.impl.domain.model.TransferValidityStatus import jp.co.soramitsu.wallet.impl.domain.model.amountFromPlanks import jp.co.soramitsu.wallet.impl.domain.model.planksFromAmount import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged @@ -79,8 +73,9 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull -import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import java.math.BigDecimal +import java.math.BigInteger import jp.co.soramitsu.core.models.Asset as CoreAsset class WalletRepositoryImpl( @@ -94,13 +89,13 @@ class WalletRepositoryImpl( private val phishingDao: PhishingDao, private val coingeckoApi: CoingeckoApi, private val chainRegistry: ChainRegistry, - private val availableFiatCurrencies: GetAvailableFiatCurrencies, private val updatesMixin: UpdatesMixin, private val remoteConfigFetcher: RemoteConfigFetcher, private val accountRepository: AccountRepository, private val chainsRepository: ChainsRepository, private val extrinsicService: ExtrinsicService, - private val remoteStorageSource: StorageDataSource + private val remoteStorageSource: StorageDataSource, + private val pricesSyncService: PricesSyncService ) : WalletRepository, UpdatesProviderUi by updatesMixin { companion object { @@ -155,97 +150,7 @@ class WalletRepositoryImpl( } override suspend fun syncAssetsRates(currencyId: String) { - val chains = chainsRepository.getChains() - syncAllRates(chains, currencyId) - } - - private suspend fun syncAllRates(chains: List, currencyId: String) { - val priceIdsWithChainlinkId = chains.map { - it.assets.mapNotNull { asset -> - asset.priceId?.let { priceId -> - priceId to if (asset.priceProvider?.isSupported == true) { - asset.priceProvider?.id - } else { - null - } - } - } - }.flatten().toSet() - - val priceIds = priceIdsWithChainlinkId.map { it.first } - val chainlinkProviderIds = priceIdsWithChainlinkId.mapNotNull { it.second } - val allPriceIds = (priceIds + chainlinkProviderIds).toSet() - - updatesMixin.startUpdateTokens(allPriceIds) - - var coingeckoPriceStats: Map> = emptyMap() - var chainlinkPrices: Map = emptyMap() - - coroutineScope { - launch { - coingeckoPriceStats = - getAssetPriceCoingecko(*priceIds.toTypedArray(), currencyId = currencyId) - } - launch { - chainlinkPrices = if (currencyId == "usd") { - getChainlinkPrices(chains) - } else { - emptyMap() - } - } - }.join() - - val newPrices = priceIdsWithChainlinkId.mapNotNull { (priceId, chainlinkId) -> - val stat = coingeckoPriceStats[priceId] ?: return@mapNotNull null - - val changeKey = "${currencyId}_24h_change" - val change = stat[changeKey] - val fiatCurrency = availableFiatCurrencies[currencyId] - - listOf( - TokenPriceLocal(priceId, stat[currencyId], fiatCurrency?.symbol, change), - chainlinkId?.let { - TokenPriceLocal( - chainlinkId, - chainlinkPrices[chainlinkId], - fiatCurrency?.symbol, - change - ) - } - ) - }.flatten().filterNotNull() - assetCache.updateTokensPrice(newPrices) - updatesMixin.finishUpdateTokens(allPriceIds) - } - - private suspend fun getChainlinkPrices(chains: List): Map { - val chainlinkProvider = chains.firstOrNull { it.chainlinkProvider } ?: return emptyMap() - - val allAssets = - chains.map { it.assets }.flatten().asSequence().filter { it.priceProvider?.isSupported == true } - .toList() - - return allAssets.mapNotNull { - val priceProvider = it.priceProvider ?: return@mapNotNull null - val price = - getChainlinkPrices(priceProvider = priceProvider, chainId = chainlinkProvider.id) - ?: return@mapNotNull null - priceProvider.id to price - }.toMap() - } - - private suspend fun getChainlinkPrices( - priceProvider: PriceProvider, - chainId: ChainId - ): BigDecimal? { - return runCatching { - ethereumSource.fetchPriceFeed( - chainId = chainId, - receiverAddress = priceProvider.id - )?.let { price -> - BigDecimal(price, priceProvider.precision) - } - }.getOrNull() + pricesSyncService.sync() } override fun assetFlow( @@ -496,23 +401,6 @@ class WalletRepositoryImpl( source = source ) - private suspend fun updateAssetRates( - priceId: String, - fiatSymbol: String?, - price: BigDecimal?, - change: BigDecimal? - ) = assetCache.updateTokenPrice(priceId) { cached -> - cached.copy( - fiatRate = price, - fiatSymbol = fiatSymbol, - recentRateChange = change - ) - } - - private suspend fun updateAssetsRates( - items: List - ) = assetCache.updateTokensPrice(items) - override suspend fun getSingleAssetPriceCoingecko( priceId: String, currency: String @@ -535,13 +423,6 @@ class WalletRepositoryImpl( return apiValue } - private suspend fun getAssetPriceCoingecko( - vararg priceId: String, - currencyId: String - ): Map> { - return apiCall { coingeckoApi.getAssetPrice(priceId.joinToString(","), currencyId, true) } - } - private suspend fun apiCall(block: suspend () -> T): T = httpExceptionHandler.wrap(block) override suspend fun getRemoteConfig(): Result { diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/di/WalletFeatureModule.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/di/WalletFeatureModule.kt index cbfe74da3..34d4f47eb 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/di/WalletFeatureModule.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/di/WalletFeatureModule.kt @@ -64,7 +64,10 @@ import jp.co.soramitsu.wallet.impl.data.network.blockchain.updaters.BalancesUpda import jp.co.soramitsu.wallet.impl.data.network.phishing.PhishingApi import jp.co.soramitsu.wallet.impl.data.network.subquery.OperationsHistoryApi import jp.co.soramitsu.wallet.impl.data.repository.AddressBookRepositoryImpl +import jp.co.soramitsu.wallet.impl.data.repository.ChainlinkPricesService +import jp.co.soramitsu.wallet.impl.data.repository.CoingeckoPricesService import jp.co.soramitsu.wallet.impl.data.repository.HistoryRepository +import jp.co.soramitsu.wallet.impl.data.repository.PricesSyncService import jp.co.soramitsu.wallet.impl.data.repository.RuntimeWalletConstants import jp.co.soramitsu.wallet.impl.data.repository.TokenRepositoryImpl import jp.co.soramitsu.wallet.impl.data.repository.WalletRepositoryImpl @@ -172,14 +175,14 @@ class WalletFeatureModule { assetCache: AssetCache, coingeckoApi: CoingeckoApi, chainRegistry: ChainRegistry, - availableFiatCurrencies: GetAvailableFiatCurrencies, updatesMixin: UpdatesMixin, remoteConfigFetcher: RemoteConfigFetcher, accountRepository: AccountRepository, chainsRepository: ChainsRepository, extrinsicService: ExtrinsicService, @Named(REMOTE_STORAGE_SOURCE) - remoteStorageSource: StorageDataSource + remoteStorageSource: StorageDataSource, + pricesSyncService: PricesSyncService ): WalletRepository = WalletRepositoryImpl( substrateSource, ethereumRemoteSource, @@ -191,13 +194,13 @@ class WalletFeatureModule { phishingDao, coingeckoApi, chainRegistry, - availableFiatCurrencies, updatesMixin, remoteConfigFetcher, accountRepository, chainsRepository, extrinsicService, - remoteStorageSource + remoteStorageSource, + pricesSyncService ) @Provides @@ -495,4 +498,43 @@ class WalletFeatureModule { interactor: AccountInteractor, addressIconGenerator: AddressIconGenerator ): AccountListingMixin = AccountListingProvider(interactor, addressIconGenerator) + + @Provides + @Singleton + fun provideCoingeckoPricesService( + coingeckoApi: CoingeckoApi, + chainsRepository: ChainsRepository + ): CoingeckoPricesService { + return CoingeckoPricesService( + coingeckoApi, + chainsRepository + ) + } + + @Provides + @Singleton + fun provideChainlinkPricesService( + ethereumSource: EthereumRemoteSource, + chainsRepository: ChainsRepository + ): ChainlinkPricesService { + return ChainlinkPricesService(ethereumSource, chainsRepository) + } + + @Provides + @Singleton + fun providePricesSyncService( + tokenPriceDao: TokenPriceDao, + coingeckoPricesService: CoingeckoPricesService, + chainlinkPricesService: ChainlinkPricesService, + selectedFiat: SelectedFiat, + availableFiatCurrencies: GetAvailableFiatCurrencies, + ): PricesSyncService { + return PricesSyncService( + tokenPriceDao, + coingeckoPricesService, + chainlinkPricesService, + selectedFiat, + availableFiatCurrencies + ) + } } From c71dab5fca938c3dc1e46846d298233cdb04bdac Mon Sep 17 00:00:00 2001 From: Faimi the Legend Zufarov Date: Wed, 9 Oct 2024 15:51:28 +0500 Subject: [PATCH 10/10] MWR-951 Replaced StartActivityForResult to PickVisualMedia --- .../soramitsu/common/scan/ScannerActivity.kt | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/common/src/main/java/jp/co/soramitsu/common/scan/ScannerActivity.kt b/common/src/main/java/jp/co/soramitsu/common/scan/ScannerActivity.kt index b8acd819e..19dcc4587 100644 --- a/common/src/main/java/jp/co/soramitsu/common/scan/ScannerActivity.kt +++ b/common/src/main/java/jp/co/soramitsu/common/scan/ScannerActivity.kt @@ -1,12 +1,12 @@ package jp.co.soramitsu.common.scan -import android.app.Activity import android.content.Intent import android.graphics.Color +import android.net.Uri import android.os.Bundle import android.view.KeyEvent -import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.LiveData @@ -24,21 +24,16 @@ import jp.co.soramitsu.common.utils.EventObserver @AndroidEntryPoint class ScannerActivity : AppCompatActivity() { - companion object { - private const val QR_CODE_IMAGE_TYPE = "image/*" - } @Inject lateinit var viewModel: ScannerViewModel private var capture: CaptureManager? = null - private val startForResultFromGallery: ActivityResultLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> - if (result.resultCode == Activity.RESULT_OK) { - result.data?.data?.let { selectedImageUri -> - viewModel.qrFileChosen(selectedImageUri) - } + private val startForResultFromGallery: ActivityResultLauncher = + registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { resultUri: Uri? -> + resultUri?.let { selectedImageUri -> + viewModel.qrFileChosen(selectedImageUri) } } @@ -89,11 +84,9 @@ class ScannerActivity : AppCompatActivity() { } private fun selectQrFromGallery() { - val intent = Intent().apply { - type = QR_CODE_IMAGE_TYPE - action = Intent.ACTION_GET_CONTENT - } - startForResultFromGallery.launch(intent) + val pickVisualMediaRequest = + PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly) + startForResultFromGallery.launch(pickVisualMediaRequest) } inline fun LiveData>.observeEvent(crossinline observer: (V) -> Unit) {