Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(wallet-mobile): balances - protocolparams #3327

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {CardanoApi} from '@yoroi/api'
import {mountAsyncStorage, mountMMKVStorage, observableStorageMaker} from '@yoroi/common'
import {createPrimaryTokenInfo} from '@yoroi/portfolio'
import {Chain, Network} from '@yoroi/types'
import {freeze} from 'immer'

import {logger} from '../../../kernel/logger/logger'
import {NetworkTokenManagers} from '../common/types'

export const primaryTokenInfoMainnet = createPrimaryTokenInfo({
Expand Down Expand Up @@ -66,6 +68,16 @@ export const shelleyPreprodEraConfig: Readonly<Network.EraConfig> = freeze(
true,
)

export const protocolParamsPlaceholder = freeze({
linearFee: {
constant: '155381',
coefficient: '44',
},
coinsPerUtxoByte: '4310',
poolDeposit: '500000000',
keyDeposit: '2000000',
})

const networkConfigs: Readonly<Record<Chain.SupportedNetworks, Readonly<Network.Config>>> = freeze({
[Chain.Network.Mainnet]: {
network: Chain.Network.Mainnet,
Expand Down Expand Up @@ -118,26 +130,35 @@ export function buildNetworkManagers({
tokenManagers: NetworkTokenManagers
}): Readonly<Record<Chain.SupportedNetworks, Network.Manager>> {
// TODO: receive and attach the explorers here as well
return freeze(
Object.entries(networkConfigs).reduce<Record<Chain.SupportedNetworks, Network.Manager>>(
(networkManagers, [network, config]) => {
const tokenManager = tokenManagers[network as Chain.SupportedNetworks]
const networkRootStorage = mountMMKVStorage({path: `/`, id: `${network}.manager.v1`})
const rootStorage = observableStorageMaker(networkRootStorage)
const legacyRootStorage = observableStorageMaker(mountAsyncStorage({path: `/legacy/${network}/v1/`}))
const networkManager: Network.Manager = {
...config,
tokenManager,
rootStorage,
// NOTE: we can't use the new rootStorage cuz all modules are async now 🥹
legacyRootStorage,
}
networkManagers[network as Chain.SupportedNetworks] = networkManager
const managers = Object.entries(networkConfigs).reduce<Record<Chain.SupportedNetworks, Network.Manager>>(
(networkManagers, [network, config]) => {
const tokenManager = tokenManagers[network as Chain.SupportedNetworks]
const networkRootStorage = mountMMKVStorage({path: `/`, id: `${network}.manager.v1`})
const rootStorage = observableStorageMaker(networkRootStorage)
const legacyRootStorage = observableStorageMaker(mountAsyncStorage({path: `/legacy/${network}/v1/`}))
const {getProtocolParams} = CardanoApi.cardanoApiMaker({network: config.network})
const api = {
protocolParams: () =>
getProtocolParams().catch((error) => {
logger.error(`networkManager: ${network} protocolParams has failed`, {error})
return protocolParamsPlaceholder
}),
}

return networkManagers
},
{} as Record<Chain.SupportedNetworks, Network.Manager>,
),
true,
const networkManager: Network.Manager = {
...config,
tokenManager,
rootStorage,
// NOTE: we can't use the new rootStorage cuz all modules are async now 🥹
legacyRootStorage,
api,
}
networkManagers[network as Chain.SupportedNetworks] = networkManager

return networkManagers
},
{} as Record<Chain.SupportedNetworks, Network.Manager>,
)

return freeze(managers, true)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {Api} from '@yoroi/types'
import {useQuery, UseQueryOptions} from 'react-query'

import {time} from '../../../kernel/constants'
import {queryInfo} from '../../../kernel/query-client'
import {useSelectedNetwork} from '../common/hooks/useSelectedNetwork'
import {protocolParamsPlaceholder} from './network-manager'

export const useProtocolParams = (
options?: UseQueryOptions<
Api.Cardano.ProtocolParams,
Error,
Api.Cardano.ProtocolParams,
[string, string, 'useProtocolParams']
>,
) => {
const {network, networkManager} = useSelectedNetwork()
const query = useQuery({
suspense: true,
// TODO: it should be infinity until it is invalided when epoch changes after conway
staleTime: time.oneHour,
cacheTime: time.oneHour,
keepPreviousData: true,
queryKey: [queryInfo.keyToPersist, network, 'useProtocolParams'],
...options,
queryFn: () => networkManager.api.protocolParams(),
})

return {
...query,
protocolParams: query.data ?? protocolParamsPlaceholder,
}
}
42 changes: 19 additions & 23 deletions apps/wallet-mobile/src/yoroi-wallets/cardano/cardano-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {walletChecksum} from '@emurgo/cip4-js'
import * as CSL from '@emurgo/cross-csl-core'
import {createSignedLedgerTxFromCbor, signRawTransaction} from '@emurgo/yoroi-lib'
import {Datum} from '@emurgo/yoroi-lib/dist/internals/models'
import {AppApi, CardanoApi} from '@yoroi/api'
import {AppApi} from '@yoroi/api'
import {isNonNullable} from '@yoroi/common'
import {Api, App, Balance, HW, Network, Portfolio, Wallet} from '@yoroi/types'
import assert from 'assert'
Expand All @@ -16,6 +16,7 @@ import {Observable} from 'rxjs'

import {buildPortfolioBalanceManager} from '../../features/Portfolio/common/helpers/build-balance-manager'
import {toBalanceManagerSyncArgs} from '../../features/Portfolio/common/transformers/toBalanceManagerSyncArgs'
import {protocolParamsPlaceholder} from '../../features/WalletManager/network-manager/network-manager'
import LocalizableError from '../../kernel/i18n/LocalizableError'
import {throwLoggedError} from '../../kernel/logger/helpers/throw-logged-error'
import {logger} from '../../kernel/logger/logger'
Expand Down Expand Up @@ -88,7 +89,6 @@ export const makeCardanoWallet = (
readonly encryptedStorage: WalletEncryptedStorage

readonly api: App.Api = appApi
private readonly cardanoApi: Api.Cardano.Actions

readonly publicKeyHex: string
readonly rewardAddressHex: string
Expand All @@ -107,6 +107,10 @@ export const makeCardanoWallet = (
readonly networkManager: Readonly<Network.Manager> = networkManager
readonly isMainnet: boolean = networkManager.isMainnet

// TODO: needs to be updated when epoch changes after conway. (query needs invalidation)
// considering pass it through the tx-builder straigh from the network manager
protocolParams: Api.Cardano.ProtocolParams = protocolParamsPlaceholder

static readonly calcChecksum = walletChecksum
static readonly implementation: Wallet.Implementation = implementation
static readonly makeKeys = keyManager(implementation)
Expand All @@ -125,7 +129,7 @@ export const makeCardanoWallet = (
accountPubKeyHex: string
accountVisual: number
}) => {
const {rootStorage: networkRootStorage, primaryTokenInfo, network, chainId, legacyRootStorage} = networkManager
const {rootStorage: networkRootStorage, primaryTokenInfo, chainId, legacyRootStorage} = networkManager
const walletRootStorage = legacyRootStorage.join(`${id}/`)
const accountStorage = walletRootStorage.join(`accounts/${accountVisual}/`)
const {legacyApiBaseUrl, tokenManager} = networkManager
Expand Down Expand Up @@ -154,12 +158,10 @@ export const makeCardanoWallet = (
implementation,
baseApiUrl: legacyApiBaseUrl,
})

const cardanoApi = CardanoApi.cardanoApiMaker({network})
const protocolParams = await networkManager.api.protocolParams()

const wallet = new CardanoWallet({
id,
cardanoApi,
accountPubKeyHex,
rewardAddressHex,
accountManager,
Expand All @@ -169,6 +171,7 @@ export const makeCardanoWallet = (
balanceManager,
portfolioPrimaryTokenInfo: primaryTokenInfo,
accountVisual,
protocolParams,
})
if (!isYoroiWallet(wallet)) throwLoggedError('ShelleyWallet: build invalid wallet')

Expand All @@ -190,9 +193,8 @@ export const makeCardanoWallet = (
balanceManager,
accountManager,

cardanoApi,

portfolioPrimaryTokenInfo,
protocolParams,
}: {
id: string
accountPubKeyHex: string
Expand All @@ -205,9 +207,8 @@ export const makeCardanoWallet = (
balanceManager: Readonly<Portfolio.Manager.Balance>
accountManager: AccountManager

cardanoApi: Api.Cardano.Actions

portfolioPrimaryTokenInfo: Readonly<Portfolio.Token.Info>
protocolParams: Api.Cardano.ProtocolParams
}) {
this.id = id
this.publicKeyHex = accountPubKeyHex
Expand All @@ -224,7 +225,7 @@ export const makeCardanoWallet = (
this.accountManager = accountManager
this.portfolioPrimaryTokenInfo = portfolioPrimaryTokenInfo

this.cardanoApi = cardanoApi
this.protocolParams = protocolParams

this.encryptedStorage = makeWalletEncryptedStorage(id)

Expand Down Expand Up @@ -386,11 +387,11 @@ export const makeCardanoWallet = (
? RegistrationStatus.DelegateOnly
: RegistrationStatus.RegisterAndDelegate
const delegatedAmountMT = {
values: [{identifier: '', amount: delegatedAmount, networkId: NETWORK_ID}],
values: [{identifier: '', amount: delegatedAmount, networkId: this.networkManager.chainId}],
defaults: PRIMARY_TOKEN,
}

const {coinsPerUtxoByte, keyDeposit, linearFee, poolDeposit} = await this.getProtocolParams()
const {coinsPerUtxoByte, keyDeposit, linearFee, poolDeposit} = this.protocolParams

const unsignedTx = await Cardano.createUnsignedDelegationTx(
absSlotNumber,
Expand Down Expand Up @@ -448,7 +449,7 @@ export const makeCardanoWallet = (
const stakingPublicKey = await this.getStakingKey()
const changeAddr = this.getAddressedChangeAddress(addressMode)

const {coinsPerUtxoByte, keyDeposit, linearFee, poolDeposit} = await this.getProtocolParams()
const {coinsPerUtxoByte, keyDeposit, linearFee, poolDeposit} = this.protocolParams

const config = {
keyDeposit,
Expand Down Expand Up @@ -545,7 +546,7 @@ export const makeCardanoWallet = (
networkManager.legacyApiBaseUrl,
)

const {coinsPerUtxoByte, keyDeposit, linearFee, poolDeposit} = await this.getProtocolParams()
const {coinsPerUtxoByte, keyDeposit, linearFee, poolDeposit} = this.protocolParams

const withdrawalTx = await Cardano.createUnsignedWithdrawalTx(
accountState,
Expand Down Expand Up @@ -600,7 +601,7 @@ export const makeCardanoWallet = (
const changeAddr = this.getAddressedChangeAddress(addressMode)
const addressedUtxos = await this.getAddressedUtxos()

const {coinsPerUtxoByte, keyDeposit, linearFee, poolDeposit} = await this.getProtocolParams()
const {coinsPerUtxoByte, keyDeposit, linearFee, poolDeposit} = this.protocolParams

try {
const unsignedTx = await Cardano.createUnsignedTx(
Expand Down Expand Up @@ -786,7 +787,7 @@ export const makeCardanoWallet = (
keyDeposit,
linearFee: {coefficient, constant},
poolDeposit,
} = await this.getProtocolParams()
} = this.protocolParams

try {
const unsignedTx = await Cardano.createUnsignedTx(
Expand Down Expand Up @@ -973,10 +974,6 @@ export const makeCardanoWallet = (
return legacyApi.checkServerStatus(networkManager.legacyApiBaseUrl)
}

getProtocolParams() {
return this.cardanoApi.getProtocolParams()
}

async submitTransaction(base64SignedTx: string) {
await legacyApi.submitTransaction(base64SignedTx, networkManager.legacyApiBaseUrl)
}
Expand All @@ -991,10 +988,9 @@ export const makeCardanoWallet = (
// if it crashes, the utxo manager will be out of sync with wallet
if (this.didUtxosUpdate(this._utxos, newUtxos) || isForced) {
// NOTE: recalc locked deposit should happen also when epoch changes after conway
const {coinsPerUtxoByte} = await this.getProtocolParams()
const lockedAsStorageCost = await calcLockedDeposit({
rawUtxos: newUtxos,
coinsPerUtxoByteStr: coinsPerUtxoByte,
coinsPerUtxoByteStr: this.protocolParams.coinsPerUtxoByte,
})

const balancesToSync = toBalanceManagerSyncArgs(newUtxos, BigInt(lockedAsStorageCost.toString()))
Expand Down
4 changes: 1 addition & 3 deletions apps/wallet-mobile/src/yoroi-wallets/cardano/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
TxMetadata as TxMetadataType,
UnsignedTx as UnsignedTxType,
} from '@emurgo/yoroi-lib'
import {Api, App, Balance, HW, Network, Portfolio, Wallet} from '@yoroi/types'
import {App, Balance, HW, Network, Portfolio, Wallet} from '@yoroi/types'
import {BigNumber} from 'bignumber.js'

import {WalletEncryptedStorage} from '../../kernel/storage/EncryptedStorage'
Expand Down Expand Up @@ -180,8 +180,6 @@ export interface YoroiWallet {

// CIP36 Payment Address
getFirstPaymentAddress(): Promise<CoreTypes.BaseAddress>

getProtocolParams(): Promise<Api.Cardano.ProtocolParamsResult>
}

export const isYoroiWallet = (wallet: unknown): wallet is YoroiWallet => {
Expand Down
24 changes: 1 addition & 23 deletions apps/wallet-mobile/src/yoroi-wallets/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {Certificate} from '@emurgo/cross-csl-core'
import AsyncStorage, {AsyncStorageStatic} from '@react-native-async-storage/async-storage'
import {mountMMKVStorage, observableStorageMaker, parseBoolean, useMutationWithInvalidations} from '@yoroi/common'
import {themeStorageMaker} from '@yoroi/theme'
import {Api, App, Balance, HW, Wallet} from '@yoroi/types'
import {App, Balance, HW, Wallet} from '@yoroi/types'
import {Buffer} from 'buffer'
import * as React from 'react'
import {useCallback, useMemo} from 'react'
Expand Down Expand Up @@ -505,28 +505,6 @@ export const useFrontendFees = (
}
}

export const useProtocolParams = (
wallet: YoroiWallet,
options?: UseQueryOptions<
Api.Cardano.ProtocolParamsResult,
Error,
Api.Cardano.ProtocolParamsResult,
[string, 'protocol-params']
>,
) => {
const query = useQuery({
suspense: true,
queryKey: [wallet.id, 'protocol-params'],
...options,
queryFn: () => wallet.getProtocolParams(),
})

return {
...query,
protocolParams: query.data,
}
}

export const useIsOnline = (
wallet: YoroiWallet,
options?: UseQueryOptions<boolean, Error, boolean, [string, 'isOnline']>,
Expand Down
5 changes: 1 addition & 4 deletions apps/wallet-mobile/src/yoroi-wallets/mocks/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import {action} from '@storybook/addon-actions'
import {AppApi, CardanoApi} from '@yoroi/api'
import {AppApi} from '@yoroi/api'
import {createPrimaryTokenInfo} from '@yoroi/portfolio'
import {Balance, Portfolio, Wallet} from '@yoroi/types'
import BigNumber from 'bignumber.js'
Expand Down Expand Up @@ -264,12 +264,9 @@ const wallet: YoroiWallet = {
resync: async (...args: unknown[]) => {
action('resync')(...args)
},
getProtocolParams: CardanoApi.mockCardanoApi.getProtocolParams,

fetchFundInfo: () => {
throw new Error('not implemented: fetchFundInfo')
},

createUnsignedGovernanceTx: () => {
throw new Error('not implemented: createUnsignedGovernanceTx')
},
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/cardano/api/protocol-params.mocks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Api} from '@yoroi/types'

export const paramsMockResponse: Api.Cardano.ProtocolParamsResult = {
export const paramsMockResponse: Api.Cardano.ProtocolParams = {
coinsPerUtxoByte: '4310',
keyDeposit: '2000000',
linearFee: {coefficient: '44', constant: '155381'},
Expand Down
Loading
Loading