Skip to content

Commit 43ccfcf

Browse files
committed
feat(wallet): quickpay
1 parent a37d15b commit 43ccfcf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1530
-857
lines changed

__tests__/todos.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
transferClosingChannelTodo,
2121
supportTodo,
2222
inviteTodo,
23-
// fastpayTodo,
23+
quickpayTodo,
2424
// discountTodo,
2525
} from '../src/store/shapes/todos';
2626
import { createNewWallet } from '../src/utils/startup';
@@ -50,7 +50,7 @@ describe('Todos selector', () => {
5050
buyBitcoinTodo,
5151
supportTodo,
5252
inviteTodo,
53-
// fastpayTodo,
53+
quickpayTodo,
5454
slashtagsProfileTodo,
5555
// discountTodo,
5656
]);

e2e/send.e2e.js

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ d('Send', () => {
172172
// - send to onchain address
173173
// - send to lightning invoice
174174
// - send to unified invoice
175+
// - quickpay to lightning invoice
176+
// - quickpay to unified invoice
175177

176178
if (checkComplete('send-2')) {
177179
return;
@@ -243,9 +245,9 @@ d('Send', () => {
243245

244246
// receive lightning funds
245247
await element(by.id('Receive')).tap();
246-
let { label: invoice1 } = await element(by.id('QRCode')).getAttributes();
247-
invoice1 = invoice1.replaceAll(/bitcoin.*=/gi, '').toLowerCase();
248-
await lnd.sendPaymentSync({ paymentRequest: invoice1, amt: 50000 });
248+
let { label: receive } = await element(by.id('QRCode')).getAttributes();
249+
receive = receive.replaceAll(/bitcoin.*=/gi, '').toLowerCase();
250+
await lnd.sendPaymentSync({ paymentRequest: receive, amt: 50000 });
249251
await waitFor(element(by.id('NewTxPrompt')))
250252
.toBeVisible()
251253
.withTimeout(10000);
@@ -278,8 +280,8 @@ d('Send', () => {
278280
.withTimeout(10000);
279281

280282
// send to lightning invoice
281-
const { paymentRequest: lnInvoice1 } = await lnd.addInvoice();
282-
await enterAddress(lnInvoice1);
283+
const { paymentRequest: invoice1 } = await lnd.addInvoice();
284+
await enterAddress(invoice1);
283285
await expect(element(by.id('AssetButton-spending'))).toBeVisible();
284286
await element(by.id('N1').withAncestor(by.id('SendAmountNumberPad'))).tap();
285287
await element(
@@ -298,11 +300,9 @@ d('Send', () => {
298300
.withTimeout(10000);
299301

300302
// send to unified invoice w/ amount
301-
const { paymentRequest: lnInvoice2 } = await lnd.addInvoice({
302-
value: 10000,
303-
});
303+
const { paymentRequest: invoice2 } = await lnd.addInvoice({ value: 10000 });
304304
const unified1 = encode(onchainAddress, {
305-
lightning: lnInvoice2,
305+
lightning: invoice2,
306306
amount: 10000,
307307
});
308308

@@ -319,11 +319,11 @@ d('Send', () => {
319319
.withTimeout(10000);
320320

321321
// send to unified invoice w/ amount exceeding balance(s)
322-
const { paymentRequest: lnInvoice3 } = await lnd.addInvoice({
322+
const { paymentRequest: invoice3 } = await lnd.addInvoice({
323323
value: 200000,
324324
});
325325
const unified2 = encode(onchainAddress, {
326-
lightning: lnInvoice3,
326+
lightning: invoice3,
327327
amount: 200000,
328328
});
329329

@@ -369,8 +369,8 @@ d('Send', () => {
369369
.withTimeout(10000);
370370

371371
// send to unified invoice w/o amount (lightning)
372-
const { paymentRequest: lnInvoice4 } = await lnd.addInvoice();
373-
const unified4 = encode(onchainAddress, { lightning: lnInvoice4 });
372+
const { paymentRequest: invoice4 } = await lnd.addInvoice();
373+
const unified4 = encode(onchainAddress, { lightning: invoice4 });
374374

375375
await enterAddress(unified4);
376376
// max amount (lightning)
@@ -396,8 +396,8 @@ d('Send', () => {
396396
.withTimeout(10000);
397397

398398
// send to unified invoice w/o amount (switch to onchain)
399-
const { paymentRequest: lnInvoice5 } = await lnd.addInvoice();
400-
const unified5 = encode(onchainAddress, { lightning: lnInvoice5 });
399+
const { paymentRequest: invoice5 } = await lnd.addInvoice();
400+
const unified5 = encode(onchainAddress, { lightning: invoice5 });
401401

402402
await enterAddress(unified5);
403403

@@ -433,6 +433,52 @@ d('Send', () => {
433433
.toHaveText('78 506')
434434
.withTimeout(10000);
435435

436+
// send to lightning invoice w/ amount (quickpay)
437+
const { paymentRequest: invoice6 } = await lnd.addInvoice({ value: 1000 });
438+
439+
// enable quickpay
440+
await element(by.id('Settings')).tap();
441+
await element(by.id('GeneralSettings')).tap();
442+
await element(by.id('QuickpaySettings')).tap();
443+
await element(by.id('QuickpayIntro-button')).tap();
444+
await element(by.id('QuickpayToggle')).tap();
445+
await element(by.id('NavigationClose')).tap();
446+
447+
await enterAddress(invoice6);
448+
await waitFor(element(by.id('SendSuccess')))
449+
.toBeVisible()
450+
.withTimeout(10000);
451+
await element(by.id('Close')).tap();
452+
await waitFor(
453+
element(by.id('MoneyText').withAncestor(by.id('TotalBalance'))),
454+
)
455+
.toHaveText('77 506')
456+
.withTimeout(10000);
457+
458+
// send to unified invoice w/ amount (quickpay)
459+
const { paymentRequest: invoice7 } = await lnd.addInvoice({ value: 1000 });
460+
const unified7 = encode(onchainAddress, {
461+
lightning: invoice7,
462+
amount: 1000,
463+
});
464+
465+
await enterAddress(unified7);
466+
await waitFor(element(by.id('SendSuccess')))
467+
.toBeVisible()
468+
.withTimeout(10000);
469+
await element(by.id('Close')).tap();
470+
await waitFor(
471+
element(by.id('MoneyText').withAncestor(by.id('TotalBalance'))),
472+
)
473+
.toHaveText('76 506')
474+
.withTimeout(10000);
475+
476+
// send to lightning invoice w/ amount (skip quickpay for large amounts)
477+
const { paymentRequest: invoice8 } = await lnd.addInvoice({ value: 10000 });
478+
await enterAddress(invoice8);
479+
await expect(element(by.id('ReviewAmount'))).toBeVisible();
480+
await element(by.id('SendSheet')).swipe('down');
481+
436482
markComplete('send-2');
437483
});
438484
});
58.8 KB
Loading
74.1 KB
Loading

src/components/HourglassSpinner.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import React, { ReactElement } from 'react';
2-
import { View, StyleSheet, StyleProp, ViewStyle, Image } from 'react-native';
2+
import {
3+
View,
4+
StyleSheet,
5+
StyleProp,
6+
ViewStyle,
7+
Image,
8+
ImageSourcePropType,
9+
} from 'react-native';
310
import { Easing, withRepeat, withTiming } from 'react-native-reanimated';
411

512
import { AnimatedView } from '../styles/components';
@@ -8,9 +15,11 @@ import { __E2E__ } from '../constants/env';
815
const imageSrc = require('../assets/illustrations/hourglass.png');
916

1017
const HourglassSpinner = ({
18+
image = imageSrc,
1119
imageSize = 256,
1220
style,
1321
}: {
22+
image?: ImageSourcePropType;
1423
imageSize?: number;
1524
style?: StyleProp<ViewStyle>;
1625
}): ReactElement => {
@@ -47,7 +56,7 @@ const HourglassSpinner = ({
4756
color="transparent"
4857
testID="HourglassSpinner">
4958
<View style={[styles.imageContainer, { width: imageSize }]}>
50-
<Image style={styles.image} source={imageSrc} />
59+
<Image style={styles.image} source={image} />
5160
</View>
5261
</AnimatedView>
5362
);

src/components/LightningSyncing.tsx

Lines changed: 3 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import React, { ReactElement, useEffect, useState } from 'react';
22
import { Image, StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
3-
import Animated, {
3+
import {
44
Easing,
55
cancelAnimation,
66
runOnJS,
77
useSharedValue,
8-
withDelay,
98
withRepeat,
10-
withSequence,
119
withTiming,
1210
} from 'react-native-reanimated';
1311
import { useTranslation } from 'react-i18next';
@@ -17,13 +15,12 @@ import { AnimatedView } from '../styles/components';
1715
import SafeAreaInset from './SafeAreaInset';
1816
import BottomSheetNavigationHeader from './BottomSheetNavigationHeader';
1917
import GradientView from './GradientView';
18+
import SyncSpinner from './SyncSpinner';
2019
import { useAppSelector } from '../hooks/redux';
2120
import { isLDKReadySelector } from '../store/reselect/ui';
2221
import { __E2E__ } from '../constants/env';
2322

2423
const imageSrc = require('../assets/illustrations/lightning.png');
25-
const imageSyncSmall = require('../assets/illustrations/ln-sync-small.png');
26-
const imageSyncLarge = require('../assets/illustrations/ln-sync-large.png');
2724

2825
const LightningSyncing = ({
2926
title,
@@ -69,62 +66,6 @@ const LightningSyncing = ({
6966
return <></>;
7067
}
7168

72-
const animationLarge = (): { initialValues: {}; animations: {} } => {
73-
'worklet';
74-
const initialValues = { transform: [{ rotate: '0deg' }] };
75-
const animations = {
76-
transform: [
77-
{
78-
rotate: withRepeat(
79-
withSequence(
80-
withTiming('-180deg', {
81-
duration: 1500,
82-
easing: Easing.inOut(Easing.ease),
83-
}),
84-
withDelay(
85-
100,
86-
withTiming('-360deg', {
87-
duration: 1500,
88-
easing: Easing.inOut(Easing.ease),
89-
}),
90-
),
91-
),
92-
-1,
93-
),
94-
},
95-
],
96-
};
97-
return { initialValues, animations };
98-
};
99-
100-
const animationSmall = (): { initialValues: {}; animations: {} } => {
101-
'worklet';
102-
const initialValues = { transform: [{ rotate: '0deg' }] };
103-
const animations = {
104-
transform: [
105-
{
106-
rotate: withRepeat(
107-
withSequence(
108-
withTiming('180deg', {
109-
duration: 1500,
110-
easing: Easing.inOut(Easing.ease),
111-
}),
112-
withDelay(
113-
100,
114-
withTiming('360deg', {
115-
duration: 1500,
116-
easing: Easing.inOut(Easing.ease),
117-
}),
118-
),
119-
),
120-
-1,
121-
),
122-
},
123-
],
124-
};
125-
return { initialValues, animations };
126-
};
127-
12869
return (
12970
<AnimatedView
13071
style={[style, { opacity: rootOpacity }]}
@@ -135,18 +76,7 @@ const LightningSyncing = ({
13576
<BodyM color="secondary">{t('wait_text_top')}</BodyM>
13677

13778
<View style={styles.imageContainer}>
138-
<View style={styles.animation}>
139-
<Animated.Image
140-
style={styles.circleSmall}
141-
source={imageSyncSmall}
142-
entering={__E2E__ ? undefined : animationSmall}
143-
/>
144-
<Animated.Image
145-
style={styles.circleLarge}
146-
source={imageSyncLarge}
147-
entering={__E2E__ ? undefined : animationLarge}
148-
/>
149-
</View>
79+
<SyncSpinner />
15080
<Image style={styles.image} source={imageSrc} />
15181
</View>
15282

@@ -182,28 +112,6 @@ const styles = StyleSheet.create({
182112
flex: 1,
183113
resizeMode: 'contain',
184114
},
185-
animation: {
186-
justifyContent: 'center',
187-
alignItems: 'center',
188-
alignSelf: 'center',
189-
position: 'absolute',
190-
width: 311,
191-
aspectRatio: 1,
192-
},
193-
circleSmall: {
194-
flex: 1,
195-
position: 'absolute',
196-
resizeMode: 'contain',
197-
width: 207,
198-
aspectRatio: 1,
199-
},
200-
circleLarge: {
201-
flex: 1,
202-
position: 'absolute',
203-
resizeMode: 'contain',
204-
width: 311,
205-
aspectRatio: 1,
206-
},
207115
bottom: {
208116
textAlign: 'center',
209117
marginTop: 'auto',

0 commit comments

Comments
 (0)