From 428c0bb09d107fa7163fd44df5b89c05e2bf4423 Mon Sep 17 00:00:00 2001 From: Aleksey Kazakov Date: Thu, 30 Nov 2023 17:59:37 +0300 Subject: [PATCH 01/35] turn off checks switch to test jenkins library branch --- Jenkinsfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 28a32a5f6a..75270da343 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('jenkins-library') +@Library('jenkins-library@feature/2890/upload-android-app-to-nexus') // Job properties def jobParams = [ @@ -7,7 +7,9 @@ def jobParams = [ def pipeline = new org.android.AppPipeline( steps: this, - sonar: true, + sonar: false, + test: false, + dojo: false, sonarCommand: './gradlew sonar -x :core-db:compileDebugUnitTestKotlin -x :core-db:compileDebugAndroidTestKotlin -x :feature-crowdloan-impl:compileDebugAndroidTestKotlin -x :runtime:compileDebugUnitTestKotlin -x :app:kaptDebugAndroidTestKotlin -x :app:compileDebugAndroidTestKotlin -Dsonar.coverage.jacoco.xmlReportPaths=**/coverage/*.xml', sonarProjectName: 'fearless-android', sonarProjectKey: 'fearless:fearless-android', From f0ca9bb8e92fd9b6e152ee8214d277d068dcd98f Mon Sep 17 00:00:00 2001 From: Aleksey Kazakov Date: Fri, 8 Dec 2023 15:05:31 +0300 Subject: [PATCH 02/35] add param upload_to_nexus --- Jenkinsfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 75270da343..54003b4b6a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,6 +3,7 @@ // Job properties def jobParams = [ booleanParam(defaultValue: false, description: 'push to the dev profile', name: 'prDeployment'), + booleanParam(defaultValue: false, description: 'Upload builds to nexus(master branches upload always)', name: 'upload_to_nexus'), ] def pipeline = new org.android.AppPipeline( @@ -19,6 +20,7 @@ def pipeline = new org.android.AppPipeline( publishCmd: 'publishReleaseApk', jobParams: jobParams, appPushNoti: true, - dojoProductType: 'android' + dojoProductType: 'android', + uploadToNexusFor: ['master','develop','stage'], ) pipeline.runPipeline('fearless') From ce395715cae349617f92deb5aa596ddb6a5eeb89 Mon Sep 17 00:00:00 2001 From: Aleksey Kazakov Date: Tue, 16 Jan 2024 13:59:11 +0300 Subject: [PATCH 03/35] return tests --- Jenkinsfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 54003b4b6a..30f578d4c7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,8 +9,6 @@ def jobParams = [ def pipeline = new org.android.AppPipeline( steps: this, sonar: false, - test: false, - dojo: false, sonarCommand: './gradlew sonar -x :core-db:compileDebugUnitTestKotlin -x :core-db:compileDebugAndroidTestKotlin -x :feature-crowdloan-impl:compileDebugAndroidTestKotlin -x :runtime:compileDebugUnitTestKotlin -x :app:kaptDebugAndroidTestKotlin -x :app:compileDebugAndroidTestKotlin -Dsonar.coverage.jacoco.xmlReportPaths=**/coverage/*.xml', sonarProjectName: 'fearless-android', sonarProjectKey: 'fearless:fearless-android', @@ -21,6 +19,6 @@ def pipeline = new org.android.AppPipeline( jobParams: jobParams, appPushNoti: true, dojoProductType: 'android', - uploadToNexusFor: ['master','develop','stage'], + uploadToNexusFor: ['master','develop','staging'] ) pipeline.runPipeline('fearless') From 62bd7d10aa041a3018533ab71be96a3382abcea0 Mon Sep 17 00:00:00 2001 From: Aleksey Kazakov Date: Tue, 16 Jan 2024 14:27:37 +0300 Subject: [PATCH 04/35] add sonar test --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 30f578d4c7..757d0c0839 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,12 +3,12 @@ // Job properties def jobParams = [ booleanParam(defaultValue: false, description: 'push to the dev profile', name: 'prDeployment'), - booleanParam(defaultValue: false, description: 'Upload builds to nexus(master branches upload always)', name: 'upload_to_nexus'), + booleanParam(defaultValue: false, description: 'Upload builds to nexus(master,develop and staging branches upload always)', name: 'upload_to_nexus'), ] def pipeline = new org.android.AppPipeline( steps: this, - sonar: false, + sonar: true, sonarCommand: './gradlew sonar -x :core-db:compileDebugUnitTestKotlin -x :core-db:compileDebugAndroidTestKotlin -x :feature-crowdloan-impl:compileDebugAndroidTestKotlin -x :runtime:compileDebugUnitTestKotlin -x :app:kaptDebugAndroidTestKotlin -x :app:compileDebugAndroidTestKotlin -Dsonar.coverage.jacoco.xmlReportPaths=**/coverage/*.xml', sonarProjectName: 'fearless-android', sonarProjectKey: 'fearless:fearless-android', From 2f546751fd7b6adec5948af6513ee2c7e2fabe3e Mon Sep 17 00:00:00 2001 From: Aleksey Kazakov Date: Thu, 18 Jan 2024 14:03:10 +0300 Subject: [PATCH 05/35] switch back on master branch for jenkins lib --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 757d0c0839..ae1e104dfb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('jenkins-library@feature/2890/upload-android-app-to-nexus') +@Library('jenkins-library') // Job properties def jobParams = [ @@ -21,4 +21,4 @@ def pipeline = new org.android.AppPipeline( dojoProductType: 'android', uploadToNexusFor: ['master','develop','staging'] ) -pipeline.runPipeline('fearless') +pipeline.runPipeline('fearless') \ No newline at end of file From ba2d9a527203e5fdce865dcbff5bb3d43bb6617a Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Tue, 6 Feb 2024 18:00:53 +0500 Subject: [PATCH 06/35] chainlink --- build.gradle | 4 +- .../jp/co/soramitsu/coredb/dao/Helpers.kt | 12 ++- .../jp/co/soramitsu/coredb/AppDatabase.kt | 4 +- .../co/soramitsu/coredb/dao/TokenPriceDao.kt | 3 + .../soramitsu/coredb/migrations/Migrations.kt | 34 +++++++++ .../coredb/model/chain/ChainAssetLocal.kt | 5 +- .../coredb/model/chain/ChainLocal.kt | 3 +- .../interfaces/AssetNotNeedAccountUseCase.kt | 1 - .../domain/AssetNotNeedAccountUseCaseImpl.kt | 6 +- .../details/AccountDetailsViewModel.kt | 16 +--- .../rewards/SoraStakingRewardsScenario.kt | 2 +- .../wallet/api/data/cache/AssetCache.kt | 35 ++++++--- .../domain/interfaces/WalletInteractor.kt | 2 - .../domain/interfaces/WalletRepository.kt | 2 - .../impl/domain/model/BuyTokenRegistry.kt | 2 +- feature-wallet-impl/build.gradle | 2 + .../blockchain/EthereumRemoteSource.kt | 54 +++++++++++++ .../data/repository/TokenRepositoryImpl.kt | 6 +- .../data/repository/WalletRepositoryImpl.kt | 76 +++++++++++++++---- .../wallet/impl/di/WalletFeatureModule.kt | 5 +- .../wallet/impl/domain/ChainInteractor.kt | 6 +- .../impl/domain/WalletInteractorImpl.kt | 4 - .../balance/list/BalanceListViewModel.kt | 2 +- .../list/model/BalanceListItemModel.kt | 2 +- gradle/libs.versions.toml | 2 +- .../runtime/multiNetwork/ChainRegistry.kt | 2 +- .../runtime/multiNetwork/chain/Mappers.kt | 27 +++++-- .../runtime/multiNetwork/chain/model/Chain.kt | 11 ++- .../chain/remote/model/ChainAssetRemote.kt | 5 +- .../multiNetwork/connection/ConnectionPool.kt | 2 +- .../chain/ChainSyncServiceTest.kt | 3 +- 31 files changed, 254 insertions(+), 86 deletions(-) diff --git a/build.gradle b/build.gradle index bc64dc3901..ddda60abe4 100644 --- a/build.gradle +++ b/build.gradle @@ -83,7 +83,7 @@ buildscript { minifyRelease = true beaconVersion = "3.2.4" - sharedFeaturesVersion = "1.1.1.20-FLW" + sharedFeaturesVersion = "1.1.1.22-FLW" coilDep = "io.coil-kt:coil:$coilVersion" coilSvg = "io.coil-kt:coil-svg:$coilVersion" @@ -207,6 +207,8 @@ buildscript { sharedFeaturesBackupDep = "jp.co.soramitsu.shared_features:backup:$sharedFeaturesVersion" web3jDep = "org.web3j:core:4.8.8-android" + web3jContractsDep = "org.web3j:contracts:4.8.8-android" + web3jGethDep = "org.web3j:geth:4.8.8-android" withoutJavaWS = { exclude module: 'java-websocket-lib' } diff --git a/core-db/src/androidTest/java/jp/co/soramitsu/coredb/dao/Helpers.kt b/core-db/src/androidTest/java/jp/co/soramitsu/coredb/dao/Helpers.kt index 54bd810cd3..6eab1eb513 100644 --- a/core-db/src/androidTest/java/jp/co/soramitsu/coredb/dao/Helpers.kt +++ b/core-db/src/androidTest/java/jp/co/soramitsu/coredb/dao/Helpers.kt @@ -40,7 +40,11 @@ fun chainOf( externalApi = null, hasCrowdloans = false, minSupportedVersion = "2.0.3", - supportStakingPool = false + supportStakingPool = false, + isEthereumChain = false, + paraId = null, + rank = null, + isChainlinkProvider = false ) fun ChainLocal.nodeOf( @@ -64,14 +68,16 @@ fun ChainLocal.assetOf( priceId = null, staking = "test", icon = "", - priceProviders = null, + purchaseProviders = null, symbol = symbol, isUtility = null, type = null, currencyId = null, existentialDeposit = null, color = null, - isNative = null + isNative = null, + ethereumType = null, + priceProvider = null ) suspend fun ChainDao.addChain(joinedChainInfo: JoinedChainInfo) { 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 45459e8db2..2940ee74e0 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 @@ -63,6 +63,7 @@ import jp.co.soramitsu.coredb.migrations.Migration_56_57 import jp.co.soramitsu.coredb.migrations.Migration_57_58 import jp.co.soramitsu.coredb.migrations.Migration_58_59 import jp.co.soramitsu.coredb.migrations.Migration_59_60 +import jp.co.soramitsu.coredb.migrations.Migration_60_61 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 @@ -88,7 +89,7 @@ import jp.co.soramitsu.coredb.model.chain.FavoriteChainLocal import jp.co.soramitsu.coredb.model.chain.MetaAccountLocal @Database( - version = 60, + version = 61, entities = [ AccountLocal::class, AddressBookContact::class, @@ -169,6 +170,7 @@ abstract class AppDatabase : RoomDatabase() { .addMigrations(Migration_57_58) .addMigrations(Migration_58_59) .addMigrations(Migration_59_60) + .addMigrations(Migration_60_61) .build() } return instance!! diff --git a/core-db/src/main/java/jp/co/soramitsu/coredb/dao/TokenPriceDao.kt b/core-db/src/main/java/jp/co/soramitsu/coredb/dao/TokenPriceDao.kt index 445b7b4372..5b4eab0d4a 100644 --- a/core-db/src/main/java/jp/co/soramitsu/coredb/dao/TokenPriceDao.kt +++ b/core-db/src/main/java/jp/co/soramitsu/coredb/dao/TokenPriceDao.kt @@ -22,6 +22,9 @@ abstract class TokenPriceDao { @Insert(onConflict = OnConflictStrategy.REPLACE) abstract suspend fun insertTokenPrice(token: TokenPriceLocal) + @Insert(onConflict = OnConflictStrategy.REPLACE) + abstract suspend fun insertTokensPrice(tokens: List) + @Insert(onConflict = OnConflictStrategy.IGNORE) abstract suspend fun insertTokenPriceOrIgnore(token: TokenPriceLocal) 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 3b871a1ab8..5b83d10592 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,40 @@ package jp.co.soramitsu.coredb.migrations import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase +val Migration_60_61 = object : Migration(60, 61) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE chains ADD COLUMN `isChainlinkProvider` INTEGER NOT NULL DEFAULT 0") + + database.execSQL("DROP TABLE IF EXISTS chain_assets") + + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS `chain_assets` ( + `id` TEXT NOT NULL, + `name` TEXT, + `symbol` TEXT NOT NULL, + `chainId` TEXT NOT NULL, + `icon` TEXT NOT NULL, + `priceId` TEXT, + `staking` TEXT NOT NULL, + `precision` INTEGER NOT NULL, + `purchaseProviders` TEXT, + `isUtility` INTEGER, + `type` TEXT, + `currencyId` TEXT, + `existentialDeposit` TEXT, + `color` TEXT, + `isNative` INTEGER, + `ethereumType` TEXT DEFAULT NULL, + `priceProvider` TEXT, + PRIMARY KEY(`chainId`, `id`), + FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE ) + """.trimIndent() + ) + database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_assets_chainId` ON `chain_assets` (`chainId`)") + } +} + val Migration_59_60 = object : Migration(59, 60) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE chains ADD COLUMN `paraId` TEXT NULL") diff --git a/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainAssetLocal.kt b/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainAssetLocal.kt index efed568351..df010a5c4c 100644 --- a/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainAssetLocal.kt +++ b/core-db/src/main/java/jp/co/soramitsu/coredb/model/chain/ChainAssetLocal.kt @@ -28,12 +28,13 @@ data class ChainAssetLocal( val priceId: String?, val staking: String, val precision: Int, - val priceProviders: String?, + val purchaseProviders: String?, val isUtility: Boolean?, val type: String?, val currencyId: String?, val existentialDeposit: String?, val color: String?, val isNative: Boolean?, - val ethereumType: String? + val ethereumType: String?, + val priceProvider: String? ) 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 cc297c4e51..e886b1075b 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 @@ -20,7 +20,8 @@ class ChainLocal( val isTestNet: Boolean, val hasCrowdloans: Boolean, val supportStakingPool: Boolean, - val isEthereumChain: Boolean + val isEthereumChain: Boolean, + val isChainlinkProvider: Boolean ) { class ExternalApi( diff --git a/feature-account-api/src/main/java/jp/co/soramitsu/account/api/domain/interfaces/AssetNotNeedAccountUseCase.kt b/feature-account-api/src/main/java/jp/co/soramitsu/account/api/domain/interfaces/AssetNotNeedAccountUseCase.kt index 23b169570d..ab3df4da98 100644 --- a/feature-account-api/src/main/java/jp/co/soramitsu/account/api/domain/interfaces/AssetNotNeedAccountUseCase.kt +++ b/feature-account-api/src/main/java/jp/co/soramitsu/account/api/domain/interfaces/AssetNotNeedAccountUseCase.kt @@ -9,7 +9,6 @@ interface AssetNotNeedAccountUseCase { * Mark asset without account - as correct, no need of account * used in lists sort */ - suspend fun markNotNeed(chainId: ChainId, metaId: Long, assetId: String, priceId: String?) suspend fun markChainAssetsNotNeed(chainId: ChainId, metaId: Long) /** diff --git a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/domain/AssetNotNeedAccountUseCaseImpl.kt b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/domain/AssetNotNeedAccountUseCaseImpl.kt index 6faaa72030..fb9cb2bf0c 100644 --- a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/domain/AssetNotNeedAccountUseCaseImpl.kt +++ b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/domain/AssetNotNeedAccountUseCaseImpl.kt @@ -17,14 +17,10 @@ class AssetNotNeedAccountUseCaseImpl( private val tokenPriceDao: TokenPriceDao ) : AssetNotNeedAccountUseCase { - override suspend fun markNotNeed(chainId: ChainId, metaId: Long, assetId: String, priceId: String?) { - updateAssetNotNeed(metaId, chainId, assetId, priceId) - } - override suspend fun markChainAssetsNotNeed(chainId: ChainId, metaId: Long) { val chainAssets = chainRegistry.getChain(chainId).assets chainAssets.forEach { - updateAssetNotNeed(metaId, chainId, it.id, it.priceId) + updateAssetNotNeed(metaId, chainId, it.id, it.priceProvider?.id ?: it.priceId) } } diff --git a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/account/details/AccountDetailsViewModel.kt b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/account/details/AccountDetailsViewModel.kt index 97f5404b98..0ba2c7e5a7 100644 --- a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/account/details/AccountDetailsViewModel.kt +++ b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/account/details/AccountDetailsViewModel.kt @@ -256,7 +256,7 @@ class AccountDetailsViewModel @Inject constructor( chainId = item.chainId, chainName = item.chainName, assetId = utilityAsset?.id.orEmpty(), - priceId = utilityAsset?.priceId, + priceId = utilityAsset?.priceProvider?.id ?: utilityAsset?.priceId, markedAsNotNeed = item.markedAsNotNeed ) accountRouter.openOptionsAddAccount(payload) @@ -277,18 +277,4 @@ class AccountDetailsViewModel @Inject constructor( fun updateAppClicked() { _openPlayMarket.value = Event(Unit) } - - fun createAccount(chainId: ChainId, metaId: Long) { - accountRouter.openOnboardingNavGraph(chainId = chainId, metaId = metaId, isImport = false) - } - - fun importAccount(chainId: ChainId, metaId: Long) { - accountRouter.openOnboardingNavGraph(chainId = chainId, metaId = metaId, isImport = true) - } - - fun noNeedAccount(chainId: ChainId, metaId: Long, assetId: String, priceId: String?) { - launch { - assetNotNeedAccount.markNotNeed(chainId = chainId, metaId = metaId, assetId = assetId, priceId = priceId) - } - } } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SoraStakingRewardsScenario.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SoraStakingRewardsScenario.kt index 7617aba743..e3f714a1d7 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SoraStakingRewardsScenario.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SoraStakingRewardsScenario.kt @@ -37,7 +37,7 @@ class SoraStakingRewardsScenario( suspend fun getRewardAsset(): Token { val chain = chainRegistry.getChain(SORA_MAIN_NET_CHAIN_ID) val rewardAsset = requireNotNull(chain.assetsById[REWARD_ASSET_ID]) - val priceId = requireNotNull(rewardAsset.priceId) + val priceId = requireNotNull(rewardAsset.priceProvider?.id ?: rewardAsset.priceId) val token = tokenDao.getTokenPrice(priceId) return Token( diff --git a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/data/cache/AssetCache.kt b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/data/cache/AssetCache.kt index 219699b8a6..c9cd697550 100644 --- a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/data/cache/AssetCache.kt +++ b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/data/cache/AssetCache.kt @@ -1,6 +1,7 @@ package jp.co.soramitsu.wallet.api.data.cache import jp.co.soramitsu.account.api.domain.interfaces.AccountRepository +import jp.co.soramitsu.common.domain.SelectedFiat import jp.co.soramitsu.common.mixin.api.UpdatesMixin import jp.co.soramitsu.common.mixin.api.UpdatesProviderUi import jp.co.soramitsu.core.models.Asset @@ -21,7 +22,8 @@ class AssetCache( private val tokenPriceDao: TokenPriceDao, private val accountRepository: AccountRepository, private val assetDao: AssetDao, - private val updatesMixin: UpdatesMixin + private val updatesMixin: UpdatesMixin, + private val selectedFiat: SelectedFiat ) : AssetReadOnlyCache by assetDao, UpdatesProviderUi by updatesMixin { @@ -35,7 +37,12 @@ class AssetCache( ) = withContext(Dispatchers.IO) { val chainId = chainAsset.chainId val assetId = chainAsset.id - val priceId = chainAsset.priceId + val shouldUseChainlinkForRates = selectedFiat.get() == "usd" && chainAsset.priceProvider?.id != null + val priceId = if (shouldUseChainlinkForRates) { + chainAsset.priceProvider?.id + } else { + chainAsset.priceId + } assetUpdateMutex.withLock { priceId?.let { tokenPriceDao.ensureTokenPrice(it) } @@ -56,26 +63,27 @@ class AssetCache( cachedAsset.accountId.contentEquals(emptyAccountIdValue) -> { assetDao.deleteAsset(metaId, emptyAccountIdValue, chainId, assetId) - assetDao.insertAsset(builder.invoke(cachedAsset.copy(accountId = accountId))) + assetDao.insertAsset(builder.invoke(cachedAsset.copy(accountId = accountId, tokenPriceId = priceId))) } else -> { - val updatedAsset = builder.invoke(cachedAsset) + val updatedAsset = builder.invoke(cachedAsset.copy(tokenPriceId = priceId)) if (cachedAsset.bondedInPlanks == updatedAsset.bondedInPlanks && cachedAsset.feeFrozenInPlanks == updatedAsset.feeFrozenInPlanks && cachedAsset.miscFrozenInPlanks == updatedAsset.miscFrozenInPlanks && cachedAsset.freeInPlanks == updatedAsset.freeInPlanks && cachedAsset.redeemableInPlanks == updatedAsset.redeemableInPlanks && cachedAsset.reservedInPlanks == updatedAsset.reservedInPlanks && - cachedAsset.unbondingInPlanks == updatedAsset.unbondingInPlanks + cachedAsset.unbondingInPlanks == updatedAsset.unbondingInPlanks && + cachedAsset.tokenPriceId == updatedAsset.tokenPriceId ) { return@withLock } assetDao.updateAsset(updatedAsset) } } - updatesMixin.finishUpdateAsset(metaId, chainId, accountId, assetId) } + updatesMixin.finishUpdateAsset(metaId, chainId, accountId, assetId) } suspend fun updateAsset( @@ -90,18 +98,21 @@ class AssetCache( } } + suspend fun updateTokensPrice( + update: List + ) = withContext(Dispatchers.IO) { + tokenPriceDao.insertTokensPrice(update) + } + suspend fun updateTokenPrice( priceId: String, builder: (local: TokenPriceLocal) -> TokenPriceLocal ) = withContext(Dispatchers.IO) { - assetUpdateMutex.withLock { - val tokenPriceLocal = - tokenPriceDao.getTokenPrice(priceId) ?: TokenPriceLocal.createEmpty(priceId) + val tokenPriceLocal = tokenPriceDao.getTokenPrice(priceId) ?: TokenPriceLocal.createEmpty(priceId) - val newToken = builder.invoke(tokenPriceLocal) + val newToken = builder.invoke(tokenPriceLocal) - tokenPriceDao.insertTokenPrice(newToken) - } + tokenPriceDao.insertTokenPrice(newToken) } suspend fun updateAsset(updateModel: List) { diff --git a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletInteractor.kt b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletInteractor.kt index 0d33b5778a..59f75fb54a 100644 --- a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletInteractor.kt +++ b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletInteractor.kt @@ -105,8 +105,6 @@ interface WalletInteractor { suspend fun getChainAddressForSelectedMetaAccount(chainId: ChainId): String? - suspend fun updateAssets(newItems: List) - suspend fun markAssetAsHidden(chainId: ChainId, chainAssetId: String) suspend fun markAssetAsShown(chainId: ChainId, chainAssetId: String) diff --git a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletRepository.kt b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletRepository.kt index cff7198fe0..18c62e8d6f 100644 --- a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletRepository.kt +++ b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/interfaces/WalletRepository.kt @@ -95,8 +95,6 @@ interface WalletRepository { suspend fun getEquilibriumAccountInfo(asset: CoreAsset, accountId: AccountId): EqAccountInfo? - suspend fun updateAssets(newItems: List) - suspend fun getRemoteConfig(): Result fun chainRegistrySyncUp() diff --git a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/model/BuyTokenRegistry.kt b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/model/BuyTokenRegistry.kt index e4c539a311..6e42482cfb 100644 --- a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/model/BuyTokenRegistry.kt +++ b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/impl/domain/model/BuyTokenRegistry.kt @@ -15,7 +15,7 @@ class BuyTokenRegistry(val availableProviders: List>) { @get:DrawableRes val icon: Int - fun isTokenSupported(chainAsset: CoreAsset) = name.lowercase() in chainAsset.priceProviders.orEmpty() + fun isTokenSupported(chainAsset: CoreAsset) = name.lowercase() in chainAsset.purchaseProviders.orEmpty() fun createIntegrator(chainAsset: CoreAsset, address: String): I } diff --git a/feature-wallet-impl/build.gradle b/feature-wallet-impl/build.gradle index 8192ef6605..2d8907d2ee 100644 --- a/feature-wallet-impl/build.gradle +++ b/feature-wallet-impl/build.gradle @@ -140,4 +140,6 @@ dependencies { implementation sharedFeaturesBackupDep implementation web3jDep + implementation web3jContractsDep +// implementation web3jGethDep } \ No newline at end of file diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/EthereumRemoteSource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/EthereumRemoteSource.kt index bc4ed8337a..f77b56dc51 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/EthereumRemoteSource.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/EthereumRemoteSource.kt @@ -25,9 +25,13 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.withContext import kotlinx.coroutines.yield +import org.web3j.abi.DefaultFunctionReturnDecoder import org.web3j.abi.FunctionEncoder +import org.web3j.abi.TypeReference import org.web3j.abi.datatypes.Address import org.web3j.abi.datatypes.Function +import org.web3j.abi.datatypes.generated.Int256 +import org.web3j.abi.datatypes.generated.Uint80 import org.web3j.crypto.Credentials import org.web3j.crypto.RawTransaction import org.web3j.crypto.TransactionEncoder @@ -137,6 +141,18 @@ class EthereumRemoteSource(private val ethereumConnectionPool: EthereumConnectio return web3.fetchEthBalance(asset, address) } + suspend fun fetchPriceFeed( + chainId: ChainId, + receiverAddress: String + ): BigInteger? { + val connection = ethereumConnectionPool.get(chainId) + connection?.connect() + + val web3 = connection?.web3j ?: return null + + return web3.fetchPriceFeed(receiverAddress) + } + private suspend fun Ethereum.fetchEthBalance(asset: Asset, address: String): BigInteger { return if (asset.isUtility) { withContext(Dispatchers.IO) { @@ -167,6 +183,44 @@ class EthereumRemoteSource(private val ethereumConnectionPool: EthereumConnectio } } + private suspend fun Ethereum.fetchPriceFeed(address: String): BigInteger? { + val outParameters = listOf( + Uint80::class.java, + Int256::class.java, + Int256::class.java, + Int256::class.java, + Uint80::class.java + ).map { + TypeReference.create(it) + } + + val latestRoundDataFunction = Function( + "latestRoundData", + emptyList(), + outParameters + ) + + val latestRoundData = withContext(Dispatchers.IO) { + kotlin.runCatching { + ethCall( + Transaction.createEthCallTransaction( + null, + Address(address).value, + latestRoundDataFunction.encode() + ), + DefaultBlockParameterName.LATEST + ).send().value + }.getOrNull() + } + + val decodeResult = DefaultFunctionReturnDecoder.decode( + latestRoundData, + latestRoundDataFunction.outputParameters + ) + + return decodeResult[1].value as? BigInteger + } + fun listenGas(transfer: Transfer, chain: Chain): Flow { val connection = requireNotNull(ethereumConnectionPool.get(chain.id)) val web3j = requireNotNull(connection.web3j) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/TokenRepositoryImpl.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/TokenRepositoryImpl.kt index 7b8fcd99d8..b23776dd2f 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/TokenRepositoryImpl.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/TokenRepositoryImpl.kt @@ -17,13 +17,15 @@ class TokenRepositoryImpl( ) : TokenRepository { override suspend fun getToken(chainAsset: Asset): Token = withContext(Dispatchers.Default) { - val tokenPriceLocal = chainAsset.priceId?.let { tokenPriceDao.getTokenPrice(it) ?: TokenPriceLocal.createEmpty(it) } + val priceId = chainAsset.priceProvider?.id ?: chainAsset.priceId + val tokenPriceLocal = priceId?.let { tokenPriceDao.getTokenPrice(it) ?: TokenPriceLocal.createEmpty(it) } combineAssetWithPrices(chainAsset, tokenPriceLocal) } override fun observeToken(chainAsset: Asset): Flow { - return when (val priceId = chainAsset.priceId) { + val priceId = chainAsset.priceProvider?.id ?: chainAsset.priceId + return when (priceId) { null -> flowOf { combineAssetWithPrices(chainAsset, null) } 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 de96091cc0..4f48e9b46d 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 @@ -20,6 +20,7 @@ import jp.co.soramitsu.common.mixin.api.UpdatesMixin import jp.co.soramitsu.common.mixin.api.UpdatesProviderUi import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.requireValue +import jp.co.soramitsu.core.models.Asset.PriceProvider import jp.co.soramitsu.core.utils.utilityAsset import jp.co.soramitsu.coredb.dao.OperationDao import jp.co.soramitsu.coredb.dao.PhishingDao @@ -28,6 +29,7 @@ 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 @@ -151,14 +153,15 @@ class WalletRepositoryImpl( private fun buildNetworkIssues(items: List): Set { return items.map { + val configuration = it.asset.token.configuration NetworkIssueItemState( - iconUrl = it.asset.token.configuration.iconUrl, - title = "${it.asset.token.configuration.chainName} ${it.asset.token.configuration.name}", + iconUrl = configuration.iconUrl, + title = "${configuration.chainName} ${configuration.name}", type = NetworkIssueType.Node, - chainId = it.asset.token.configuration.chainId, - chainName = it.asset.token.configuration.chainName, - assetId = it.asset.token.configuration.id, - priceId = it.asset.token.configuration.priceId + chainId = configuration.chainId, + chainName = configuration.chainName, + assetId = configuration.id, + priceId = configuration.priceProvider?.id ?: configuration.priceId ) }.toSet() } @@ -189,13 +192,51 @@ class WalletRepositoryImpl( override suspend fun syncAssetsRates(currencyId: String) { val chains = chainsRepository.getChains() + if (currencyId == "usd") { + syncChainlinkRates(chains) + } + syncCoingeckoRates(chains, currencyId) + } + + private suspend fun syncChainlinkRates(chains: List) { + val chainlinkIds = chains.map { it.assets.mapNotNull { it.priceProvider?.id } }.flatten().toSet() + + val chainlinkProvider = chains.firstOrNull { it.chainlinkProvider } + val chainlinkProviderId = chainlinkProvider?.id + println("!!! chainlinkProvider is ${chainlinkProvider?.name} $chainlinkProviderId ") + + val chainlinkTokens = chainlinkIds.map { priceId -> + val assetConfig = chains.flatMap { it.assets }.firstOrNull { it.priceProvider?.id == priceId } + val priceProvider = assetConfig?.priceProvider + + val price = if (chainlinkProviderId != null && priceProvider != null) { + getChainlinkPrices(priceProvider = priceProvider, chainId = chainlinkProviderId) + } else { + null + } + val usdCurrency = availableFiatCurrencies["usd"] + + TokenPriceLocal( + priceId = priceId, + fiatRate = price, + fiatSymbol = usdCurrency?.symbol, + recentRateChange = null + ) + } + + updatesMixin.startUpdateTokens(chainlinkIds) + updateAssetsRates(chainlinkTokens) + updatesMixin.finishUpdateTokens(chainlinkIds) + } + + private suspend fun syncCoingeckoRates(chains: List, currencyId: String) { val priceIds = chains.map { it.assets.mapNotNull { it.priceId } }.flatten().toSet() - val priceStats = getAssetPriceCoingecko(*priceIds.toTypedArray(), currencyId = currencyId) + val coingeckoPriceStats = getAssetPriceCoingecko(*priceIds.toTypedArray(), currencyId = currencyId) updatesMixin.startUpdateTokens(priceIds) priceIds.forEach { priceId -> - val stat = priceStats[priceId] ?: return@forEach + val stat = coingeckoPriceStats[priceId] ?: return@forEach val price = stat[currencyId] val changeKey = "${currencyId}_24h_change" val change = stat[changeKey] @@ -206,6 +247,15 @@ class WalletRepositoryImpl( updatesMixin.finishUpdateTokens(priceIds) } + private suspend fun getChainlinkPrices(priceProvider: PriceProvider, chainId: ChainId): BigDecimal? { + return ethereumSource.fetchPriceFeed( + chainId = chainId, + receiverAddress = priceProvider.id + )?.let { price -> + BigDecimal(price, priceProvider.precision) + } + } + override fun assetFlow( metaId: Long, accountId: AccountId, @@ -243,7 +293,7 @@ class WalletRepositoryImpl( id = chainAsset.id, sortIndex = Int.MAX_VALUE, // Int.MAX_VALUE on sorting because we don't use it anymore - just random value enabled = !isHidden, - tokenPriceId = chainAsset.priceId + tokenPriceId = chainAsset.priceProvider?.id ?: chainAsset.priceId ) ) @@ -441,10 +491,6 @@ class WalletRepositoryImpl( override suspend fun getEquilibriumAccountInfo(asset: CoreAsset, accountId: AccountId) = substrateSource.getEquilibriumAccountInfo(asset, accountId) - override suspend fun updateAssets(newItems: List) { - assetCache.updateAsset(newItems) - } - private fun createOperation( hash: String, transfer: Transfer, @@ -479,6 +525,10 @@ class WalletRepositoryImpl( ) } + private suspend fun updateAssetsRates( + items: List + ) = assetCache.updateTokensPrice(items) + override suspend fun getSingleAssetPriceCoingecko( priceId: String, currency: String 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 9ba651da32..0493cfb4a9 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 @@ -113,9 +113,10 @@ class WalletFeatureModule { tokenPriceDao: TokenPriceDao, assetDao: AssetDao, accountRepository: AccountRepository, - updatesMixin: UpdatesMixin + updatesMixin: UpdatesMixin, + selectedFiat: SelectedFiat ): AssetCache { - return AssetCache(tokenPriceDao, accountRepository, assetDao, updatesMixin) + return AssetCache(tokenPriceDao, accountRepository, assetDao, updatesMixin, selectedFiat) } @Provides diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/ChainInteractor.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/ChainInteractor.kt index 556e309cf3..3f8f3921e5 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/ChainInteractor.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/ChainInteractor.kt @@ -6,6 +6,7 @@ import jp.co.soramitsu.core.models.ChainAssetType import jp.co.soramitsu.core.models.ChainId import jp.co.soramitsu.coredb.dao.ChainDao import jp.co.soramitsu.runtime.multiNetwork.chain.mapChainLocalToChain +import jp.co.soramitsu.runtime.multiNetwork.chain.mapToPriceProvider import jp.co.soramitsu.runtime.multiNetwork.chain.model.Chain import jp.co.soramitsu.runtime.multiNetwork.chain.model.polkadotChainId import jp.co.soramitsu.wallet.api.domain.model.XcmChainType @@ -37,7 +38,7 @@ class ChainInteractor( priceId = it.priceId, precision = it.precision, staking = Asset.StakingType.UNSUPPORTED, - priceProviders = emptyList(), + purchaseProviders = emptyList(), chainName = "", chainIcon = it.icon, isTestNet = false, @@ -47,7 +48,8 @@ class ChainInteractor( currencyId = it.currencyId, existentialDeposit = it.existentialDeposit, color = it.color, - isNative = it.isNative + isNative = it.isNative, + priceProvider = mapToPriceProvider(it.priceProvider) ) } } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/WalletInteractorImpl.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/WalletInteractorImpl.kt index 9969afd203..a3e37f2840 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/WalletInteractorImpl.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/domain/WalletInteractorImpl.kt @@ -413,10 +413,6 @@ class WalletInteractorImpl( } } - override suspend fun updateAssets(newItems: List) { - walletRepository.updateAssets(newItems) - } - private fun mapAccountToWalletAccount(chain: Chain, account: MetaAccount) = with(account) { WalletAccount(account.address(chain)!!, name) } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/BalanceListViewModel.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/BalanceListViewModel.kt index a2940ff0e2..2987bf8b50 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/BalanceListViewModel.kt @@ -273,7 +273,7 @@ class BalanceListViewModel @Inject constructor( chainAssetId = chainAsset.id, isSupported = true, isHidden = false, - priceId = chainAsset.priceId, + priceId = chainAsset.priceProvider?.id ?: chainAsset.priceId, isTestnet = chainAsset.isTestNet ?: false ) }.filter { selectedChainId.value == null || selectedChainId.value == it.chainId } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/model/BalanceListItemModel.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/model/BalanceListItemModel.kt index 156c598727..633836a960 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/model/BalanceListItemModel.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/model/BalanceListItemModel.kt @@ -36,6 +36,6 @@ fun BalanceListItemModel.toAssetState(index: Int? = null) = AssetListItemViewSta chainAssetId = asset.id, isSupported = chain?.isSupported != false, isHidden = isHidden, - priceId = asset.priceId, + priceId = asset.priceProvider?.id ?: asset.priceId, isTestnet = chain?.isTestNet == true ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e186b8eb5b..6e08840bf7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ detekt = "1.23.0" kotlin = "1.8.10" dagger = "2.47" android_plugin = "7.4.2" -sharedFeaturesVersion = "1.1.1.20-FLW" +sharedFeaturesVersion = "1.1.1.22-FLW" web3j = "4.8.8-android" walletconnectBom = "1.18.0" coilVersion = "2.2.2" 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 7c1efda9c9..bdc62e31d6 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 @@ -267,6 +267,6 @@ fun Chain.toSyncIssue(): NetworkIssueItemState { chainId = this.id, chainName = this.name, assetId = this.utilityAsset?.id.orEmpty(), - priceId = this.utilityAsset?.priceId + priceId = this.utilityAsset?.priceProvider?.id ?: this.utilityAsset?.priceId ) } 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 9bc190bc94..3a45f66853 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 @@ -5,6 +5,7 @@ import com.google.gson.reflect.TypeToken import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.core.models.ChainAssetType import jp.co.soramitsu.core.models.ChainNode +import jp.co.soramitsu.core.runtime.mappers.mapRemoteToModel import jp.co.soramitsu.coredb.model.chain.ChainAssetLocal import jp.co.soramitsu.coredb.model.chain.ChainExplorerLocal import jp.co.soramitsu.coredb.model.chain.ChainLocal @@ -16,6 +17,7 @@ import jp.co.soramitsu.runtime.multiNetwork.chain.remote.model.ChainRemote private const val ETHEREUM_BASED_OPTION = "ethereumBased" private const val ETHEREUM_OPTION = "ethereum" +private const val CHAINLINK_PROVIDER_OPTION = "chainlinkProvider" private const val CROWDLOAN_OPTION = "crowdloans" private const val TESTNET_OPTION = "testnet" private const val NOMINATION_POOL_OPTION = "poolStaking" @@ -146,6 +148,7 @@ fun ChainRemote.toChain(): Chain { hasCrowdloans = CROWDLOAN_OPTION in optionsOrEmpty, supportStakingPool = NOMINATION_POOL_OPTION in optionsOrEmpty, isEthereumChain = ETHEREUM_OPTION in optionsOrEmpty, + chainlinkProvider = CHAINLINK_PROVIDER_OPTION in optionsOrEmpty, paraId = this.paraId ) } @@ -166,7 +169,7 @@ private fun ChainRemote.assetConfigs(): List? { priceId = chainAsset.priceId, precision = chainAsset.precision ?: DEFAULT_PRECISION, staking = mapStakingStringToStakingType(chainAsset.staking), - priceProviders = chainAsset.purchaseProviders, + purchaseProviders = chainAsset.purchaseProviders, supportStakingPool = NOMINATION_POOL_OPTION in this.options.orEmpty(), isUtility = chainAsset.isUtility ?: false, type = ChainAssetType.from(chainAsset.type), @@ -174,7 +177,8 @@ private fun ChainRemote.assetConfigs(): List? { existentialDeposit = chainAsset.existentialDeposit, color = chainAsset.color, isNative = chainAsset.isNative, - ethereumType = mapEthereumTypeStringToEthereumType(chainAsset.ethereumType) + ethereumType = mapEthereumTypeStringToEthereumType(chainAsset.ethereumType), + priceProvider = chainAsset.priceProvider?.mapRemoteToModel() ) } }.getOrNull() @@ -201,7 +205,7 @@ fun mapChainLocalToChain(chainLocal: JoinedChainInfo): Chain { priceId = it.priceId, precision = it.precision, staking = mapStakingTypeFromLocal(it.staking), - priceProviders = mapToList(it.priceProviders), + purchaseProviders = mapToList(it.purchaseProviders), chainName = chainLocal.chain.name, chainIcon = chainLocal.chain.icon, isTestNet = chainLocal.chain.isTestNet, @@ -212,7 +216,8 @@ fun mapChainLocalToChain(chainLocal: JoinedChainInfo): Chain { existentialDeposit = it.existentialDeposit, color = it.color, isNative = it.isNative, - ethereumType = mapEthereumTypeStringToEthereumType(it.ethereumType) + ethereumType = mapEthereumTypeStringToEthereumType(it.ethereumType), + priceProvider = mapToPriceProvider(it.priceProvider) ) } @@ -250,7 +255,8 @@ fun mapChainLocalToChain(chainLocal: JoinedChainInfo): Chain { hasCrowdloans = hasCrowdloans, supportStakingPool = supportStakingPool, isEthereumChain = isEthereumChain, - paraId = paraId + paraId = paraId, + chainlinkProvider = isChainlinkProvider ) } } @@ -276,14 +282,15 @@ fun mapChainToChainLocal(chain: Chain): JoinedChainInfo { chainId = chain.id, priceId = it.priceId, staking = mapStakingTypeToLocal(it.staking), - priceProviders = it.priceProviders?.let { Gson().toJson(it) }, + purchaseProviders = it.purchaseProviders?.let { Gson().toJson(it) }, isUtility = it.isUtility, type = it.type?.name, currencyId = it.currencyId, existentialDeposit = it.existentialDeposit, color = it.color, isNative = it.isNative, - ethereumType = mapEthereumTypeToLocal(it.ethereumType) + ethereumType = mapEthereumTypeToLocal(it.ethereumType), + priceProvider = it.priceProvider?.let { Gson().toJson(it) } ) } @@ -319,7 +326,8 @@ fun mapChainToChainLocal(chain: Chain): JoinedChainInfo { hasCrowdloans = hasCrowdloans, supportStakingPool = supportStakingPool, isEthereumChain = isEthereumChain, - paraId = paraId + paraId = paraId, + isChainlinkProvider = chainlinkProvider ) } @@ -333,3 +341,6 @@ fun mapChainToChainLocal(chain: Chain): JoinedChainInfo { private fun mapToList(json: String?) = json?.let { Gson().fromJson>(it, object : TypeToken>() {}.type) } + +fun mapToPriceProvider(json: String?) = + json?.let { Gson().fromJson(it, object : TypeToken() {}.type) } \ 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 6f97706acb..2525a91b85 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 @@ -49,7 +49,8 @@ data class Chain( val hasCrowdloans: Boolean, override val parentId: String?, val supportStakingPool: Boolean, - val isEthereumChain: Boolean + val isEthereumChain: Boolean, + val chainlinkProvider: Boolean, ) : IChain { val assetsById = assets.associateBy(CoreAsset::id) @@ -85,6 +86,7 @@ data class Chain( other as Chain if (id != other.id) return false + if (paraId != other.paraId) return false if (rank != other.rank) return false if (name != other.name) return false if (minSupportedVersion != other.minSupportedVersion) return false @@ -97,6 +99,9 @@ data class Chain( if (isTestNet != other.isTestNet) return false if (hasCrowdloans != other.hasCrowdloans) return false if (parentId != other.parentId) return false + if (supportStakingPool != other.supportStakingPool) return false + if (isEthereumChain != other.isEthereumChain) return false + if (chainlinkProvider != other.chainlinkProvider) return false // custom comparison logic val defaultNodes = nodes.filter { it.isDefault } @@ -111,6 +116,7 @@ data class Chain( override fun hashCode(): Int { var result = id.hashCode() + result = 31 * result + (paraId?.hashCode() ?: 0) result = 31 * result + (rank?.hashCode() ?: 0) result = 31 * result + name.hashCode() result = 31 * result + (minSupportedVersion?.hashCode() ?: 0) @@ -124,6 +130,9 @@ data class Chain( result = 31 * result + isTestNet.hashCode() result = 31 * result + hasCrowdloans.hashCode() result = 31 * result + (parentId?.hashCode() ?: 0) + result = 31 * result + supportStakingPool.hashCode() + result = 31 * result + isEthereumChain.hashCode() + result = 31 * result + chainlinkProvider.hashCode() return result } } diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/remote/model/ChainAssetRemote.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/remote/model/ChainAssetRemote.kt index 8b8bef0b83..04942ed29e 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/remote/model/ChainAssetRemote.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/remote/model/ChainAssetRemote.kt @@ -1,5 +1,7 @@ package jp.co.soramitsu.runtime.multiNetwork.chain.remote.model +import jp.co.soramitsu.core.models.remote.PriceProvider + class ChainAssetRemote( val id: String?, val name: String?, @@ -15,5 +17,6 @@ class ChainAssetRemote( val staking: String?, val purchaseProviders: List?, val type: String?, - val ethereumType: String? + val ethereumType: String?, + val priceProvider: PriceProvider? ) diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/connection/ConnectionPool.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/connection/ConnectionPool.kt index f072056b39..fe122221f2 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/connection/ConnectionPool.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/connection/ConnectionPool.kt @@ -71,7 +71,7 @@ class ConnectionPool @Inject constructor( chainId = chain.id, chainName = chain.name, assetId = chain.utilityAsset?.id.orEmpty(), - priceId = chain.utilityAsset?.priceId + priceId = chain.utilityAsset?.priceProvider?.id ?: chain.utilityAsset?.priceId ) } issues diff --git a/runtime/src/test/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSyncServiceTest.kt b/runtime/src/test/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSyncServiceTest.kt index e22b8558a5..0fdbd7427e 100644 --- a/runtime/src/test/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSyncServiceTest.kt +++ b/runtime/src/test/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSyncServiceTest.kt @@ -41,7 +41,8 @@ class ChainSyncServiceTest { existentialDeposit = null, color = null, isNative = null, - ethereumType = null + ethereumType = null, + priceProvider = null ) ), nodes = listOf( From 94925f89c3e52d8e8f0393cd819c067bee55756a Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Tue, 6 Feb 2024 22:47:41 +0500 Subject: [PATCH 07/35] chainlink, usd only check --- app/build.gradle | 1 - .../app/root/navigation/Navigator.kt | 4 +- build.gradle | 2 - .../common/compose/component/AssetListItem.kt | 1 - .../compose/component/NetworkIssueItem.kt | 3 +- .../common/compose/component/SwipeBox.kt | 1 - .../viewstate/AssetListItemViewState.kt | 1 - .../soramitsu/common/domain/SelectedFiat.kt | 1 + .../actions/AddAccountBottomSheet.kt | 49 ------------------- .../presentation/actions/AddAccountPayload.kt | 14 ++++++ .../account/impl/di/AccountFeatureModule.kt | 5 +- .../domain/AssetNotNeedAccountUseCaseImpl.kt | 7 ++- .../impl/presentation/AccountRouter.kt | 4 +- .../details/AccountDetailsViewModel.kt | 6 +-- .../OptionsAddAccountContent.kt | 6 +-- .../OptionsAddAccountFragment.kt | 4 +- .../OptionsAddAccountViewModel.kt | 10 ++-- .../staking/impl/di/StakingFeatureModule.kt | 5 +- .../rewards/SoraStakingRewardsScenario.kt | 9 ++-- .../wallet/api/data/cache/AssetCache.kt | 2 +- feature-wallet-impl/build.gradle | 2 - .../data/repository/TokenRepositoryImpl.kt | 30 +++++++++--- .../data/repository/WalletRepositoryImpl.kt | 11 +++-- .../wallet/impl/di/WalletFeatureModule.kt | 12 +++-- .../wallet/impl/presentation/WalletRouter.kt | 4 +- .../balance/list/BalanceListViewModel.kt | 1 - .../presentation/balance/list/WalletScreen.kt | 1 - .../list/model/BalanceListItemModel.kt | 1 - .../networkissues/NetworkIssuesViewModel.kt | 6 +-- .../runtime/multiNetwork/ChainRegistry.kt | 3 +- .../multiNetwork/connection/ConnectionPool.kt | 3 +- 31 files changed, 91 insertions(+), 118 deletions(-) delete mode 100644 feature-account-api/src/main/java/jp/co/soramitsu/account/api/presentation/actions/AddAccountBottomSheet.kt create mode 100644 feature-account-api/src/main/java/jp/co/soramitsu/account/api/presentation/actions/AddAccountPayload.kt diff --git a/app/build.gradle b/app/build.gradle index 583bd8f5c7..9fde9d42a9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -196,7 +196,6 @@ dependencies { implementation lifeCycleKtxDep -// implementation retrofitDep implementation gsonConvertedDep implementation gifDep diff --git a/app/src/main/java/jp/co/soramitsu/app/root/navigation/Navigator.kt b/app/src/main/java/jp/co/soramitsu/app/root/navigation/Navigator.kt index 030143d015..5e27d07cd3 100644 --- a/app/src/main/java/jp/co/soramitsu/app/root/navigation/Navigator.kt +++ b/app/src/main/java/jp/co/soramitsu/app/root/navigation/Navigator.kt @@ -19,7 +19,7 @@ import it.airgap.beaconsdk.blockchain.substrate.data.SubstrateSignerPayload import java.math.BigDecimal import jp.co.soramitsu.account.api.domain.model.ImportMode import jp.co.soramitsu.account.api.presentation.account.create.ChainAccountCreatePayload -import jp.co.soramitsu.account.api.presentation.actions.AddAccountBottomSheet +import jp.co.soramitsu.account.api.presentation.actions.AddAccountPayload import jp.co.soramitsu.account.api.presentation.create_backup_password.CreateBackupPasswordPayload import jp.co.soramitsu.account.impl.domain.account.details.AccountInChain import jp.co.soramitsu.account.impl.presentation.AccountRouter @@ -1279,7 +1279,7 @@ class Navigator : navController?.navigate(R.id.networkIssuesFragment) } - override fun openOptionsAddAccount(payload: AddAccountBottomSheet.Payload) { + override fun openOptionsAddAccount(payload: AddAccountPayload) { val bundle = OptionsAddAccountFragment.getBundle(payload) navController?.navigate(R.id.optionsAddAccountFragment, bundle) } diff --git a/build.gradle b/build.gradle index ddda60abe4..1278b446c0 100644 --- a/build.gradle +++ b/build.gradle @@ -207,8 +207,6 @@ buildscript { sharedFeaturesBackupDep = "jp.co.soramitsu.shared_features:backup:$sharedFeaturesVersion" web3jDep = "org.web3j:core:4.8.8-android" - web3jContractsDep = "org.web3j:contracts:4.8.8-android" - web3jGethDep = "org.web3j:geth:4.8.8-android" withoutJavaWS = { exclude module: 'java-websocket-lib' } diff --git a/common/src/main/java/jp/co/soramitsu/common/compose/component/AssetListItem.kt b/common/src/main/java/jp/co/soramitsu/common/compose/component/AssetListItem.kt index 38cfb96bfa..e71d7986bf 100644 --- a/common/src/main/java/jp/co/soramitsu/common/compose/component/AssetListItem.kt +++ b/common/src/main/java/jp/co/soramitsu/common/compose/component/AssetListItem.kt @@ -351,7 +351,6 @@ private fun PreviewAssetListItem() { chainAssetId = "", isSupported = true, isHidden = false, - priceId = null, isTestnet = false ) FearlessAppTheme { diff --git a/common/src/main/java/jp/co/soramitsu/common/compose/component/NetworkIssueItem.kt b/common/src/main/java/jp/co/soramitsu/common/compose/component/NetworkIssueItem.kt index 19c3bbc376..1f7f949e80 100644 --- a/common/src/main/java/jp/co/soramitsu/common/compose/component/NetworkIssueItem.kt +++ b/common/src/main/java/jp/co/soramitsu/common/compose/component/NetworkIssueItem.kt @@ -58,8 +58,7 @@ data class NetworkIssueItemState( val chainId: String, val chainName: String, - val assetId: String, - val priceId: String? = null + val assetId: String ) { override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/common/src/main/java/jp/co/soramitsu/common/compose/component/SwipeBox.kt b/common/src/main/java/jp/co/soramitsu/common/compose/component/SwipeBox.kt index 22c1d066cd..58258f02d8 100644 --- a/common/src/main/java/jp/co/soramitsu/common/compose/component/SwipeBox.kt +++ b/common/src/main/java/jp/co/soramitsu/common/compose/component/SwipeBox.kt @@ -175,7 +175,6 @@ private fun AssetItemSwipeBoxPreview() { chainAssetId = "", isSupported = true, isHidden = false, - priceId = null, isTestnet = false ) diff --git a/common/src/main/java/jp/co/soramitsu/common/compose/viewstate/AssetListItemViewState.kt b/common/src/main/java/jp/co/soramitsu/common/compose/viewstate/AssetListItemViewState.kt index 76b549d632..f1ee3f5c66 100644 --- a/common/src/main/java/jp/co/soramitsu/common/compose/viewstate/AssetListItemViewState.kt +++ b/common/src/main/java/jp/co/soramitsu/common/compose/viewstate/AssetListItemViewState.kt @@ -15,7 +15,6 @@ data class AssetListItemViewState( val chainAssetId: String, val isSupported: Boolean, val isHidden: Boolean, - val priceId: String?, val isTestnet: Boolean ) { val key = listOf(index ?: 0, chainAssetId, chainId, isHidden).joinToString() diff --git a/common/src/main/java/jp/co/soramitsu/common/domain/SelectedFiat.kt b/common/src/main/java/jp/co/soramitsu/common/domain/SelectedFiat.kt index 75d870673c..55baf11ec3 100644 --- a/common/src/main/java/jp/co/soramitsu/common/domain/SelectedFiat.kt +++ b/common/src/main/java/jp/co/soramitsu/common/domain/SelectedFiat.kt @@ -9,6 +9,7 @@ private const val DEFAULT_SELECTED_FIAT = "usd" class SelectedFiat(private val preferences: Preferences) { fun flow() = preferences.stringFlow(SELECTED_FIAT_KEY) { get() }.filterNotNull() fun get() = preferences.getString(SELECTED_FIAT_KEY, DEFAULT_SELECTED_FIAT) + fun isUsd() = get() == DEFAULT_SELECTED_FIAT fun set(value: String) { preferences.putString(SELECTED_FIAT_KEY, value) diff --git a/feature-account-api/src/main/java/jp/co/soramitsu/account/api/presentation/actions/AddAccountBottomSheet.kt b/feature-account-api/src/main/java/jp/co/soramitsu/account/api/presentation/actions/AddAccountBottomSheet.kt deleted file mode 100644 index c76b4172aa..0000000000 --- a/feature-account-api/src/main/java/jp/co/soramitsu/account/api/presentation/actions/AddAccountBottomSheet.kt +++ /dev/null @@ -1,49 +0,0 @@ -package jp.co.soramitsu.account.api.presentation.actions - -import android.content.Context -import android.os.Bundle -import android.os.Parcelable -import jp.co.soramitsu.common.R -import jp.co.soramitsu.common.view.bottomSheet.list.fixed.FixedListBottomSheet -import jp.co.soramitsu.common.view.bottomSheet.list.fixed.textItem -import jp.co.soramitsu.runtime.multiNetwork.chain.model.ChainId -import kotlinx.parcelize.Parcelize - -class AddAccountBottomSheet( - context: Context, - private val payload: Payload, - private val onCreate: (chainId: ChainId, metaId: Long) -> Unit, - private val onImport: (chainId: ChainId, metaId: Long) -> Unit, - private val onNoNeed: (chainId: ChainId, metaId: Long, assetId: String, priceId: String?) -> Unit -) : FixedListBottomSheet(context) { - - @Parcelize - data class Payload( - val metaId: Long, - val chainId: ChainId, - val chainName: String, - val assetId: String, - val priceId: String?, - val markedAsNotNeed: Boolean - ) : Parcelable - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setTitle(context.getString(R.string.account_template, payload.chainName)) - - textItem(R.string.create_new_account) { - onCreate(payload.chainId, payload.metaId) - } - - textItem(R.string.already_have_account) { - onImport(payload.chainId, payload.metaId) - } - - if (!payload.markedAsNotNeed) { - textItem(R.string.i_dont_need_account) { - onNoNeed(payload.chainId, payload.metaId, payload.assetId, payload.priceId) - } - } - } -} diff --git a/feature-account-api/src/main/java/jp/co/soramitsu/account/api/presentation/actions/AddAccountPayload.kt b/feature-account-api/src/main/java/jp/co/soramitsu/account/api/presentation/actions/AddAccountPayload.kt new file mode 100644 index 0000000000..e36903340f --- /dev/null +++ b/feature-account-api/src/main/java/jp/co/soramitsu/account/api/presentation/actions/AddAccountPayload.kt @@ -0,0 +1,14 @@ +package jp.co.soramitsu.account.api.presentation.actions + +import android.os.Parcelable +import jp.co.soramitsu.runtime.multiNetwork.chain.model.ChainId +import kotlinx.parcelize.Parcelize + +@Parcelize +data class AddAccountPayload( + val metaId: Long, + val chainId: ChainId, + val chainName: String, + val assetId: String, + val markedAsNotNeed: Boolean +) : Parcelable \ No newline at end of file diff --git a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/di/AccountFeatureModule.kt b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/di/AccountFeatureModule.kt index 68de31b86c..330e80ab2d 100644 --- a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/di/AccountFeatureModule.kt +++ b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/di/AccountFeatureModule.kt @@ -203,9 +203,10 @@ class AccountFeatureModule { fun provideAssetNotNeedAccountUseCase( chainRegistry: ChainRegistry, assetDao: AssetDao, - tokenPriceDao: TokenPriceDao + tokenPriceDao: TokenPriceDao, + selectedFiat: SelectedFiat ): AssetNotNeedAccountUseCase { - return AssetNotNeedAccountUseCaseImpl(chainRegistry, assetDao, tokenPriceDao) + return AssetNotNeedAccountUseCaseImpl(chainRegistry, assetDao, tokenPriceDao, selectedFiat) } @Provides diff --git a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/domain/AssetNotNeedAccountUseCaseImpl.kt b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/domain/AssetNotNeedAccountUseCaseImpl.kt index fb9cb2bf0c..eec8285647 100644 --- a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/domain/AssetNotNeedAccountUseCaseImpl.kt +++ b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/domain/AssetNotNeedAccountUseCaseImpl.kt @@ -1,6 +1,7 @@ package jp.co.soramitsu.account.impl.domain import jp.co.soramitsu.account.api.domain.interfaces.AssetNotNeedAccountUseCase +import jp.co.soramitsu.common.domain.SelectedFiat import jp.co.soramitsu.common.model.AssetKey import jp.co.soramitsu.coredb.dao.AssetDao import jp.co.soramitsu.coredb.dao.TokenPriceDao @@ -14,13 +15,15 @@ import kotlinx.coroutines.flow.map class AssetNotNeedAccountUseCaseImpl( private val chainRegistry: ChainRegistry, private val assetDao: AssetDao, - private val tokenPriceDao: TokenPriceDao + private val tokenPriceDao: TokenPriceDao, + private val selectedFiat: SelectedFiat ) : AssetNotNeedAccountUseCase { override suspend fun markChainAssetsNotNeed(chainId: ChainId, metaId: Long) { val chainAssets = chainRegistry.getChain(chainId).assets chainAssets.forEach { - updateAssetNotNeed(metaId, chainId, it.id, it.priceProvider?.id ?: it.priceId) + val priceId = it.priceProvider?.id?.takeIf { selectedFiat.isUsd() } ?: it.priceId + updateAssetNotNeed(metaId, chainId, it.id, priceId) } } diff --git a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/AccountRouter.kt b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/AccountRouter.kt index 9b46754208..79f28b8e8d 100644 --- a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/AccountRouter.kt +++ b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/AccountRouter.kt @@ -1,7 +1,7 @@ package jp.co.soramitsu.account.impl.presentation import jp.co.soramitsu.account.api.presentation.account.create.ChainAccountCreatePayload -import jp.co.soramitsu.account.api.presentation.actions.AddAccountBottomSheet +import jp.co.soramitsu.account.api.presentation.actions.AddAccountPayload import jp.co.soramitsu.account.api.presentation.create_backup_password.CreateBackupPasswordPayload import jp.co.soramitsu.account.impl.domain.account.details.AccountInChain import jp.co.soramitsu.account.impl.presentation.exporting.json.confirm.ExportJsonConfirmPayload @@ -85,7 +85,7 @@ interface AccountRouter : SecureRouter { fun openExperimentalFeatures() - fun openOptionsAddAccount(payload: AddAccountBottomSheet.Payload) + fun openOptionsAddAccount(payload: AddAccountPayload) fun openPolkaswapDisclaimerFromProfile() diff --git a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/account/details/AccountDetailsViewModel.kt b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/account/details/AccountDetailsViewModel.kt index 0ba2c7e5a7..d48ced6e4e 100644 --- a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/account/details/AccountDetailsViewModel.kt +++ b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/account/details/AccountDetailsViewModel.kt @@ -9,7 +9,7 @@ import javax.inject.Inject import jp.co.soramitsu.account.api.domain.interfaces.AssetNotNeedAccountUseCase import jp.co.soramitsu.account.api.domain.interfaces.TotalBalanceUseCase import jp.co.soramitsu.account.api.domain.model.hasChainAccount -import jp.co.soramitsu.account.api.presentation.actions.AddAccountBottomSheet +import jp.co.soramitsu.account.api.presentation.actions.AddAccountPayload import jp.co.soramitsu.account.api.presentation.actions.ExternalAccountActions import jp.co.soramitsu.account.api.presentation.exporting.ExportSource import jp.co.soramitsu.account.api.presentation.exporting.ExportSourceChooserPayload @@ -23,6 +23,7 @@ import jp.co.soramitsu.common.base.BaseViewModel import jp.co.soramitsu.common.compose.component.ChangeBalanceViewState import jp.co.soramitsu.common.compose.component.WalletItemViewState import jp.co.soramitsu.common.data.network.BlockExplorerUrlBuilder +import jp.co.soramitsu.common.domain.SelectedFiat import jp.co.soramitsu.common.list.headers.TextHeader import jp.co.soramitsu.common.list.toListWithHeaders import jp.co.soramitsu.common.resources.ResourceManager @@ -251,12 +252,11 @@ class AccountDetailsViewModel @Inject constructor( externalAccountActions.showExternalActions(ExternalAccountActions.Payload(item.address, item.chainId, item.chainName, supportedExplorers)) } else { val utilityAsset = chainRegistry.getChain(item.chainId).utilityAsset - val payload = AddAccountBottomSheet.Payload( + val payload = AddAccountPayload( metaId = walletId, chainId = item.chainId, chainName = item.chainName, assetId = utilityAsset?.id.orEmpty(), - priceId = utilityAsset?.priceProvider?.id ?: utilityAsset?.priceId, markedAsNotNeed = item.markedAsNotNeed ) accountRouter.openOptionsAddAccount(payload) diff --git a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/optionsaddaccount/OptionsAddAccountContent.kt b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/optionsaddaccount/OptionsAddAccountContent.kt index 0f623beb82..57f4b3bf3d 100644 --- a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/optionsaddaccount/OptionsAddAccountContent.kt +++ b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/optionsaddaccount/OptionsAddAccountContent.kt @@ -30,8 +30,7 @@ data class OptionsAddAccountScreenViewState( val chainId: ChainId, val chainName: String, val markedAsNotNeed: Boolean, - val assetId: String, - val priceId: String? + val assetId: String ) @Composable @@ -114,8 +113,7 @@ private fun OptionsAddAccountScreenPreview() { chainId = "", chainName = "Kusama", markedAsNotNeed = false, - assetId = "", - priceId = null + assetId = "" ), onCreate = { t, t2 -> }, onImport = { t, t2 -> }, diff --git a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/optionsaddaccount/OptionsAddAccountFragment.kt b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/optionsaddaccount/OptionsAddAccountFragment.kt index 875e2ee759..b53066ee9f 100644 --- a/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/optionsaddaccount/OptionsAddAccountFragment.kt +++ b/feature-account-impl/src/main/java/jp/co/soramitsu/account/impl/presentation/optionsaddaccount/OptionsAddAccountFragment.kt @@ -9,7 +9,7 @@ import androidx.core.os.bundleOf import androidx.fragment.app.viewModels import com.google.android.material.bottomsheet.BottomSheetBehavior import dagger.hilt.android.AndroidEntryPoint -import jp.co.soramitsu.account.api.presentation.actions.AddAccountBottomSheet +import jp.co.soramitsu.account.api.presentation.actions.AddAccountPayload import jp.co.soramitsu.common.base.BaseComposeBottomSheetDialogFragment @AndroidEntryPoint @@ -18,7 +18,7 @@ class OptionsAddAccountFragment : BaseComposeBottomSheetDialogFragment = selectedWallet.mapNotNull { - savedStateHandle.get(KEY_PAYLOAD)?.let { payload -> + savedStateHandle.get(KEY_PAYLOAD)?.let { payload -> OptionsAddAccountScreenViewState( metaId = it.id, chainId = payload.chainId, chainName = payload.chainName, markedAsNotNeed = payload.markedAsNotNeed, - assetId = payload.assetId, - priceId = payload.priceId + assetId = payload.assetId ) } }.stateIn( @@ -49,8 +48,7 @@ class OptionsAddAccountViewModel @Inject constructor( chainId = "", chainName = "Dotsama", markedAsNotNeed = false, - assetId = "", - priceId = null + assetId = "" ) ) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/di/StakingFeatureModule.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/di/StakingFeatureModule.kt index e614ab7117..4c0e5a4e30 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/di/StakingFeatureModule.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/di/StakingFeatureModule.kt @@ -15,6 +15,7 @@ import jp.co.soramitsu.common.data.network.AppLinksProvider import jp.co.soramitsu.common.data.network.rpc.BulkRetriever import jp.co.soramitsu.common.data.network.subquery.SoraEraInfoValidatorResponse import jp.co.soramitsu.common.data.storage.Preferences +import jp.co.soramitsu.common.domain.SelectedFiat import jp.co.soramitsu.common.resources.ResourceManager import jp.co.soramitsu.core.extrinsic.ExtrinsicService import jp.co.soramitsu.core.extrinsic.mortality.IChainStateRepository @@ -587,8 +588,8 @@ class StakingFeatureModule { fun provideIdentitiesUseCase(identityRepository: IdentityRepository) = GetIdentitiesUseCase(identityRepository) @Provides - fun soraTokensRateUseCase(rpcCalls: RpcCalls, chainRegistry: ChainRegistry, tokenPriceDao: TokenPriceDao) = - SoraStakingRewardsScenario(rpcCalls, chainRegistry, tokenPriceDao) + fun soraTokensRateUseCase(rpcCalls: RpcCalls, chainRegistry: ChainRegistry, tokenPriceDao: TokenPriceDao, selectedFiat: SelectedFiat) = + SoraStakingRewardsScenario(rpcCalls, chainRegistry, tokenPriceDao, selectedFiat) @Provides @Singleton diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SoraStakingRewardsScenario.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SoraStakingRewardsScenario.kt index e3f714a1d7..c3c850168d 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SoraStakingRewardsScenario.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/rewards/SoraStakingRewardsScenario.kt @@ -1,6 +1,7 @@ package jp.co.soramitsu.staking.impl.domain.rewards import java.math.BigInteger +import jp.co.soramitsu.common.domain.SelectedFiat import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.core.rpc.RpcCalls import jp.co.soramitsu.core.rpc.calls.liquidityProxyQuote @@ -12,7 +13,8 @@ import jp.co.soramitsu.wallet.impl.domain.model.Token class SoraStakingRewardsScenario( private val rpcCalls: RpcCalls, private val chainRegistry: ChainRegistry, - private val tokenDao: TokenPriceDao + private val tokenDao: TokenPriceDao, + private val selectedFiat: SelectedFiat ) { companion object { private const val SORA_MAIN_NET_CHAIN_ID = @@ -37,8 +39,9 @@ class SoraStakingRewardsScenario( suspend fun getRewardAsset(): Token { val chain = chainRegistry.getChain(SORA_MAIN_NET_CHAIN_ID) val rewardAsset = requireNotNull(chain.assetsById[REWARD_ASSET_ID]) - val priceId = requireNotNull(rewardAsset.priceProvider?.id ?: rewardAsset.priceId) - val token = tokenDao.getTokenPrice(priceId) + val priceId = rewardAsset.priceProvider?.id?.takeIf { selectedFiat.isUsd() } ?: rewardAsset.priceId + val requirePriceId = requireNotNull(priceId) + val token = tokenDao.getTokenPrice(requirePriceId) return Token( configuration = rewardAsset, diff --git a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/data/cache/AssetCache.kt b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/data/cache/AssetCache.kt index c9cd697550..544a210550 100644 --- a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/data/cache/AssetCache.kt +++ b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/data/cache/AssetCache.kt @@ -37,7 +37,7 @@ class AssetCache( ) = withContext(Dispatchers.IO) { val chainId = chainAsset.chainId val assetId = chainAsset.id - val shouldUseChainlinkForRates = selectedFiat.get() == "usd" && chainAsset.priceProvider?.id != null + val shouldUseChainlinkForRates = selectedFiat.isUsd() && chainAsset.priceProvider?.id != null val priceId = if (shouldUseChainlinkForRates) { chainAsset.priceProvider?.id } else { diff --git a/feature-wallet-impl/build.gradle b/feature-wallet-impl/build.gradle index 2d8907d2ee..8192ef6605 100644 --- a/feature-wallet-impl/build.gradle +++ b/feature-wallet-impl/build.gradle @@ -140,6 +140,4 @@ dependencies { implementation sharedFeaturesBackupDep implementation web3jDep - implementation web3jContractsDep -// implementation web3jGethDep } \ No newline at end of file diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/TokenRepositoryImpl.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/TokenRepositoryImpl.kt index b23776dd2f..6ff1ee7daf 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/TokenRepositoryImpl.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/repository/TokenRepositoryImpl.kt @@ -1,5 +1,6 @@ package jp.co.soramitsu.wallet.impl.data.repository +import jp.co.soramitsu.common.domain.SelectedFiat import jp.co.soramitsu.common.utils.flowOf import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.coredb.dao.TokenPriceDao @@ -9,28 +10,41 @@ import jp.co.soramitsu.wallet.impl.domain.interfaces.TokenRepository import jp.co.soramitsu.wallet.impl.domain.model.Token import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext class TokenRepositoryImpl( - private val tokenPriceDao: TokenPriceDao + private val tokenPriceDao: TokenPriceDao, + private val selectedFiat: SelectedFiat ) : TokenRepository { override suspend fun getToken(chainAsset: Asset): Token = withContext(Dispatchers.Default) { - val priceId = chainAsset.priceProvider?.id ?: chainAsset.priceId + val priceId = if (selectedFiat.isUsd() && chainAsset.priceProvider?.id != null) { + chainAsset.priceProvider?.id + } else { + chainAsset.priceId + } val tokenPriceLocal = priceId?.let { tokenPriceDao.getTokenPrice(it) ?: TokenPriceLocal.createEmpty(it) } combineAssetWithPrices(chainAsset, tokenPriceLocal) } override fun observeToken(chainAsset: Asset): Flow { - val priceId = chainAsset.priceProvider?.id ?: chainAsset.priceId - return when (priceId) { - null -> flowOf { - combineAssetWithPrices(chainAsset, null) + return selectedFiat.flow().map { + if (it == "usd" && chainAsset.priceProvider?.id != null) { + chainAsset.priceProvider?.id + } else { + chainAsset.priceId } - else -> tokenPriceDao.observeTokenPrice(priceId).map { - combineAssetWithPrices(chainAsset, it) + }.flatMapLatest { priceId -> + when (priceId) { + null -> flowOf { + combineAssetWithPrices(chainAsset, null) + } + else -> tokenPriceDao.observeTokenPrice(priceId).map { + combineAssetWithPrices(chainAsset, it) + } } } } 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 4f48e9b46d..50f2ef536b 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 @@ -16,6 +16,7 @@ import jp.co.soramitsu.common.data.secrets.v2.KeyPairSchema import jp.co.soramitsu.common.data.secrets.v2.MetaAccountSecrets import jp.co.soramitsu.common.data.storage.Preferences import jp.co.soramitsu.common.domain.GetAvailableFiatCurrencies +import jp.co.soramitsu.common.domain.SelectedFiat import jp.co.soramitsu.common.mixin.api.UpdatesMixin import jp.co.soramitsu.common.mixin.api.UpdatesProviderUi import jp.co.soramitsu.common.utils.orZero @@ -83,7 +84,8 @@ class WalletRepositoryImpl( private val remoteConfigFetcher: RemoteConfigFetcher, private val preferences: Preferences, private val accountRepository: AccountRepository, - private val chainsRepository: ChainsRepository + private val chainsRepository: ChainsRepository, + private val selectedFiat: SelectedFiat ) : WalletRepository, UpdatesProviderUi by updatesMixin { companion object { @@ -160,8 +162,7 @@ class WalletRepositoryImpl( type = NetworkIssueType.Node, chainId = configuration.chainId, chainName = configuration.chainName, - assetId = configuration.id, - priceId = configuration.priceProvider?.id ?: configuration.priceId + assetId = configuration.id ) }.toSet() } @@ -203,7 +204,6 @@ class WalletRepositoryImpl( val chainlinkProvider = chains.firstOrNull { it.chainlinkProvider } val chainlinkProviderId = chainlinkProvider?.id - println("!!! chainlinkProvider is ${chainlinkProvider?.name} $chainlinkProviderId ") val chainlinkTokens = chainlinkIds.map { priceId -> val assetConfig = chains.flatMap { it.assets }.firstOrNull { it.priceProvider?.id == priceId } @@ -285,6 +285,7 @@ class WalletRepositoryImpl( isHidden: Boolean, chainAsset: CoreAsset ) { + val tokenPriceId = chainAsset.priceProvider?.id?.takeIf { selectedFiat.isUsd() } ?: chainAsset.priceId val updateItems = listOf( AssetUpdateItem( metaId = metaId, @@ -293,7 +294,7 @@ class WalletRepositoryImpl( id = chainAsset.id, sortIndex = Int.MAX_VALUE, // Int.MAX_VALUE on sorting because we don't use it anymore - just random value enabled = !isHidden, - tokenPriceId = chainAsset.priceProvider?.id ?: chainAsset.priceId + tokenPriceId = tokenPriceId ) ) 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 0493cfb4a9..b74f397e28 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 @@ -145,9 +145,11 @@ class WalletFeatureModule { @Provides fun provideTokenRepository( - tokenPriceDao: TokenPriceDao + tokenPriceDao: TokenPriceDao, + selectedFiat: SelectedFiat ): TokenRepository = TokenRepositoryImpl( - tokenPriceDao + tokenPriceDao, + selectedFiat ) @Provides @@ -171,7 +173,8 @@ class WalletFeatureModule { remoteConfigFetcher: RemoteConfigFetcher, preferences: Preferences, accountRepository: AccountRepository, - chainsRepository: ChainsRepository + chainsRepository: ChainsRepository, + selectedFiat: SelectedFiat ): WalletRepository = WalletRepositoryImpl( substrateSource, ethereumRemoteSource, @@ -188,7 +191,8 @@ class WalletFeatureModule { remoteConfigFetcher, preferences, accountRepository, - chainsRepository + chainsRepository, + selectedFiat ) @Provides diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/WalletRouter.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/WalletRouter.kt index 16399320e5..4eedfdf180 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/WalletRouter.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/WalletRouter.kt @@ -4,7 +4,7 @@ import android.graphics.drawable.Drawable import it.airgap.beaconsdk.blockchain.substrate.data.SubstrateSignerPayload import java.math.BigDecimal import jp.co.soramitsu.account.api.domain.model.ImportMode -import jp.co.soramitsu.account.api.presentation.actions.AddAccountBottomSheet +import jp.co.soramitsu.account.api.presentation.actions.AddAccountPayload import jp.co.soramitsu.common.AlertViewState import jp.co.soramitsu.common.navigation.DelayedNavigation import jp.co.soramitsu.common.navigation.PinRequired @@ -144,7 +144,7 @@ interface WalletRouter : SecureRouter, WalletRouterApi { fun openGetSoraCard() - fun openOptionsAddAccount(payload: AddAccountBottomSheet.Payload) + fun openOptionsAddAccount(payload: AddAccountPayload) fun openOptionsSwitchNode( metaId: Long, diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/BalanceListViewModel.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/BalanceListViewModel.kt index 2987bf8b50..b45185c9fd 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/BalanceListViewModel.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/BalanceListViewModel.kt @@ -273,7 +273,6 @@ class BalanceListViewModel @Inject constructor( chainAssetId = chainAsset.id, isSupported = true, isHidden = false, - priceId = chainAsset.priceProvider?.id ?: chainAsset.priceId, isTestnet = chainAsset.isTestNet ?: false ) }.filter { selectedChainId.value == null || selectedChainId.value == it.chainId } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/WalletScreen.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/WalletScreen.kt index 8c12e23fc1..7752e0459b 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/WalletScreen.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/WalletScreen.kt @@ -243,7 +243,6 @@ private fun PreviewWalletScreen() { chainAssetId = "", isSupported = true, isHidden = false, - priceId = null, isTestnet = false ) ) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/model/BalanceListItemModel.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/model/BalanceListItemModel.kt index 633836a960..f57fdedc7f 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/model/BalanceListItemModel.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/list/model/BalanceListItemModel.kt @@ -36,6 +36,5 @@ fun BalanceListItemModel.toAssetState(index: Int? = null) = AssetListItemViewSta chainAssetId = asset.id, isSupported = chain?.isSupported != false, isHidden = isHidden, - priceId = asset.priceProvider?.id ?: asset.priceId, isTestnet = chain?.isTestNet == true ) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/networkissues/NetworkIssuesViewModel.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/networkissues/NetworkIssuesViewModel.kt index 22b0be2281..2716e848b8 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/networkissues/NetworkIssuesViewModel.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/networkissues/NetworkIssuesViewModel.kt @@ -5,7 +5,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import jp.co.soramitsu.account.api.domain.interfaces.AccountInteractor import jp.co.soramitsu.account.api.domain.interfaces.AssetNotNeedAccountUseCase -import jp.co.soramitsu.account.api.presentation.actions.AddAccountBottomSheet +import jp.co.soramitsu.account.api.presentation.actions.AddAccountPayload import jp.co.soramitsu.common.AlertViewState import jp.co.soramitsu.common.base.BaseViewModel import jp.co.soramitsu.common.compose.component.NetworkIssueItemState @@ -20,7 +20,6 @@ import jp.co.soramitsu.wallet.impl.domain.interfaces.WalletInteractor import jp.co.soramitsu.wallet.impl.presentation.WalletRouter import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -104,12 +103,11 @@ class NetworkIssuesViewModel @Inject constructor( NetworkIssueType.Account -> launch { val meta = accountInteractor.selectedMetaAccountFlow().first() - val payload = AddAccountBottomSheet.Payload( + val payload = AddAccountPayload( metaId = meta.id, chainId = issue.chainId, chainName = issue.chainName, assetId = issue.assetId, - priceId = issue.priceId, markedAsNotNeed = false ) walletRouter.openOptionsAddAccount(payload) 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 bdc62e31d6..aa1facfca4 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 @@ -266,7 +266,6 @@ fun Chain.toSyncIssue(): NetworkIssueItemState { }, chainId = this.id, chainName = this.name, - assetId = this.utilityAsset?.id.orEmpty(), - priceId = this.utilityAsset?.priceProvider?.id ?: this.utilityAsset?.priceId + assetId = this.utilityAsset?.id.orEmpty() ) } diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/connection/ConnectionPool.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/connection/ConnectionPool.kt index fe122221f2..09bf2bd629 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/connection/ConnectionPool.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/connection/ConnectionPool.kt @@ -70,8 +70,7 @@ class ConnectionPool @Inject constructor( }, chainId = chain.id, chainName = chain.name, - assetId = chain.utilityAsset?.id.orEmpty(), - priceId = chain.utilityAsset?.priceProvider?.id ?: chain.utilityAsset?.priceId + assetId = chain.utilityAsset?.id.orEmpty() ) } issues From d4875cc95515b8353fd8a5ca6c70c366bc4ea16d Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Wed, 7 Feb 2024 13:28:01 +0500 Subject: [PATCH 08/35] pr fix --- .../blockchain/EthereumRemoteSource.kt | 3 +- .../data/repository/WalletRepositoryImpl.kt | 41 +++++++++++++++---- .../wallet/impl/di/WalletFeatureModule.kt | 6 ++- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/EthereumRemoteSource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/EthereumRemoteSource.kt index f77b56dc51..fe4173395a 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/EthereumRemoteSource.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/EthereumRemoteSource.kt @@ -148,7 +148,8 @@ class EthereumRemoteSource(private val ethereumConnectionPool: EthereumConnectio val connection = ethereumConnectionPool.get(chainId) connection?.connect() - val web3 = connection?.web3j ?: return null + val web3 = connection?.web3j + ?: throw RuntimeException("There is no connection created for chain ${chainId}") return web3.fetchPriceFeed(receiverAddress) } 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 50f2ef536b..7882c35263 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 @@ -25,6 +25,7 @@ import jp.co.soramitsu.core.models.Asset.PriceProvider import jp.co.soramitsu.core.utils.utilityAsset import jp.co.soramitsu.coredb.dao.OperationDao import jp.co.soramitsu.coredb.dao.PhishingDao +import jp.co.soramitsu.coredb.dao.TokenPriceDao import jp.co.soramitsu.coredb.dao.emptyAccountIdValue import jp.co.soramitsu.coredb.model.AssetUpdateItem import jp.co.soramitsu.coredb.model.AssetWithToken @@ -85,7 +86,8 @@ class WalletRepositoryImpl( private val preferences: Preferences, private val accountRepository: AccountRepository, private val chainsRepository: ChainsRepository, - private val selectedFiat: SelectedFiat + private val selectedFiat: SelectedFiat, + private val tokenPriceDao: TokenPriceDao ) : WalletRepository, UpdatesProviderUi by updatesMixin { companion object { @@ -243,19 +245,44 @@ class WalletRepositoryImpl( val fiatCurrency = availableFiatCurrencies[currencyId] updateAssetRates(priceId, fiatCurrency?.symbol, price, change) + + if (currencyId == "usd") { + val assetsWithChainlinkPrice = chains.map { it.assets.filter { it.priceProvider?.id != null } }.flatten().toSet() + + updateChainlinkPriceWithCoingeckoChange(assetsWithChainlinkPrice, priceId, change) + } } updatesMixin.finishUpdateTokens(priceIds) } - private suspend fun getChainlinkPrices(priceProvider: PriceProvider, chainId: ChainId): BigDecimal? { - return ethereumSource.fetchPriceFeed( - chainId = chainId, - receiverAddress = priceProvider.id - )?.let { price -> - BigDecimal(price, priceProvider.precision) + private suspend fun WalletRepositoryImpl.updateChainlinkPriceWithCoingeckoChange(assetsWithChainlinkPrice: Set, priceId: String, change: BigDecimal?) { + val chainlinkId = assetsWithChainlinkPrice.firstOrNull { + it.priceId == priceId + }?.priceProvider?.id + + chainlinkId?.let { + val tokenPrice = tokenPriceDao.getTokenPrice(chainlinkId) + + updateAssetRates( + priceId = chainlinkId, + fiatSymbol = tokenPrice?.fiatSymbol, + price = tokenPrice?.fiatRate, + change = change + ) } } + 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() + } + override fun assetFlow( metaId: Long, accountId: AccountId, 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 b74f397e28..76badf314c 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 @@ -174,7 +174,8 @@ class WalletFeatureModule { preferences: Preferences, accountRepository: AccountRepository, chainsRepository: ChainsRepository, - selectedFiat: SelectedFiat + selectedFiat: SelectedFiat, + tokenPriceDao: TokenPriceDao ): WalletRepository = WalletRepositoryImpl( substrateSource, ethereumRemoteSource, @@ -192,7 +193,8 @@ class WalletFeatureModule { preferences, accountRepository, chainsRepository, - selectedFiat + selectedFiat, + tokenPriceDao ) @Provides From dc017295e15bb3795ead819dd3d5fbb572eb44b3 Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Thu, 8 Feb 2024 13:00:23 +0500 Subject: [PATCH 09/35] fix crash --- .../app/root/presentation/main/MainFragment.kt | 11 +++++++++-- build.gradle | 2 +- gradle/libs.versions.toml | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/jp/co/soramitsu/app/root/presentation/main/MainFragment.kt b/app/src/main/java/jp/co/soramitsu/app/root/presentation/main/MainFragment.kt index 3ffaa0b033..586a261ad6 100644 --- a/app/src/main/java/jp/co/soramitsu/app/root/presentation/main/MainFragment.kt +++ b/app/src/main/java/jp/co/soramitsu/app/root/presentation/main/MainFragment.kt @@ -1,5 +1,7 @@ package jp.co.soramitsu.app.root.presentation.main +import android.os.Bundle +import android.view.View import androidx.activity.OnBackPressedCallback import androidx.fragment.app.viewModels import androidx.navigation.NavController @@ -25,7 +27,7 @@ class MainFragment : BaseFragment(R.layout.fragment_main) { } } - private val binding by viewBinding(FragmentMainBinding::bind) + private lateinit var binding: FragmentMainBinding override val viewModel: MainViewModel by viewModels() @@ -35,6 +37,11 @@ class MainFragment : BaseFragment(R.layout.fragment_main) { backCallback.isEnabled = false } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + binding = FragmentMainBinding.bind(view) + super.onViewCreated(view, savedInstanceState) + } + override fun initViews() { binding.bottomNavigationView.setOnApplyWindowInsetsListener { _, insets -> // overwrite BottomNavigation behavior and ignore insets @@ -60,7 +67,7 @@ class MainFragment : BaseFragment(R.layout.fragment_main) { binding.bottomNavigationView.setupWithNavController(navController!!) - binding.bottomNavigationView.setOnNavigationItemSelectedListener { item -> + binding.bottomNavigationView.setOnItemSelectedListener { item -> onNavDestinationSelected(item, navController!!) } diff --git a/build.gradle b/build.gradle index 1278b446c0..855d13af62 100644 --- a/build.gradle +++ b/build.gradle @@ -79,7 +79,7 @@ buildscript { serializationVersion = '1.5.1' activityKtx = '1.7.0' - fragmentKtx = '1.5.6' + fragmentKtx = '1.6.2' minifyRelease = true beaconVersion = "3.2.4" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6e08840bf7..fc76b1436c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] compose = "1.5.1" composeFoundation = "1.5.1" -fragmentKtx = "1.5.6" +fragmentKtx = "1.6.2" composeThemeAdapter = "1.2.1" googleServices = "4.3.15" junit = "4.13.2" From f723f133ec17457a101d97339de74a690b89384a Mon Sep 17 00:00:00 2001 From: Deneath Date: Mon, 22 Jan 2024 17:34:54 +0700 Subject: [PATCH 10/35] WIP --- .../runtime/multiNetwork/runtime/RuntimeProvider.kt | 7 +++++++ .../runtime/multiNetwork/runtime/RuntimeSyncService.kt | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt index c10acd556e..2acc77de8e 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt @@ -1,5 +1,6 @@ package jp.co.soramitsu.runtime.multiNetwork.runtime +import android.util.Log import jp.co.soramitsu.common.mixin.api.NetworkStateMixin import jp.co.soramitsu.core.runtime.ConstructedRuntime import jp.co.soramitsu.core.runtime.RuntimeFactory @@ -128,9 +129,15 @@ class RuntimeProvider( val runtime = runtimeFactory.constructRuntime(metadataRaw, ownTypesRaw, runtimeVersion) + if(chainId == "7834781d38e4798d548e34ec947d19deea29df148a7bf32484b7b24dacf8d4b7"){ + Log.d("&&&", "reef runtime construction: ${runtime.runtime}") + } runtimeFlow.emit(runtime) networkStateMixin.notifyChainSyncSuccess(chainId) }.onFailure { + if(chainId == "7834781d38e4798d548e34ec947d19deea29df148a7bf32484b7b24dacf8d4b7"){ + Log.d("&&&", "reef runtime construction failure: $it ${it.message}") + } networkStateMixin.notifyChainSyncProblem(chain.toSyncIssue()) when (it) { ChainInfoNotInCacheException -> runtimeSyncService.cacheNotFound(chainId) diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeSyncService.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeSyncService.kt index abcea704dc..0e95d5881f 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeSyncService.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeSyncService.kt @@ -109,7 +109,9 @@ class RuntimeSyncService( GetMetadataRequest, mapper = pojo().nonNull() ).getOrNull() - + if(chainId == "7834781d38e4798d548e34ec947d19deea29df148a7bf32484b7b24dacf8d4b7"){ + Log.d("&&&", "reef metadata length: ${runtimeMetadata?.length}") + } runtimeMetadata?.let { runtimeFilesCache.saveChainMetadata(chainId, runtimeMetadata) From 0be294312e716ac7c566855094b7a7a9eb2d6083 Mon Sep 17 00:00:00 2001 From: Deneath Date: Tue, 23 Jan 2024 13:13:34 +0700 Subject: [PATCH 11/35] add default types loading, add v13 runtime construction method for reef, add balance update for reef --- .../updaters/BalancesUpdateSystem.kt | 20 ++++++-- .../network/model/SubstrateBalancesUtils.kt | 50 ++++++++++++++++++- runtime/build.gradle | 1 + .../multiNetwork/chain/ChainSpecificUtils.kt | 20 ++++++++ .../multiNetwork/runtime/RuntimeProvider.kt | 16 +++--- .../runtime/RuntimeSyncService.kt | 6 +-- 6 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSpecificUtils.kt diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/updaters/BalancesUpdateSystem.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/updaters/BalancesUpdateSystem.kt index a1b7ff2dbc..8826796a75 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/updaters/BalancesUpdateSystem.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/updaters/BalancesUpdateSystem.kt @@ -1,21 +1,30 @@ package jp.co.soramitsu.wallet.impl.data.network.blockchain.updaters import android.util.Log +import io.emeraldpay.polkaj.scale.ScaleCodecReader import it.airgap.beaconsdk.core.internal.utils.failure import it.airgap.beaconsdk.core.internal.utils.onEachFailure +import java.math.BigInteger +import java.nio.ByteOrder 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 import jp.co.soramitsu.account.api.domain.model.address import jp.co.soramitsu.common.data.network.rpc.BulkRetriever +import jp.co.soramitsu.common.data.network.runtime.binding.AccountData +import jp.co.soramitsu.common.data.network.runtime.binding.AccountInfo import jp.co.soramitsu.common.data.network.runtime.binding.ExtrinsicStatusEvent import jp.co.soramitsu.common.data.network.runtime.binding.SimpleBalanceData +import jp.co.soramitsu.common.data.network.runtime.binding.bindNonce +import jp.co.soramitsu.common.data.network.runtime.binding.cast import jp.co.soramitsu.common.mixin.api.NetworkStateMixin import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.requireException import jp.co.soramitsu.common.utils.requireValue +import jp.co.soramitsu.common.utils.system import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.core.models.ChainAssetType +import jp.co.soramitsu.core.runtime.storage.returnType import jp.co.soramitsu.core.updater.UpdateSystem import jp.co.soramitsu.core.updater.Updater import jp.co.soramitsu.core.utils.utilityAsset @@ -28,8 +37,14 @@ import jp.co.soramitsu.runtime.multiNetwork.getSocket import jp.co.soramitsu.runtime.multiNetwork.getSocketOrNull import jp.co.soramitsu.runtime.multiNetwork.toSyncIssue import jp.co.soramitsu.runtime.network.subscriptionFlowCatching +import jp.co.soramitsu.shared_utils.extensions.fromUnsignedBytes import jp.co.soramitsu.shared_utils.runtime.AccountId import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot +import jp.co.soramitsu.shared_utils.runtime.definitions.types.composite.Struct +import jp.co.soramitsu.shared_utils.runtime.definitions.types.fromHexOrNull +import jp.co.soramitsu.shared_utils.runtime.metadata.storage +import jp.co.soramitsu.shared_utils.scale.dataType.uint128 +import jp.co.soramitsu.shared_utils.scale.utils.toUnsignedBytes import jp.co.soramitsu.shared_utils.wsrpc.request.runtime.storage.SubscribeStorageRequest import jp.co.soramitsu.shared_utils.wsrpc.request.runtime.storage.storageChange import jp.co.soramitsu.wallet.api.data.cache.AssetCache @@ -175,10 +190,9 @@ class BalancesUpdateSystem( storageKeyToHex.mapNotNull { (key, hexRaw) -> val metadata = storageKeys.firstOrNull { it.key == key } ?: return@mapNotNull null - val balanceData = handleBalanceResponse( runtime, - metadata.asset.typeExtra, + metadata.asset, hexRaw ).onFailure { logError(chain, it) } @@ -240,7 +254,7 @@ class BalancesUpdateSystem( val balanceData = handleBalanceResponse( runtime, - keyWithMetadata.asset.typeExtra, + keyWithMetadata.asset, hexRaw ).onFailure { logError(chain, it) } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/SubstrateBalancesUtils.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/SubstrateBalancesUtils.kt index 73800a34a7..d667fb410d 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/SubstrateBalancesUtils.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/SubstrateBalancesUtils.kt @@ -1,14 +1,26 @@ package jp.co.soramitsu.wallet.impl.data.network.model import android.util.Log +import java.math.BigInteger +import jp.co.soramitsu.common.data.network.runtime.binding.AccountData +import jp.co.soramitsu.common.data.network.runtime.binding.AccountInfo import jp.co.soramitsu.common.data.network.runtime.binding.AssetBalanceData import jp.co.soramitsu.common.data.network.runtime.binding.EmptyBalance +import jp.co.soramitsu.common.data.network.runtime.binding.bindNonce +import jp.co.soramitsu.common.data.network.runtime.binding.cast import jp.co.soramitsu.common.utils.Modules +import jp.co.soramitsu.common.utils.failure +import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.system import jp.co.soramitsu.common.utils.tokens import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.core.models.ChainAssetType +import jp.co.soramitsu.core.runtime.storage.returnType +import jp.co.soramitsu.runtime.multiNetwork.chain.ReefBalance +import jp.co.soramitsu.runtime.multiNetwork.chain.model.reefChainId import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot +import jp.co.soramitsu.shared_utils.runtime.definitions.types.composite.Struct +import jp.co.soramitsu.shared_utils.runtime.definitions.types.fromHexOrNull import jp.co.soramitsu.shared_utils.runtime.metadata.module import jp.co.soramitsu.shared_utils.runtime.metadata.storage import jp.co.soramitsu.shared_utils.runtime.metadata.storageKey @@ -65,11 +77,14 @@ fun constructBalanceKey( fun handleBalanceResponse( runtime: RuntimeSnapshot, - assetType: ChainAssetType?, + asset: Asset, scale: String? ): Result { return runCatching { - when (assetType) { + if (asset.chainId == reefChainId) { + return bindReefAccountInfo(runtime, scale) + } + when (asset.typeExtra) { null, ChainAssetType.Normal, ChainAssetType.SoraUtilityAsset -> { @@ -103,3 +118,34 @@ fun handleBalanceResponse( } } } + +private fun bindReefAccountInfo(runtime: RuntimeSnapshot, scale: String?): Result { + return runCatching { + val type = runtime.metadata.system().storage("Account") + .returnType() + + val dynamicInstance = type.fromHexOrNull( + runtime, + scale ?: return Result.failure("Reef system.Account returned null hex result") + ).cast() + + AccountInfo( + nonce = bindNonce(dynamicInstance["nonce"]), + data = dynamicInstance.get("data") + .let { + val freeBalance = ReefBalance((it?.get("free") as? BigInteger).orZero()) + val reservedBalance = ReefBalance((it?.get("reserved") as? BigInteger).orZero()) + val miscFrozenBalance = + ReefBalance((it?.get("miscFrozen") as? BigInteger).orZero()) + val feeFrozenBalance = + ReefBalance((it?.get("feeFrozen") as? BigInteger).orZero()) + AccountData( + free = freeBalance.planks, + reserved = reservedBalance.planks, + miscFrozen = miscFrozenBalance.planks, + feeFrozen = feeFrozenBalance.planks + ) + } + ) + } +} \ No newline at end of file diff --git a/runtime/build.gradle b/runtime/build.gradle index c10fa10dd9..8ac37469a6 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -14,6 +14,7 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildConfigField "String", "TYPES_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/master/chains/all_chains_types_android.json\"" buildConfigField "String", "APP_VERSION_NAME", "\"${rootProject.versionName}\"" + buildConfigField("String", "DEFAULT_V13_TYPES_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/reef/chains/default_v13_types.json\"") } buildTypes { diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSpecificUtils.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSpecificUtils.kt new file mode 100644 index 0000000000..a0618b24a8 --- /dev/null +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSpecificUtils.kt @@ -0,0 +1,20 @@ +package jp.co.soramitsu.runtime.multiNetwork.chain + +import io.emeraldpay.polkaj.scale.ScaleCodecReader +import java.math.BigInteger +import java.nio.ByteOrder +import jp.co.soramitsu.shared_utils.extensions.fromUnsignedBytes +import jp.co.soramitsu.shared_utils.scale.dataType.uint128 +import jp.co.soramitsu.shared_utils.scale.utils.toUnsignedBytes + +@JvmInline +value class ReefBalance(val value: BigInteger) { + val planks: BigInteger + get() { + val bytes = value.toUnsignedBytes().fromUnsignedBytes(ByteOrder.LITTLE_ENDIAN).toByteArray() + val newArray = ByteArray(16) + bytes.copyInto(newArray) + val reader = ScaleCodecReader(newArray) + return uint128.read(reader) + } +} \ No newline at end of file diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt index 2acc77de8e..bcc9cf0ae8 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt @@ -1,11 +1,11 @@ package jp.co.soramitsu.runtime.multiNetwork.runtime -import android.util.Log import jp.co.soramitsu.common.mixin.api.NetworkStateMixin import jp.co.soramitsu.core.runtime.ConstructedRuntime import jp.co.soramitsu.core.runtime.RuntimeFactory import jp.co.soramitsu.coredb.dao.ChainDao import jp.co.soramitsu.runtime.multiNetwork.chain.model.Chain +import jp.co.soramitsu.runtime.multiNetwork.chain.model.reefChainId import jp.co.soramitsu.runtime.multiNetwork.toSyncIssue import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot import kotlinx.coroutines.CoroutineScope @@ -127,17 +127,19 @@ class RuntimeProvider( runCatching { chainDao.getTypes(chainId) ?: throw ChainInfoNotInCacheException } .getOrElse { throw ChainInfoNotInCacheException } - val runtime = + val runtime = if (chainId == reefChainId) { + val defaultTypes = + runCatching { + chainDao.getTypes("default") ?: throw ChainInfoNotInCacheException + } + .getOrElse { throw ChainInfoNotInCacheException } + runtimeFactory.constructRuntimeV13(metadataRaw, ownTypesRaw, defaultTypes) + } else { runtimeFactory.constructRuntime(metadataRaw, ownTypesRaw, runtimeVersion) - if(chainId == "7834781d38e4798d548e34ec947d19deea29df148a7bf32484b7b24dacf8d4b7"){ - Log.d("&&&", "reef runtime construction: ${runtime.runtime}") } runtimeFlow.emit(runtime) networkStateMixin.notifyChainSyncSuccess(chainId) }.onFailure { - if(chainId == "7834781d38e4798d548e34ec947d19deea29df148a7bf32484b7b24dacf8d4b7"){ - Log.d("&&&", "reef runtime construction failure: $it ${it.message}") - } networkStateMixin.notifyChainSyncProblem(chain.toSyncIssue()) when (it) { ChainInfoNotInCacheException -> runtimeSyncService.cacheNotFound(chainId) diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeSyncService.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeSyncService.kt index 0e95d5881f..bed5f4e901 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeSyncService.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeSyncService.kt @@ -109,9 +109,6 @@ class RuntimeSyncService( GetMetadataRequest, mapper = pojo().nonNull() ).getOrNull() - if(chainId == "7834781d38e4798d548e34ec947d19deea29df148a7bf32484b7b24dacf8d4b7"){ - Log.d("&&&", "reef metadata length: ${runtimeMetadata?.length}") - } runtimeMetadata?.let { runtimeFilesCache.saveChainMetadata(chainId, runtimeMetadata) @@ -140,13 +137,14 @@ class RuntimeSyncService( suspend fun syncTypes() { val types = typesFetcher.getTypes(BuildConfig.TYPES_URL) + val defaultTypes = typesFetcher.getTypes(BuildConfig.DEFAULT_V13_TYPES_URL) val array = Json.decodeFromString(types) val chainIdToTypes = array.mapNotNull { element -> val chainId = element.jsonObject["chainId"]?.jsonPrimitive?.content ?: return@mapNotNull null ChainTypesLocal(chainId, element.toString()) - } + }.toMutableList().apply { add(ChainTypesLocal("default", defaultTypes)) } chainDao.insertTypes(chainIdToTypes) } From 7f01ad63595ae4a66c4a6fb9d472af2431fc37a6 Mon Sep 17 00:00:00 2001 From: Deneath Date: Wed, 24 Jan 2024 18:07:45 +0700 Subject: [PATCH 12/35] clean code, add reef operations history --- .../historySource/HistorySourceProvider.kt | 1 + .../data/historySource/ReefHistorySource.kt | 93 +++++++++++++++++++ .../network/model/SubstrateBalancesUtils.kt | 46 --------- .../model/request/ReefHistoryRequest.kt | 39 ++++++++ .../model/response/ReefHistoryResponse.kt | 30 ++++++ .../network/subquery/OperationsHistoryApi.kt | 8 ++ .../multiNetwork/chain/ChainSpecificUtils.kt | 20 ---- .../runtime/multiNetwork/chain/Mappers.kt | 2 + .../runtime/multiNetwork/chain/model/Chain.kt | 6 +- .../multiNetwork/runtime/RuntimeProvider.kt | 2 +- 10 files changed, 177 insertions(+), 70 deletions(-) create mode 100644 feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt create mode 100644 feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt create mode 100644 feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt delete mode 100644 runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSpecificUtils.kt diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/HistorySourceProvider.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/HistorySourceProvider.kt index ef2ad5a3a4..c560d874a7 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/HistorySourceProvider.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/HistorySourceProvider.kt @@ -26,6 +26,7 @@ class HistorySourceProvider( Chain.ExternalApi.Section.Type.ETHERSCAN -> EtherscanHistorySource(walletOperationsApi, historyUrl) Chain.ExternalApi.Section.Type.OKLINK -> OkLinkHistorySource(walletOperationsApi, historyUrl) Chain.ExternalApi.Section.Type.ZETA -> ZetaHistorySource(walletOperationsApi, historyUrl) + Chain.ExternalApi.Section.Type.REEF -> ReefHistorySource(walletOperationsApi, historyUrl) else -> null } } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt new file mode 100644 index 0000000000..d6494b7e70 --- /dev/null +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt @@ -0,0 +1,93 @@ +package jp.co.soramitsu.wallet.impl.data.historySource + +import android.os.Build +import java.text.SimpleDateFormat +import java.time.Instant +import java.util.Locale +import jp.co.soramitsu.common.data.model.CursorPage +import jp.co.soramitsu.core.models.Asset +import jp.co.soramitsu.runtime.multiNetwork.chain.model.Chain +import jp.co.soramitsu.shared_utils.runtime.AccountId +import jp.co.soramitsu.wallet.impl.data.network.model.request.ReefHistoryRequest +import jp.co.soramitsu.wallet.impl.data.network.subquery.OperationsHistoryApi +import jp.co.soramitsu.wallet.impl.domain.interfaces.TransactionFilter +import jp.co.soramitsu.wallet.impl.domain.model.Operation + +class ReefHistorySource( + private val walletOperationsApi: OperationsHistoryApi, + private val url: String +) : HistorySource { + override suspend fun getOperations( + pageSize: Int, + cursor: String?, + filters: Set, + accountId: AccountId, + chain: Chain, + chainAsset: Asset, + accountAddress: String + ): CursorPage { + val overridePageSize = 50 + val offset = cursor?.toIntOrNull().takeIf { it != 0 } + val response = walletOperationsApi.getReefOperationsHistory( + url = url, + ReefHistoryRequest( + accountAddress = accountAddress, + overridePageSize, + offset.toString() + ) + ) + if (!filters.contains(TransactionFilter.TRANSFER)) { + return CursorPage(null, emptyList()) + } + val operations = response.data.transfersConnection.edges.map { it.node }.map { + Operation( + id = it.extrinsic?.hash ?: it.id, + address = accountAddress, + time = parseTimeToMillis(it.timestamp), + chainAsset = chainAsset, + type = Operation.Type.Transfer( + hash = it.extrinsic?.hash, + myAddress = accountAddress, + amount = it.amount, + receiver = it.to.id, + sender = it.from.id, + status = Operation.Status.fromSuccess(it.success), + fee = it.feeAmount + ) + ) + } + val pageInfo = response.data.transfersConnection.pageInfo + val nextCursor = if (pageInfo.hasNextPage && (pageInfo.endCursor.toIntOrNull() + ?: 0) >= overridePageSize + ) { + pageInfo.endCursor + } else { + null + } + return CursorPage(nextCursor, operations) + } + + private fun TransactionFilter.isAppliedOrNull(filters: Collection) = when { + this in filters -> true + else -> null + } + + private val reefDateFormat by lazy { + SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ", + Locale.getDefault() + ) + } + + private fun parseTimeToMillis(timestamp: String): Long { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Instant.parse(timestamp).toEpochMilli() + } else { + try { + reefDateFormat.parse(timestamp)?.time ?: 0 + } catch (e: Exception) { + 0 + } + } + } +} diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/SubstrateBalancesUtils.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/SubstrateBalancesUtils.kt index d667fb410d..ebc8e194f3 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/SubstrateBalancesUtils.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/SubstrateBalancesUtils.kt @@ -1,26 +1,14 @@ package jp.co.soramitsu.wallet.impl.data.network.model import android.util.Log -import java.math.BigInteger -import jp.co.soramitsu.common.data.network.runtime.binding.AccountData -import jp.co.soramitsu.common.data.network.runtime.binding.AccountInfo import jp.co.soramitsu.common.data.network.runtime.binding.AssetBalanceData import jp.co.soramitsu.common.data.network.runtime.binding.EmptyBalance -import jp.co.soramitsu.common.data.network.runtime.binding.bindNonce -import jp.co.soramitsu.common.data.network.runtime.binding.cast import jp.co.soramitsu.common.utils.Modules -import jp.co.soramitsu.common.utils.failure -import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.system import jp.co.soramitsu.common.utils.tokens import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.core.models.ChainAssetType -import jp.co.soramitsu.core.runtime.storage.returnType -import jp.co.soramitsu.runtime.multiNetwork.chain.ReefBalance -import jp.co.soramitsu.runtime.multiNetwork.chain.model.reefChainId import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot -import jp.co.soramitsu.shared_utils.runtime.definitions.types.composite.Struct -import jp.co.soramitsu.shared_utils.runtime.definitions.types.fromHexOrNull import jp.co.soramitsu.shared_utils.runtime.metadata.module import jp.co.soramitsu.shared_utils.runtime.metadata.storage import jp.co.soramitsu.shared_utils.runtime.metadata.storageKey @@ -81,9 +69,6 @@ fun handleBalanceResponse( scale: String? ): Result { return runCatching { - if (asset.chainId == reefChainId) { - return bindReefAccountInfo(runtime, scale) - } when (asset.typeExtra) { null, ChainAssetType.Normal, @@ -118,34 +103,3 @@ fun handleBalanceResponse( } } } - -private fun bindReefAccountInfo(runtime: RuntimeSnapshot, scale: String?): Result { - return runCatching { - val type = runtime.metadata.system().storage("Account") - .returnType() - - val dynamicInstance = type.fromHexOrNull( - runtime, - scale ?: return Result.failure("Reef system.Account returned null hex result") - ).cast() - - AccountInfo( - nonce = bindNonce(dynamicInstance["nonce"]), - data = dynamicInstance.get("data") - .let { - val freeBalance = ReefBalance((it?.get("free") as? BigInteger).orZero()) - val reservedBalance = ReefBalance((it?.get("reserved") as? BigInteger).orZero()) - val miscFrozenBalance = - ReefBalance((it?.get("miscFrozen") as? BigInteger).orZero()) - val feeFrozenBalance = - ReefBalance((it?.get("feeFrozen") as? BigInteger).orZero()) - AccountData( - free = freeBalance.planks, - reserved = reservedBalance.planks, - miscFrozen = miscFrozenBalance.planks, - feeFrozen = feeFrozenBalance.planks - ) - } - ) - } -} \ No newline at end of file diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt new file mode 100644 index 0000000000..64a5883ae4 --- /dev/null +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt @@ -0,0 +1,39 @@ +package jp.co.soramitsu.wallet.impl.data.network.model.request + +class ReefHistoryRequest( + accountAddress: String, + limit: Int = 50, + offset: String? = null +) { + val query = """ +query MyQuery { + transfersConnection(where: {AND: [{type_eq: Native}, {OR: [{from: {id_eq: "$accountAddress"}}, {to: {id_eq: "$accountAddress"}}]}]}, orderBy: timestamp_DESC, first: $limit, after: $offset) { + edges { + node { + id + amount + feeAmount + type + timestamp + success + denom + to { + id + } + from { + id + } + extrinsic { + hash + } + } + } + pageInfo { + endCursor + hasNextPage + startCursor + } + } +} +""".trimIndent() +} diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt new file mode 100644 index 0000000000..ae6a33066b --- /dev/null +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt @@ -0,0 +1,30 @@ +package jp.co.soramitsu.wallet.impl.data.network.model.response + +import java.math.BigInteger + +data class ReefHistoryResponse(val transfersConnection: ReefElementsConnection) + +class ReefElementsConnection( + val pageInfo: SubsquidPageInfo, + val edges: List +) + +class ReefHistoryEdge(val node: ReefHistoryNode) +class ReefHistoryNode( + val id: String, + val amount: BigInteger, + val feeAmount: BigInteger, + val type: String, + val timestamp: String, + val success: Boolean, + val denom: String, + val to: ReefAddress, + val from: ReefAddress, + val extrinsic: ReefExtrinsic? +) + +class ReefExtrinsic(val hash: String) + +class ReefAddress( + val id: String +) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt index 407c3d627d..fada86b5dd 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt @@ -5,11 +5,13 @@ import jp.co.soramitsu.common.data.network.subquery.GiantsquidResponse import jp.co.soramitsu.common.data.network.subquery.SubQueryResponse import jp.co.soramitsu.common.data.network.subquery.SubsquidResponse import jp.co.soramitsu.wallet.impl.data.network.model.request.GiantsquidHistoryRequest +import jp.co.soramitsu.wallet.impl.data.network.model.request.ReefHistoryRequest import jp.co.soramitsu.wallet.impl.data.network.model.request.SubqueryHistoryRequest import jp.co.soramitsu.wallet.impl.data.network.model.request.SubsquidHistoryRequest import jp.co.soramitsu.wallet.impl.data.network.model.response.EtherscanHistoryResponse import jp.co.soramitsu.wallet.impl.data.network.model.response.GiantsquidHistoryResponse import jp.co.soramitsu.wallet.impl.data.network.model.response.OkLinkHistoryResponse +import jp.co.soramitsu.wallet.impl.data.network.model.response.ReefHistoryResponse import jp.co.soramitsu.wallet.impl.data.network.model.response.SubqueryHistoryElementResponse import jp.co.soramitsu.wallet.impl.data.network.model.response.SubsquidHistoryElementsConnectionResponse import jp.co.soramitsu.wallet.impl.data.network.model.response.ZetaHistoryResponse @@ -65,4 +67,10 @@ interface OperationsHistoryApi { suspend fun getZetaOperationsHistory( @Url url: String ): ZetaHistoryResponse + + @POST + suspend fun getReefOperationsHistory( + @Url url: String, + @Body body: ReefHistoryRequest + ): SubsquidResponse } \ No newline at end of file diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSpecificUtils.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSpecificUtils.kt deleted file mode 100644 index a0618b24a8..0000000000 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/chain/ChainSpecificUtils.kt +++ /dev/null @@ -1,20 +0,0 @@ -package jp.co.soramitsu.runtime.multiNetwork.chain - -import io.emeraldpay.polkaj.scale.ScaleCodecReader -import java.math.BigInteger -import java.nio.ByteOrder -import jp.co.soramitsu.shared_utils.extensions.fromUnsignedBytes -import jp.co.soramitsu.shared_utils.scale.dataType.uint128 -import jp.co.soramitsu.shared_utils.scale.utils.toUnsignedBytes - -@JvmInline -value class ReefBalance(val value: BigInteger) { - val planks: BigInteger - get() { - val bytes = value.toUnsignedBytes().fromUnsignedBytes(ByteOrder.LITTLE_ENDIAN).toByteArray() - val newArray = ByteArray(16) - bytes.copyInto(newArray) - val reader = ScaleCodecReader(newArray) - return uint128.read(reader) - } -} \ No newline at end of file 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 3a45f66853..7c11dcae54 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 @@ -31,6 +31,7 @@ private fun mapSectionTypeRemoteToSectionType(section: String) = when (section) "etherscan" -> Chain.ExternalApi.Section.Type.ETHERSCAN "oklink" -> Chain.ExternalApi.Section.Type.OKLINK "zeta" -> Chain.ExternalApi.Section.Type.ZETA + "reef" -> Chain.ExternalApi.Section.Type.REEF else -> Chain.ExternalApi.Section.Type.UNKNOWN } @@ -40,6 +41,7 @@ private fun mapExplorerTypeRemoteToExplorerType(explorer: String) = when (explor "etherscan" -> Chain.Explorer.Type.ETHERSCAN "oklink" -> Chain.Explorer.Type.OKLINK "zeta" -> Chain.Explorer.Type.ZETA + "reef" -> Chain.Explorer.Type.REEF else -> Chain.Explorer.Type.UNKNOWN } 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 2525a91b85..f1a16f545a 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 @@ -64,16 +64,16 @@ data class Chain( ) { data class Section(val type: Type, val url: String) { enum class Type { - SUBQUERY, SORA, SUBSQUID, GIANTSQUID, ETHERSCAN, OKLINK, ZETA, UNKNOWN, GITHUB; + SUBQUERY, SORA, SUBSQUID, GIANTSQUID, ETHERSCAN, OKLINK, ZETA, REEF, UNKNOWN, GITHUB; - fun isHistory() = this in listOf(SUBQUERY, SORA, SUBSQUID, GIANTSQUID, ETHERSCAN, OKLINK, ZETA) + fun isHistory() = this in listOf(SUBQUERY, SORA, SUBSQUID, GIANTSQUID, ETHERSCAN, OKLINK, ZETA, REEF) } } } data class Explorer(val type: Type, val types: List, val url: String) { enum class Type { - POLKASCAN, SUBSCAN, ETHERSCAN, OKLINK, ZETA, UNKNOWN; + POLKASCAN, SUBSCAN, ETHERSCAN, OKLINK, ZETA, REEF, UNKNOWN; val capitalizedName: String = name.lowercase().replaceFirstChar { it.titlecase() } } diff --git a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt index bcc9cf0ae8..799235418c 100644 --- a/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt +++ b/runtime/src/main/java/jp/co/soramitsu/runtime/multiNetwork/runtime/RuntimeProvider.kt @@ -133,7 +133,7 @@ class RuntimeProvider( chainDao.getTypes("default") ?: throw ChainInfoNotInCacheException } .getOrElse { throw ChainInfoNotInCacheException } - runtimeFactory.constructRuntimeV13(metadataRaw, ownTypesRaw, defaultTypes) + runtimeFactory.constructRuntimeV13(metadataRaw, ownTypesRaw, defaultTypes, runtimeVersion) } else { runtimeFactory.constructRuntime(metadataRaw, ownTypesRaw, runtimeVersion) } From 62d7f69e8f7f737ce46c89c698baf840dae4e411 Mon Sep 17 00:00:00 2001 From: Deneath Date: Thu, 25 Jan 2024 17:23:49 +0700 Subject: [PATCH 13/35] add reef staking rewards --- .../subquery/ReefStakingRewardsResponse.kt | 96 +++++++++++++++++++ .../impl/data/network/subquery/StakingApi.kt | 8 ++ .../request/ReefStakingRewardsRequest.kt | 26 +++++ .../SubqueryStakingRewardsDataSource.kt | 22 +++++ 4 files changed, 152 insertions(+) create mode 100644 common/src/main/java/jp/co/soramitsu/common/data/network/subquery/ReefStakingRewardsResponse.kt create mode 100644 feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/request/ReefStakingRewardsRequest.kt diff --git a/common/src/main/java/jp/co/soramitsu/common/data/network/subquery/ReefStakingRewardsResponse.kt b/common/src/main/java/jp/co/soramitsu/common/data/network/subquery/ReefStakingRewardsResponse.kt new file mode 100644 index 0000000000..64cc9d51c7 --- /dev/null +++ b/common/src/main/java/jp/co/soramitsu/common/data/network/subquery/ReefStakingRewardsResponse.kt @@ -0,0 +1,96 @@ +package jp.co.soramitsu.common.data.network.subquery + +import java.math.BigInteger + +class ReefStakingRewardsResponse ( + val stakingsConnection: ReefRewardsConnection +) + +class SubsquidPageInfo( + val hasNextPage: Boolean, + val endCursor: String +) + +class ReefRewardsConnection( + val edges: List, + val pageInfo: SubsquidPageInfo +) +class ReefRewardsEdge( + val node: ReefRewardsNode +) +class ReefRewardsNode( + val id: String, + val type: String, + val amount: BigInteger, + val timestamp: String, + val signer: ReefAddress +) + +class ReefAddress( + val id: String +) +//"stakingsConnection": { +// "edges": [ +// { +// "node": { +// "id": "0008435587-000012-2d7db", +// "type": "Reward", +// "amount": "0", +// "timestamp": "2024-01-24T13:36:30.000000Z", +// "signer": { +// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" +// } +// } +// }, +// { +// "node": { +// "id": "0008435117-000011-2e965", +// "type": "Reward", +// "amount": "306857767686205", +// "timestamp": "2024-01-24T12:18:10.000000Z", +// "signer": { +// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" +// } +// } +// }, +// { +// "node": { +// "id": "0008427594-000032-42e47", +// "type": "Reward", +// "amount": "0", +// "timestamp": "2024-01-23T15:24:20.000000Z", +// "signer": { +// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" +// } +// } +// }, +// { +// "node": { +// "id": "0008427594-000015-42e47", +// "type": "Reward", +// "amount": "0", +// "timestamp": "2024-01-23T15:24:20.000000Z", +// "signer": { +// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" +// } +// } +// }, +// { +// "node": { +// "id": "0008427594-000024-42e47", +// "type": "Reward", +// "amount": "0", +// "timestamp": "2024-01-23T15:24:20.000000Z", +// "signer": { +// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" +// } +// } +// } +// ], +// "totalCount": 198, +// "pageInfo": { +// "endCursor": "5", +// "hasNextPage": true +// } +// } +// } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/StakingApi.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/StakingApi.kt index c0074d3ded..32678b0eb1 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/StakingApi.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/StakingApi.kt @@ -2,6 +2,7 @@ package jp.co.soramitsu.staking.impl.data.network.subquery import jp.co.soramitsu.common.data.network.subquery.EraValidatorInfoQueryResponse import jp.co.soramitsu.common.data.network.subquery.GiantsquidRewardAmountResponse +import jp.co.soramitsu.common.data.network.subquery.ReefStakingRewardsResponse import jp.co.soramitsu.common.data.network.subquery.SoraEraInfoValidatorResponse import jp.co.soramitsu.common.data.network.subquery.StakingCollatorsApyResponse import jp.co.soramitsu.common.data.network.subquery.StakingHistoryRemote @@ -16,6 +17,7 @@ import jp.co.soramitsu.common.data.network.subquery.SubsquidRewardResponse import jp.co.soramitsu.common.data.network.subquery.SubsquidSoraStakingRewards import jp.co.soramitsu.common.data.network.subquery.TransactionHistoryRemote import jp.co.soramitsu.staking.impl.data.network.subquery.request.GiantsquidRewardAmountRequest +import jp.co.soramitsu.staking.impl.data.network.subquery.request.ReefStakingRewardsRequest import jp.co.soramitsu.staking.impl.data.network.subquery.request.StakingAllCollatorsApyRequest import jp.co.soramitsu.staking.impl.data.network.subquery.request.StakingCollatorsApyRequest import jp.co.soramitsu.staking.impl.data.network.subquery.request.StakingDelegatorHistoryRequest @@ -118,4 +120,10 @@ interface StakingApi { @Url url: String, @Body body: SubsquidSoraStakingRewardsRequest ): SubsquidResponse + + @POST + suspend fun getReefRewards( + @Url url: String, + @Body body: ReefStakingRewardsRequest + ): SubsquidResponse } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/request/ReefStakingRewardsRequest.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/request/ReefStakingRewardsRequest.kt new file mode 100644 index 0000000000..adfeb278ba --- /dev/null +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/request/ReefStakingRewardsRequest.kt @@ -0,0 +1,26 @@ +package jp.co.soramitsu.staking.impl.data.network.subquery.request + +class ReefStakingRewardsRequest(address: String, pageSize: Int = 100, offset: String? = null) { + val query = """ + query MyQuery { + stakingsConnection(orderBy: timestamp_DESC, where: {signer: {id_eq: "$address"}}, first: $pageSize, after: $offset) { + edges { + node { + id + type + amount + timestamp + signer { + id + } + } + } + totalCount + pageInfo { + endCursor + hasNextPage + } + } + } + """.trimIndent() +} \ No newline at end of file diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/datasource/SubqueryStakingRewardsDataSource.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/datasource/SubqueryStakingRewardsDataSource.kt index 2cfdad56d5..e3d0059eb0 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/datasource/SubqueryStakingRewardsDataSource.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/datasource/SubqueryStakingRewardsDataSource.kt @@ -1,6 +1,8 @@ package jp.co.soramitsu.staking.impl.data.repository.datasource +import java.math.BigInteger import jp.co.soramitsu.common.base.errors.RewardsNotSupportedWarning +import jp.co.soramitsu.common.data.network.subquery.ReefRewardsNode import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.sumByBigDecimal import jp.co.soramitsu.common.utils.sumByBigInteger @@ -19,6 +21,7 @@ import jp.co.soramitsu.staking.impl.data.mappers.mapSubqueryHistoryToTotalReward import jp.co.soramitsu.staking.impl.data.mappers.mapTotalRewardLocalToTotalReward import jp.co.soramitsu.staking.impl.data.network.subquery.StakingApi import jp.co.soramitsu.staking.impl.data.network.subquery.request.GiantsquidRewardAmountRequest +import jp.co.soramitsu.staking.impl.data.network.subquery.request.ReefStakingRewardsRequest import jp.co.soramitsu.staking.impl.data.network.subquery.request.StakingSumRewardRequest import jp.co.soramitsu.staking.impl.data.network.subquery.request.SubsquidEthRewardAmountRequest import jp.co.soramitsu.staking.impl.data.network.subquery.request.SubsquidRelayRewardAmountRequest @@ -73,6 +76,10 @@ class SubqueryStakingRewardsDataSource( syncGiantsquidRelay(stakingUrl, accountAddress) } + stakingType == Chain.ExternalApi.Section.Type.REEF -> { + syncReefRewards(stakingUrl, accountAddress) + } + else -> throw RewardsNotSupportedWarning() } } @@ -106,6 +113,21 @@ class SubqueryStakingRewardsDataSource( stakingTotalRewardDao.insert(TotalRewardLocal(accountAddress, totalInPlanks)) } + private suspend fun syncReefRewards(stakingUrl: String, accountAddress: String) { + var hasNextPage = true + var nextCursor: String? = null + var rewardsTotal = BigInteger.ZERO + + while (hasNextPage) { + val response = stakingApi.getReefRewards(stakingUrl, ReefStakingRewardsRequest(accountAddress, offset = nextCursor?.let { "\"$it\"" })) + hasNextPage = response.data.stakingsConnection.pageInfo.hasNextPage + nextCursor = response.data.stakingsConnection.pageInfo.endCursor + rewardsTotal += response.data.stakingsConnection.edges.map { it.node }.sumByBigInteger { it.amount } + } + + stakingTotalRewardDao.insert(TotalRewardLocal(accountAddress, rewardsTotal)) + } + private suspend fun syncSubquery(stakingUrl: String, accountAddress: String) = withContext(Dispatchers.IO) { val r = stakingApi.getSumReward( stakingUrl, From c3efae82e7ddd976f7e092a23f6b9a18cc615b7c Mon Sep 17 00:00:00 2001 From: Deneath Date: Thu, 25 Jan 2024 18:47:25 +0700 Subject: [PATCH 14/35] load reef staking rewards with transfers --- .../subquery/ReefStakingRewardsResponse.kt | 67 +---------- .../request/ReefStakingRewardsRequest.kt | 2 +- .../data/historySource/ReefHistorySource.kt | 79 ++++++++----- .../model/request/ReefHistoryRequest.kt | 106 +++++++++++++----- .../model/response/ReefHistoryResponse.kt | 7 +- .../network/subquery/OperationsHistoryApi.kt | 1 + 6 files changed, 136 insertions(+), 126 deletions(-) diff --git a/common/src/main/java/jp/co/soramitsu/common/data/network/subquery/ReefStakingRewardsResponse.kt b/common/src/main/java/jp/co/soramitsu/common/data/network/subquery/ReefStakingRewardsResponse.kt index 64cc9d51c7..5d76f8c587 100644 --- a/common/src/main/java/jp/co/soramitsu/common/data/network/subquery/ReefStakingRewardsResponse.kt +++ b/common/src/main/java/jp/co/soramitsu/common/data/network/subquery/ReefStakingRewardsResponse.kt @@ -28,69 +28,4 @@ class ReefRewardsNode( class ReefAddress( val id: String -) -//"stakingsConnection": { -// "edges": [ -// { -// "node": { -// "id": "0008435587-000012-2d7db", -// "type": "Reward", -// "amount": "0", -// "timestamp": "2024-01-24T13:36:30.000000Z", -// "signer": { -// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" -// } -// } -// }, -// { -// "node": { -// "id": "0008435117-000011-2e965", -// "type": "Reward", -// "amount": "306857767686205", -// "timestamp": "2024-01-24T12:18:10.000000Z", -// "signer": { -// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" -// } -// } -// }, -// { -// "node": { -// "id": "0008427594-000032-42e47", -// "type": "Reward", -// "amount": "0", -// "timestamp": "2024-01-23T15:24:20.000000Z", -// "signer": { -// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" -// } -// } -// }, -// { -// "node": { -// "id": "0008427594-000015-42e47", -// "type": "Reward", -// "amount": "0", -// "timestamp": "2024-01-23T15:24:20.000000Z", -// "signer": { -// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" -// } -// } -// }, -// { -// "node": { -// "id": "0008427594-000024-42e47", -// "type": "Reward", -// "amount": "0", -// "timestamp": "2024-01-23T15:24:20.000000Z", -// "signer": { -// "id": "5GecoStYi2bHzKz6LwE2LWa8MWJxaZYAGjx2WeH8r4RTnQ6e" -// } -// } -// } -// ], -// "totalCount": 198, -// "pageInfo": { -// "endCursor": "5", -// "hasNextPage": true -// } -// } -// } +) \ No newline at end of file diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/request/ReefStakingRewardsRequest.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/request/ReefStakingRewardsRequest.kt index adfeb278ba..883ec80c14 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/request/ReefStakingRewardsRequest.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/subquery/request/ReefStakingRewardsRequest.kt @@ -3,7 +3,7 @@ package jp.co.soramitsu.staking.impl.data.network.subquery.request class ReefStakingRewardsRequest(address: String, pageSize: Int = 100, offset: String? = null) { val query = """ query MyQuery { - stakingsConnection(orderBy: timestamp_DESC, where: {signer: {id_eq: "$address"}}, first: $pageSize, after: $offset) { + stakingsConnection(orderBy: timestamp_DESC, where: {AND: {signer: {id_eq: "$address"}, amount_gt: "0"}}, first: $pageSize, after: $offset) { edges { node { id diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt index d6494b7e70..9b49ba872b 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt @@ -9,6 +9,7 @@ import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.runtime.multiNetwork.chain.model.Chain import jp.co.soramitsu.shared_utils.runtime.AccountId import jp.co.soramitsu.wallet.impl.data.network.model.request.ReefHistoryRequest +import jp.co.soramitsu.wallet.impl.data.network.model.request.ReefRequestBuilder import jp.co.soramitsu.wallet.impl.data.network.subquery.OperationsHistoryApi import jp.co.soramitsu.wallet.impl.domain.interfaces.TransactionFilter import jp.co.soramitsu.wallet.impl.domain.model.Operation @@ -28,43 +29,71 @@ class ReefHistorySource( ): CursorPage { val overridePageSize = 50 val offset = cursor?.toIntOrNull().takeIf { it != 0 } + val response = walletOperationsApi.getReefOperationsHistory( url = url, - ReefHistoryRequest( + ReefRequestBuilder( + filters, accountAddress = accountAddress, overridePageSize, offset.toString() - ) + ).buildRequest() ) - if (!filters.contains(TransactionFilter.TRANSFER)) { - return CursorPage(null, emptyList()) + val operations = mutableListOf() + if(filters.contains(TransactionFilter.TRANSFER)) { + operations.addAll(response.data.transfersConnection.edges.map { it.node }.map { + Operation( + id = it.extrinsic?.hash ?: it.id, + address = accountAddress, + time = parseTimeToMillis(it.timestamp), + chainAsset = chainAsset, + type = Operation.Type.Transfer( + hash = it.extrinsic?.hash, + myAddress = accountAddress, + amount = it.amount, + receiver = it.to.id, + sender = it.from.id, + status = Operation.Status.fromSuccess(it.success), + fee = it.feeAmount + ) + ) + }) } - val operations = response.data.transfersConnection.edges.map { it.node }.map { - Operation( - id = it.extrinsic?.hash ?: it.id, - address = accountAddress, - time = parseTimeToMillis(it.timestamp), - chainAsset = chainAsset, - type = Operation.Type.Transfer( - hash = it.extrinsic?.hash, - myAddress = accountAddress, - amount = it.amount, - receiver = it.to.id, - sender = it.from.id, - status = Operation.Status.fromSuccess(it.success), - fee = it.feeAmount + if(filters.contains(TransactionFilter.REWARD)) { + operations.addAll(response.data.stakingsConnection.edges.map { it.node }.map { + Operation( + id = it.id, + address = accountAddress, + time = parseTimeToMillis(it.timestamp), + chainAsset = chainAsset, + type = Operation.Type.Reward( + amount = it.amount, + isReward = true, + era = 0, + validator = null + ) ) - ) + }) } - val pageInfo = response.data.transfersConnection.pageInfo - val nextCursor = if (pageInfo.hasNextPage && (pageInfo.endCursor.toIntOrNull() - ?: 0) >= overridePageSize - ) { - pageInfo.endCursor + + val transfersPageInfo = response.data.transfersConnection.pageInfo + val rewardsPageInfo = response.data.stakingsConnection.pageInfo + + val shouldLoadTransfersNextPage = transfersPageInfo.hasNextPage + val shouldLoadRewardsNextPage = rewardsPageInfo.hasNextPage + + val hasNextPage = shouldLoadTransfersNextPage || shouldLoadRewardsNextPage + + val nextCursor = if(hasNextPage) { + val transfersOffset = transfersPageInfo.endCursor.toIntOrNull() ?: 0 + val rewardsOffset = rewardsPageInfo.endCursor.toIntOrNull() ?: 0 + val nextOffset = maxOf(transfersOffset, rewardsOffset) + if(nextOffset >= overridePageSize) nextOffset.toString() else null } else { null } - return CursorPage(nextCursor, operations) + + return CursorPage(nextCursor, operations.sortedByDescending { it.time }) } private fun TransactionFilter.isAppliedOrNull(filters: Collection) = when { diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt index 64a5883ae4..2c8f1fd63c 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt @@ -1,39 +1,85 @@ package jp.co.soramitsu.wallet.impl.data.network.model.request -class ReefHistoryRequest( - accountAddress: String, - limit: Int = 50, - offset: String? = null +import jp.co.soramitsu.wallet.impl.domain.interfaces.TransactionFilter + +class ReefRequestBuilder( + private val filters: Set, + private val accountAddress: String, + private val limit: Int = 50, + private val transfersOffset: String? = null, + private val rewardsOffset: String? = null ) { - val query = """ -query MyQuery { - transfersConnection(where: {AND: [{type_eq: Native}, {OR: [{from: {id_eq: "$accountAddress"}}, {to: {id_eq: "$accountAddress"}}]}]}, orderBy: timestamp_DESC, first: $limit, after: $offset) { - edges { - node { - id - amount - feeAmount - type - timestamp - success - denom - to { - id + fun buildRequest(): ReefHistoryRequest { + val query = StringBuilder() + if (filters.contains(TransactionFilter.TRANSFER)) { + query.append( + """ + transfersConnection(where: {AND: [{type_eq: Native}, {OR: [{from: {id_eq: "$accountAddress"}}, {to: {id_eq: "$accountAddress"}}]}]}, orderBy: timestamp_DESC, first: $limit, after: $transfersOffset) { + edges { + node { + id + amount + feeAmount + type + timestamp + success + denom + to { + id + } + from { + id + } + extrinsic { + hash + } + } + } + pageInfo { + endCursor + hasNextPage + startCursor + } + } + """.trimIndent() + ) } - from { - id + if (filters.contains(TransactionFilter.REWARD)) { + query.append( + """ + stakingsConnection(orderBy: timestamp_DESC, where: {AND: {signer: {id_eq: "$accountAddress"}, amount_gt: "0"}}, first: $limit, after: $rewardsOffset) { + edges { + node { + id + type + amount + timestamp + signer { + id + } + } + } + totalCount + pageInfo { + endCursor + hasNextPage + } + } + """.trimIndent() + ) } - extrinsic { - hash - } - } - } - pageInfo { - endCursor - hasNextPage - startCursor + + return ReefHistoryRequest(query.toString()) } - } + +} + +class ReefHistoryRequest( + query: String +) { + val query = """ +query MyQuery { + $query } """.trimIndent() } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt index ae6a33066b..8947fc4b09 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt @@ -1,8 +1,10 @@ package jp.co.soramitsu.wallet.impl.data.network.model.response import java.math.BigInteger +import jp.co.soramitsu.common.data.network.subquery.ReefAddress +import jp.co.soramitsu.common.data.network.subquery.ReefRewardsConnection -data class ReefHistoryResponse(val transfersConnection: ReefElementsConnection) +data class ReefHistoryResponse(val transfersConnection: ReefElementsConnection, val stakingsConnection: ReefRewardsConnection) class ReefElementsConnection( val pageInfo: SubsquidPageInfo, @@ -25,6 +27,3 @@ class ReefHistoryNode( class ReefExtrinsic(val hash: String) -class ReefAddress( - val id: String -) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt index fada86b5dd..bca81368f3 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt @@ -2,6 +2,7 @@ package jp.co.soramitsu.wallet.impl.data.network.subquery import jp.co.soramitsu.common.BuildConfig import jp.co.soramitsu.common.data.network.subquery.GiantsquidResponse +import jp.co.soramitsu.common.data.network.subquery.ReefStakingRewardsResponse import jp.co.soramitsu.common.data.network.subquery.SubQueryResponse import jp.co.soramitsu.common.data.network.subquery.SubsquidResponse import jp.co.soramitsu.wallet.impl.data.network.model.request.GiantsquidHistoryRequest From 7bc87dd9c2ec4f38249902f13293b1759a774627 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 26 Jan 2024 16:14:15 +0700 Subject: [PATCH 15/35] switch configs to master --- runtime/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/build.gradle b/runtime/build.gradle index 8ac37469a6..1a8b4ef3e3 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -14,7 +14,7 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildConfigField "String", "TYPES_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/master/chains/all_chains_types_android.json\"" buildConfigField "String", "APP_VERSION_NAME", "\"${rootProject.versionName}\"" - buildConfigField("String", "DEFAULT_V13_TYPES_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/reef/chains/default_v13_types.json\"") + buildConfigField("String", "DEFAULT_V13_TYPES_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/master/chains/default_v13_types.json\"") } buildTypes { From fc5ae1ed0783b3c901e9d0860c17bea0fcdef3a5 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 2 Feb 2024 15:56:17 +0700 Subject: [PATCH 16/35] Fixed transactions history for reef --- .../data/historySource/ReefHistorySource.kt | 32 +++++++++---------- .../model/request/ReefHistoryRequest.kt | 16 +++------- .../model/response/ReefHistoryResponse.kt | 7 ++-- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt index 9b49ba872b..fce01a0de6 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt @@ -8,7 +8,6 @@ import jp.co.soramitsu.common.data.model.CursorPage import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.runtime.multiNetwork.chain.model.Chain import jp.co.soramitsu.shared_utils.runtime.AccountId -import jp.co.soramitsu.wallet.impl.data.network.model.request.ReefHistoryRequest import jp.co.soramitsu.wallet.impl.data.network.model.request.ReefRequestBuilder import jp.co.soramitsu.wallet.impl.data.network.subquery.OperationsHistoryApi import jp.co.soramitsu.wallet.impl.domain.interfaces.TransactionFilter @@ -36,19 +35,20 @@ class ReefHistorySource( filters, accountAddress = accountAddress, overridePageSize, - offset.toString() + offset?.toString() ).buildRequest() ) + val operations = mutableListOf() - if(filters.contains(TransactionFilter.TRANSFER)) { - operations.addAll(response.data.transfersConnection.edges.map { it.node }.map { + if(filters.contains(TransactionFilter.TRANSFER) && response.data.transfersConnection != null) { + operations.addAll(response.data.transfersConnection?.edges?.map { it.node }?.map { Operation( - id = it.extrinsic?.hash ?: it.id, + id = it.extrinsicHash ?: it.id, address = accountAddress, time = parseTimeToMillis(it.timestamp), chainAsset = chainAsset, type = Operation.Type.Transfer( - hash = it.extrinsic?.hash, + hash = it.extrinsicHash, myAddress = accountAddress, amount = it.amount, receiver = it.to.id, @@ -57,10 +57,10 @@ class ReefHistorySource( fee = it.feeAmount ) ) - }) + }.orEmpty()) } - if(filters.contains(TransactionFilter.REWARD)) { - operations.addAll(response.data.stakingsConnection.edges.map { it.node }.map { + if(filters.contains(TransactionFilter.REWARD) && response.data.stakingsConnection != null) { + operations.addAll(response.data.stakingsConnection?.edges?.map { it.node }?.map { Operation( id = it.id, address = accountAddress, @@ -73,20 +73,20 @@ class ReefHistorySource( validator = null ) ) - }) + }.orEmpty()) } - val transfersPageInfo = response.data.transfersConnection.pageInfo - val rewardsPageInfo = response.data.stakingsConnection.pageInfo + val transfersPageInfo = response.data.transfersConnection?.pageInfo + val rewardsPageInfo = response.data.stakingsConnection?.pageInfo - val shouldLoadTransfersNextPage = transfersPageInfo.hasNextPage - val shouldLoadRewardsNextPage = rewardsPageInfo.hasNextPage + val shouldLoadTransfersNextPage = transfersPageInfo?.hasNextPage ?: false + val shouldLoadRewardsNextPage = rewardsPageInfo?.hasNextPage ?: false val hasNextPage = shouldLoadTransfersNextPage || shouldLoadRewardsNextPage val nextCursor = if(hasNextPage) { - val transfersOffset = transfersPageInfo.endCursor.toIntOrNull() ?: 0 - val rewardsOffset = rewardsPageInfo.endCursor.toIntOrNull() ?: 0 + val transfersOffset = transfersPageInfo?.endCursor?.toIntOrNull() ?: 0 + val rewardsOffset = rewardsPageInfo?.endCursor?.toIntOrNull() ?: 0 val nextOffset = maxOf(transfersOffset, rewardsOffset) if(nextOffset >= overridePageSize) nextOffset.toString() else null } else { diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt index 2c8f1fd63c..fd8233d152 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt @@ -6,33 +6,28 @@ class ReefRequestBuilder( private val filters: Set, private val accountAddress: String, private val limit: Int = 50, - private val transfersOffset: String? = null, - private val rewardsOffset: String? = null + private val transfersOffset: String? = null ) { fun buildRequest(): ReefHistoryRequest { + val offset = transfersOffset?.let { "\"$it\"" } val query = StringBuilder() if (filters.contains(TransactionFilter.TRANSFER)) { query.append( """ - transfersConnection(where: {AND: [{type_eq: Native}, {OR: [{from: {id_eq: "$accountAddress"}}, {to: {id_eq: "$accountAddress"}}]}]}, orderBy: timestamp_DESC, first: $limit, after: $transfersOffset) { + transfersConnection(where: {AND: [{type_eq: Native}, {OR: [{from: {id_eq: "$accountAddress"}}, {to: {id_eq: "$accountAddress"}}]}]}, orderBy: timestamp_DESC, first: $limit, after: $offset) { edges { node { id amount - feeAmount - type timestamp success - denom to { id } from { id } - extrinsic { - hash - } + extrinsicHash } } pageInfo { @@ -47,11 +42,10 @@ class ReefRequestBuilder( if (filters.contains(TransactionFilter.REWARD)) { query.append( """ - stakingsConnection(orderBy: timestamp_DESC, where: {AND: {signer: {id_eq: "$accountAddress"}, amount_gt: "0"}}, first: $limit, after: $rewardsOffset) { + stakingsConnection(orderBy: timestamp_DESC, where: {AND: {signer: {id_eq: "$accountAddress"}, amount_gt: "0"}}, first: ${limit * 2}, after: $offset) { edges { node { id - type amount timestamp signer { diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt index 8947fc4b09..d13334ec0e 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt @@ -4,7 +4,7 @@ import java.math.BigInteger import jp.co.soramitsu.common.data.network.subquery.ReefAddress import jp.co.soramitsu.common.data.network.subquery.ReefRewardsConnection -data class ReefHistoryResponse(val transfersConnection: ReefElementsConnection, val stakingsConnection: ReefRewardsConnection) +data class ReefHistoryResponse(val transfersConnection: ReefElementsConnection? = null, val stakingsConnection: ReefRewardsConnection? = null) class ReefElementsConnection( val pageInfo: SubsquidPageInfo, @@ -19,11 +19,8 @@ class ReefHistoryNode( val type: String, val timestamp: String, val success: Boolean, - val denom: String, val to: ReefAddress, val from: ReefAddress, - val extrinsic: ReefExtrinsic? + val extrinsicHash: String? ) -class ReefExtrinsic(val hash: String) - From cf8750dad49c9d68b33daafbcb1425e8e4710b94 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 2 Feb 2024 16:43:18 +0700 Subject: [PATCH 17/35] rebase fixes --- .../jp/co/soramitsu/success/presentation/SuccessViewModel.kt | 1 + .../co/soramitsu/runtime/multiNetwork/chain/ChainSyncService.kt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/feature-success-impl/src/main/kotlin/jp/co/soramitsu/success/presentation/SuccessViewModel.kt b/feature-success-impl/src/main/kotlin/jp/co/soramitsu/success/presentation/SuccessViewModel.kt index 875d57ece0..eb2bab41ff 100644 --- a/feature-success-impl/src/main/kotlin/jp/co/soramitsu/success/presentation/SuccessViewModel.kt +++ b/feature-success-impl/src/main/kotlin/jp/co/soramitsu/success/presentation/SuccessViewModel.kt @@ -74,6 +74,7 @@ class SuccessViewModel @Inject constructor( BlockExplorerUrlBuilder(explorerItem.url, explorerItem.types).build(BlockExplorerUrlBuilder.Type.TX, operationHash) } + Chain.Explorer.Type.REEF -> BlockExplorerUrlBuilder(explorerItem.url, explorerItem.types).build(BlockExplorerUrlBuilder.Type.EXTRINSIC, operationHash) Chain.Explorer.Type.UNKNOWN -> null }?.let { url -> explorerItem.type to url 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 c9f207ef4d..80f3f21d99 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 @@ -19,7 +19,7 @@ class ChainSyncService( val remoteChains = chainFetcher.getChains() .filter { - !it.disabled && (it.assets?.isNotEmpty() == true) && it.chainId != reefChainId // todo reef + !it.disabled && (it.assets?.isNotEmpty() == true) } .map { it.toChain() From bc0e953c8c29325144f168ee2122798a8f828fd2 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 2 Feb 2024 17:37:14 +0700 Subject: [PATCH 18/35] Fix transactions history fee --- .../impl/data/historySource/ReefHistorySource.kt | 4 ++-- .../data/network/model/request/ReefHistoryRequest.kt | 2 +- .../network/model/response/ReefHistoryResponse.kt | 11 ++++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt index fce01a0de6..46b53d82a4 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt @@ -43,7 +43,7 @@ class ReefHistorySource( if(filters.contains(TransactionFilter.TRANSFER) && response.data.transfersConnection != null) { operations.addAll(response.data.transfersConnection?.edges?.map { it.node }?.map { Operation( - id = it.extrinsicHash ?: it.id, + id = it.extrinsicHash ?: it.id ?: it.hashCode().toString(), address = accountAddress, time = parseTimeToMillis(it.timestamp), chainAsset = chainAsset, @@ -54,7 +54,7 @@ class ReefHistorySource( receiver = it.to.id, sender = it.from.id, status = Operation.Status.fromSuccess(it.success), - fee = it.feeAmount + fee = it.signedData?.fee?.partialFee ) ) }.orEmpty()) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt index fd8233d152..aaee312017 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/request/ReefHistoryRequest.kt @@ -17,7 +17,6 @@ class ReefRequestBuilder( transfersConnection(where: {AND: [{type_eq: Native}, {OR: [{from: {id_eq: "$accountAddress"}}, {to: {id_eq: "$accountAddress"}}]}]}, orderBy: timestamp_DESC, first: $limit, after: $offset) { edges { node { - id amount timestamp success @@ -27,6 +26,7 @@ class ReefRequestBuilder( from { id } + signedData extrinsicHash } } diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt index d13334ec0e..d8816a6bba 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/model/response/ReefHistoryResponse.kt @@ -13,14 +13,19 @@ class ReefElementsConnection( class ReefHistoryEdge(val node: ReefHistoryNode) class ReefHistoryNode( - val id: String, + val id: String? = null, val amount: BigInteger, - val feeAmount: BigInteger, val type: String, val timestamp: String, val success: Boolean, val to: ReefAddress, val from: ReefAddress, - val extrinsicHash: String? + val extrinsicHash: String?, + val signedData: ReefSignedData? ) +class ReefSignedData(val fee: ReefFeeData?) + +class ReefFeeData( + val partialFee: BigInteger? +) \ No newline at end of file From 10ce0274e90ce29d697780f92ed38ee2e7b5cc74 Mon Sep 17 00:00:00 2001 From: Deneath Date: Tue, 6 Feb 2024 00:58:51 +0700 Subject: [PATCH 19/35] Added oversubscribed validators alert --- .../staking/impl/domain/alerts/Alert.kt | 1 + .../impl/domain/alerts/AlertsInteractor.kt | 25 +++++++++++++------ .../StakingRelaychainScenarioViewModel.kt | 13 ++++++++-- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/Alert.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/Alert.kt index 44d79777fc..7fe0a2a0d0 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/Alert.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/Alert.kt @@ -12,6 +12,7 @@ sealed class Alert { class BondMoreTokens(val minimalStake: BigDecimal, val token: Token) : Alert() object ChangeValidators : Alert() + object AllValidatorsAreOversubscribed : Alert() object WaitingForNextEra : Alert() diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/AlertsInteractor.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/AlertsInteractor.kt index ace9cabba1..db7bde09f9 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/AlertsInteractor.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/alerts/AlertsInteractor.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import java.math.BigDecimal import java.math.BigInteger +import jp.co.soramitsu.shared_utils.extensions.toHexString import jp.co.soramitsu.core.models.Asset as CoreAsset private const val NOMINATIONS_ACTIVE_MEMO = "NOMINATIONS_ACTIVE_MEMO" @@ -38,7 +39,8 @@ class AlertsInteractor( val maxRewardedNominatorsPerValidator: Int, val minimumNominatorBond: BigInteger, val activeEra: BigInteger, - val asset: Asset + val asset: Asset, + val maxNominators: Int ) { val memo = mutableMapOf() @@ -63,11 +65,17 @@ class AlertsInteractor( private fun produceChangeValidatorsAlert(context: AlertContext): Alert? { return requireState(context.stakingState) { nominatorState: StakingState.Stash.Nominator -> - Alert.ChangeValidators.takeIf { - // staking is inactive - context.isStakingActive(nominatorState.stashId).not() && - // there is no pending change - nominatorState.nominations.isWaiting(context.activeEra).not() + val allValidatorsAreOversubscribed = nominatorState.nominations.targets.mapNotNull { context.exposures[it.toHexString()] }.all { it.others.size > context.maxNominators } + val stakingIsNotActive = context.isStakingActive(nominatorState.stashId).not() + + if (stakingIsNotActive.not()) return null + + return@requireState when { + stakingIsNotActive && allValidatorsAreOversubscribed -> Alert.AllValidatorsAreOversubscribed + stakingIsNotActive && nominatorState.nominations.isWaiting(context.activeEra) + .not() -> Alert.ChangeValidators + + else -> null } } } @@ -124,6 +132,8 @@ class AlertsInteractor( val minimumNominatorBond = stakingRepository.minimumNominatorBond(chainAsset) val meta = accountRepository.getSelectedMetaAccount() + val maxNominators = stakingConstantsRepository.maxRewardedNominatorPerValidator(chain.id) + val alertsFlow = combine( stakingRepository.electedExposuresInActiveEra(chain.id), walletRepository.assetFlow(meta.id, stakingState.accountId, chainAsset, chain.minSupportedVersion), @@ -136,7 +146,8 @@ class AlertsInteractor( maxRewardedNominatorsPerValidator = maxRewardedNominatorsPerValidator, minimumNominatorBond = minimumNominatorBond, asset = asset, - activeEra = activeEra + activeEra = activeEra, + maxNominators = maxNominators ) alertProducers.mapNotNull { it.invoke(context) } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt index 9234f9e4b5..e1f9f43c7b 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingRelaychainScenarioViewModel.kt @@ -194,7 +194,7 @@ class StakingRelaychainScenarioViewModel( private fun mapAlertToAlertModel(alert: Alert): AlertModel { return when (alert) { - Alert.ChangeValidators -> { + is Alert.ChangeValidators -> { AlertModel( WARNING_ICON, resourceManager.getString(R.string.staking_alert_change_validators), @@ -203,6 +203,15 @@ class StakingRelaychainScenarioViewModel( ) } + is Alert.AllValidatorsAreOversubscribed -> { + AlertModel( + WARNING_ICON, + resourceManager.getString(R.string.staking_alert_change_validators), + resourceManager.getString(R.string.staking_your_oversubscribed_message), + AlertModel.Type.CallToAction { baseViewModel.openCurrentValidators() } + ) + } + is Alert.RedeemTokens -> { AlertModel( WARNING_ICON, @@ -230,7 +239,7 @@ class StakingRelaychainScenarioViewModel( AlertModel.Type.Info ) - Alert.SetValidators -> AlertModel( + is Alert.SetValidators -> AlertModel( WARNING_ICON, resourceManager.getString(R.string.staking_set_validators_title), resourceManager.getString(R.string.staking_set_validators_message), From a21e53447dc022519002fbdba888575648db0d4b Mon Sep 17 00:00:00 2001 From: Deneath Date: Thu, 8 Feb 2024 17:06:58 +0700 Subject: [PATCH 20/35] fix reef bugs --- .../staking/bond/confirm/ConfirmBondMoreViewModel.kt | 1 + feature-staking-impl/src/main/res/layout/view_stake_summary.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/bond/confirm/ConfirmBondMoreViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/bond/confirm/ConfirmBondMoreViewModel.kt index 8c5fd9f862..4291f43531 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/bond/confirm/ConfirmBondMoreViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/bond/confirm/ConfirmBondMoreViewModel.kt @@ -150,6 +150,7 @@ class ConfirmBondMoreViewModel @Inject constructor( showMessage(resourceManager.getString(R.string.common_transaction_submitted)) finishFlow() + result.getOrNull()?.let { router.openOperationSuccess(it, token.configuration.chainId) } } else { showError(result.requireException()) } diff --git a/feature-staking-impl/src/main/res/layout/view_stake_summary.xml b/feature-staking-impl/src/main/res/layout/view_stake_summary.xml index abafac7e25..940a398bff 100644 --- a/feature-staking-impl/src/main/res/layout/view_stake_summary.xml +++ b/feature-staking-impl/src/main/res/layout/view_stake_summary.xml @@ -62,7 +62,7 @@ android:layout_marginEnd="16dp" android:layout_weight="1" app:startWithLoading="true" - app:titleText="@string/staking_rewards_apr" /> + app:titleText="@string/staking_total_rewards_v1.9.0" /> Date: Thu, 8 Feb 2024 17:41:53 +0500 Subject: [PATCH 21/35] fix crash --- .../pool/join/SetupStakingPoolViewModel.kt | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/setup/pool/join/SetupStakingPoolViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/setup/pool/join/SetupStakingPoolViewModel.kt index 00ce7c0f11..2ff591a674 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/setup/pool/join/SetupStakingPoolViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/setup/pool/join/SetupStakingPoolViewModel.kt @@ -22,7 +22,6 @@ import jp.co.soramitsu.common.utils.formatCrypto import jp.co.soramitsu.common.utils.formatCryptoDetail import jp.co.soramitsu.common.utils.formatFiat import jp.co.soramitsu.common.utils.inBackground -import jp.co.soramitsu.common.utils.isNotZero import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.validation.AmountTooLowToStakeException import jp.co.soramitsu.common.validation.ExistentialDepositCrossedException @@ -155,43 +154,48 @@ class SetupStakingPoolViewModel @Inject constructor( val amount = enteredAmountFlow.value viewModelScope.launch { - isValid(amount).fold({ - stakingPoolSharedStateProvider.joinFlowState.set(setupFlow.copy(amount = amount)) - router.openSelectPool() - }, { throwable -> - val message = - throwable.localizedMessage ?: throwable.message ?: resourceManager.getString(R.string.common_undefined_error_message) - val errorAlertViewState = (throwable as? ValidationException)?.let { (title, message) -> - AlertViewState( - title = title, + isValid(amount).fold( + onSuccess = { + stakingPoolSharedStateProvider.joinFlowState.set(setupFlow.copy(amount = amount)) + router.openSelectPool() + }, + onFailure = { throwable -> + val message = + throwable.localizedMessage ?: throwable.message ?: resourceManager.getString(R.string.common_undefined_error_message) + val errorAlertViewState = (throwable as? ValidationException)?.let { (title, message) -> + AlertViewState( + title = title, + message = message, + buttonText = resourceManager.getString(R.string.common_ok), + iconRes = R.drawable.ic_status_warning_16 + ) + } ?: AlertViewState( + title = resourceManager.getString(R.string.common_error_general_title), message = message, - buttonText = resourceManager.getString(R.string.common_ok), + buttonText = resourceManager.getString(R.string.common_got_it), iconRes = R.drawable.ic_status_warning_16 ) - } ?: AlertViewState( - title = resourceManager.getString(R.string.common_error_general_title), - message = message, - buttonText = resourceManager.getString(R.string.common_got_it), - iconRes = R.drawable.ic_status_warning_16 - ) - router.openAlert(errorAlertViewState) - }) + router.openAlert(errorAlertViewState) + }) } } private suspend fun isValid(amount: BigDecimal): Result { - val amountInPlanks = asset.token.planksFromAmount(amount) - val transferableInPlanks = asset.token.planksFromAmount(asset.transferable) - val minToJoinInPlanks = stakingPoolInteractor.getMinToJoinPool(chain.id) - val minToJoinFormatted = minToJoinInPlanks.formatCryptoDetailFromPlanks(asset.token.configuration) - val existentialDeposit = existentialDepositUseCase(asset.token.configuration) - val feeInPlanks = feeInPlanksFlow.value ?: return Result.failure(WaitForFeeCalculationException(resourceManager)) - - return when { - amountInPlanks + feeInPlanks >= transferableInPlanks -> Result.failure(StakeInsufficientBalanceException(resourceManager)) - transferableInPlanks - amountInPlanks - feeInPlanks <= existentialDeposit -> Result.failure(ExistentialDepositCrossedException(resourceManager, existentialDeposit.formatCryptoDetailFromPlanks(asset.token.configuration))) - amountInPlanks < minToJoinInPlanks -> Result.failure(AmountTooLowToStakeException(resourceManager, minToJoinFormatted)) - else -> Result.success(Unit) + return runCatching { + val amountInPlanks = asset.token.planksFromAmount(amount) + val transferableInPlanks = asset.token.planksFromAmount(asset.transferable) + val minToJoinInPlanks = stakingPoolInteractor.getMinToJoinPool(chain.id) + val minToJoinFormatted = minToJoinInPlanks.formatCryptoDetailFromPlanks(asset.token.configuration) + val existentialDeposit = existentialDepositUseCase(asset.token.configuration) + val feeInPlanks = feeInPlanksFlow.value + + when { + feeInPlanks == null -> throw WaitForFeeCalculationException(resourceManager) + amountInPlanks + feeInPlanks >= transferableInPlanks -> throw StakeInsufficientBalanceException(resourceManager) + transferableInPlanks - amountInPlanks - feeInPlanks <= existentialDeposit -> throw ExistentialDepositCrossedException(resourceManager, existentialDeposit.formatCryptoDetailFromPlanks(asset.token.configuration)) + amountInPlanks < minToJoinInPlanks -> throw AmountTooLowToStakeException(resourceManager, minToJoinFormatted) + else -> Unit + } } } From f220a5cf1bc97b86a74305e540aea339c6f9e991 Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Thu, 8 Feb 2024 18:06:06 +0500 Subject: [PATCH 22/35] fix crash --- .../pool/create/CreatePoolSetupViewModel.kt | 13 ++-- .../main/scenarios/StakingPoolViewModel.kt | 64 ++++++++++--------- .../staking/unbond/PoolUnstakeViewModel.kt | 22 ++++--- 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/setup/pool/create/CreatePoolSetupViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/setup/pool/create/CreatePoolSetupViewModel.kt index 20703c03d7..c3cb02380f 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/setup/pool/create/CreatePoolSetupViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/setup/pool/create/CreatePoolSetupViewModel.kt @@ -218,10 +218,15 @@ class CreatePoolSetupViewModel @Inject constructor( val fee = feeInPlanksFlow.value val transferableInPlanks = asset.token.planksFromAmount(asset.transferable) - val minToCreate = poolInteractor.getMinToCreate(chain.id) - if (amountInPlanks < minToCreate) { - val minToCreateFormatted = minToCreate.formatCryptoDetailFromPlanks(asset.token.configuration) - showError(MinPoolCreationThresholdException(resourceManager, minToCreateFormatted)) + try { + val minToCreate = poolInteractor.getMinToCreate(chain.id) + if (amountInPlanks < minToCreate) { + val minToCreateFormatted = minToCreate.formatCryptoDetailFromPlanks(asset.token.configuration) + showError(MinPoolCreationThresholdException(resourceManager, minToCreateFormatted)) + return@launch + } + } catch (e: NullPointerException) { + showError(e.message.orEmpty()) return@launch } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingPoolViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingPoolViewModel.kt index 897d081a9d..2285e60d88 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingPoolViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/scenarios/StakingPoolViewModel.kt @@ -43,7 +43,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.stateIn class StakingPoolViewModel( @@ -148,35 +148,39 @@ class StakingPoolViewModel( } override suspend fun networkInfo(): Flow> { - return stakingInteractor.currentAssetFlow().filter { it.token.configuration.supportStakingPool }.map { asset -> - val config = asset.token.configuration - val chainId = config.chainId - - val minToJoinPoolInPlanks = stakingPoolInteractor.getMinToJoinPool(chainId) - val minToJoinPool = asset.token.configuration.amountFromPlanks(minToJoinPoolInPlanks) - val minToJoinPoolFormatted = minToJoinPool.formatCryptoDetail(config.symbol) - val minToJoinPoolFiat = asset.token.fiatAmount(minToJoinPool)?.formatFiat(asset.token.fiatSymbol) - - val minToCreatePoolInPlanks = stakingPoolInteractor.getMinToCreate(chainId) - val minToCreatePool = asset.token.configuration.amountFromPlanks(minToCreatePoolInPlanks) - val minToCreatePoolFormatted = minToCreatePool.formatCryptoDetail(config.symbol) - val minToCreatePoolFiat = asset.token.fiatAmount(minToCreatePool)?.formatFiat(asset.token.fiatSymbol) - - val existingPools = stakingPoolInteractor.getExistingPools(chainId).toString() - val possiblePools = stakingPoolInteractor.getPossiblePools(chainId).toString() - val maxMembersInPool = stakingPoolInteractor.getMaxMembersInPool(chainId).toString() - val maxPoolsMembers = stakingPoolInteractor.getMaxPoolsMembers(chainId).toString() - - StakingNetworkInfoModel.Pool( - minToJoinPoolFormatted, - minToJoinPoolFiat, - minToCreatePoolFormatted, - minToCreatePoolFiat, - existingPools, - possiblePools, - maxMembersInPool, - maxPoolsMembers - ) + return stakingInteractor.currentAssetFlow().filter { it.token.configuration.supportStakingPool }.mapNotNull { asset -> + try { + val config = asset.token.configuration + val chainId = config.chainId + + val minToJoinPoolInPlanks = stakingPoolInteractor.getMinToJoinPool(chainId) + val minToJoinPool = asset.token.configuration.amountFromPlanks(minToJoinPoolInPlanks) + val minToJoinPoolFormatted = minToJoinPool.formatCryptoDetail(config.symbol) + val minToJoinPoolFiat = asset.token.fiatAmount(minToJoinPool)?.formatFiat(asset.token.fiatSymbol) + + val minToCreatePoolInPlanks = stakingPoolInteractor.getMinToCreate(chainId) + val minToCreatePool = asset.token.configuration.amountFromPlanks(minToCreatePoolInPlanks) + val minToCreatePoolFormatted = minToCreatePool.formatCryptoDetail(config.symbol) + val minToCreatePoolFiat = asset.token.fiatAmount(minToCreatePool)?.formatFiat(asset.token.fiatSymbol) + + val existingPools = stakingPoolInteractor.getExistingPools(chainId).toString() + val possiblePools = stakingPoolInteractor.getPossiblePools(chainId).toString() + val maxMembersInPool = stakingPoolInteractor.getMaxMembersInPool(chainId).toString() + val maxPoolsMembers = stakingPoolInteractor.getMaxPoolsMembers(chainId).toString() + + StakingNetworkInfoModel.Pool( + minToJoinPoolFormatted, + minToJoinPoolFiat, + minToCreatePoolFormatted, + minToCreatePoolFiat, + existingPools, + possiblePools, + maxMembersInPool, + maxPoolsMembers + ) + } catch (e: NullPointerException) { + null + } }.withLoading() } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/unbond/PoolUnstakeViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/unbond/PoolUnstakeViewModel.kt index ff5c1a6850..eb73c1b382 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/unbond/PoolUnstakeViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/unbond/PoolUnstakeViewModel.kt @@ -36,17 +36,19 @@ class PoolUnstakeViewModel @Inject constructor( ) }, onNextStep = { amount -> - val minToCreate = stakingPoolInteractor.getMinToCreate(stakingPoolSharedStateProvider.requireMainState.requireChain.id) + try { + val minToCreate = stakingPoolInteractor.getMinToCreate(stakingPoolSharedStateProvider.requireMainState.requireChain.id) - val isDepositor = stakingPoolSharedStateProvider.requireManageState.userRole == RoleInPool.Depositor - if (isDepositor && (stakingPoolSharedStateProvider.requireManageState.stakedInPlanks - amount) < minToCreate) { - val asset = stakingPoolSharedStateProvider.requireMainState.requireAsset - val minToCreateFormatted = minToCreate.formatCryptoDetailFromPlanks(asset.token.configuration) - router.openPoolFullUnstakeDepositorAlertFragment(minToCreateFormatted) - } else { - stakingPoolSharedStateProvider.manageState.get()?.copy(amountInPlanks = amount)?.let { stakingPoolSharedStateProvider.manageState.set(it) } - router.openPoolConfirmUnstake() - } + val isDepositor = stakingPoolSharedStateProvider.requireManageState.userRole == RoleInPool.Depositor + if (isDepositor && (stakingPoolSharedStateProvider.requireManageState.stakedInPlanks - amount) < minToCreate) { + val asset = stakingPoolSharedStateProvider.requireMainState.requireAsset + val minToCreateFormatted = minToCreate.formatCryptoDetailFromPlanks(asset.token.configuration) + router.openPoolFullUnstakeDepositorAlertFragment(minToCreateFormatted) + } else { + stakingPoolSharedStateProvider.manageState.get()?.copy(amountInPlanks = amount)?.let { stakingPoolSharedStateProvider.manageState.set(it) } + router.openPoolConfirmUnstake() + } + } catch (_: NullPointerException) {} }, validations = arrayOf( Validation( From 16173174c61e9fcb677b348fa6c04a8c0287a3be Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Thu, 8 Feb 2024 18:37:34 +0500 Subject: [PATCH 23/35] fix crash --- .../staking/balance/StakingBalanceFragment.kt | 2 +- .../balance/StakingBalanceViewModel.kt | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/balance/StakingBalanceFragment.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/balance/StakingBalanceFragment.kt index 68899dc038..5f513c2ec0 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/balance/StakingBalanceFragment.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/balance/StakingBalanceFragment.kt @@ -61,7 +61,7 @@ class StakingBalanceFragment : BaseFragment(R.layout.fr viewModel.redeemTitle?.let { binding.stakingBalanceActions.redeem.setText(it) } - viewModel.stakingBalanceModelLiveData.observe { + viewModel.stakingBalanceModelFlow.observe { binding.stakingBalanceSwipeRefresh.isRefreshing = false with(binding.stakingBalanceInfo) { diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/balance/StakingBalanceViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/balance/StakingBalanceViewModel.kt index c1e359447f..232f8117f7 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/balance/StakingBalanceViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/balance/StakingBalanceViewModel.kt @@ -3,7 +3,11 @@ package jp.co.soramitsu.staking.impl.presentation.staking.balance import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import java.math.BigDecimal +import java.math.BigInteger +import javax.inject.Inject import jp.co.soramitsu.common.base.BaseViewModel import jp.co.soramitsu.common.mixin.api.Validatable import jp.co.soramitsu.common.resources.ResourceManager @@ -32,18 +36,19 @@ import jp.co.soramitsu.staking.impl.scenarios.StakingScenarioInteractor import jp.co.soramitsu.wallet.api.presentation.model.mapAmountToAmountModel import jp.co.soramitsu.wallet.impl.domain.model.amountFromPlanks import jp.co.soramitsu.wallet.impl.domain.model.planksFromAmount +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch -import java.math.BigDecimal -import java.math.BigInteger -import javax.inject.Inject +@OptIn(ExperimentalCoroutinesApi::class) @HiltViewModel class StakingBalanceViewModel @Inject constructor( private val router: StakingRouter, @@ -62,8 +67,9 @@ class StakingBalanceViewModel @Inject constructor( private val assetFlow = interactor.currentAssetFlow() .share() - val stakingBalanceModelLiveData: Flow = refresh.flatMapLatest { + val stakingBalanceModelFlow: Flow = refresh.flatMapLatest { stakingScenarioInteractor.getStakingBalanceFlow(collatorAddress?.fromHex()) + .catch { } }.share() private val unbondingsFlow: Flow> = refresh.flatMapLatest { @@ -72,13 +78,13 @@ class StakingBalanceViewModel @Inject constructor( val redeemTitle = stakingScenarioInteractor.overrideRedeemActionTitle() - val redeemEnabledLiveData = stakingBalanceModelLiveData.map { + val redeemEnabledLiveData = stakingBalanceModelFlow.map { it.redeemable.amount > BigDecimal.ZERO }.asLiveData() val pendingAction = MutableLiveData(false) - val shouldBlockStakeMore = stakingBalanceModelLiveData.map { + val shouldBlockStakeMore = stakingBalanceModelFlow.map { val isParachain = assetFlow.first().token.configuration.staking == Asset.StakingType.PARACHAIN val isUnstakingFullAmount = (it.staked.amount - it.unstaking.amount).isZero() val isReadyForUnlockFullAmount = (it.staked.amount - it.redeemable.amount).isZero() @@ -88,7 +94,7 @@ class StakingBalanceViewModel @Inject constructor( isFullUnstake.and(isParachain) }.onStart { emit(true) }.asLiveData() - val shouldBlockUnstake = stakingBalanceModelLiveData.map { + val shouldBlockUnstake = stakingBalanceModelFlow.map { val asset = assetFlow.first() val isParachain = asset.token.configuration.staking == Asset.StakingType.PARACHAIN val stakedAmountIsZero = asset.token.planksFromAmount(it.staked.amount) == BigInteger.ZERO From 805cd3014b43a1b925c777db27e44649f178f8eb Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Thu, 8 Feb 2024 21:26:52 +0500 Subject: [PATCH 24/35] fix crash --- .../balance/detail/BalanceDetailViewModel.kt | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/detail/BalanceDetailViewModel.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/detail/BalanceDetailViewModel.kt index 2cc49758b1..06cea90e58 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/detail/BalanceDetailViewModel.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/balance/detail/BalanceDetailViewModel.kt @@ -65,7 +65,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -112,20 +112,22 @@ class BalanceDetailViewModel @Inject constructor( private val chainsItemStateFlow = chainsFlow.mapList { it.toChainItemState() } @OptIn(ExperimentalCoroutinesApi::class) - private val assetModelFlow = selectedChainId.map { selectedChainId -> - val chains = chainsFlow.first() - val selectedChain = chains.first { it.id == selectedChainId } - val initialSelectedChain = chains.first { it.id == assetPayloadInitial.chainId } + private val assetModelFlow = selectedChainId.mapNotNull { selectedChainId -> + val chains = chainsFlow.firstOrNull() + val selectedChain = chains?.firstOrNull { it.id == selectedChainId } + val initialSelectedChain = chains?.firstOrNull { it.id == assetPayloadInitial.chainId } val initialSelectedAssetSymbol = - initialSelectedChain.assets.first { it.id == assetPayloadInitial.chainAssetId }.symbol + initialSelectedChain?.assets?.firstOrNull { it.id == assetPayloadInitial.chainAssetId }?.symbol val newSelectedAsset = - selectedChain.assets.first { it.symbol == initialSelectedAssetSymbol } + selectedChain?.assets?.firstOrNull { it.symbol == initialSelectedAssetSymbol } - AssetPayload( - chainId = selectedChainId, - chainAssetId = newSelectedAsset.id - ) + newSelectedAsset?.id?.let { + AssetPayload( + chainId = selectedChainId, + chainAssetId = it + ) + } } .flatMapLatest { interactor.assetFlow(it.chainId, it.chainAssetId) @@ -170,14 +172,14 @@ class BalanceDetailViewModel @Inject constructor( selectedChainId, chainsItemStateFlow ) { chainId, chainItems -> - val selectedChain = chainItems.first { + val selectedChain = chainItems.firstOrNull { it.id == chainId } LoadingState.Loaded( MainToolbarViewState( title = interactor.getSelectedMetaAccount().name, homeIconState = ToolbarHomeIconState(navigationIcon = R.drawable.ic_arrow_back_24dp), - selectorViewState = ChainSelectorViewState(selectedChain.title, selectedChain.id) + selectorViewState = ChainSelectorViewState(selectedChain?.title, selectedChain?.id) ) ) }.stateIn(scope = this, started = SharingStarted.Eagerly, initialValue = LoadingState.Loading()) @@ -492,15 +494,16 @@ class BalanceDetailViewModel @Inject constructor( private fun openBalanceDetails() { launch { - val assetModel = assetModelFlow.first() - router.openFrozenTokens( - FrozenAssetPayload( - assetSymbol = assetModel.token.configuration.symbol, - locked = assetModel.locked, - reserved = assetModel.reserved, - redeemable = assetModel.redeemable + assetModelFlow.firstOrNull()?.let { assetModel -> + router.openFrozenTokens( + FrozenAssetPayload( + assetSymbol = assetModel.token.configuration.symbol, + locked = assetModel.locked, + reserved = assetModel.reserved, + redeemable = assetModel.redeemable + ) ) - ) + } } } } From 730b9d396ec51c0b7c5a63f7aed3c077623d4606 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 9 Feb 2024 13:32:36 +0700 Subject: [PATCH 25/35] fix lint --- .../SubqueryStakingRewardsDataSource.kt | 1 - .../impl/data/historySource/ReefHistorySource.kt | 5 ----- .../blockchain/updaters/BalancesUpdateSystem.kt | 15 --------------- .../data/network/subquery/OperationsHistoryApi.kt | 1 - 4 files changed, 22 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/datasource/SubqueryStakingRewardsDataSource.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/datasource/SubqueryStakingRewardsDataSource.kt index e3d0059eb0..dddcf43e1c 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/datasource/SubqueryStakingRewardsDataSource.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/repository/datasource/SubqueryStakingRewardsDataSource.kt @@ -2,7 +2,6 @@ package jp.co.soramitsu.staking.impl.data.repository.datasource import java.math.BigInteger import jp.co.soramitsu.common.base.errors.RewardsNotSupportedWarning -import jp.co.soramitsu.common.data.network.subquery.ReefRewardsNode import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.sumByBigDecimal import jp.co.soramitsu.common.utils.sumByBigInteger diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt index 46b53d82a4..5d1af7333d 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/historySource/ReefHistorySource.kt @@ -96,11 +96,6 @@ class ReefHistorySource( return CursorPage(nextCursor, operations.sortedByDescending { it.time }) } - private fun TransactionFilter.isAppliedOrNull(filters: Collection) = when { - this in filters -> true - else -> null - } - private val reefDateFormat by lazy { SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ", diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/updaters/BalancesUpdateSystem.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/updaters/BalancesUpdateSystem.kt index 8826796a75..1eae78846e 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/updaters/BalancesUpdateSystem.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/blockchain/updaters/BalancesUpdateSystem.kt @@ -1,30 +1,21 @@ package jp.co.soramitsu.wallet.impl.data.network.blockchain.updaters import android.util.Log -import io.emeraldpay.polkaj.scale.ScaleCodecReader import it.airgap.beaconsdk.core.internal.utils.failure import it.airgap.beaconsdk.core.internal.utils.onEachFailure -import java.math.BigInteger -import java.nio.ByteOrder 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 import jp.co.soramitsu.account.api.domain.model.address import jp.co.soramitsu.common.data.network.rpc.BulkRetriever -import jp.co.soramitsu.common.data.network.runtime.binding.AccountData -import jp.co.soramitsu.common.data.network.runtime.binding.AccountInfo import jp.co.soramitsu.common.data.network.runtime.binding.ExtrinsicStatusEvent import jp.co.soramitsu.common.data.network.runtime.binding.SimpleBalanceData -import jp.co.soramitsu.common.data.network.runtime.binding.bindNonce -import jp.co.soramitsu.common.data.network.runtime.binding.cast import jp.co.soramitsu.common.mixin.api.NetworkStateMixin import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.common.utils.requireException import jp.co.soramitsu.common.utils.requireValue -import jp.co.soramitsu.common.utils.system import jp.co.soramitsu.core.models.Asset import jp.co.soramitsu.core.models.ChainAssetType -import jp.co.soramitsu.core.runtime.storage.returnType import jp.co.soramitsu.core.updater.UpdateSystem import jp.co.soramitsu.core.updater.Updater import jp.co.soramitsu.core.utils.utilityAsset @@ -37,14 +28,8 @@ import jp.co.soramitsu.runtime.multiNetwork.getSocket import jp.co.soramitsu.runtime.multiNetwork.getSocketOrNull import jp.co.soramitsu.runtime.multiNetwork.toSyncIssue import jp.co.soramitsu.runtime.network.subscriptionFlowCatching -import jp.co.soramitsu.shared_utils.extensions.fromUnsignedBytes import jp.co.soramitsu.shared_utils.runtime.AccountId import jp.co.soramitsu.shared_utils.runtime.RuntimeSnapshot -import jp.co.soramitsu.shared_utils.runtime.definitions.types.composite.Struct -import jp.co.soramitsu.shared_utils.runtime.definitions.types.fromHexOrNull -import jp.co.soramitsu.shared_utils.runtime.metadata.storage -import jp.co.soramitsu.shared_utils.scale.dataType.uint128 -import jp.co.soramitsu.shared_utils.scale.utils.toUnsignedBytes import jp.co.soramitsu.shared_utils.wsrpc.request.runtime.storage.SubscribeStorageRequest import jp.co.soramitsu.shared_utils.wsrpc.request.runtime.storage.storageChange import jp.co.soramitsu.wallet.api.data.cache.AssetCache diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt index bca81368f3..fada86b5dd 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/data/network/subquery/OperationsHistoryApi.kt @@ -2,7 +2,6 @@ package jp.co.soramitsu.wallet.impl.data.network.subquery import jp.co.soramitsu.common.BuildConfig import jp.co.soramitsu.common.data.network.subquery.GiantsquidResponse -import jp.co.soramitsu.common.data.network.subquery.ReefStakingRewardsResponse import jp.co.soramitsu.common.data.network.subquery.SubQueryResponse import jp.co.soramitsu.common.data.network.subquery.SubsquidResponse import jp.co.soramitsu.wallet.impl.data.network.model.request.GiantsquidHistoryRequest From 3c11dd58048fd7b0ae5152994ce224901bb2ded6 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 9 Feb 2024 16:31:59 +0700 Subject: [PATCH 26/35] staking pools fee exception catching --- .../impl/presentation/swap_tokens/SwapTokensViewModel.kt | 4 +++- .../confirm/pool/join/ConfirmJoinPoolViewModel.kt | 5 ++++- .../wallet/api/presentation/BaseConfirmViewModel.kt | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/feature-polkaswap-impl/src/main/kotlin/jp/co/soramitsu/polkaswap/impl/presentation/swap_tokens/SwapTokensViewModel.kt b/feature-polkaswap-impl/src/main/kotlin/jp/co/soramitsu/polkaswap/impl/presentation/swap_tokens/SwapTokensViewModel.kt index 9426d63a14..163b4f209e 100644 --- a/feature-polkaswap-impl/src/main/kotlin/jp/co/soramitsu/polkaswap/impl/presentation/swap_tokens/SwapTokensViewModel.kt +++ b/feature-polkaswap-impl/src/main/kotlin/jp/co/soramitsu/polkaswap/impl/presentation/swap_tokens/SwapTokensViewModel.kt @@ -207,7 +207,9 @@ class SwapTokensViewModel @Inject constructor( ) val fee = desiredAsset.token.amountFromPlanks(feeInPlanks) emit(LoadingState.Loaded(fee)) - }.stateIn(viewModelScope, SharingStarted.Eagerly, LoadingState.Loaded(null)) + } + .catch { emit(LoadingState.Loaded(null)) } + .stateIn(viewModelScope, SharingStarted.Eagerly, LoadingState.Loaded(null)) private val networkFeeViewStateFlow = networkFeeFlow.map { amountLoading -> amountLoading.map { diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/confirm/pool/join/ConfirmJoinPoolViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/confirm/pool/join/ConfirmJoinPoolViewModel.kt index 5ca854e842..154d671e80 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/confirm/pool/join/ConfirmJoinPoolViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/confirm/pool/join/ConfirmJoinPoolViewModel.kt @@ -22,6 +22,7 @@ import jp.co.soramitsu.wallet.impl.domain.model.amountFromPlanks import jp.co.soramitsu.wallet.impl.domain.model.planksFromAmount import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -77,7 +78,9 @@ class ConfirmJoinPoolViewModel @Inject constructor( feeFormatted, feeFiat ) - }.stateIn( + } + .catch { emit(defaultFeeState) } + .stateIn( viewModelScope, SharingStarted.Eagerly, defaultFeeState diff --git a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/presentation/BaseConfirmViewModel.kt b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/presentation/BaseConfirmViewModel.kt index d7e028b39e..44f7c761b4 100644 --- a/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/presentation/BaseConfirmViewModel.kt +++ b/feature-wallet-api/src/main/java/jp/co/soramitsu/wallet/api/presentation/BaseConfirmViewModel.kt @@ -29,6 +29,7 @@ import jp.co.soramitsu.wallet.impl.domain.model.planksFromAmount import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map @@ -99,7 +100,9 @@ abstract class BaseConfirmViewModel( feeFormatted, feeFiat ) - }.stateIn( + } + .catch { emit(defaultFeeState) } + .stateIn( viewModelScope, SharingStarted.Eagerly, defaultFeeState From a929d66a53fa8e222fdeec19bd73d41f9e80b608 Mon Sep 17 00:00:00 2001 From: Deneath Date: Fri, 9 Feb 2024 16:36:02 +0700 Subject: [PATCH 27/35] request executor --- build.gradle | 2 +- .../java/jp/co/soramitsu/common/di/modules/NetworkModule.kt | 3 ++- gradle/libs.versions.toml | 2 +- .../main/java/jp/co/soramitsu/testshared/CreateTestSocket.kt | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 855d13af62..737b4794ed 100644 --- a/build.gradle +++ b/build.gradle @@ -83,7 +83,7 @@ buildscript { minifyRelease = true beaconVersion = "3.2.4" - sharedFeaturesVersion = "1.1.1.22-FLW" + sharedFeaturesVersion = "1.1.1.23-FLW" coilDep = "io.coil-kt:coil:$coilVersion" coilSvg = "io.coil-kt:coil-svg:$coilVersion" diff --git a/common/src/main/java/jp/co/soramitsu/common/di/modules/NetworkModule.kt b/common/src/main/java/jp/co/soramitsu/common/di/modules/NetworkModule.kt index c3e3fc083d..4af739ce87 100644 --- a/common/src/main/java/jp/co/soramitsu/common/di/modules/NetworkModule.kt +++ b/common/src/main/java/jp/co/soramitsu/common/di/modules/NetworkModule.kt @@ -20,6 +20,7 @@ import jp.co.soramitsu.common.resources.ResourceManager import jp.co.soramitsu.shared_utils.wsrpc.SocketService import jp.co.soramitsu.shared_utils.wsrpc.logging.Logger import jp.co.soramitsu.shared_utils.wsrpc.recovery.Reconnector +import jp.co.soramitsu.shared_utils.wsrpc.request.CoroutinesRequestExecutor import jp.co.soramitsu.shared_utils.wsrpc.request.RequestExecutor import okhttp3.Cache import okhttp3.OkHttpClient @@ -93,7 +94,7 @@ class NetworkModule { @Provides @Singleton - fun provideRequestExecutor() = RequestExecutor() + fun provideRequestExecutor(): RequestExecutor = CoroutinesRequestExecutor() @Provides fun provideSocketService( diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fc76b1436c..936fa4203c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ detekt = "1.23.0" kotlin = "1.8.10" dagger = "2.47" android_plugin = "7.4.2" -sharedFeaturesVersion = "1.1.1.22-FLW" +sharedFeaturesVersion = "1.1.1.23-FLW" web3j = "4.8.8-android" walletconnectBom = "1.18.0" coilVersion = "2.2.2" diff --git a/test-shared/src/main/java/jp/co/soramitsu/testshared/CreateTestSocket.kt b/test-shared/src/main/java/jp/co/soramitsu/testshared/CreateTestSocket.kt index 2f1441bc93..66a920f71b 100644 --- a/test-shared/src/main/java/jp/co/soramitsu/testshared/CreateTestSocket.kt +++ b/test-shared/src/main/java/jp/co/soramitsu/testshared/CreateTestSocket.kt @@ -4,6 +4,6 @@ import com.google.gson.Gson import com.neovisionaries.ws.client.WebSocketFactory import jp.co.soramitsu.shared_utils.wsrpc.SocketService import jp.co.soramitsu.shared_utils.wsrpc.recovery.Reconnector -import jp.co.soramitsu.shared_utils.wsrpc.request.RequestExecutor +import jp.co.soramitsu.shared_utils.wsrpc.request.CoroutinesRequestExecutor -fun createTestSocket() = SocketService(Gson(), NoOpLogger, WebSocketFactory(), Reconnector(), RequestExecutor()) +fun createTestSocket() = SocketService(Gson(), NoOpLogger, WebSocketFactory(), Reconnector(), CoroutinesRequestExecutor()) From 54beaa4b2ea7345e0c9f112bb2a8158f57fd9b81 Mon Sep 17 00:00:00 2001 From: Sergey Pankratov Date: Fri, 9 Feb 2024 21:17:57 +0500 Subject: [PATCH 28/35] FLW-4270 XOR. SWAP. History. There is no wallet name and no full address --- .../account/api/domain/model/MetaAccount.kt | 7 ++++++ .../detail/swap/SwapDetailContent.kt | 5 +++- .../detail/swap/SwapDetailViewModel.kt | 24 +++++++++++++++++-- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/feature-account-api/src/main/java/jp/co/soramitsu/account/api/domain/model/MetaAccount.kt b/feature-account-api/src/main/java/jp/co/soramitsu/account/api/domain/model/MetaAccount.kt index 986d1c3080..e372d12c6a 100644 --- a/feature-account-api/src/main/java/jp/co/soramitsu/account/api/domain/model/MetaAccount.kt +++ b/feature-account-api/src/main/java/jp/co/soramitsu/account/api/domain/model/MetaAccount.kt @@ -135,6 +135,13 @@ fun MetaAccount.address(chain: Chain): String? { } } +fun LightMetaAccount.address(chain: Chain): String? { + return when { + chain.isEthereumBased -> ethereumAddress?.ethereumAddressToHex() + else -> substrateAccountId.toAddress(chain.addressPrefix.toShort()) + } +} + fun MetaAccount.chainAddress(chain: Chain): String? { return when { hasChainAccount(chain.id) -> chain.addressOf(chainAccounts.getValue(chain.id).accountId) diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/transaction/detail/swap/SwapDetailContent.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/transaction/detail/swap/SwapDetailContent.kt index a229f3dd16..2dc36db556 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/transaction/detail/swap/SwapDetailContent.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/transaction/detail/swap/SwapDetailContent.kt @@ -39,6 +39,7 @@ data class SwapDetailState( val toTokenName: String, val statusAppearance: SwapStatusAppearance, val address: String, + val addressName: String?, val hash: String, val fromTokenOnToToken: String, val liquidityProviderFee: String, @@ -110,7 +111,8 @@ fun SwapPreviewContent( ), TitleValueViewState( title = stringResource(R.string.polkaswap_from), - value = state.address + value = state.addressName ?: state.address, + additionalValue = state.address.takeIf { state.addressName != null } ), TitleValueViewState( title = stringResource(R.string.common_date), @@ -175,6 +177,7 @@ fun SwapDetailContentPreview() { fromTokenOnToToken = "0", networkFee = "0.0007", address = "asdfqwaefgqwef2fr", + addressName = "Contact addressbook name", hash = "asdfqwaefgqwef2fr", statusAppearance = SwapStatusAppearance.COMPLETED, time = 1675834923575L, diff --git a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/transaction/detail/swap/SwapDetailViewModel.kt b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/transaction/detail/swap/SwapDetailViewModel.kt index e9f368e640..bb2b5bf7b7 100644 --- a/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/transaction/detail/swap/SwapDetailViewModel.kt +++ b/feature-wallet-impl/src/main/java/jp/co/soramitsu/wallet/impl/presentation/transaction/detail/swap/SwapDetailViewModel.kt @@ -7,6 +7,8 @@ import androidx.lifecycle.SavedStateHandle import dagger.hilt.android.lifecycle.HiltViewModel import java.math.BigDecimal import javax.inject.Inject +import jp.co.soramitsu.account.api.domain.interfaces.AccountRepository +import jp.co.soramitsu.account.api.domain.model.address import jp.co.soramitsu.common.base.BaseViewModel import jp.co.soramitsu.common.compose.component.GradientIconState import jp.co.soramitsu.common.compose.theme.greenText @@ -16,6 +18,7 @@ import jp.co.soramitsu.common.mixin.api.Browserable import jp.co.soramitsu.common.resources.ClipboardManager import jp.co.soramitsu.common.resources.ResourceManager import jp.co.soramitsu.common.utils.Event +import jp.co.soramitsu.common.utils.flowOf import jp.co.soramitsu.common.utils.formatCryptoDetail import jp.co.soramitsu.common.utils.orZero import jp.co.soramitsu.feature_wallet_impl.R @@ -30,6 +33,7 @@ import jp.co.soramitsu.wallet.impl.domain.model.amountFromPlanks import jp.co.soramitsu.wallet.impl.presentation.WalletRouter import jp.co.soramitsu.wallet.impl.presentation.model.OperationParcelizeModel import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map @@ -42,6 +46,7 @@ class SwapDetailViewModel @Inject constructor( private val chainRegistry: ChainRegistry, private val resourceManager: ResourceManager, private val clipboardManager: ClipboardManager, + private val accountRepository: AccountRepository, savedStateHandle: SavedStateHandle ) : BaseViewModel(), SwapDetailCallbacks, Browserable { @@ -78,6 +83,7 @@ class SwapDetailViewModel @Inject constructor( toTokenName = swap.targetAsset?.symbol?.uppercase() ?: "???", statusAppearance = swap.status.mapToStatusAppearance(), address = swap.address, + addressName = null, hash = swap.hash, fromTokenOnToToken = swapRate.formatCryptoDetail(), liquidityProviderFee = swap.liquidityProviderFee.formatCryptoDetailFromPlanks(swap.chainAsset), @@ -87,8 +93,22 @@ class SwapDetailViewModel @Inject constructor( isShowSubscanButtons = false ) - val state = subscanUrlFlow.map { url -> - initialState.copy(isShowSubscanButtons = url.isNullOrEmpty().not()) + // swaps are only for selected account + private val addressNameFlow = flowOf { swap.address }.map { + val selectedLightMetaAccount = accountRepository.getSelectedLightMetaAccount() + val chain = chainRegistry.getChain(swap.chainAsset.chainId) + if (selectedLightMetaAccount.address(chain) == swap.address) { + selectedLightMetaAccount.name + } else { + null + } + } + + val state = combine( + subscanUrlFlow, + addressNameFlow + ) { url, name -> + initialState.copy(isShowSubscanButtons = url.isNullOrEmpty().not(), addressName = name) }.stateIn(this, SharingStarted.Eagerly, initialState) override fun onBackClick() { From 47b16abd94ec8a9c6ecd0ca275f5df6718c3ff93 Mon Sep 17 00:00:00 2001 From: Deneath Date: Mon, 12 Feb 2024 14:41:29 +0700 Subject: [PATCH 29/35] increase version --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 737b4794ed..eab9498c3a 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ apply plugin: "org.sonarqube" buildscript { ext { // App version - versionName = '3.2.2' - versionCode = 152 + versionName = '3.3.1' + versionCode = 153 // SDK and tools compileSdkVersion = 34 From 978f586a8a30bbf9061dae3aa7a6ba80fc2cca94 Mon Sep 17 00:00:00 2001 From: Deneath Date: Mon, 12 Feb 2024 18:16:42 +0700 Subject: [PATCH 30/35] Show hash after successfully extrinsics on staking --- .../staking/redeem/RedeemConsequences.kt | 3 ++- .../domain/staking/redeem/RedeemInteractor.kt | 3 ++- .../rebond/confirm/ConfirmRebondViewModel.kt | 26 ++++++++++++++----- .../staking/redeem/RedeemViewModel.kt | 1 + .../unbond/confirm/ConfirmUnbondViewModel.kt | 1 + 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/staking/redeem/RedeemConsequences.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/staking/redeem/RedeemConsequences.kt index 37e68a3316..e7951c06a9 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/staking/redeem/RedeemConsequences.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/staking/redeem/RedeemConsequences.kt @@ -1,5 +1,6 @@ package jp.co.soramitsu.staking.impl.domain.staking.redeem class RedeemConsequences( - val willKillStash: Boolean + val willKillStash: Boolean, + val hash: String ) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/staking/redeem/RedeemInteractor.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/staking/redeem/RedeemInteractor.kt index c9bd343aac..0f9d2bd527 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/staking/redeem/RedeemInteractor.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/domain/staking/redeem/RedeemInteractor.kt @@ -33,7 +33,8 @@ class RedeemInteractor( formExtrinsic.invoke(this) }.map { RedeemConsequences( - willKillStash = asset.redeemable == asset.locked + willKillStash = asset.redeemable == asset.locked, + hash = it ) } } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/rebond/confirm/ConfirmRebondViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/rebond/confirm/ConfirmRebondViewModel.kt index 3615f59cf0..864cfd4fbd 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/rebond/confirm/ConfirmRebondViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/rebond/confirm/ConfirmRebondViewModel.kt @@ -5,6 +5,8 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import javax.inject.Named import jp.co.soramitsu.account.api.presentation.actions.ExternalAccountActions import jp.co.soramitsu.common.address.AddressIconGenerator import jp.co.soramitsu.common.address.createAddressModel @@ -34,8 +36,6 @@ import jp.co.soramitsu.wallet.impl.domain.model.planksFromAmount import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch -import javax.inject.Inject -import javax.inject.Named @HiltViewModel class ConfirmRebondViewModel @Inject constructor( @@ -68,8 +68,14 @@ class ConfirmRebondViewModel @Inject constructor( val assetModelFlow = assetFlow .map { - val retrieveAmount = stakingScenarioInteractor.getRebondAvailableAmount(it, payload.amount) - mapAssetToAssetModel(it, resourceManager, { retrieveAmount }, R.string.staking_unbonding_format) + val retrieveAmount = + stakingScenarioInteractor.getRebondAvailableAmount(it, payload.amount) + mapAssetToAssetModel( + it, + resourceManager, + { retrieveAmount }, + R.string.staking_unbonding_format + ) } .inBackground() .asLiveData() @@ -86,7 +92,8 @@ class ConfirmRebondViewModel @Inject constructor( val address = it.executionAddress val account = interactor.getProjectedAccount(address) - val addressModel = iconGenerator.createAddressModel(address, AddressIconGenerator.SIZE_SMALL, account.name) + val addressModel = + iconGenerator.createAddressModel(address, AddressIconGenerator.SIZE_SMALL, account.name) addressModel } @@ -109,7 +116,10 @@ class ConfirmRebondViewModel @Inject constructor( val originAddressModel = originAddressModelLiveData.value ?: return@launch val chainId = assetFlow.first().token.configuration.chainId val chain = chainRegistry.getChain(chainId) - val supportedExplorers = chain.explorers.getSupportedExplorers(BlockExplorerUrlBuilder.Type.ACCOUNT, originAddressModel.address) + val supportedExplorers = chain.explorers.getSupportedExplorers( + BlockExplorerUrlBuilder.Type.ACCOUNT, + originAddressModel.address + ) val externalActionsPayload = ExternalAccountActions.Payload( value = originAddressModel.address, chainId = chainId, @@ -166,6 +176,10 @@ class ConfirmRebondViewModel @Inject constructor( showMessage(resourceManager.getString(R.string.common_transaction_submitted)) router.returnToStakingBalance() + router.openOperationSuccess( + it, + validPayload.controllerAsset.token.configuration.chainId + ) } .onFailure(::showError) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/redeem/RedeemViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/redeem/RedeemViewModel.kt index c375d7ad75..7b699a6aa3 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/redeem/RedeemViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/redeem/RedeemViewModel.kt @@ -211,6 +211,7 @@ class RedeemViewModel @Inject constructor( result.requireValue().willKillStash -> router.returnToMain() else -> router.returnToStakingBalance() } + result.getOrNull()?.let { router.openOperationSuccess(it.hash, redeemValidationPayload.asset.token.configuration.chainId) } } else { showError(result.requireException()) } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/unbond/confirm/ConfirmUnbondViewModel.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/unbond/confirm/ConfirmUnbondViewModel.kt index 9585bc4fd2..c894b74bf4 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/unbond/confirm/ConfirmUnbondViewModel.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/unbond/confirm/ConfirmUnbondViewModel.kt @@ -154,6 +154,7 @@ class ConfirmUnbondViewModel @Inject constructor( showMessage(resourceManager.getString(R.string.common_transaction_submitted)) router.returnToStakingBalance() + result.getOrNull()?.let { router.openOperationSuccess(it, validPayload.asset.token.configuration.chainId) } } else { showError(result.requireException()) } From 5e9a23c50d3dcf3160c7f2a2184dd7bf49e72c6a Mon Sep 17 00:00:00 2001 From: Deneath Date: Mon, 12 Feb 2024 19:14:04 +0700 Subject: [PATCH 31/35] catch the possible staking states exception in era calculator. This will never happen in usual work. --- .../impl/data/network/blockhain/bindings/Era.kt | 12 ++++++------ .../StakingRelayChainScenarioRepository.kt | 8 ++++---- runtime/build.gradle | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Era.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Era.kt index 55d5e7344f..f89f494f2b 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Era.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/data/network/blockhain/bindings/Era.kt @@ -53,31 +53,31 @@ fun bindCurrentEra( @UseCaseBinding fun bindCurrentIndex( - scale: String, + scale: String?, runtime: RuntimeSnapshot ): BigInteger { val returnType = runtime.metadata.storageReturnType("Session", "CurrentIndex") - return bindSessionIndex(returnType.fromHexOrNull(runtime, scale)) + return scale ?. let { bindSessionIndex(returnType.fromHexOrNull(runtime, scale)) } ?: BigInteger.ZERO } @UseCaseBinding fun bindCurrentSlot( - scale: String, + scale: String?, runtime: RuntimeSnapshot ): BigInteger { val returnType = runtime.metadata.storageReturnType("Babe", "CurrentSlot") - return bindSlot(returnType.fromHexOrNull(runtime, scale)) + return scale?.let { bindSlot(returnType.fromHexOrNull(runtime, scale)) } ?: BigInteger.ZERO } @UseCaseBinding fun bindErasStartSessionIndex( - scale: String, + scale: String?, runtime: RuntimeSnapshot ): BigInteger { val returnType = runtime.metadata.storageReturnType("Staking", "ErasStartSessionIndex") - val decoded = returnType.fromHexOrNull(runtime, scale) + val decoded = scale?.let { returnType.fromHexOrNull(runtime, scale) } return bindSessionIndex(decoded) } diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt index 5936c3dc48..c51d0758f0 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/scenarios/relaychain/StakingRelayChainScenarioRepository.kt @@ -99,20 +99,20 @@ class StakingRelayChainScenarioRepository( return runtime.metadata.babe().numberConstant("EpochDuration", runtime) // How many blocks per session } - suspend fun currentSessionIndex(chainId: ChainId) = remoteStorage.queryNonNull( + suspend fun currentSessionIndex(chainId: ChainId) = remoteStorage.query( // Current session index keyBuilder = { it.metadata.session().storage("CurrentIndex").storageKey() }, binding = ::bindCurrentIndex, chainId = chainId ) - suspend fun currentSlot(chainId: ChainId) = remoteStorage.queryNonNull( + suspend fun currentSlot(chainId: ChainId) = remoteStorage.query( keyBuilder = { it.metadata.babe().storage("CurrentSlot").storageKey() }, binding = ::bindCurrentSlot, chainId = chainId ) - suspend fun genesisSlot(chainId: ChainId) = remoteStorage.queryNonNull( + suspend fun genesisSlot(chainId: ChainId) = remoteStorage.query( keyBuilder = { it.metadata.babe().storage("GenesisSlot").storageKey() }, binding = ::bindCurrentSlot, chainId = chainId @@ -120,7 +120,7 @@ class StakingRelayChainScenarioRepository( suspend fun eraStartSessionIndex(chainId: ChainId, currentEra: BigInteger): EraIndex { val runtime = runtimeFor(chainId) - return remoteStorage.queryNonNull( // Index of session from with the era started + return remoteStorage.query( // Index of session from with the era started keyBuilder = { it.metadata.staking().storage("ErasStartSessionIndex").storageKey(runtime, currentEra) }, binding = ::bindErasStartSessionIndex, chainId = chainId diff --git a/runtime/build.gradle b/runtime/build.gradle index 1a8b4ef3e3..d39de13bc1 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -23,7 +23,7 @@ android { } release { - buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/master/chains/v7/chains.json\"" + buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/develop-free/chains/v7/chains_dev.json\"" } } From 1cf7a1ed9fc5830e3a1763142d97931e406d944a Mon Sep 17 00:00:00 2001 From: Deneath Date: Mon, 12 Feb 2024 19:18:21 +0700 Subject: [PATCH 32/35] fix staked value formatting --- .../impl/presentation/staking/main/StakingViewStateOld.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/StakingViewStateOld.kt b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/StakingViewStateOld.kt index f019ef0f73..6b8dfdbe3e 100644 --- a/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/StakingViewStateOld.kt +++ b/feature-staking-impl/src/main/java/jp/co/soramitsu/staking/impl/presentation/staking/main/StakingViewStateOld.kt @@ -206,7 +206,7 @@ sealed class StakeViewState( return StakeSummaryModel( status = summary.status, - totalStaked = summary.totalStaked.formatCrypto(tokenType.symbol), + totalStaked = summary.totalStaked.formatCryptoDetail(tokenType.symbol), totalStakedFiat = token.fiatAmount(summary.totalStaked)?.formatFiat(token.fiatSymbol), totalRewards = summary.totalReward.formatCryptoDetail(tokenType.symbol), totalRewardsFiat = token.fiatAmount(summary.totalReward)?.formatFiat(token.fiatSymbol), From d4486c98606fc6ab1153932c25f7519136b28f22 Mon Sep 17 00:00:00 2001 From: Deneath Date: Mon, 12 Feb 2024 19:19:08 +0700 Subject: [PATCH 33/35] switch release chains.json back to master --- runtime/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/build.gradle b/runtime/build.gradle index d39de13bc1..1a8b4ef3e3 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -23,7 +23,7 @@ android { } release { - buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/develop-free/chains/v7/chains_dev.json\"" + buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/master/chains/v7/chains.json\"" } } From bf7ca0d458df1cf8c6413c82a7c23f3d09557f9a Mon Sep 17 00:00:00 2001 From: Deneath Date: Tue, 13 Feb 2024 15:32:20 +0700 Subject: [PATCH 34/35] increase versionCode --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index eab9498c3a..8403fd1dce 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { ext { // App version versionName = '3.3.1' - versionCode = 153 + versionCode = 154 // SDK and tools compileSdkVersion = 34 From b37ce6fc6b277bb428b84bba4d8e70a3338576dc Mon Sep 17 00:00:00 2001 From: Deneath Date: Tue, 13 Feb 2024 18:43:22 +0700 Subject: [PATCH 35/35] switch to chains V8, increase version code --- build.gradle | 2 +- runtime/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 8403fd1dce..e7a1355985 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { ext { // App version versionName = '3.3.1' - versionCode = 154 + versionCode = 155 // SDK and tools compileSdkVersion = 34 diff --git a/runtime/build.gradle b/runtime/build.gradle index 1a8b4ef3e3..90fba27a5f 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -23,7 +23,7 @@ android { } release { - buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/master/chains/v7/chains.json\"" + buildConfigField "String", "CHAINS_URL", "\"https://raw.githubusercontent.com/soramitsu/shared-features-utils/master/chains/v8/chains.json\"" } }