diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/PoolContributionProcessor.kt b/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/PoolContributionProcessor.kt index f0e5c0ce81..8e66fc615f 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/PoolContributionProcessor.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/PoolContributionProcessor.kt @@ -4,9 +4,6 @@ import com.babylon.wallet.android.domain.model.Transferable import com.babylon.wallet.android.domain.model.TransferableAsset import com.babylon.wallet.android.domain.model.assets.Asset import com.babylon.wallet.android.domain.model.assets.PoolUnit -import com.babylon.wallet.android.domain.model.resources.Resource -import com.babylon.wallet.android.domain.model.resources.metadata.poolUnit -import com.babylon.wallet.android.domain.usecases.assets.GetPoolDetailsUseCase import com.babylon.wallet.android.domain.usecases.assets.ResolveAssetsFromAddressUseCase import com.babylon.wallet.android.presentation.transaction.AccountWithTransferableResources import com.babylon.wallet.android.presentation.transaction.PreviewType @@ -22,23 +19,34 @@ import javax.inject.Inject class PoolContributionProcessor @Inject constructor( private val resolveAssetsFromAddressUseCase: ResolveAssetsFromAddressUseCase, - private val getPoolDetailsUseCase: GetPoolDetailsUseCase, private val getProfileUseCase: GetProfileUseCase ) : PreviewTypeProcessor { - @Suppress("LongMethod") + override suspend fun process(summary: ExecutionSummary, classification: DetailedManifestClass.PoolContribution): PreviewType { val assets = resolveAssetsFromAddressUseCase( fungibleAddresses = summary.involvedFungibleAddresses(), nonFungibleIds = summary.involvedNonFungibleIds() ).getOrThrow() - val involvedPools = getPoolDetailsUseCase(classification.poolAddresses.map { it.addressString() }.toSet()).getOrThrow() val defaultDepositGuarantee = getProfileUseCase.invoke().first().appPreferences.transaction.defaultDepositGuarantee val accountsWithdrawnFrom = summary.accountWithdraws.keys val ownedAccountsWithdrawnFrom = getProfileUseCase.accountsOnCurrentNetwork().filter { accountsWithdrawnFrom.contains(it.address) } val from = summary.extractWithdraws(ownedAccountsWithdrawnFrom, assets) - val to = summary.accountDeposits.map { depositsPerAddress -> + val to = summary.extractDeposits(classification, assets, defaultDepositGuarantee) + return PreviewType.Transfer.Pool( + from = from, + to = to, + actionType = PreviewType.Transfer.Pool.ActionType.Contribution + ) + } + + private suspend fun ExecutionSummary.extractDeposits( + classification: DetailedManifestClass.PoolContribution, + assets: List, + defaultDepositGuarantee: Double + ): List { + val to = accountDeposits.map { depositsPerAddress -> val ownedAccount = getProfileUseCase.accountOnCurrentNetwork(depositsPerAddress.key) ?: error("No account found") val deposits = depositsPerAddress.value.map { deposit -> val resourceAddress = deposit.resourceAddress @@ -46,26 +54,19 @@ class PoolContributionProcessor @Inject constructor( it.poolUnitsResourceAddress.addressString() == resourceAddress } if (contributions.isEmpty()) { - resolveGeneralAsset(deposit, summary, assets, defaultDepositGuarantee) + resolveGeneralAsset(deposit, this, assets, defaultDepositGuarantee) } else { - val pool = involvedPools.find { it.address == contributions.first().poolAddress.addressString() } - ?: error("No pool found") - val poolResource = assets.find { - it.resource.resourceAddress == pool.metadata.poolUnit() - }?.resource as? Resource.FungibleResource - ?: error("No pool resource found") + val poolUnit = assets.find { it.resource.resourceAddress == resourceAddress } as? PoolUnit + ?: error("No pool unit found") val contributedResourceAddresses = contributions.first().contributedResources.keys val guaranteeType = deposit.guaranteeType(defaultDepositGuarantee) val poolUnitAmount = contributions.find { - it.poolUnitsResourceAddress.addressString() == poolResource.resourceAddress + it.poolUnitsResourceAddress.addressString() == poolUnit.resourceAddress }?.poolUnitsAmount?.asStr()?.toBigDecimalOrNull() Transferable.Depositing( transferable = TransferableAsset.Fungible.PoolUnitAsset( amount = contributions.map { it.poolUnitsAmount.asStr().toBigDecimal() }.sumOf { it }, - unit = PoolUnit( - stake = poolResource.copy(ownedAmount = poolUnitAmount), - pool = pool - ), + unit = poolUnit.copy(stake = poolUnit.stake.copy(ownedAmount = poolUnitAmount)), contributionPerResource = contributedResourceAddresses.associateWith { contributedResourceAddress -> contributions.mapNotNull { it.contributedResources[contributedResourceAddress]?.asStr()?.toBigDecimal() } .sumOf { it } @@ -80,11 +81,7 @@ class PoolContributionProcessor @Inject constructor( resources = deposits ) } - return PreviewType.Transfer.Pool( - from = from, - to = to, - actionType = PreviewType.Transfer.Pool.ActionType.Contribution - ) + return to } private fun resolveGeneralAsset( diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/TransactionTypeExtensions.kt b/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/TransactionTypeExtensions.kt index 02002c438e..b04d51a7bb 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/TransactionTypeExtensions.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/TransactionTypeExtensions.kt @@ -372,7 +372,7 @@ val NonFungibleResourceIndicator.nonFungibleLocalIds: List is NonFungibleResourceIndicator.ByIds -> ids } -private fun Map.toMetadata(): List = mapNotNull { it.toMetadata() } +fun Map.toMetadata(): List = mapNotNull { it.toMetadata() } @Suppress("CyclomaticComplexMethod", "LongMethod") private fun Map.Entry.toMetadata(): Metadata? = when (val typed = value) { diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/ValidatorStakeProcessor.kt b/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/ValidatorStakeProcessor.kt index 4097a77acf..00158f2ef6 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/ValidatorStakeProcessor.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/ValidatorStakeProcessor.kt @@ -31,7 +31,7 @@ class ValidatorStakeProcessor @Inject constructor( val involvedValidators = getValidatorsUseCase(classification.involvedValidatorAddresses).getOrThrow() val fromAccounts = extractWithdrawals(summary, getProfileUseCase, resources) - val toAccounts = classification.extractDeposits( + val toAccounts = extractDeposits( executionSummary = summary, getProfileUseCase = getProfileUseCase, resources = resources, @@ -45,7 +45,7 @@ class ValidatorStakeProcessor @Inject constructor( ) } - private suspend fun DetailedManifestClass.ValidatorStake.extractDeposits( + private suspend fun extractDeposits( executionSummary: ExecutionSummary, getProfileUseCase: GetProfileUseCase, resources: List, @@ -53,21 +53,22 @@ class ValidatorStakeProcessor @Inject constructor( ) = executionSummary.accountDeposits.map { depositsPerAccount -> val ownedAccount = getProfileUseCase.accountOnCurrentNetwork(depositsPerAccount.key) ?: error("No account found") val defaultDepositGuarantees = getProfileUseCase.invoke().first().appPreferences.transaction.defaultDepositGuarantee - val depositingLsu = depositsPerAccount.value.map { depositedResource -> - val resourceAddress = depositedResource.resourceAddress + val depositingLsu = depositsPerAccount.value.groupBy { it.resourceAddress }.map { depositedResources -> val lsuResource = resources.find { - it.resourceAddress == resourceAddress + it.resourceAddress == depositedResources.key } as? Resource.FungibleResource ?: error("No resource found") - val stakes = validatorStakes.filter { it.liquidStakeUnitAddress.asStr() == resourceAddress } + val validatorAddress = lsuResource.validatorAddress ?: error("No validator address found") val validator = - involvedValidators.find { it.address == stakes.first().validatorAddress.addressString() } ?: error("No validator found") - val amount = stakes.sumOf { it.liquidStakeUnitAmount.asStr().toBigDecimal() } - val guaranteeType = depositedResource.guaranteeType(defaultDepositGuarantees) + involvedValidators.find { it.address == validatorAddress } ?: error("No validator found") + val lsuAmount = depositedResources.value.sumOf { it.amount } + val xrdWorth = lsuAmount.divide(lsuResource.currentSupply, lsuResource.mathContext) + .multiply(validator.totalXrdStake, lsuResource.mathContext) + val guaranteeType = depositedResources.value.first().guaranteeType(defaultDepositGuarantees) Transferable.Depositing( transferable = TransferableAsset.Fungible.LSUAsset( - amount = amount, - lsu = LiquidStakeUnit(lsuResource.copy(ownedAmount = amount), validator), - xrdWorth = stakes.sumOf { it.xrdAmount.asStr().toBigDecimal() }, + amount = lsuAmount, + lsu = LiquidStakeUnit(lsuResource.copy(ownedAmount = lsuAmount), validator), + xrdWorth = xrdWorth, ), guaranteeType = guaranteeType ) diff --git a/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/ValidatorUnstakeProcessor.kt b/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/ValidatorUnstakeProcessor.kt index c4a16563a1..bcc9677b20 100644 --- a/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/ValidatorUnstakeProcessor.kt +++ b/app/src/main/java/com/babylon/wallet/android/presentation/transaction/analysis/processor/ValidatorUnstakeProcessor.kt @@ -13,6 +13,8 @@ import com.babylon.wallet.android.presentation.transaction.AccountWithTransferab import com.babylon.wallet.android.presentation.transaction.PreviewType import com.radixdlt.ret.DetailedManifestClass import com.radixdlt.ret.ExecutionSummary +import com.radixdlt.ret.NonFungibleGlobalId +import com.radixdlt.ret.ResourceIndicator import kotlinx.coroutines.flow.first import rdx.works.profile.domain.GetProfileUseCase import rdx.works.profile.domain.accountOnCurrentNetwork @@ -30,7 +32,7 @@ class ValidatorUnstakeProcessor @Inject constructor( val resources = getResourcesUseCase(addresses = summary.involvedResourceAddresses + xrdAddress, withDetails = true).getOrThrow() val involvedValidators = getValidatorsUseCase(classification.involvedValidatorAddresses).getOrThrow() - val fromAccounts = classification.extractWithdrawals(summary, getProfileUseCase, resources, involvedValidators) + val fromAccounts = extractWithdrawals(summary, getProfileUseCase, resources, involvedValidators) val toAccounts = classification.extractDeposits(summary, getProfileUseCase, resources, involvedValidators) val validatorAddressesSet = classification.validatorAddresses.map { it.addressString() }.toSet() return PreviewType.Transfer.Staking( @@ -49,26 +51,23 @@ class ValidatorUnstakeProcessor @Inject constructor( ) = executionSummary.accountDeposits.map { claimsPerAddress -> val ownedAccount = getProfileUseCase.accountOnCurrentNetwork(claimsPerAddress.key) ?: error("No account found") val defaultDepositGuarantees = getProfileUseCase.invoke().first().appPreferences.transaction.defaultDepositGuarantee - val depositingNfts = claimsPerAddress.value.map { claimedResource -> - val resourceAddress = claimedResource.resourceAddress + val depositingNfts = claimsPerAddress.value.filterIsInstance().map { claimedResource -> + val resourceAddress = claimedResource.resourceAddress.addressString() val nftResource = resources.find { it.resourceAddress == resourceAddress } as? Resource.NonFungibleResource ?: error("No resource found") - val validatorUnstake = validatorUnstakes.find { it.claimNftAddress.addressString() == resourceAddress } - ?: error("No validator claim found") - val lsuResource = resources.find { - it.resourceAddress == validatorUnstake.liquidStakeUnitAddress.addressString() - } as? Resource.FungibleResource ?: error("No resource found") val validator = - involvedValidators.find { validatorUnstake.validatorAddress.addressString() == it.address } ?: error("No validator found") - val lsuAmount = validatorUnstake.liquidStakeUnitAmount.asStr().toBigDecimal() - val xrdWorth = lsuAmount.divide(lsuResource.currentSupply, lsuResource.mathContext) - .multiply(validator.totalXrdStake, lsuResource.mathContext) - val stakeClaimNftItems = validatorUnstake.claimNftIds.map { localId -> + involvedValidators.find { nftResource.validatorAddress == it.address } ?: error("No validator found") + val stakeClaimNftItems = claimedResource.indicator.nonFungibleLocalIds.map { localId -> + val globalId = NonFungibleGlobalId.fromParts(claimedResource.resourceAddress, localId) + val claimAmount = + claimsNonFungibleData.find { it.nonFungibleGlobalId.asStr() == globalId.asStr() }?.data?.claimAmount?.asStr() + ?.toBigDecimal() + ?: error("No claim amount found") Resource.NonFungibleResource.Item( collectionAddress = resourceAddress, localId = Resource.NonFungibleResource.Item.ID.from(localId) - ) to xrdWorth + ) to claimAmount } val guaranteeType = claimedResource.guaranteeType(defaultDepositGuarantees) Transferable.Depositing( @@ -91,22 +90,21 @@ class ValidatorUnstakeProcessor @Inject constructor( ) } - private suspend fun DetailedManifestClass.ValidatorUnstake.extractWithdrawals( + private suspend fun extractWithdrawals( executionSummary: ExecutionSummary, getProfileUseCase: GetProfileUseCase, resources: List, involvedValidators: List ) = executionSummary.accountWithdraws.map { withdrawalsPerAccount -> val ownedAccount = getProfileUseCase.accountOnCurrentNetwork(withdrawalsPerAccount.key) ?: error("No account found") - val withdrawingLsu = withdrawalsPerAccount.value.map { depositedResource -> - val resourceAddress = depositedResource.resourceAddress + val withdrawingLsu = withdrawalsPerAccount.value.groupBy { it.resourceAddress }.map { depositedResources -> + val resourceAddress = depositedResources.key val lsuResource = resources.find { it.resourceAddress == resourceAddress } as? Resource.FungibleResource ?: error("No resource found") - val unstakes = validatorUnstakes.filter { it.liquidStakeUnitAddress.asStr() == resourceAddress } - val validator = - involvedValidators.find { it.address == unstakes.first().validatorAddress.addressString() } ?: error("No validator found") - val totalLSU = unstakes.sumOf { it.liquidStakeUnitAmount.asStr().toBigDecimal() } + val validatorAddress = lsuResource.validatorAddress ?: error("No validator address found") + val validator = involvedValidators.find { it.address == validatorAddress } ?: error("No validator found") + val totalLSU = depositedResources.value.sumOf { it.amount } val xrdWorth = totalLSU.divide(lsuResource.currentSupply, lsuResource.mathContext) .multiply(validator.totalXrdStake, lsuResource.mathContext) Transferable.Withdrawing( diff --git a/app/src/test/java/com/babylon/wallet/android/presentation/transaction/TransactionReviewViewModelTest.kt b/app/src/test/java/com/babylon/wallet/android/presentation/transaction/TransactionReviewViewModelTest.kt index cb5b921c11..6cd3f6618b 100644 --- a/app/src/test/java/com/babylon/wallet/android/presentation/transaction/TransactionReviewViewModelTest.kt +++ b/app/src/test/java/com/babylon/wallet/android/presentation/transaction/TransactionReviewViewModelTest.kt @@ -137,7 +137,6 @@ internal class TransactionReviewViewModelTest : StateViewModelTest