diff --git a/apps/wallet-mobile/src/features/Portfolio/common/TokenAmountItem/TokenAmountItem.tsx b/apps/wallet-mobile/src/features/Portfolio/common/TokenAmountItem/TokenAmountItem.tsx index fad9ebebcf..3caa47b63f 100644 --- a/apps/wallet-mobile/src/features/Portfolio/common/TokenAmountItem/TokenAmountItem.tsx +++ b/apps/wallet-mobile/src/features/Portfolio/common/TokenAmountItem/TokenAmountItem.tsx @@ -1,4 +1,4 @@ -import {amountFormatter, infoExtractName} from '@yoroi/portfolio' +import {amountFormatter, infoExtractName, isNft} from '@yoroi/portfolio' import {useTheme} from '@yoroi/theme' import {Portfolio} from '@yoroi/types' import {Swap} from '@yoroi/types' @@ -73,7 +73,7 @@ export const TokenAmountItem = ({ - {info.type !== Portfolio.Token.Type.NFT && variant !== 'swap' && ( + {!isNft(info) && variant !== 'swap' && ( {priceImpactRisk === 'moderate' && } diff --git a/apps/wallet-mobile/src/features/Send/useCases/ListAmountsToSend/AddToken/SelectTokenFromListScreenV2.tsx b/apps/wallet-mobile/src/features/Send/useCases/ListAmountsToSend/AddToken/SelectTokenFromListScreenV2.tsx index ee4bcc3d76..3fcb41b8cd 100644 --- a/apps/wallet-mobile/src/features/Send/useCases/ListAmountsToSend/AddToken/SelectTokenFromListScreenV2.tsx +++ b/apps/wallet-mobile/src/features/Send/useCases/ListAmountsToSend/AddToken/SelectTokenFromListScreenV2.tsx @@ -1,13 +1,13 @@ import {useFocusEffect, useNavigation} from '@react-navigation/native' import {FlashList} from '@shopify/flash-list' +import {isPrimaryToken} from '@yoroi/portfolio' import {useTheme} from '@yoroi/theme' import {targetGetTokenBalanceBreakdown, useTransfer} from '@yoroi/transfer' import {Balance, Portfolio} from '@yoroi/types' import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' -import {Boundary, Spacer, Text} from '../../../../../components' -import {AmountItem} from '../../../../../components/AmountItem/AmountItem' +import {Spacer, Text} from '../../../../../components' import {NftImageGallery} from '../../../../../components/NftImageGallery' import {useMetrics} from '../../../../../metrics/metricsManager' import {TxHistoryRouteNavigation} from '../../../../../navigation' @@ -15,9 +15,10 @@ import {useSearch, useSearchOnNavBar} from '../../../../../Search/SearchContext' import {sortTokenInfos} from '../../../../../utils' import {YoroiWallet} from '../../../../../yoroi-wallets/cardano/types' import {limitOfSecondaryAmountsPerTx} from '../../../../../yoroi-wallets/contants' -import {useAllTokenInfos, useBalances, useIsWalletEmpty, useNfts} from '../../../../../yoroi-wallets/hooks' -import {Amounts, Quantities} from '../../../../../yoroi-wallets/utils' +import {useBalances, useIsWalletEmpty, useNfts} from '../../../../../yoroi-wallets/hooks' +import {Amounts} from '../../../../../yoroi-wallets/utils' import {usePortfolioBalances} from '../../../../Portfolio/common/hooks/usePortfolioBalances' +import {usePortfolioPrimaryBreakdown} from '../../../../Portfolio/common/hooks/usePortfolioPrimaryBreakdown' import {useSelectedWallet} from '../../../../WalletManager/Context' import {filterByFungibility} from '../../../common/filterByFungibility' import {filterBySearch} from '../../../common/filterBySearch' @@ -25,10 +26,7 @@ import {useOverridePreviousSendTxRoute} from '../../../common/navigation' import {NoAssetFoundImage} from '../../../common/NoAssetFoundImage' import {useStrings} from '../../../common/strings' import {useSelectedSecondaryAmountsCounter} from '../../../common/useSelectedSecondaryAmountsCounter' -import {useTokenQuantities} from '../../../common/useTokenQuantities' import {MaxAmountsPerTx} from './Show/MaxAmountsPerTx' -import {usePortfolioPrimaryBreakdown} from '../../../../Portfolio/common/hooks/usePortfolioPrimaryBreakdown' -import {isPrimary, isPrimaryToken} from '@yoroi/portfolio' export const SelectTokenFromListScreen = () => { const strings = useStrings() @@ -37,7 +35,7 @@ export const SelectTokenFromListScreen = () => { const wallet = useSelectedWallet() const balances = usePortfolioBalances({wallet}) - const [fungibilityFilter, setFungibilityFilter] = React.useState('all') + const [fungibilityFilter, setFungibilityFilter] = React.useState>('all') const [isPending, startTransition] = React.useTransition() const showOnlyNfts = fungibilityFilter === 'nfts' const filteredBalancesByFungibility = balances[fungibilityFilter] @@ -45,6 +43,7 @@ export const SelectTokenFromListScreen = () => { () => filteredBalancesByFungibility.filter(filterOutSelected(targets[selectedTargetIndex].entry.amounts)), [filteredBalancesByFungibility, selectedTargetIndex, targets], ) + const balancesBreakdown = const counter = withoutSelected.length @@ -113,12 +112,12 @@ type ListProps = { const List = ({showOnlyNfts, isSearching, canAddAmount}: ListProps) => { const showNftList = showOnlyNfts && !isSearching - if (showNftList) return + if (showNftList) return - return + return } -const NftList = ({canAddAmount}: {canAddAmount: boolean}) => { +const ListSpendableNfts = ({canAddAmount}: {canAddAmount: boolean}) => { const {styles} = useStyles() const wallet = useSelectedWallet() const navigation = useNavigation() @@ -159,11 +158,11 @@ const NftList = ({canAddAmount}: {canAddAmount: boolean}) => { ) } -type ListAvailableBalancesProps = { +type ListSpendableBalancesProps = { canAddAmount: boolean availableBalances: ReadonlyArray } -const ListAvailableBalances = ({canAddAmount, availableBalances}: ListAvailableBalancesProps) => { +const ListSpendableBalances = ({canAddAmount, availableBalances}: ListSpendableBalancesProps) => { const {styles} = useStyles() return ( @@ -232,31 +231,30 @@ const SelectableAssetItem = ({amount, disabled, wallet}: SelectableAssetItemProp const isPrimary = isPrimaryToken(amount.info) - const onSelect = () => { + const handleOnSelect = React.useCallback(() => { tokenSelectedChanged(amount.info.id) closeSearch() // if the balance is atomic there is no need to edit the amount - if (tokenInfo.kind === 'ft' && spendable === 1n) { - amountChanged(spendable) - navigation.navigate('send-list-amounts-to-send') - } else if (tokenInfo.kind === 'nft') { - const quantity = Amounts.getAmount(balances, tokenInfo.id).quantity - amountChanged(quantity) + if (spendable === 1n && amount.info.decimals === 0) { + amountChanged({ + info: amount.info, + quantity: spendable, + }) navigation.navigate('send-list-amounts-to-send') } else { navigation.navigate('send-edit-amount') } - } + }, [amount.info, amountChanged, closeSearch, navigation, spendable, tokenSelectedChanged]) return ( - + ) } diff --git a/packages/transfer/src/helpers/target-get-allocated-in-others.test.ts b/packages/transfer/src/helpers/target-get-allocated-in-others.test.ts new file mode 100644 index 0000000000..0336073415 --- /dev/null +++ b/packages/transfer/src/helpers/target-get-allocated-in-others.test.ts @@ -0,0 +1,55 @@ +import {Transfer} from '@yoroi/types' +import {tokenBalanceMocks} from '@yoroi/portfolio' + +import {targetGetUsedByOtherTargets} from './target-get-allocated-in-others' + +describe('targetGetUsedByOtherTargets()', () => { + it('should calculate balances breakdown correctly', () => { + const targets: Transfer.Target[] = [ + { + receiver: { + resolve: '', + as: 'address', + selectedNameServer: undefined, + addressRecords: undefined, + }, + entry: { + address: '', + amounts: { + [tokenBalanceMocks.ftNoTicker.info.id]: { + ...tokenBalanceMocks.ftNoTicker, + quantity: 100n, + }, + }, + }, + }, + { + receiver: { + resolve: 'address2', + as: 'address', + addressRecords: undefined, + selectedNameServer: undefined, + }, + entry: { + address: 'address2', + amounts: { + [tokenBalanceMocks.ftNoTicker.info.id]: { + ...tokenBalanceMocks.ftNoTicker, + quantity: 200n, + }, + }, + }, + }, + ] + + const result = targetGetUsedByOtherTargets({targets}) + + expect(result.size).toEqual(1) + expect(result.get(0)?.get(tokenBalanceMocks.ftNoTicker.info.id)).toEqual({ + used: 200n, + }) + expect(result.get(0)?.get(tokenBalanceMocks.ftNoTicker.info.id)).toEqual({ + used: 100n, + }) + }) +}) diff --git a/packages/transfer/src/helpers/target-get-allocated-in-others.ts b/packages/transfer/src/helpers/target-get-allocated-in-others.ts new file mode 100644 index 0000000000..21f22bd48b --- /dev/null +++ b/packages/transfer/src/helpers/target-get-allocated-in-others.ts @@ -0,0 +1,31 @@ +import {Portfolio, Transfer} from '@yoroi/types' +import {freeze} from 'immer' + +import {TransferUsedByOtherTargets} from '../types' +import {targetGetTokenTotalUsedByOthers} from './target-get-token-allocated-to-others' + +export function targetGetUsedByOtherTargets({ + targets, +}: { + targets: Readonly +}) { + const usedByOtherTargets: TransferUsedByOtherTargets = new Map() + + targets.forEach((target, targetIndex) => { + Object.keys(target.entry.amounts).forEach((untypedTokenId) => { + const tokenId = untypedTokenId as Portfolio.Token.Id + const allocated = targetGetTokenTotalUsedByOthers({ + targets, + targetIndex, + tokenId, + }) + const currentTarget = usedByOtherTargets.get(targetIndex) ?? new Map() + + currentTarget.set(tokenId, { + allocated, + }) + }) + }) + + return freeze(usedByOtherTargets, true) +} diff --git a/packages/transfer/src/helpers/target-get-token-total-used-by-others.test.ts b/packages/transfer/src/helpers/target-get-token-allocated-to-others.test.ts similarity index 78% rename from packages/transfer/src/helpers/target-get-token-total-used-by-others.test.ts rename to packages/transfer/src/helpers/target-get-token-allocated-to-others.test.ts index a23e899bf3..b61ce96710 100644 --- a/packages/transfer/src/helpers/target-get-token-total-used-by-others.test.ts +++ b/packages/transfer/src/helpers/target-get-token-allocated-to-others.test.ts @@ -1,8 +1,8 @@ import {tokenBalanceMocks} from '@yoroi/portfolio' -import {targetGetTokenTotalUsedByOthers} from './target-get-token-total-used-by-others' +import {targetGetTokenAllocatedToOthers} from './target-get-token-allocated-to-others' import {Transfer} from '@yoroi/types' -describe('targetGetTokenTotalUsedByOthers', () => { +describe('targetGetTokenAllocatedToOthers', () => { it('should return the total amount of tokens used by other targets', () => { const targets: Transfer.Target[] = [ { @@ -40,13 +40,13 @@ describe('targetGetTokenTotalUsedByOthers', () => { }, }, ] - const selectedTargetIndex = 0 - const selectedTokenId = tokenBalanceMocks.ftNoTicker.info.id + const targetIndex = 0 + const tokenId = tokenBalanceMocks.ftNoTicker.info.id - const totalUsed = targetGetTokenTotalUsedByOthers({ + const totalUsed = targetGetTokenAllocatedToOthers({ targets, - selectedTargetIndex, - selectedTokenId, + targetIndex, + tokenId, }) expect(totalUsed).toBe(200n) @@ -72,13 +72,13 @@ describe('targetGetTokenTotalUsedByOthers', () => { }, }, ] - const selectedTargetIndex = 0 - const selectedTokenId = tokenBalanceMocks.ftNoTicker.info.id + const targetIndex = 0 + const tokenId = tokenBalanceMocks.ftNoTicker.info.id - const totalUsed = targetGetTokenTotalUsedByOthers({ + const totalUsed = targetGetTokenAllocatedToOthers({ targets, - selectedTargetIndex, - selectedTokenId, + targetIndex, + tokenId, }) expect(totalUsed).toBe(0n) @@ -121,13 +121,13 @@ describe('targetGetTokenTotalUsedByOthers', () => { }, }, ] - const selectedTargetIndex = 0 - const selectedTokenId = 'anyOther.token' + const targetIndex = 0 + const tokenId = 'anyOther.token' - const totalUsed = targetGetTokenTotalUsedByOthers({ + const totalUsed = targetGetTokenAllocatedToOthers({ targets, - selectedTargetIndex, - selectedTokenId, + targetIndex, + tokenId, }) expect(totalUsed).toBe(0n) diff --git a/packages/transfer/src/helpers/target-get-token-total-used-by-others.ts b/packages/transfer/src/helpers/target-get-token-allocated-to-others.ts similarity index 55% rename from packages/transfer/src/helpers/target-get-token-total-used-by-others.ts rename to packages/transfer/src/helpers/target-get-token-allocated-to-others.ts index ef23b6d5d1..fc5f083d79 100644 --- a/packages/transfer/src/helpers/target-get-token-total-used-by-others.ts +++ b/packages/transfer/src/helpers/target-get-token-allocated-to-others.ts @@ -4,23 +4,22 @@ import {Portfolio, Transfer} from '@yoroi/types' * @summary Returns the total amount of tokens used by other targets * @returns BigInt */ -export function targetGetTokenTotalUsedByOthers({ +export function targetGetTokenAllocatedToOthers({ targets, - selectedTargetIndex, - selectedTokenId, + targetIndex, + tokenId, }: { targets: Readonly - selectedTargetIndex: number - selectedTokenId: Portfolio.Token.Id + targetIndex: number + tokenId: Portfolio.Token.Id }) { const isNotTheSelectedTarget = (_: Transfer.Target, index: number) => - index !== selectedTargetIndex + index !== targetIndex return targets .filter(isNotTheSelectedTarget) .reduce( - (acc, target) => - acc + (target.entry.amounts[selectedTokenId]?.quantity ?? 0n), + (acc, target) => acc + (target.entry.amounts[tokenId]?.quantity ?? 0n), 0n, ) } diff --git a/packages/transfer/src/helpers/target-get-token-balance-breakdown.test.ts b/packages/transfer/src/helpers/target-get-token-balance-breakdown.test.ts deleted file mode 100644 index 71abc6f6a3..0000000000 --- a/packages/transfer/src/helpers/target-get-token-balance-breakdown.test.ts +++ /dev/null @@ -1,269 +0,0 @@ -import {tokenBalanceMocks} from '@yoroi/portfolio' -import {targetGetTokenBalanceBreakdown} from './target-get-token-balance-breakdown' -import {Transfer, Portfolio} from '@yoroi/types' - -describe('targetGetTokenBalanceBreakdown', () => { - it('should calculate the token balance breakdown correctly secondary', () => { - const targets: Transfer.Target[] = [ - { - receiver: { - resolve: '', - as: 'address', - selectedNameServer: undefined, - addressRecords: undefined, - }, - entry: { - address: '', - amounts: { - [tokenBalanceMocks.ftNoTicker.info.id]: { - ...tokenBalanceMocks.ftNoTicker, - quantity: 100n, - }, - }, - }, - }, - { - receiver: { - resolve: 'address2', - as: 'address', - addressRecords: undefined, - selectedNameServer: undefined, - }, - entry: { - address: 'address2', - amounts: { - [tokenBalanceMocks.ftNoTicker.info.id]: { - ...tokenBalanceMocks.ftNoTicker, - quantity: 200n, - }, - }, - }, - }, - ] - const selectedTargetIndex = 0 - const selectedTokenId = tokenBalanceMocks.ftNoTicker.info.id - - const balances: Portfolio.Token.Balances['records'] = new Map([ - [tokenBalanceMocks.ftNoTicker.info.id, tokenBalanceMocks.ftNoTicker], - ]) - - const primaryBreakdown: Portfolio.PrimaryBreakdown = { - availableRewards: 0n, - lockedAsStorageCost: 0n, - totalFromTxs: 0n, - } - - const result = targetGetTokenBalanceBreakdown({ - targets, - balances, - primaryBreakdown, - selectedTokenId, - selectedTargetIndex, - }) - - expect(result.balance).toBe(3_000_003n) - expect(result.used).toBe(200n) - expect(result.available).toBe(2999803n) - expect(result.initialQuantity).toBe(100n) - expect(result.locked).toBe(0n) - expect(result.spendable).toBe(2999803n) - }) - - it('should calculate the token balance breakdown correctly primary', () => { - const targets: Transfer.Target[] = [ - { - receiver: { - resolve: '', - as: 'address', - selectedNameServer: undefined, - addressRecords: undefined, - }, - entry: { - address: '', - amounts: { - [tokenBalanceMocks.primaryETH.info.id]: { - ...tokenBalanceMocks.primaryETH, - quantity: 100_000n, - }, - }, - }, - }, - { - receiver: { - resolve: 'address2', - as: 'address', - addressRecords: undefined, - selectedNameServer: undefined, - }, - entry: { - address: 'address2', - amounts: { - [tokenBalanceMocks.primaryETH.info.id]: { - ...tokenBalanceMocks.primaryETH, - quantity: 200_000n, - }, - }, - }, - }, - ] - const selectedTargetIndex = 0 - const selectedTokenId = tokenBalanceMocks.primaryETH.info.id - - const balances: Portfolio.Token.Balances['records'] = new Map([ - [tokenBalanceMocks.primaryETH.info.id, tokenBalanceMocks.primaryETH], - ]) - - const primaryBreakdown: Portfolio.PrimaryBreakdown = { - availableRewards: 0n, - lockedAsStorageCost: 800_000n, - totalFromTxs: 0n, - } - - const result = targetGetTokenBalanceBreakdown({ - targets, - balances, - primaryBreakdown, - selectedTokenId, - selectedTargetIndex, - }) - - expect(result.balance).toBe(1_000_000n) - expect(result.used).toBe(200_000n) - expect(result.available).toBe(800_000n) - expect(result.initialQuantity).toBe(100_000n) - expect(result.locked).toBe(800_000n) - expect(result.spendable).toBe(0n) - }) - - it('should return 0 when not informed', () => { - const targets: Transfer.Target[] = [ - { - receiver: { - resolve: '', - as: 'address', - selectedNameServer: undefined, - addressRecords: undefined, - }, - entry: { - address: '', - amounts: { - [tokenBalanceMocks.ftNoTicker.info.id]: { - ...tokenBalanceMocks.ftNoTicker, - quantity: 100n, - }, - }, - }, - }, - { - receiver: { - resolve: 'address2', - as: 'address', - addressRecords: undefined, - selectedNameServer: undefined, - }, - entry: { - address: 'address2', - amounts: { - [tokenBalanceMocks.ftNoTicker.info.id]: { - ...tokenBalanceMocks.ftNoTicker, - quantity: 200n, - }, - }, - }, - }, - ] - const selectedTargetIndex = 0 - const selectedTokenId = tokenBalanceMocks.nftCryptoKitty.info.id - - const balances: Portfolio.Token.Balances['records'] = new Map([ - [tokenBalanceMocks.ftNoTicker.info.id, tokenBalanceMocks.ftNoTicker], - ]) - - const primaryBreakdown: Portfolio.PrimaryBreakdown = { - availableRewards: 0n, - lockedAsStorageCost: 0n, - totalFromTxs: 0n, - } - - const result = targetGetTokenBalanceBreakdown({ - targets, - balances, - primaryBreakdown, - selectedTokenId, - selectedTargetIndex, - }) - - expect(result.balance).toBe(0n) - expect(result.used).toBe(0n) - expect(result.available).toBe(0n) - expect(result.initialQuantity).toBe(0n) - expect(result.locked).toBe(0n) - expect(result.spendable).toBe(0n) - }) - - it('should return 0 when not wrong target', () => { - const targets: Transfer.Target[] = [ - { - receiver: { - resolve: '', - as: 'address', - selectedNameServer: undefined, - addressRecords: undefined, - }, - entry: { - address: '', - amounts: { - [tokenBalanceMocks.ftNoTicker.info.id]: { - ...tokenBalanceMocks.ftNoTicker, - quantity: 100n, - }, - }, - }, - }, - { - receiver: { - resolve: 'address2', - as: 'address', - addressRecords: undefined, - selectedNameServer: undefined, - }, - entry: { - address: 'address2', - amounts: { - [tokenBalanceMocks.ftNoTicker.info.id]: { - ...tokenBalanceMocks.ftNoTicker, - quantity: 200n, - }, - }, - }, - }, - ] - const selectedTargetIndex = 3 - const selectedTokenId = tokenBalanceMocks.nftCryptoKitty.info.id - - const balances: Portfolio.Token.Balances['records'] = new Map([ - [tokenBalanceMocks.ftNoTicker.info.id, tokenBalanceMocks.ftNoTicker], - ]) - - const primaryBreakdown: Portfolio.PrimaryBreakdown = { - availableRewards: 0n, - lockedAsStorageCost: 0n, - totalFromTxs: 0n, - } - - const result = targetGetTokenBalanceBreakdown({ - targets, - balances, - primaryBreakdown, - selectedTokenId, - selectedTargetIndex, - }) - - expect(result.balance).toBe(0n) - expect(result.used).toBe(0n) - expect(result.available).toBe(0n) - expect(result.initialQuantity).toBe(0n) - expect(result.locked).toBe(0n) - expect(result.spendable).toBe(0n) - }) -}) diff --git a/packages/transfer/src/helpers/target-get-token-balance-breakdown.ts b/packages/transfer/src/helpers/target-get-token-balance-breakdown.ts deleted file mode 100644 index 0931977395..0000000000 --- a/packages/transfer/src/helpers/target-get-token-balance-breakdown.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {Portfolio, Transfer} from '@yoroi/types' -import {targetGetTokenTotalUsedByOthers} from './target-get-token-total-used-by-others' -import {isPrimaryToken} from '@yoroi/portfolio' - -export function targetGetTokenBalanceBreakdown({ - balances, - selectedTokenId, - primaryBreakdown, - targets, - selectedTargetIndex, -}: { - targets: Readonly - balances: Portfolio.Token.Balances['records'] - primaryBreakdown: Readonly - selectedTokenId: Portfolio.Token.Id - selectedTargetIndex: number -}) { - const target = targets[selectedTargetIndex] - - let balance = 0n - let available = 0n - let locked = 0n - let spendable = 0n - let initialQuantity = 0n - let used = 0n - - if (target) { - initialQuantity = target.entry.amounts[selectedTokenId]?.quantity ?? 0n - - used = targetGetTokenTotalUsedByOthers({ - targets, - selectedTokenId, - selectedTargetIndex, - }) - - const amount = balances.get(selectedTokenId) - - if (amount) { - balance = amount.quantity - available = balance - used - locked = isPrimaryToken(amount.info) - ? primaryBreakdown.lockedAsStorageCost - : 0n - spendable = available - locked - } - } - - return { - balance, - used, - available, - initialQuantity, - locked, - spendable, - } -} diff --git a/packages/transfer/src/index.ts b/packages/transfer/src/index.ts index 8f67ba0481..612e3b551c 100644 --- a/packages/transfer/src/index.ts +++ b/packages/transfer/src/index.ts @@ -2,5 +2,4 @@ export * from './translators/reactjs/provider/TransferProvider' export * from './translators/reactjs/state/state' export * from './translators/reactjs/hooks/useTransfer' -export * from './helpers/target-get-token-balance-breakdown' -export * from './helpers/target-get-token-total-used-by-others' +export * from './helpers/target-get-token-allocated-to-others' diff --git a/packages/transfer/src/translators/reactjs/state/state.ts b/packages/transfer/src/translators/reactjs/state/state.ts index e894c00c4e..4110374e69 100644 --- a/packages/transfer/src/translators/reactjs/state/state.ts +++ b/packages/transfer/src/translators/reactjs/state/state.ts @@ -2,6 +2,8 @@ import {isNameServer, isResolvableDomain} from '@yoroi/resolver' import {Chain, Links, Portfolio, Resolver, Transfer} from '@yoroi/types' import {castDraft, freeze, produce} from 'immer' +import {TransferAllocatedByOtherTargets} from '../../../types' + export const combinedReducers = ( state: TransferState, action: TransferAction | TargetAction, @@ -40,6 +42,10 @@ const transferReducer = (state: TransferState, action: TransferAction) => { draft.linkAction = castDraft(defaultTransferState.linkAction) draft.targets = defaultTransferState.targets break + case TransferActionType.BalancesUpdated: + draft.balances = action.balances + draft.primaryBreakdown = action.primaryBreakdown + break } }) } @@ -140,26 +146,15 @@ const targetsReducer = (state: TransferState, action: TargetAction) => { export const defaultTransferState: TransferState = freeze( { - balances: new Map(), - primaryBalanceBreakdown: { - availableRewards: 0n, - lockedAsStorageCost: 0n, - totalFromTxs: 0n, - }, + allocated: new Map(), - selectedTokenBalanceBreakdown: { - balance: 0n, - used: 0n, - available: 0n, - initialQuantity: 0n, - locked: 0n, - spendable: 0n, - }, selectedTargetIndex: 0, selectedTokenId: '.', // it's ok satisfying the type here, if ptId is dif it needs init by the client unsignedTx: undefined, memo: '', + linkAction: undefined, + targets: [ { receiver: { @@ -192,6 +187,7 @@ const defaultStateActions: TransferActions = { reset: missingInit, memoChanged: missingInit, linkActionChanged: missingInit, + balancesUpdated: missingInit, } export const defaultTransferActions = { @@ -200,11 +196,20 @@ export const defaultTransferActions = { } as const export type TransferState = Readonly<{ + balances: Map + primaryBreakdown: Portfolio.PrimaryBreakdown + + // inputs selectedTargetIndex: number selectedTokenId: Portfolio.Token.Id unsignedTx: Chain.Cardano.UnsignedTx | undefined memo: string + + // derived state targets: Transfer.Targets + allocated: TransferAllocatedByOtherTargets + + // injected when deeplink request transfer linkAction: Links.YoroiAction | undefined }> @@ -223,11 +228,15 @@ export type TargetActions = Readonly<{ }> export type TransferActions = Readonly<{ - unsignedTxChanged: (UnsignedTx: Chain.Cardano.UnsignedTx | undefined) => void + unsignedTxChanged: (UnsignedTx: Chain.Cardano.UnsignedTx) => void tokenSelectedChanged: (tokenId: Portfolio.Token.Id) => void reset: () => void memoChanged: (memo: string) => void linkActionChanged: (linkAction: Links.YoroiAction) => void + balancesUpdated: ( + balances: TransferState['balances'], + primaryBreakdown: TransferState['primaryBreakdown'], + ) => void }> export type TargetAction = Readonly< @@ -275,12 +284,17 @@ export type TransferAction = Readonly< } | { type: TransferActionType.UnsignedTxChanged - unsignedTx: Chain.Cardano.UnsignedTx | undefined + unsignedTx: Chain.Cardano.UnsignedTx } | { type: TransferActionType.LinkActionChanged linkAction: Links.YoroiAction } + | { + type: TransferActionType.BalancesUpdated + balances: TransferState['balances'] + primaryBreakdown: TransferState['primaryBreakdown'] + } > export enum TransferActionType { @@ -295,9 +309,10 @@ export enum TransferActionType { MemoChanged = 'memoChanged', UnsignedTxChanged = 'unsignedTxChanged', LinkActionChanged = 'linkActionChanged', + BalancesUpdated = 'balancesUpdated', } /* istanbul ignore next */ function missingInit() { - console.error('[@yoroi/swap] missing initialization') + console.error('[@yoroi/transfer] missing initialization') } diff --git a/packages/transfer/src/types.ts b/packages/transfer/src/types.ts new file mode 100644 index 0000000000..87c592f1fa --- /dev/null +++ b/packages/transfer/src/types.ts @@ -0,0 +1,11 @@ +import {Portfolio} from '@yoroi/types' + +export type TransferAllocatedByOtherTargets = Map< + number, + Map< + Portfolio.Token.Id, + { + allocated: bigint + } + > +>