Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inbound routing fees #2354

Merged
merged 6 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backends/CLNRest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,4 +426,5 @@ export default class CLNRest {
return supportsOffers;
};
isLNDBased = () => false;
supportInboundFees = () => false;
}
1 change: 1 addition & 0 deletions backends/Eclair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ export default class Eclair {
supportsLSPS1rest = () => true;
supportsOffers = () => false;
isLNDBased = () => false;
supportInboundFees = () => false;
}

const mapInvoice =
Expand Down
1 change: 1 addition & 0 deletions backends/EmbeddedLND.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,5 @@ export default class EmbeddedLND extends LND {
supportsLSPS1rest = () => false;
supportsOffers = () => false;
isLNDBased = () => true;
supportInboundFees = () => this.supports('v0.18.0');
}
17 changes: 16 additions & 1 deletion backends/LND.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,13 +498,21 @@ export default class LND {
fee_rate,
time_lock_delta,
min_htlc,
max_htlc
max_htlc,
base_fee_msat_inbound,
fee_rate_inbound
} = data;

if (data.global) {
return this.postRequest('/v1/chanpolicy', {
base_fee_msat,
fee_rate: `${Number(fee_rate) / 100}`,
...(this.supportInboundFees() && {
inboundFee: {
base_fee_msat: base_fee_msat_inbound,
fee_rate_ppm: `${Number(fee_rate_inbound) * 10000}`
}
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you're gonna go with this approach, be sure to update it in the LNC backend file as well - otherwise you can do something similar in the store

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did the changes!

global: true,
time_lock_delta: Number(time_lock_delta),
min_htlc_msat: min_htlc ? `${Number(min_htlc) * 1000}` : null,
Expand All @@ -515,6 +523,12 @@ export default class LND {
return this.postRequest('/v1/chanpolicy', {
base_fee_msat,
fee_rate: `${Number(fee_rate) / 100}`,
...(this.supportInboundFees() && {
inboundFee: {
base_fee_msat: base_fee_msat_inbound,
fee_rate_ppm: `${Number(fee_rate_inbound) * 10000}`
}
}),
chan_point: {
funding_txid_str: chan_point.funding_txid_str,
output_index: chan_point.output_index
Expand Down Expand Up @@ -673,4 +687,5 @@ export default class LND {
supportsLSPS1rest = () => false;
supportsOffers = (): Promise<boolean> | boolean => false;
isLNDBased = () => true;
supportInboundFees = () => this.supports('v0.18.0');
}
14 changes: 14 additions & 0 deletions backends/LightningNodeConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,13 @@ export default class LightningNodeConnect {
params = {
base_fee_msat,
fee_rate: `${Number(fee_rate) / 100}`,
...(this.supportInboundFees() && {
inboundFee: {
base_fee_msat: data.base_fee_msat_inbound,
fee_rate_ppm: `${Number(data.fee_rate_inbound) * 10000}`
}
}),

global: true,
time_lock_delta: Number(data.time_lock_delta),
min_htlc_msat: data.min_htlc
Expand All @@ -339,6 +346,12 @@ export default class LightningNodeConnect {
params = {
base_fee_msat,
fee_rate: `${Number(fee_rate) / 100}`,
...(this.supportInboundFees() && {
inboundFee: {
base_fee_msat: data.base_fee_msat_inbound,
fee_rate_ppm: `${Number(data.fee_rate_inbound) * 10000}`
}
}),
chan_point: {
funding_txid_str: data.chan_point.funding_txid_str,
output_index: data.chan_point.output_index
Expand Down Expand Up @@ -495,4 +508,5 @@ export default class LightningNodeConnect {
supportsLSPS1rest = () => false;
supportsOffers = () => false;
isLNDBased = () => true;
supportInboundFees = () => this.supports('v0.18.0');
}
1 change: 1 addition & 0 deletions backends/LndHub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,5 @@ export default class LndHub extends LND {
supportsLSPS1rest = () => false;
supportsOffers = () => false;
isLNDBased = () => false;
supportInboundFees = () => false;
}
1 change: 1 addition & 0 deletions backends/Spark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,4 +384,5 @@ export default class Spark {
supportsLSPS1rest = () => true;
supportsOffers = () => false;
isLNDBased = () => false;
supportInboundFees = () => false;
}
36 changes: 36 additions & 0 deletions components/FeeBreakdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import DateTimeUtils from '../utils/DateTimeUtils';
import { localeString } from '../utils/LocaleUtils';
import { themeColor } from '../utils/ThemeUtils';
import UrlUtils from '../utils/UrlUtils';
import BackendUtils from '../utils/BackendUtils';

import { Divider } from 'react-native-elements';

Expand Down Expand Up @@ -146,6 +147,41 @@ export default class FeeBreakdown extends React.Component<
}%`}
sensitive
/>
{BackendUtils.supportInboundFees() && (
<>
<KeyValue
keyValue={localeString(
'views.Channel.inboundBaseFee'
)}
value={
<Amount
sats={
localPolicy.inbound_fee_base_msat
? Number(
localPolicy.inbound_fee_base_msat
) / 1000
: undefined
}
toggleable
sensitive
/>
}
/>
<KeyValue
keyValue={localeString(
'views.Channel.inboundFeeRate'
)}
value={`${
localPolicy.inbound_fee_rate_milli_msat
? Number(
localPolicy.inbound_fee_rate_milli_msat
) / 10000
: undefined
}%`}
sensitive
/>
</>
)}
</React.Fragment>
)}
{isClosed && (
Expand Down
92 changes: 78 additions & 14 deletions components/SetFeesForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ interface SetFeesFormProps {
SettingsStore?: SettingsStore;
baseFee?: string;
feeRate?: string;
baseFeeInbound?: string;
feeRateInbound?: string;
timeLockDelta?: string;
channelPoint?: string;
channelId?: string;
Expand All @@ -36,6 +38,8 @@ interface SetFeesFormState {
feesSubmitted: boolean;
newBaseFee: string;
newFeeRate: string;
newBaseFeeInbound: string;
newFeeRateInbound: string;
newTimeLockDelta: string;
newMinHtlc: string;
newMaxHtlc: string;
Expand All @@ -54,6 +58,8 @@ export default class SetFeesForm extends React.Component<
feesSubmitted: false,
newBaseFee: props.baseFee || '',
newFeeRate: props.feeRate || '',
newBaseFeeInbound: props.baseFeeInbound || '',
newFeeRateInbound: props.feeRateInbound || '',
newTimeLockDelta: props.timeLockDelta || '',
newMinHtlc: props.minHtlc || '',
newMaxHtlc: props.maxHtlc || ''
Expand All @@ -65,6 +71,8 @@ export default class SetFeesForm extends React.Component<
feesSubmitted,
newBaseFee,
newFeeRate,
newBaseFeeInbound,
newFeeRateInbound,
newTimeLockDelta,
newMinHtlc,
newMaxHtlc
Expand All @@ -75,6 +83,8 @@ export default class SetFeesForm extends React.Component<
SettingsStore,
baseFee,
feeRate,
baseFeeInbound,
feeRateInbound,
timeLockDelta,
channelPoint,
channelId,
Expand All @@ -93,6 +103,20 @@ export default class SetFeesForm extends React.Component<

return (
<React.Fragment>
{feesSubmitted && setFeesSuccess && (
<SuccessMessage
message={localeString('components.SetFeesForm.success')}
/>
)}
{feesSubmitted && setFeesError && (
<ErrorMessage
message={
setFeesErrorMsg
? setFeesErrorMsg
: localeString('components.SetFeesForm.error')
}
/>
)}
<Text
style={{
...styles.text,
Expand Down Expand Up @@ -149,6 +173,58 @@ export default class SetFeesForm extends React.Component<
autoCapitalize="none"
autoCorrect={false}
/>
{BackendUtils.supportInboundFees() && (
<>
<Text
style={{
...styles.text,
color: themeColor('secondaryText')
}}
>
{`${localeString(
'components.SetFeesForm.baseFee'
)} ${localeString(
'views.Channel.inbound'
)} (${localeString('general.sats')})`}
</Text>
<TextInput
keyboardType="numeric"
placeholder={baseFeeInbound || '1'}
value={newBaseFeeInbound}
onChangeText={(text: string) =>
this.setState({
newBaseFeeInbound: text
})
}
autoCapitalize="none"
autoCorrect={false}
/>
<Text
style={{
...styles.text,
color: themeColor('secondaryText')
}}
>
{`${localeString(
'components.SetFeesForm.feeRate'
)} ${localeString(
'views.Channel.inbound'
)} (${localeString('general.percentage')})`}
</Text>
<TextInput
keyboardType="numeric"
placeholder={feeRateInbound || '1'}
value={newFeeRateInbound}
onChangeText={(text: string) =>
this.setState({
newFeeRateInbound: text
})
}
autoCapitalize="none"
autoCorrect={false}
/>
</>
)}

{BackendUtils.isLNDBased() && (
<>
Expand Down Expand Up @@ -230,6 +306,8 @@ export default class SetFeesForm extends React.Component<
setFees(
newBaseFee,
newFeeRate,
newBaseFeeInbound,
newFeeRateInbound,
Number(newTimeLockDelta),
channelPoint,
channelId,
Expand All @@ -254,20 +332,6 @@ export default class SetFeesForm extends React.Component<
/>
</View>
)}
{feesSubmitted && setFeesSuccess && (
<SuccessMessage
message={localeString('components.SetFeesForm.success')}
/>
)}
{feesSubmitted && setFeesError && (
<ErrorMessage
message={
setFeesErrorMsg
? setFeesErrorMsg
: localeString('components.SetFeesForm.error')
}
/>
)}
</React.Fragment>
);
}
Expand Down
3 changes: 3 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,9 @@
"views.Channel.localBaseFee": "Local Base Fee",
"views.Channel.remoteFeeRate": "Remote Fee Rate",
"views.Channel.remoteBaseFee": "Remote Base Fee",
"views.Channel.inbound": "Inbound",
"views.Channel.inboundBaseFee": "Inbound Base Fee",
"views.Channel.inboundFeeRate": "Inbound Fee Fee",
"views.Channel.feeRate": "Fee Rate",
"views.Channel.channelPayments": "Channel Payments",
"views.Channel.localMin": "Local Min",
Expand Down
2 changes: 2 additions & 0 deletions models/ChannelInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ interface RoutingPolicy {
min_htlc: string;
fee_base_msat: string;
fee_rate_milli_msat: string;
inbound_fee_base_msat?: string;
inbound_fee_rate_milli_msat?: string;
disabled: boolean;
max_htlc_msat: string;
last_update: number;
Expand Down
6 changes: 5 additions & 1 deletion stores/FeeStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ export default class FeeStore {
public setFees = (
newBaseFee: string,
newFeeRate: string,
baseFeeInbound: string,
feeRateInbound: string,
timeLockDelta = 4,
channelPoint?: string,
channelId?: string,
Expand All @@ -134,6 +136,8 @@ export default class FeeStore {
const data: any = {
base_fee_msat: `${Number(baseFee) * 1000}`,
fee_rate: feeRate,
base_fee_msat_inbound: `${Number(baseFeeInbound) * 1000}`,
fee_rate_inbound: feeRateInbound,
time_lock_delta: timeLockDelta
};

Expand Down Expand Up @@ -168,7 +172,7 @@ export default class FeeStore {
this.setFeesSuccess = true;
})
.catch((err: any) => {
this.setFeesErrorMsg = err.toString();
this.setFeesErrorMsg = errorToUserFriendly(err);
this.loading = false;
this.setFeesError = true;
});
Expand Down
1 change: 1 addition & 0 deletions utils/BackendUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ class BackendUtils {
supportsChannelBatching = () => this.call('supportsChannelBatching');
supportsOffers = () => this.call('supportsOffers');
isLNDBased = () => this.call('isLNDBased');
supportInboundFees = () => this.call('supportInboundFees');

// LNC
initLNC = (...args: any[]) => this.call('initLNC', args);
Expand Down
1 change: 1 addition & 0 deletions utils/LndMobileUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const writeLndConfig = async (
tlsdisableautofill=1
maxpendingchannels=1000
max-commit-fee-rate-anchors=21
accept-positive-inbound-fees=true
payments-expiration-grace-period=168h
${rescan ? 'reset-wallet-transactions=true' : ''}

Expand Down
13 changes: 13 additions & 0 deletions views/Routing/SetFees.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ export default class SetFees extends React.PureComponent<SetFeesProps, {}> {
feeRate={`${
Number(policy.fee_rate_milli_msat) / 10000
}`}
baseFeeInbound={`${
policy.inbound_fee_base_msat
? Number(policy.inbound_fee_base_msat) /
1000
: undefined
}`}
feeRateInbound={`${
policy.inbound_fee_rate_milli_msat
? Number(
policy.inbound_fee_rate_milli_msat
) / 10000
: undefined
}`}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for these two, let's check to see if they exist or return null - otherwise there will be cases here where it returns NaN

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be better to return 0 instead of null ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined would be best

timeLockDelta={policy.time_lock_delta.toString()}
minHtlc={`${Number(policy.min_htlc) / 1000}`}
maxHtlc={`${
Expand Down
Loading