Skip to content

Commit

Permalink
fix(pubkeys): Fix pubkeys and dashboard PTR (#4148)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonis-bc committed Nov 24, 2022
1 parent ba652ce commit b3cde6f
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 67 deletions.
Expand Up @@ -215,11 +215,13 @@ class DashboardActionInteractor(
activeAssets: Set<Currency>,
walletMode: WalletMode,
): Disposable {
loadBalances(activeAssets, model, walletMode).forEach {
loadBalances(activeAssets, model, walletMode)?.let {
it.addTo(balancesDisposable)
}
warmWalletModeBalanceCache()
warmProductsCache()
warmWalletModeBalanceCache().forEach {
it.addTo(balancesDisposable)
}
balancesDisposable += warmProductsCache()
return balancesDisposable
}

Expand Down Expand Up @@ -249,14 +251,17 @@ class DashboardActionInteractor(
assets: Set<Currency>,
model: DashboardModel,
walletMode: WalletMode
): List<Disposable> {
return assets.takeIf { it.isNotEmpty() }?.map { asset ->
refreshAssetBalance(asset, model, walletMode).subscribeBy(onError = {
): Disposable? {
return if (assets.isNotEmpty()) {
val balances = assets.map {
refreshAssetBalance(it, model, walletMode)
}
Observable.merge(balances).subscribeBy(onError = {
Timber.e(it)
})
} ?: kotlin.run {
} else {
model.process(DashboardIntent.NoActiveAssets)
emptyList()
null
}
}

Expand Down Expand Up @@ -314,6 +319,9 @@ class DashboardActionInteractor(
.map { (accountBalance, _) ->
accountBalance.total
}
.onErrorReturn {
Money.zero(currency)
}
}

private fun refreshPricesWith24HDelta(model: DashboardModel, crypto: AssetInfo): Disposable =
Expand Down
Expand Up @@ -23,6 +23,7 @@ import piuk.blockchain.android.ui.dashboard.model.DashboardItem.Companion.DASHBO
import piuk.blockchain.android.ui.dashboard.model.DashboardItem.Companion.LOCKS_INDEX
import piuk.blockchain.android.ui.dashboard.navigation.DashboardNavigationAction
import piuk.blockchain.android.ui.dashboard.sheets.BackupDetails
import timber.log.Timber

class AssetMap(private val map: Map<Currency, DashboardAsset>) :
Map<Currency, DashboardAsset> by map {
Expand Down Expand Up @@ -138,6 +139,11 @@ data class DashboardState(
val isStakingEnabled: Boolean = false
) : MviState, DashboardBalanceStateHost {

init {
val loadingAssets = activeAssets.values.filter { it.isFetchingBalance }.map { it.currency.networkTicker }
Timber.i("Fetching balances for assets: $loadingAssets")
}

override val dashboardBalance: DashboardBalance?
get() = when {
activeAssets.isEmpty() -> null
Expand Down
Expand Up @@ -70,8 +70,8 @@ import org.bitcoinj.core.LegacyAddress
BchAddress(address_ = it, label = label)
}

override suspend fun publicKey(): String {
return internalAccount.xpubs().default.address
override suspend fun publicKey(): List<String> {
return listOf(internalAccount.xpubs().default.address)
}

override fun getOnChainBalance(): Observable<Money> =
Expand Down
Expand Up @@ -102,8 +102,8 @@ import io.reactivex.rxjava3.core.Single
payloadDataManager.getAddressBalanceRefresh(xpubs, false)
.map { it }

override suspend fun publicKey(): String {
return xpubs.default.address
override suspend fun publicKey(): List<String> {
return xpubs.allAddresses()
}

override val index: Int
Expand Down
Expand Up @@ -66,7 +66,7 @@ class Erc20NonCustodialAccount(
override val index: Int
get() = DEFAULT_SINGLE_ACCOUNT_INDEX

override suspend fun publicKey(): String {
override suspend fun publicKey(): List<String> {
throw IllegalAccessException("Public key of an erc20 cannot be accessed use the L1")
}

Expand Down
Expand Up @@ -82,8 +82,10 @@ import kotlinx.coroutines.flow.flowOf
flowOf(DataResource.Data(Money.fromMajor(currency, BigDecimal.ZERO)))
}.asObservable()

override suspend fun publicKey(): String =
jsonAccount.publicKey ?: throw IllegalStateException("Public key for Eth account hasn't been derived")
override suspend fun publicKey(): List<String> =
jsonAccount.publicKey?.let {
listOf(it)
} ?: throw IllegalStateException("Public key for Eth account hasn't been derived")

override val index: Int
get() = NetworkWallet.DEFAULT_SINGLE_ACCOUNT_INDEX
Expand Down
Expand Up @@ -61,8 +61,10 @@ class L1EvmNonCustodialAccount(
override val index: Int
get() = DEFAULT_SINGLE_ACCOUNT_INDEX

override suspend fun publicKey(): String =
ethDataManager.ehtAccount.publicKey ?: throw IllegalStateException(
override suspend fun publicKey(): List<String> =
ethDataManager.ehtAccount.publicKey?.let {
listOf(it)
} ?: throw IllegalStateException(
"Public key for Eth account hasn't been derived"
)

Expand Down
Expand Up @@ -142,6 +142,6 @@ class DynamicNonCustodialAccount(
override val index: Int
get() = 0

override suspend fun publicKey(): String =
String(Hex.encode(internalAccount.address.pubKey))
override suspend fun publicKey(): List<String> =
listOf(String(Hex.encode(internalAccount.address.pubKey)))
}
Expand Up @@ -84,8 +84,9 @@ internal class XlmCryptoWalletAccount(
xlmManager.getBalanceAndMin()
.toObservable()

override suspend fun publicKey(): String {
return xlmManager.publicKey.await()
override suspend fun publicKey(): List<String> {
val pubKey = xlmManager.publicKey.await()
return listOf(pubKey)
}

override val index: Int
Expand Down
Expand Up @@ -401,8 +401,8 @@ private class NonCustodialTestAccount(
override val index: Int
get() = 1

override suspend fun publicKey(): String {
return ""
override suspend fun publicKey(): List<String> {
return listOf("")
}

override fun createTxEngine(target: TransactionTarget, action: AssetAction): TxEngine = mock()
Expand Down
Expand Up @@ -8,10 +8,12 @@ import com.blockchain.api.selfcustody.SubscriptionInfo
import com.blockchain.data.DataResource
import com.blockchain.data.FreshnessStrategy
import com.blockchain.data.FreshnessStrategy.Companion.withKey
import com.blockchain.data.map
import com.blockchain.logging.RemoteLogger
import com.blockchain.outcome.getOrThrow
import com.blockchain.preferences.CurrencyPrefs
import com.blockchain.store.firstOutcome
import com.blockchain.store.flatMapData
import com.blockchain.store.mapData
import com.blockchain.unifiedcryptowallet.domain.balances.NetworkAccountsService
import com.blockchain.unifiedcryptowallet.domain.balances.NetworkBalance
Expand All @@ -26,6 +28,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onEach

internal class UnifiedBalancesRepository(
Expand All @@ -46,52 +49,55 @@ internal class UnifiedBalancesRepository(
val pubKeys = networkWallets.associateWith {
it.publicKey()
}
try {
subscribe(pubKeys)

emitAll(
unifiedBalancesStore.stream(FreshnessStrategy.Cached(true)).mapData { response ->
logResponse(networkWallets, response)
response.balances.filter {
if (wallet == null) true
else it.currency == wallet.currency.networkTicker && it.account.index == wallet.index &&
it.account.name == wallet.label
}.mapNotNull {
val cc = assetCatalogue.fromNetworkTicker(it.currency)
NetworkBalance(
currency = cc ?: return@mapNotNull null,
balance = it.balance?.amount?.let { amount ->
Money.fromMinor(cc, amount)
} ?: return@mapNotNull null,
unconfirmedBalance = it.pending?.amount?.let { amount ->
Money.fromMinor(cc, amount)
} ?: return@mapNotNull null,
exchangeRate = ExchangeRate(
from = cc,
to = currencyPrefs.selectedFiatCurrency,
rate = it.price
)
subscribe(pubKeys)

emitAll(
unifiedBalancesStore.stream(FreshnessStrategy.Cached(true)).mapData { response ->
logResponse(networkWallets, response)
response.balances.filter {
if (wallet == null) true
else it.currency == wallet.currency.networkTicker && it.account.index == wallet.index &&
it.account.name == wallet.label
}.mapNotNull {
val cc = assetCatalogue.fromNetworkTicker(it.currency)
NetworkBalance(
currency = cc ?: return@mapNotNull null,
balance = it.balance?.amount?.let { amount ->
Money.fromMinor(cc, amount)
} ?: return@mapNotNull null,
unconfirmedBalance = it.pending?.amount?.let { amount ->
Money.fromMinor(cc, amount)
} ?: return@mapNotNull null,
exchangeRate = ExchangeRate(
from = cc,
to = currencyPrefs.selectedFiatCurrency,
rate = it.price
)
}
)
}
)
} catch (e: Exception) {
emit(DataResource.Error(e))
}
}
)
}.catch {
emit(DataResource.Error(it as Exception))
}
}

override fun balanceForWallet(
wallet: NetworkWallet
): Flow<DataResource<NetworkBalance>> {
return balances(wallet).mapData {
it.firstOrNull() ?: throw UnifiedBalanceNotFoundException(
currency = wallet.currency.networkTicker,
name = wallet.label,
index = wallet.index
return balances(wallet).flatMapData {
it.firstOrNull()?.let { balance ->
flowOf(DataResource.Data(balance))
} ?: flowOf(
DataResource.Error(
UnifiedBalanceNotFoundException(
currency = wallet.currency.networkTicker,
name = wallet.label,
index = wallet.index
)
)
)
}.catch {
emit(DataResource.Error(Exception(it)))
}.onEach {
if (it is DataResource.Error) {
remoteLogger.logException(
Expand All @@ -102,7 +108,7 @@ internal class UnifiedBalancesRepository(
}
}

private suspend fun subscribe(networkAccountsPubKeys: Map<NetworkWallet, String>): CommonResponse {
private suspend fun subscribe(networkAccountsPubKeys: Map<NetworkWallet, List<String>>): CommonResponse {

val subscriptions = networkAccountsPubKeys.keys.map {
check(networkAccountsPubKeys[it] != null)
Expand All @@ -112,13 +118,13 @@ internal class UnifiedBalancesRepository(
index = it.index,
name = it.label
),
pubKeys = listOf(
pubKeys = networkAccountsPubKeys[it]!!.map { pubKey ->
PubKeyInfo(
pubKey = networkAccountsPubKeys[it]!!,
pubKey = pubKey,
style = it.style,
descriptor = it.descriptor
)
)
}
)
}
return unifiedBalancesSubscribeStore.stream(FreshnessStrategy.Cached(false).withKey(subscriptions))
Expand Down
Expand Up @@ -20,6 +20,7 @@ interface NetworkWallet {
val networkBalance: Flow<DataResource<NetworkBalance>>
val isImported: Boolean
get() = false

/**
* The descriptor field will need some explanation. Over time some currencies change the
* way that keys are derived as well as how such keys are used. Most notably, Bitcoin uses
Expand All @@ -37,7 +38,7 @@ interface NetworkWallet {
val pubKeyDescriptor: String
get() = LEGACY_DESCRIPTOR

suspend fun publicKey(): String
suspend fun publicKey(): List<String>

companion object {
const val DEFAULT_SINGLE_ACCOUNT_INDEX = 0
Expand Down Expand Up @@ -70,7 +71,7 @@ class CryptoNetworkWallet(
override val style: PubKeyStyle
get() = config.style

override suspend fun publicKey(): String = pubKeyService.publicKey()
override suspend fun publicKey(): List<String> = pubKeyService.publicKey()
}

class NetworkWalletGroup(
Expand All @@ -81,7 +82,7 @@ class NetworkWalletGroup(

private val balancesService: UnifiedBalancesService by scopedInject()

suspend fun publicKey(): String {
suspend fun publicKey(): List<String> {
return parentChainNetwork.publicKey()
}

Expand All @@ -97,7 +98,7 @@ class NetworkWalletGroup(
data class NetworkConfig(val descriptor: Int, val style: PubKeyStyle)

interface PublicKeyService {
suspend fun publicKey(): String
suspend fun publicKey(): List<String>
}

inline fun <reified T> KoinComponent.scopedInject(
Expand Down

0 comments on commit b3cde6f

Please sign in to comment.