Skip to content

Commit

Permalink
fix(lightning): update transfer UI (#1553)
Browse files Browse the repository at this point in the history
  • Loading branch information
pwltr authored Feb 12, 2024
1 parent d7d8099 commit 688f864
Show file tree
Hide file tree
Showing 47 changed files with 719 additions and 399 deletions.
101 changes: 30 additions & 71 deletions __tests__/todos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@ import {
backupSeedPhraseTodo,
btFailedTodo,
buyBitcoinTodo,
lightningConnectingTodo,
lightningReadyTodo,
lightningSettingUpTodo,
lightningTodo,
pinTodo,
slashtagsProfileTodo,
transferClosingChannel,
transferToSavingsTodo,
transferToSpendingTodo,
transferPendingTodo,
transferClosingChannelTodo,
} from '../src/store/shapes/todos';
import { createNewWallet } from '../src/utils/startup';
import { EAvailableNetwork } from '../src/utils/networks';
import { ETransferStatus, ETransferType } from '../src/store/types/wallet';

describe('Todos selector', () => {
let s: RootState;
Expand Down Expand Up @@ -101,59 +100,20 @@ describe('Todos selector', () => {
assert.deepEqual(todosFullSelector(state), []);
});

it('should return lightningSettingUpTodo if there is a pending BT order', () => {
it('should return lightningSettingUpTodo if there is a pending transfer to spending', () => {
const state = cloneDeep(s);
state.blocktank.orders.push({
id: 'order1',
state: 'created',
} as IBtOrder);
state.blocktank.paidOrders = { order1: 'txid' };

state.wallet.wallets.wallet0.transfers.bitcoinRegtest.push({
txId: 'txid',
type: ETransferType.open,
status: ETransferStatus.pending,
amount: 100000,
orderId: 'order1',
});
expect(todosFullSelector(state)).toEqual(
expect.arrayContaining([lightningSettingUpTodo]),
);
});

it('should return lightningConnectingTodo if there is a pending channel', () => {
const state = cloneDeep(s);

const channel1 = {
channel_id: 'channel1',
is_channel_ready: false,
} as TChannel;
state.lightning.nodes.wallet0.channels.bitcoinRegtest = { channel1 };
state.lightning.nodes.wallet0.openChannelIds.bitcoinRegtest = ['channel1'];

expect(todosFullSelector(state)).toEqual(
expect.arrayContaining([lightningConnectingTodo]),
);
});

it('should return lightningConnectingTodo if there is a pending channel and open channels', () => {
const state = cloneDeep(s);

const channel1 = {
channel_id: 'channel1',
is_channel_ready: true,
} as TChannel;
const channel2 = {
channel_id: 'channel2',
is_channel_ready: false,
} as TChannel;
state.lightning.nodes.wallet0.channels.bitcoinRegtest = {
channel1,
channel2,
};
state.lightning.nodes.wallet0.openChannelIds.bitcoinRegtest = [
'channel1',
'channel2',
];

expect(todosFullSelector(state)).toEqual(
expect.arrayContaining([lightningConnectingTodo]),
);
});

it('should return transferClosingChannel if there are gracefully closing channels', () => {
const state = cloneDeep(s);

Expand All @@ -166,42 +126,41 @@ describe('Todos selector', () => {
state.user.startCoopCloseTimestamp = 123;

expect(todosFullSelector(state)).toEqual(
expect.arrayContaining([transferClosingChannel]),
expect.arrayContaining([transferClosingChannelTodo]),
);
});

it('should return transferToSpendingTodo if there are new pending BT orders', () => {
it('should return transferPendingTodo for addtional pending transfers to spending', () => {
const state = cloneDeep(s);

const channel1 = {
channel_id: 'channel1',
is_channel_ready: true,
} as TChannel;
state.lightning.nodes.wallet0.channels.bitcoinRegtest = { channel1 };
state.lightning.nodes.wallet0.openChannelIds.bitcoinRegtest = ['channel1'];
state.blocktank.orders.push({ id: 'order1', state: 'created' } as IBtOrder);
state.blocktank.paidOrders = { order1: 'txid' };

state.wallet.wallets.wallet0.transfers.bitcoinRegtest.push({
txId: 'txid',
type: ETransferType.open,
status: ETransferStatus.pending,
amount: 100000,
orderId: 'order1',
});
expect(todosFullSelector(state)).toEqual(
expect.arrayContaining([transferToSpendingTodo]),
expect.arrayContaining([{ ...transferPendingTodo, duration: 10 }]),
);
});

it('should return transferToSavingsTodo if there is a new claimable balance', () => {
it('should return transferPendingTodo if there is a transfer to savings', () => {
const state = cloneDeep(s);

const channel1 = {
channel_id: 'channel1',
is_channel_ready: true,
} as TChannel;
state.lightning.nodes.wallet0.channels.bitcoinRegtest = { channel1 };
state.lightning.nodes.wallet0.openChannelIds.bitcoinRegtest = ['channel1'];
state.lightning.nodes.wallet0.claimableBalances.bitcoinRegtest = [
{ amount_satoshis: 123, type: 'ClaimableOnChannelClose' },
];

state.wallet.wallets.wallet0.transfers.bitcoinRegtest.push({
txId: 'txid',
type: ETransferType.coopClose,
status: ETransferStatus.pending,
amount: 100000,
confirmations: 1,
});
expect(todosFullSelector(state)).toEqual(
expect.arrayContaining([transferToSavingsTodo]),
expect.arrayContaining([{ ...transferPendingTodo, duration: 50 }]),
);
});

Expand Down
13 changes: 8 additions & 5 deletions src/assets/icons/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
export const transferIcon = (
color = 'white',
): string => `<svg width="16" height="13" viewBox="0 0 16 13" xmlns="http://www.w3.org/2000/svg">
<path d="M3.70898 0.500433L0.516113 3.76948C0.370117 3.91547 0.28125 4.13129 0.28125 4.32807C0.28125 4.77241 0.592285 5.08344 1.03662 5.08344C1.24609 5.08344 1.42383 5.01362 1.56348 4.86762L2.86475 3.51557L3.55664 2.71576L3.51855 3.96625V11.6977C3.51855 12.142 3.83594 12.4658 4.28027 12.4658C4.71826 12.4658 5.04199 12.142 5.04199 11.6977V3.96625L4.99756 2.71576L5.68945 3.51557L6.99072 4.86762C7.13037 5.01362 7.30811 5.08344 7.51758 5.08344C7.96191 5.08344 8.27295 4.77241 8.27295 4.32807C8.27295 4.13129 8.18408 3.91547 8.03809 3.76948L4.84521 0.500433C4.52783 0.170355 4.03271 0.164007 3.70898 0.500433ZM12.2847 12.2182L15.4839 8.93647C15.6235 8.79047 15.7188 8.57465 15.7188 8.38422C15.7188 7.93989 15.4014 7.62885 14.9634 7.62885C14.7539 7.62885 14.5698 7.69868 14.4302 7.84467L13.1289 9.19672L12.4434 9.99653L12.4814 8.73969V1.01459C12.4814 0.576605 12.1577 0.252874 11.7197 0.252874C11.2817 0.252874 10.958 0.576605 10.958 1.01459V8.73969L10.9961 9.99653L10.3105 9.19672L9.00928 7.84467C8.86963 7.69868 8.68555 7.62885 8.47607 7.62885C8.03809 7.62885 7.7207 7.93989 7.7207 8.38422C7.7207 8.57465 7.81592 8.79047 7.95557 8.93647L11.1548 12.2182C11.4658 12.5483 11.9673 12.5546 12.2847 12.2182Z" fill="${color}"/>
</svg>`;
export const transferIcon = (color = 'white'): string => `
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 2.5C5.27614 2.5 5.5 2.7052 5.5 2.95833V13.0417C5.5 13.2948 5.27614 13.5 5 13.5C4.72386 13.5 4.5 13.2948 4.5 13.0417V2.95833C4.5 2.7052 4.72386 2.5 5 2.5Z" fill="${color}"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.64645 2.64645C4.84171 2.45118 5.15829 2.45118 5.35355 2.64645L8.35355 5.64645C8.54882 5.84171 8.54882 6.15829 8.35355 6.35355C8.15829 6.54882 7.84171 6.54882 7.64645 6.35355L5 3.70711L2.35355 6.35355C2.15829 6.54882 1.84171 6.54882 1.64645 6.35355C1.45118 6.15829 1.45118 5.84171 1.64645 5.64645L4.64645 2.64645Z" fill="${color}"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 13.5C11.7239 13.5 11.5 13.2948 11.5 13.0417L11.5 2.95833C11.5 2.7052 11.7239 2.5 12 2.5C12.2761 2.5 12.5 2.7052 12.5 2.95833L12.5 13.0417C12.5 13.2948 12.2761 13.5 12 13.5Z" fill="${color}"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.3536 13.3536C12.1583 13.5488 11.8417 13.5488 11.6464 13.3536L8.64645 10.3536C8.45119 10.1583 8.45119 9.84171 8.64645 9.64645C8.84171 9.45118 9.15829 9.45118 9.35355 9.64645L12 12.2929L14.6464 9.64645C14.8417 9.45118 15.1583 9.45118 15.3536 9.64645C15.5488 9.84171 15.5488 10.1583 15.3536 10.3536L12.3536 13.3536Z" fill="${color}"/>
</svg>
`;

export const unitBitcoinIcon = (color = 'white'): string => `
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand Down
20 changes: 10 additions & 10 deletions src/components/AssetCard.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
import React, { memo, ReactElement } from 'react';
import { View, GestureResponderEvent, StyleSheet } from 'react-native';

import { ClockIcon } from '../styles/icons';
import { TransferIcon } from '../styles/icons';
import { Text01M, Caption13M } from '../styles/text';
import { TouchableOpacity } from '../styles/components';
import { useBalance } from '../hooks/wallet';
import Money from '../components/Money';
import { useAppSelector } from '../hooks/redux';
import { openChannelIdsSelector } from '../store/reselect/lightning';

const AssetCard = ({
name,
ticker,
icon,
satoshis,
pending,
testID,
onPress,
}: {
name: string;
ticker: string;
icon: ReactElement;
satoshis: number;
pending?: boolean;
testID?: string;
onPress: (event: GestureResponderEvent) => void;
}): ReactElement => {
const openChannelIds = useAppSelector(openChannelIdsSelector);

const isTransferToSavings = openChannelIds.length === 0;
const { balanceInTransferToSpending, balanceInTransferToSavings } =
useBalance();

return (
<View style={styles.container}>
Expand All @@ -43,15 +39,19 @@ const AssetCard = ({

<View style={styles.amount}>
<View style={styles.primary}>
{pending && (
<ClockIcon color={isTransferToSavings ? 'orange' : 'purple'} />
{balanceInTransferToSpending !== 0 && (
<TransferIcon color="purple" />
)}
{balanceInTransferToSavings !== 0 && (
<TransferIcon color="orange" />
)}
<Money
style={styles.primaryAmount}
sats={satoshis}
enableHide={true}
size="text01m"
unitType="primary"
symbol={true}
/>
</View>
<Money
Expand Down
3 changes: 1 addition & 2 deletions src/components/Assets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { WalletNavigationProp } from '../navigation/wallet/WalletNavigator'
const Assets = (): ReactElement => {
const { t } = useTranslation('wallet');
const navigation = useNavigation<WalletNavigationProp>();
const { totalBalance, claimableBalance } = useBalance();
const { totalBalance } = useBalance();

return (
<>
Expand All @@ -23,7 +23,6 @@ const Assets = (): ReactElement => {
name="Bitcoin"
ticker="BTC"
satoshis={totalBalance}
pending={claimableBalance > 0}
icon={<BitcoinCircleIcon color="bitcoin" />}
testID="BitcoinAsset"
onPress={(): void => {
Expand Down
6 changes: 3 additions & 3 deletions src/components/BalanceHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { unitSelector, hideBalanceSelector } from '../store/reselect/settings';
const BalanceHeader = (): ReactElement => {
const { t } = useTranslation('wallet');
const onSwitchUnit = useSwitchUnitAnnounced();
const { totalBalance, claimableBalance } = useBalance();
const { totalBalance, pendingBalance } = useBalance();
const dispatch = useAppDispatch();
const unit = useAppSelector(unitSelector);
const hideBalance = useAppSelector(hideBalanceSelector);
Expand All @@ -28,7 +28,7 @@ const BalanceHeader = (): ReactElement => {
return (
<View style={styles.container}>
<View style={styles.totalBalanceRow}>
{claimableBalance ? (
{pendingBalance ? (
<Trans
t={t}
i18nKey="balance_total_pending"
Expand All @@ -38,7 +38,7 @@ const BalanceHeader = (): ReactElement => {
<Money
color="gray1"
size="caption13Up"
sats={claimableBalance}
sats={pendingBalance}
unit={unit}
enableHide={true}
symbol={false}
Expand Down
4 changes: 3 additions & 1 deletion src/components/SuggestionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ const SuggestionCard = ({
</View>
<View>
<Text01M>{title}</Text01M>
<Caption13M color={dismissable ? 'lightGray' : 'purple'}>
<Caption13M
color={dismissable ? 'lightGray' : 'purple'}
numberOfLines={1}>
{description}
</Caption13M>
</View>
Expand Down
8 changes: 5 additions & 3 deletions src/components/Suggestions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useFocusEffect, useNavigation } from '@react-navigation/native';
import { Caption13Up } from '../styles/text';
import { View as ThemedView } from '../styles/components';
import { showToast } from '../utils/notifications';
import { TTodoType } from '../store/types/todos';
import { ITodo, TTodoType } from '../store/types/todos';
import { channelsNotificationsShown, hideTodo } from '../store/slices/todos';
import { showBottomSheet } from '../store/utils/ui';
import {
Expand Down Expand Up @@ -114,9 +114,11 @@ const Suggestions = (): ReactElement => {
);

const handleRenderItem = useCallback(
({ item }): ReactElement => {
// eslint-disable-next-line react/no-unused-prop-types
({ item }: { item: ITodo }): ReactElement => {
const title = t(`${item.id}.title`);
let description = t(`${item.id}.description`);
const duration = item.duration;
let description = t(`${item.id}.description`, { duration });

if (item.id === 'lightningSettingUp') {
description = t(`${item.id}.description${lightningSettingUpStep}`);
Expand Down
37 changes: 36 additions & 1 deletion src/hooks/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import {
currentWalletSelector,
selectedNetworkSelector,
selectedWalletSelector,
transfersSelector,
} from '../store/reselect/wallet';
import { useCurrency } from './displayValues';
import i18n from '../utils/i18n';
import { showToast } from '../utils/notifications';
import { ignoresSwitchUnitToastSelector } from '../store/reselect/user';
import { ignoreSwitchUnitToast } from '../store/slices/user';
import { EUnit } from '../store/types/wallet';
import { newChannelsNotificationsSelector } from '../store/reselect/todos';

/**
* Retrieves wallet balances for the currently selected wallet and network.
Expand All @@ -29,15 +31,20 @@ export const useBalance = (): {
reserveBalance: number; // Share of lightning funds that are locked up in channels
claimableBalance: number; // Funds that will be available after a channel opens/closes
spendableBalance: number; // Total spendable funds (onchain + spendable lightning)
balanceInTransferToSpending: number;
balanceInTransferToSavings: number;
pendingBalance: number; // Funds that are currently in transfer
totalBalance: number; // Total funds (all of the above)
} => {
const selectedWallet = useAppSelector(selectedWalletSelector);
const selectedNetwork = useAppSelector(selectedNetworkSelector);
const currentWallet = useAppSelector((state) => {
return currentWalletSelector(state, selectedWallet);
});
const transfers = useAppSelector(transfersSelector);
const openChannels = useAppSelector(openChannelsSelector);
const claimableBalance = useAppSelector(claimableBalanceSelector);
const newChannels = useAppSelector(newChannelsNotificationsSelector);

// Get the total spending & reserved balance of all open channels
let spendingBalance = 0;
Expand All @@ -54,8 +61,33 @@ export const useBalance = (): {
const onchainBalance = currentWallet.balance[selectedNetwork];
const lightningBalance = spendingBalance + reserveBalance + claimableBalance;
const spendableBalance = onchainBalance + spendingBalance;

let balanceInTransferToSpending = transfers.reduce((acc, transfer) => {
if (transfer.type === 'open' && transfer.status === 'pending') {
return acc + transfer.amount;
}
return acc;
}, 0);
let balanceInTransferToSavings = transfers.reduce((acc, transfer) => {
if (transfer.type === 'coop-close' && transfer.status === 'pending') {
return acc + transfer.amount;
}
return acc;
}, 0);

const pendingBalance =
balanceInTransferToSpending + balanceInTransferToSavings;

if (newChannels.length > 0) {
// avoid flashing wrong balance on channel open
balanceInTransferToSpending = 0;
}

const totalBalance =
onchainBalance + spendingBalance + reserveBalance + claimableBalance;
onchainBalance +
spendingBalance +
reserveBalance +
balanceInTransferToSpending;

return {
onchainBalance,
Expand All @@ -64,6 +96,9 @@ export const useBalance = (): {
reserveBalance,
claimableBalance,
spendableBalance,
pendingBalance,
balanceInTransferToSpending,
balanceInTransferToSavings,
totalBalance,
};
};
Expand Down
1 change: 0 additions & 1 deletion src/screens/Activity/ActivityFiltered.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ const ActivityFiltered = ({
<ActivityList
style={styles.txList}
panGestureRef={panGestureRef}
showTitle={false}
contentContainerStyle={activityPadding}
progressViewOffset={radiusContainerHeight + 10}
filter={filter}
Expand Down
Loading

0 comments on commit 688f864

Please sign in to comment.