Skip to content

Commit aa72719

Browse files
feat: implement auto coin select (#2462)
* feat: implement auto coin select Implement and enable auto coin select functionality in Advanced Settings. * fix: lint errors * fix: revert electrum regtest host * fix: update e2e tests * fix: remove address placeholder * chore: update blur dependency
1 parent 53d487c commit aa72719

File tree

15 files changed

+169
-439
lines changed

15 files changed

+169
-439
lines changed

e2e/transfer.e2e.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,12 @@ d('Transfer', () => {
312312
await element(
313313
by.id('NRemove').withAncestor(by.id('FeeCustomNumberPad')),
314314
).tap();
315+
// wait for input to register
316+
await sleep(1000);
315317
await element(by.id('FeeCustomContinue')).tap();
316318
await element(by.id('N5').withAncestor(by.id('FeeCustomNumberPad'))).tap();
319+
// wait for input to register
320+
await sleep(1000);
317321
await element(by.id('FeeCustomContinue')).tap();
318322

319323
// Swipe to confirm (set x offset to avoid navigating back)

ios/Podfile.lock

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ PODS:
3131
- ReactCommon/turbomodule/bridging
3232
- ReactCommon/turbomodule/core
3333
- Yoga
34-
- MMKV (2.0.0):
35-
- MMKVCore (~> 2.0.0)
36-
- MMKVCore (2.0.0)
34+
- MMKV (2.0.2):
35+
- MMKVCore (~> 2.0.2)
36+
- MMKVCore (2.0.2)
3737
- OpenSSL-Universal (3.3.2000)
3838
- RCT-Folly (2024.01.01.00):
3939
- boost
@@ -1288,7 +1288,7 @@ PODS:
12881288
- Yoga
12891289
- react-native-biometrics (3.0.1):
12901290
- React-Core
1291-
- react-native-blur (4.4.0):
1291+
- react-native-blur (4.4.1):
12921292
- DoubleConversion
12931293
- glog
12941294
- hermes-engine
@@ -2216,8 +2216,8 @@ SPEC CHECKSUMS:
22162216
hermes-engine: 3b6e0717ca847e2fc90a201e59db36caf04dee88
22172217
lottie-ios: e047b1d2e6239b787cc5e9755b988869cf190494
22182218
lottie-react-native: 31197e5c65aa7cb59e6affcefaf901588bb708c4
2219-
MMKV: f7d1d5945c8765f97f39c3d121f353d46735d801
2220-
MMKVCore: c04b296010fcb1d1638f2c69405096aac12f6390
2219+
MMKV: 3eacda84cd1c4fc95cf848d3ecb69d85ed56006c
2220+
MMKVCore: 508b4d3a8ce031f1b5c8bd235f0517fb3f4c73a9
22212221
OpenSSL-Universal: b60a3702c9fea8b3145549d421fdb018e53ab7b4
22222222
RCT-Folly: 4464f4d875961fce86008d45f4ecf6cef6de0740
22232223
RCTDeprecation: 34cbf122b623037ea9facad2e92e53434c5c7422
@@ -2250,7 +2250,7 @@ SPEC CHECKSUMS:
22502250
React-microtasksnativemodule: 87b8de96f937faefece8afd2cb3a518321b2ef99
22512251
react-native-address-generator: 06f3ba094377dac5a1b472dd1daabf4ce0580807
22522252
react-native-biometrics: 352e5a794bfffc46a0c86725ea7dc62deb085bdc
2253-
react-native-blur: 42522e76bf44daf9a16d341408caeb900b5f9424
2253+
react-native-blur: a1bf334589f44658a58a859b1f3defe28e367fcf
22542254
react-native-image-picker: 2fbbafdae7a7c6db9d25df2f2b1db4442d2ca2ad
22552255
react-native-ldk: 9ea2f29a6f96cc55f839ee180caf8dc9e58cd6eb
22562256
react-native-mmkv: 7d0b6c2a79e73100b933f2947a9c8741d664e18b
@@ -2308,7 +2308,7 @@ SPEC CHECKSUMS:
23082308
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
23092309
sodium-react-native-direct: 8feb9a6d0d88ce65efa305d6cc774c11c62d9a15
23102310
SSZipArchive: c69881e8ac5521f0e622291387add5f60f30f3c4
2311-
Yoga: a1d7895431387402a674fd0d1c04ec85e87909b8
2311+
Yoga: 2a45d7e59592db061217551fd3bbe2dd993817ae
23122312
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5
23132313

23142314
PODFILE CHECKSUM: cb153cb4a39e6c92c8b869eafab65a4bba7b869f

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"@gorhom/bottom-sheet": "4.6.3",
4141
"@notifee/react-native": "7.8.2",
4242
"@react-native-clipboard/clipboard": "1.14.1",
43-
"@react-native-community/blur": "4.4.0",
43+
"@react-native-community/blur": "4.4.1",
4444
"@react-native-community/netinfo": "11.3.1",
4545
"@react-navigation/native": "7.0.14",
4646
"@react-navigation/native-stack": "7.2.0",
@@ -60,7 +60,7 @@
6060
"@synonymdev/slashtags-widget-news-feed": "1.1.0",
6161
"@synonymdev/slashtags-widget-price-feed": "1.1.0",
6262
"@synonymdev/web-relay": "1.0.7",
63-
"beignet": "0.0.51",
63+
"beignet": "0.0.52",
6464
"bip21": "2.0.3",
6565
"bip32": "4.0.0",
6666
"bitcoin-address-validation": "2.2.3",

src/screens/Settings/CoinSelectPreference/index.tsx

Lines changed: 75 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
1-
import React, { memo, ReactElement, useMemo } from 'react';
1+
import React, { memo, ReactElement, useCallback, useMemo } from 'react';
22
import { useTranslation } from 'react-i18next';
33
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
44

5+
import { ECoinSelectPreference } from 'beignet';
56
import { EItemType, IListData } from '../../../components/List';
6-
import { coinSelectAutoSelector } from '../../../store/reselect/settings';
7+
import {
8+
coinSelectAutoSelector,
9+
coinSelectPreferenceSelector,
10+
} from '../../../store/reselect/settings';
711
import { updateSettings } from '../../../store/slices/settings';
12+
import { updateCoinSelectPreference } from '../../../utils/settings';
13+
import { getOnChainWalletAsync } from '../../../utils/wallet';
814
import SettingsView from '../SettingsView';
915

1016
const CoinSelectSettings = (): ReactElement => {
1117
const { t } = useTranslation('settings');
1218
const dispatch = useAppDispatch();
1319
const selectedAutoPilot = useAppSelector(coinSelectAutoSelector);
14-
//const coinSelectPreference = useAppSelector(coinSelectPreferenceSelector);
20+
const coinSelectPreference = useAppSelector(coinSelectPreferenceSelector);
1521

1622
const settingsListData: IListData[] = useMemo(
1723
() => [
@@ -22,73 +28,88 @@ const CoinSelectSettings = (): ReactElement => {
2228
title: t('adv.cs_manual'),
2329
value: !selectedAutoPilot,
2430
type: EItemType.button,
25-
onPress: (): void => {
31+
onPress: async (): Promise<void> => {
32+
// Update the coin selection preference in beignet.
33+
const wallet = await getOnChainWalletAsync();
34+
// Set beignet to consolidate if manual coin control is enabled in Bitkit.
35+
wallet.updateCoinSelectPreference(
36+
ECoinSelectPreference.consolidate,
37+
);
2638
dispatch(updateSettings({ coinSelectAuto: false }));
2739
},
2840
},
2941
{
3042
title: t('adv.cs_auto'),
3143
value: selectedAutoPilot,
3244
type: EItemType.button,
33-
onPress: (): void => {
45+
onPress: async (): Promise<void> => {
46+
// Update the coin selection preference in beignet.
47+
const wallet = await getOnChainWalletAsync();
48+
wallet.updateCoinSelectPreference(coinSelectPreference);
3449
dispatch(updateSettings({ coinSelectAuto: true }));
3550
},
3651
},
3752
],
3853
},
39-
/*{
40-
// TODO: Re-Add and enable this feature once thoroughly tested in Beignet.
41-
title: selectedAutoPilot ? t('adv.cs_auto_mode') : '',
42-
data: [
43-
{
44-
title: t('adv.cs_max'),
45-
description: t('adv.cs_max_description'),
46-
value: coinSelectPreference === 'large',
47-
type: EItemType.button,
48-
hide: !selectedAutoPilot,
49-
onPress: (): void => {
50-
dispatch(
51-
updateSettings({
52-
coinSelectAuto: true,
53-
coinSelectPreference: 'large',
54-
}),
55-
);
54+
{
55+
title: selectedAutoPilot ? t('adv.cs_auto_mode') : '',
56+
data: [
57+
{
58+
title: t('adv.cs_max'),
59+
description: t('adv.cs_max_description'),
60+
value: coinSelectPreference === ECoinSelectPreference.small,
61+
type: EItemType.button,
62+
hide: !selectedAutoPilot,
63+
onPress: (): void => {
64+
updateCoinSelectPreference(ECoinSelectPreference.small);
65+
},
66+
},
67+
{
68+
title: t('adv.cs_min'),
69+
description: t('adv.cs_min_description'),
70+
value: coinSelectPreference === ECoinSelectPreference.large,
71+
type: EItemType.button,
72+
hide: !selectedAutoPilot,
73+
onPress: (): void => {
74+
updateCoinSelectPreference(ECoinSelectPreference.large);
75+
},
76+
},
77+
{
78+
title: t('adv.cs_consolidate'),
79+
description: t('adv.cs_consolidate_description'),
80+
value: coinSelectPreference === ECoinSelectPreference.consolidate,
81+
type: EItemType.button,
82+
hide: !selectedAutoPilot,
83+
onPress: (): void => {
84+
updateCoinSelectPreference(ECoinSelectPreference.consolidate);
85+
},
5686
},
57-
},
58-
{
59-
title: t('adv.cs_min'),
60-
description: t('adv.cs_min_description'),
61-
value: coinSelectPreference === 'small',
62-
type: EItemType.button,
63-
hide: !selectedAutoPilot,
64-
onPress: (): void => {
65-
dispatch(
66-
updateSettings({
67-
coinSelectAuto: true,
68-
coinSelectPreference: 'small',
69-
}),
70-
);
87+
{
88+
title: t('adv.cs_first_in_first_out'),
89+
description: t('adv.cs_first_in_first_out_description'),
90+
value:
91+
coinSelectPreference === ECoinSelectPreference.firstInFirstOut,
92+
type: EItemType.button,
93+
hide: !selectedAutoPilot,
94+
onPress: (): void => {
95+
updateCoinSelectPreference(ECoinSelectPreference.firstInFirstOut);
96+
},
7197
},
72-
},
73-
{
74-
title: t('adv.cs_consolidate'),
75-
description: t('adv.cs_consolidate_description'),
76-
value: coinSelectPreference === 'consolidate',
77-
type: EItemType.button,
78-
hide: !selectedAutoPilot,
79-
onPress: (): void => {
80-
dispatch(
81-
updateSettings({
82-
coinSelectAuto: true,
83-
coinSelectPreference: 'consolidate',
84-
}),
85-
);
98+
{
99+
title: t('adv.cs_last_in_last_out'),
100+
description: t('adv.cs_last_in_last_out_description'),
101+
value:
102+
coinSelectPreference === ECoinSelectPreference.lastInFirstOut,
103+
type: EItemType.button,
104+
hide: !selectedAutoPilot,
105+
onPress: (): void => {
106+
updateCoinSelectPreference(ECoinSelectPreference.lastInFirstOut);
107+
},
86108
},
87-
},
88-
],
89-
},*/
109+
],
110+
},
90111
],
91-
[selectedAutoPilot, t, dispatch],
112+
[selectedAutoPilot, coinSelectPreference, t, dispatch],
92113
);
93114

94115
return (

src/screens/Transfer/ExternalNode/Confirm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ const ExternalConfirm = ({
3636

3737
useFocusEffect(
3838
useCallback(() => {
39-
// Using a placeholder address here to enable the FeeCustom screen to function properly.
39+
// Using an empty address here to enable the FeeCustom screen to function properly.
4040
// The actual funding address will be updated later in createFundedChannel.
4141
updateBeignetSendTransaction({
42-
outputs: [{ address: 'xxx', value: localBalance, index: 0 }],
42+
outputs: [{ address: '', value: localBalance, index: 0 }],
4343
});
4444
}, [localBalance]),
4545
);

src/store/reselect/settings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { createSelector } from '@reduxjs/toolkit';
22

3+
import { ECoinSelectPreference } from 'beignet';
34
import { RootState } from '..';
45
import themes, { IThemeColors } from '../../styles/themes';
56
import { TSettings } from '../slices/settings';
67
import {
78
ETransactionSpeed,
89
ICustomElectrumPeer,
9-
TCoinSelectPreference,
1010
TCustomElectrumPeers,
1111
TReceiveOption,
1212
TTheme,
@@ -63,7 +63,7 @@ export const pinOnIdleSelector = (state: RootState): boolean => {
6363
};
6464
export const coinSelectPreferenceSelector = (
6565
state: RootState,
66-
): TCoinSelectPreference => {
66+
): ECoinSelectPreference => {
6767
return state.settings.coinSelectPreference;
6868
};
6969
export const rapidGossipSyncUrlSelector = (state: RootState): string => {

src/store/shapes/settings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EProtocol, TServer } from 'beignet';
1+
import { ECoinSelectPreference, EProtocol, TServer } from 'beignet';
22
import cloneDeep from 'lodash/cloneDeep';
33

44
import {
@@ -91,7 +91,7 @@ export const initialSettingsState: TSettings = {
9191
customElectrumPeers: defaultElectrumPeer,
9292
rapidGossipSyncUrl: 'https://rgs.blocktank.to/snapshot/',
9393
coinSelectAuto: true,
94-
coinSelectPreference: 'small',
94+
coinSelectPreference: ECoinSelectPreference.small,
9595
receivePreference: defaultReceivePreference,
9696
enableDevOptions: __DEV__,
9797
enableOfflinePayments: false,

src/store/slices/settings.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
2-
import { TServer } from 'beignet';
2+
import { ECoinSelectPreference, TServer } from 'beignet';
33

44
import { EAvailableNetwork } from '../../utils/networks';
55
import { initialSettingsState } from '../shapes/settings';
66
import {
77
ETransactionSpeed,
88
ICustomElectrumPeer,
99
TChest,
10-
TCoinSelectPreference,
1110
TReceiveOption,
1211
TTheme,
1312
} from '../types/settings';
@@ -31,7 +30,7 @@ export type TSettings = {
3130
selectedCurrency: string;
3231
selectedLanguage: string;
3332
coinSelectAuto: boolean;
34-
coinSelectPreference: TCoinSelectPreference;
33+
coinSelectPreference: ECoinSelectPreference;
3534
receivePreference: TReceiveOption[];
3635
enableDevOptions: boolean;
3736
enableOfflinePayments: boolean;

src/store/types/settings.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,6 @@ export enum ETransactionSpeed {
1717
custom = 'custom',
1818
}
1919

20-
/**
21-
* large = Sort by and use largest UTXO first. Lowest fee, but reveals your largest UTXO's.
22-
* small = Sort by and use smallest UTXO first. Higher fee, but hides your largest UTXO's.
23-
* consolidate = Use all available UTXO's regardless of the amount being sent. Preferable to use this method when fees are low in order to reduce fees in future transactions.
24-
*/
25-
export type TCoinSelectPreference = 'small' | 'large' | 'consolidate';
26-
2720
export interface ICustomElectrumPeer {
2821
host: string;
2922
ssl: number; //ssl port

src/utils/helpers.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,7 @@ import isPlainObject from 'lodash/isPlainObject';
55
import keys from 'lodash/keys';
66
import { Linking, Vibration } from 'react-native';
77
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
8-
9-
import { TServer } from 'beignet';
10-
import {
11-
TLastUsedTags,
12-
TPendingInvoice,
13-
TSlashTagsUrls,
14-
TTags,
15-
TTxComments,
16-
} from '../store/types/metadata';
17-
import {
18-
ETransactionSpeed,
19-
TChest,
20-
TCoinSelectPreference,
21-
TReceiveOption,
22-
TTheme,
23-
} from '../store/types/settings';
24-
import { EDenomination, EUnit } from '../store/types/wallet';
25-
import { TWidgets } from '../store/types/widgets';
268
import { i18nTime } from '../utils/i18n';
27-
import { EAvailableNetwork } from './networks';
289

2910
/**
3011
* Returns the result of a promise, or an error if the promise takes too long to resolve.

0 commit comments

Comments
 (0)