Skip to content

Commit

Permalink
chore(wallet-mobile): wip wiring up portoflio
Browse files Browse the repository at this point in the history
  • Loading branch information
stackchain committed Apr 25, 2024
1 parent c601197 commit d46d28d
Show file tree
Hide file tree
Showing 37 changed files with 545 additions and 386 deletions.
2 changes: 1 addition & 1 deletion apps/wallet-mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"prestart": "sb-rn-get-stories",
"start": "yarn react-native start --reset-cache --verbose",
"storybook:watch": "sb-rn-watcher",
"test": "jest src --ci --bail --silent",
"test": "jest src --ci --bail --silent --maxWorkers=1",
"tsc": "tsc --noEmit -p tsconfig.json",
"tsc:cover": "yarn typescript-coverage-report -i '**/*.test.*' -i '**/*.stories*' -t html --threshold=100"
},
Expand Down
6 changes: 2 additions & 4 deletions apps/wallet-mobile/src/TxHistory/BalanceBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@ import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {Boundary, ResetErrorRef, Spacer} from '../components'
import {Icon} from '../components/Icon'
import {PairedBalance} from '../components/PairedBalance/PairedBalance'
import { usePrimaryBalance } from '../features/Portfolio/common/hooks/usePrimaryBalance'
import {usePrivacyMode} from '../features/Settings/PrivacyMode/PrivacyMode'
import {useSelectedWallet} from '../features/WalletManager/Context'
import {formatTokenWithText, formatTokenWithTextWhenHidden} from '../legacy/format'
import {useBalances} from '../yoroi-wallets/hooks'
import {Amounts} from '../yoroi-wallets/utils'

export const BalanceBanner = React.forwardRef<ResetErrorRef>((_, ref) => {
const wallet = useSelectedWallet()
const styles = useStyles()
const balances = useBalances(wallet)
const primaryAmount = Amounts.getAmount(balances, wallet.primaryTokenInfo.id)
const primary = usePrimaryBalance({wallet})

Check failure on line 17 in apps/wallet-mobile/src/TxHistory/BalanceBanner.tsx

View workflow job for this annotation

GitHub Actions / check

'primary' is assigned a value but never used. Allowed unused vars must match /^_/u
const {isPrivacyOff, togglePrivacyMode} = usePrivacyMode()

return (
Expand Down Expand Up @@ -47,7 +46,6 @@ const hiddenBalance = '*.******'
const Balance = ({isPrivacyOff}: {isPrivacyOff: boolean}) => {
const styles = useStyles()
const wallet = useSelectedWallet()
const balances = useBalances(wallet)

const balance = isPrivacyOff
? formatTokenWithTextWhenHidden(hiddenBalance, wallet.primaryToken)
Expand Down
24 changes: 5 additions & 19 deletions apps/wallet-mobile/src/TxHistory/LockedDeposit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,23 @@ import React from 'react'
import {useIntl} from 'react-intl'
import {StyleSheet, View} from 'react-native'

import {Boundary, Spacer, Text} from '../components'
import {Spacer, Text} from '../components'
import {usePrimaryBreakdown} from '../features/Portfolio/common/hooks/usePrimaryBreakdown'
import {usePrivacyMode} from '../features/Settings/PrivacyMode/PrivacyMode'
import {useSelectedWallet} from '../features/WalletManager/Context'
import globalMessages from '../i18n/global-messages'
import {formatTokenWithText, formatTokenWithTextWhenHidden} from '../legacy/format'
import {useLockedAmount} from '../yoroi-wallets/hooks'
import {asQuantity} from '../yoroi-wallets/utils'

export const LockedDeposit = () => {
const {isPrivacyOff} = usePrivacyMode()
const wallet = useSelectedWallet()
const loadingAmount = formatTokenWithTextWhenHidden('...', wallet.primaryToken)
const hiddenAmount = formatTokenWithTextWhenHidden('*.******', wallet.primaryToken)
const {lockedAsStorageCost} = usePrimaryBreakdown({wallet})
const amount = formatTokenWithText(asQuantity(lockedAsStorageCost.toString()), wallet.primaryToken)

if (isPrivacyOff) return <FormattedAmount amount={hiddenAmount} />

return (
<Boundary
loading={{
fallback: <FormattedAmount amount={loadingAmount} />,
}}
error={{size: 'inline'}}
>
<LockedAmount />
</Boundary>
)
}

const LockedAmount = () => {
const wallet = useSelectedWallet()
const lockedAmount = useLockedAmount({wallet})
const amount = formatTokenWithText(lockedAmount, wallet.primaryToken)
return <FormattedAmount amount={amount} />
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const TxHistoryList = (props: Props) => {
)

const transactionsInfo = useTransactionInfos(wallet)
const groupedTransactions = getTransactionsByDate(transactionsInfo)
const groupedTransactions = React.useMemo(() => getTransactionsByDate(transactionsInfo), [transactionsInfo])

return (
<View style={styles.container}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {Portfolio} from '@yoroi/types'

import {filterBySyncEvent} from './filterBySyncEvent'

describe('filterBySyncEvent', () => {
it('should return true if the event is a sync event', () => {
const event: Portfolio.Event.BalanceManager = {
on: Portfolio.Event.ManagerOn.Sync,
mode: 'all',
sourceId: '1',
}
expect(filterBySyncEvent(event)).toBe(true)
})

it('should return false if the event is not a sync event', () => {
const event: Portfolio.Event.BalanceManager = {
on: Portfolio.Event.ManagerOn.Hydrate,
sourceId: '1',
}
expect(filterBySyncEvent(event)).toBe(false)
})

it('should work with TokenManager events as well', () => {
const event: Portfolio.Event.TokenManager = {
on: Portfolio.Event.ManagerOn.Sync,
ids: [],
sourceId: '1',
}
expect(filterBySyncEvent(event)).toBe(true)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {Portfolio} from '@yoroi/types'

export function filterBySyncEvent({on}: Portfolio.Event.BalanceManager | Portfolio.Event.TokenManager) {
return on === Portfolio.Event.ManagerOn.Sync
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {useObservableValue} from '@yoroi/common'
import * as React from 'react'
import {filter} from 'rxjs'

import {YoroiWallet} from '../../../../yoroi-wallets/cardano/types'
import {filterBySyncEvent as isSyncEvent} from '../helpers/filterBySyncEvent'

export const useBalances = ({wallet}: {wallet: YoroiWallet}) => {
const observable$ = React.useMemo(() => wallet.balance$.pipe(filter(isSyncEvent)), [wallet])
const executor = React.useCallback(() => wallet.balances, [wallet])

return useObservableValue({
observable$,
executor,
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {createPrimaryTokenInfo, portfolioBalanceManagerMaker, portfolioBalanceSt
import {Chain, Portfolio} from '@yoroi/types'
import * as React from 'react'

import {YoroiWallet} from '../../../yoroi-wallets/cardano/types'
import {YoroiWallet} from '../../../../yoroi-wallets/cardano/types'

export const usePortfolioBalanceManager = ({
tokenManager,
Expand Down Expand Up @@ -38,6 +38,7 @@ export const buildPortfolioBalanceManager = ({
const balanceStorage = portfolioBalanceStorageMaker({
balanceStorage: observableStorageMaker(balanceStorageMounted),
primaryBreakdownStorage: observableStorageMaker(primaryBreakdownStorageMounted),
primaryTokenId: primaryTokenInfo.id,
})

const balanceManager = portfolioBalanceManagerMaker({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {useObservableValue} from '@yoroi/common'
import * as React from 'react'
import {filter} from 'rxjs'

import {YoroiWallet} from '../../../../yoroi-wallets/cardano/types'
import {filterBySyncEvent as isSyncEvent} from '../helpers/filterBySyncEvent'

export const usePrimaryBalance = ({wallet}: {wallet: YoroiWallet}) => {
const observable$ = React.useMemo(() => wallet.balance$.pipe(filter(isSyncEvent)), [wallet])
const executor = React.useCallback(() => wallet.primaryBalance, [wallet])

return useObservableValue({
observable$,
executor,
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {useObservableValue} from '@yoroi/common'
import * as React from 'react'
import {filter} from 'rxjs'

import {YoroiWallet} from '../../../../yoroi-wallets/cardano/types'
import {filterBySyncEvent as isSyncEvent} from '../helpers/filterBySyncEvent'

export const usePrimaryBreakdown = ({wallet}: {wallet: YoroiWallet}) => {
const observable$ = React.useMemo(() => wallet.balance$.pipe(filter(isSyncEvent)), [wallet])
const executor = React.useCallback(() => wallet.primaryBreakdown, [wallet])

return useObservableValue({
observable$,
executor,
})
}
49 changes: 0 additions & 49 deletions apps/wallet-mobile/src/features/Portfolio/common/transformers.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {RawUtxo} from '../../../../yoroi-wallets/types'
import {toBalanceManagerSyncArgs} from './toBalanceManagerSyncArgs'

describe('toBalanceManagerSyncArgs', () => {
const policyId = new Array(56).fill('1').join('')
it('should calculate primaryStated and secondaryBalances correctly', () => {
const rawUtxos: RawUtxo[] = [
{
amount: '100',
receiver: '',
tx_hash: '',
tx_index: 0,
utxo_id: '',
assets: [
{assetId: `${policyId}.DEAD`, amount: '50', policyId, name: 'DEAD'},
{assetId: `${policyId}.DEADFEED`, amount: '30', policyId, name: 'DEADFEED'},
],
},
{
receiver: '',
tx_hash: '',
tx_index: 0,
utxo_id: '',
amount: '200',
assets: [
{assetId: `${policyId}.DEAD`, amount: '70', policyId, name: 'DEAD'},
{assetId: `${policyId}.3031`, amount: '80', policyId, name: '3031'},
],
},
]
const lockedAsStorageCost = 10n

const result = toBalanceManagerSyncArgs(rawUtxos, lockedAsStorageCost)

expect(result.primaryStated.totalFromTxs).toBe(300n)
expect(result.primaryStated.lockedAsStorageCost).toBe(10n)
expect(result.secondaryBalances.get(`${policyId}.DEAD`)?.balance).toBe(120n)
expect(result.secondaryBalances.get(`${policyId}.DEADFEED`)?.balance).toBe(30n)
expect(result.secondaryBalances.get(`${policyId}.3031`)?.balance).toBe(80n)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {Portfolio} from '@yoroi/types'

import {RawUtxo} from '../../../../yoroi-wallets/types'

export function toBalanceManagerSyncArgs(rawUtxos: RawUtxo[], lockedAsStorageCost: bigint) {
let primaryTokenBalance = 0n
const secondaries = new Map<Portfolio.Token.Id, Omit<Portfolio.Token.Balance, 'info'>>()
for (const utxo of rawUtxos) {
primaryTokenBalance += BigInt(utxo.amount)
for (const record of utxo.assets) {
const tokenId: Portfolio.Token.Id = `${record.policyId}.${record.name}`
const balance = (secondaries.get(tokenId)?.balance ?? 0n) + BigInt(record.amount)
secondaries.set(tokenId, {
balance,
})
}
}

return {
primaryStated: {
totalFromTxs: primaryTokenBalance,
lockedAsStorageCost,
},
secondaryBalances: new Map(secondaries),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {Chain} from '@yoroi/types'

import {toChainSupportedNetwork} from './toChainSupportedNetwork'

describe('toChainSupportedNetwork', () => {
it('should return Chain.Network.Main for networkId 0', () => {
expect(toChainSupportedNetwork(0)).toBe(Chain.Network.Main)
})

it('should return Chain.Network.Main for networkId 1', () => {
expect(toChainSupportedNetwork(1)).toBe(Chain.Network.Main)
})

it('should return Chain.Network.Sancho for networkId 450', () => {
expect(toChainSupportedNetwork(450)).toBe(Chain.Network.Sancho)
})

it('should return Chain.Network.Preprod for unknown networkId', () => {
expect(toChainSupportedNetwork(999 as never)).toBe(Chain.Network.Preprod)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {Chain} from '@yoroi/types'

import {NetworkId} from '../../../../yoroi-wallets/types'

export function toChainSupportedNetwork(networkId: NetworkId): Chain.SupportedNetworks {
switch (networkId) {
case 0:
case 1:
return Chain.Network.Main
case 450:
return Chain.Network.Sancho
default:
return Chain.Network.Preprod
}
}

0 comments on commit d46d28d

Please sign in to comment.