Skip to content

Commit

Permalink
POS: add confirmation preference
Browse files Browse the repository at this point in the history
  • Loading branch information
kaloudis committed Jan 17, 2023
1 parent 7c8d477 commit 18323b9
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 54 deletions.
1 change: 1 addition & 0 deletions backends/LND.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ export default class LND {
});
subscribeInvoice = (r_hash: string) =>
this.getRequest(`/v2/invoices/subscribe/${r_hash}`);
subscribeTransactions = () => this.getRequest('/v1/transactions/subscribe');

supportsMessageSigning = () => true;
supportsOnchainSends = () => true;
Expand Down
10 changes: 5 additions & 5 deletions stores/InvoicesStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ export default class InvoicesStore {
routeHints?: boolean,
addressType?: string
) => {
if (BackendUtils.supportsOnchainReceiving()) {
this.getNewAddress(addressType ? { type: addressType } : null);
}

const rHash = this.createInvoice(
memo,
value,
Expand All @@ -120,11 +124,7 @@ export default class InvoicesStore {
routeHints
);

if (BackendUtils.supportsOnchainReceiving()) {
this.getNewAddress(addressType ? { type: addressType } : null);
}

return rHash;
return { rHash, onChainAddress: this.onChainAddress };
};

@action
Expand Down
10 changes: 9 additions & 1 deletion stores/SettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ interface PosSettings {
squareEnabled?: boolean;
squareAccessToken?: string;
squareLocationId?: string;
confirmationPreference?: string;
}

interface Settings {
Expand Down Expand Up @@ -176,6 +177,12 @@ export const DEFAULT_THEME = 'dark';
export const DEFAULT_FIAT = 'Disabled';
export const DEFAULT_LOCALE = 'English';

export const POS_CONF_PREF_KEYS = [
{ key: '0 conf', value: '0conf' },
{ key: '1 conf', value: '1conf' },
{ key: 'LN only', value: 'lnOnly' }
];

const STORAGE_KEY = 'zeus-settings';

export default class SettingsStore {
Expand All @@ -195,7 +202,8 @@ export default class SettingsStore {
pos: {
squareEnabled: false,
squareAccessToken: '',
squareLocationId: ''
squareLocationId: '',
confirmationPreference: 'lnOnly'
},
scramblePin: true,
loginBackground: false,
Expand Down
2 changes: 2 additions & 0 deletions views/Channels/ChannelsPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { localeString } from '../../utils/LocaleUtils';
import { Spacer } from '../../components/layout/Spacer';

import ChannelsStore from '../../stores/ChannelsStore';
import SettingsStore from '../../stores/SettingsStore';

// TODO: does this belong in the model? Or can it be computed from the model?
export enum Status {
Expand All @@ -24,6 +25,7 @@ export enum Status {
interface ChannelsProps {
navigation: any;
ChannelsStore: ChannelsStore;
SettingsStore: SettingsStore;
}

@inject('ChannelsStore', 'SettingsStore')
Expand Down
176 changes: 136 additions & 40 deletions views/Receive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export default class Receive extends React.Component<
ReceiveState
> {
listener: any;
listenerSecondary: any;
state = {
selectedIndex: 0,
addressType: '0',
Expand All @@ -87,8 +88,16 @@ export default class Receive extends React.Component<
};

componentDidMount() {
const { navigation, InvoicesStore } = this.props;
const { navigation, InvoicesStore, SettingsStore } = this.props;
const { reset } = InvoicesStore;
const { settings, posStatus } = SettingsStore;
const lnOnly =
settings &&
posStatus &&
posStatus === 'active' &&
settings.pos &&
settings.pos.confirmationPreference &&
settings.pos.confirmationPreference === 'lnOnly';

reset();
const lnurl: LNURLWithdrawParams | undefined =
Expand Down Expand Up @@ -124,6 +133,12 @@ export default class Receive extends React.Component<
});
}

if (lnOnly) {
this.setState({
selectedIndex: 1
});
}

if (autoGenerate)
this.autoGenerateInvoice(this.getSatAmount(amount), memo);
}
Expand All @@ -132,27 +147,36 @@ export default class Receive extends React.Component<
if (this.listener && this.listener.stop) this.listener.stop();
}

autoGenerateInvoice = (amount?: string, memo?: string) => {
autoGenerateInvoice = async (amount?: string, memo?: string) => {
const { InvoicesStore } = this.props;
const { createUnifiedInvoice } = InvoicesStore;
const { expiry, ampInvoice, routeHints, addressType } = this.state;

createUnifiedInvoice(
const { rHash, onChainAddress } = await createUnifiedInvoice(
memo || '',
amount || '0',
expiry,
undefined,
ampInvoice,
routeHints,
BackendUtils.supportsAddressTypeSelection() ? addressType : null
).then((rHash: string) => this.subscribeInvoice(rHash));
);

this.subscribeInvoice(rHash, onChainAddress || '');
};

subscribeInvoice = (rHash: string) => {
subscribeInvoice = (rHash: string, onChainAddress: string) => {
console.log('!!!subscribeInvoice', { rHash, onChainAddress });
const { InvoicesStore, PosStore, SettingsStore } = this.props;
const { orderId, orderAmount, orderTip } = this.state;
const { implementation } = SettingsStore;
const { orderId, orderAmount, orderTip, value } = this.state;
const { implementation, settings } = SettingsStore;
const { setWatchedInvoicePaid } = InvoicesStore;

const numConfPreference =
settings.pos && settings.pos.confirmationPreference === '1conf'
? 1
: 0;

if (implementation === 'lightning-node-connect') {
const { LncModule } = NativeModules;
const eventName = BackendUtils.subscribeInvoice(rHash);
Expand All @@ -179,18 +203,69 @@ export default class Receive extends React.Component<
}
}
);

const eventName2 = BackendUtils.subscribeTransactions();
const eventEmitter2 = new NativeEventEmitter(LncModule);
this.listenerSecondary = eventEmitter2.addListener(
eventName2,
(event: any) => {
if (event.result) {
try {
const result = JSON.parse(event.result);
if (
result.dest_addresses.includes(
onChainAddress
) &&
result.num_confirmations >= numConfPreference &&
result.amount >= Number(value)
) {
setWatchedInvoicePaid(result.amount);
if (orderId)
PosStore.makePayment({
orderId,
orderAmount,
orderTip
});
this.listenerSecondary = null;
}
} catch (error) {
console.error(error);
}
}
}
);
}

if (implementation === 'lnd') {
BackendUtils.subscribeInvoice(rHash).then((response: any) => {
if (response.result && response.result.settled) {
setWatchedInvoicePaid(response.result.amt_paid_sat);
// BackendUtils.subscribeInvoice(rHash).then((response: any) => {
// const result = response.result;
// if (result && result.settled) {
// setWatchedInvoicePaid(result.amt_paid_sat);
// if (orderId)
// PosStore.makePayment({
// orderId,
// orderAmount,
// orderTip
// });
// }
// });

BackendUtils.subscribeTransactions().then((response: any) => {
const result = response.result;
console.log('RESULT', result);
if (
result.dest_addresses.includes(onChainAddress) &&
result.num_confirmations >= numConfPreference &&
result.amount >= Number(value)
) {
setWatchedInvoicePaid(result.amount);
if (orderId)
PosStore.makePayment({
orderId,
orderAmount,
orderTip
});
this.listener = null;
}
});
}
Expand Down Expand Up @@ -278,10 +353,18 @@ export default class Receive extends React.Component<
clearUnified,
reset
} = InvoicesStore;
const { implementation, posStatus } = SettingsStore;
const { implementation, posStatus, settings } = SettingsStore;
const loading = SettingsStore.loading || InvoicesStore.loading;
const address = onChainAddress;

const lnOnly =
settings &&
posStatus &&
posStatus === 'active' &&
settings.pos &&
settings.pos.confirmationPreference &&
settings.pos.confirmationPreference === 'lnOnly';

const satAmount = this.getSatAmount();

const lnurl: LNURLWithdrawParams | undefined =
Expand Down Expand Up @@ -623,28 +706,32 @@ export default class Receive extends React.Component<
textBottom
/>
)}
{!belowDustLimit && haveUnifiedInvoice && (
<ButtonGroup
onPress={this.updateIndex}
selectedIndex={selectedIndex}
buttons={buttons}
selectedButtonStyle={{
backgroundColor:
themeColor('highlight'),
borderRadius: 12
}}
containerStyle={{
backgroundColor:
themeColor('secondary'),
borderRadius: 12,
borderColor:
themeColor('secondary')
}}
innerBorderStyle={{
color: themeColor('secondary')
}}
/>
)}
{!belowDustLimit &&
haveUnifiedInvoice &&
!lnOnly && (
<ButtonGroup
onPress={this.updateIndex}
selectedIndex={selectedIndex}
buttons={buttons}
selectedButtonStyle={{
backgroundColor:
themeColor('highlight'),
borderRadius: 12
}}
containerStyle={{
backgroundColor:
themeColor('secondary'),
borderRadius: 12,
borderColor:
themeColor('secondary')
}}
innerBorderStyle={{
color: themeColor(
'secondary'
)
}}
/>
)}
</View>
)}
{!loading && !haveInvoice && (
Expand Down Expand Up @@ -847,7 +934,7 @@ export default class Receive extends React.Component<
)} ${lnurl.domain}`
: '')
}
onPress={() =>
onPress={() => {
createUnifiedInvoice(
memo,
satAmount.toString() || '0',
Expand All @@ -857,11 +944,19 @@ export default class Receive extends React.Component<
routeHints,
BackendUtils.supportsAddressTypeSelection()
? addressType
: null
).then((rHash: string) =>
this.subscribeInvoice(rHash)
)
}
: undefined
).then(
({
rHash,
onChainAddress
}: any) => {
this.subscribeInvoice(
rHash,
onChainAddress || ''
);
}
);
}}
/>
</View>
</>
Expand Down Expand Up @@ -894,8 +989,9 @@ export default class Receive extends React.Component<
>
{localeString('views.Receive.addressType')}
</Text>
{_map(ADDRESS_TYPES, (d) => (
{_map(ADDRESS_TYPES, (d, index) => (
<TouchableOpacity
key={index}
onPress={() => {
InvoicesStore.clearAddress();
this.setState({ addressType: d.value });
Expand Down
Loading

0 comments on commit 18323b9

Please sign in to comment.