Skip to content

Commit f63af91

Browse files
authored
chore: improve channel open (#550)
1 parent accdc5e commit f63af91

File tree

7 files changed

+150
-69
lines changed

7 files changed

+150
-69
lines changed

schema.gql

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ type Mutation {
445445
lnUrlWithdraw(amount: Float!, callback: String!, description: String, k1: String!): String!
446446
loginAmboss: Boolean!
447447
logout: Boolean!
448-
openChannel(amount: Float!, isPrivate: Boolean, partnerPublicKey: String!, pushTokens: Float = 0, tokensPerVByte: Float): OpenOrCloseChannel!
448+
openChannel(input: OpenChannelParams!): OpenOrCloseChannel!
449449
pay(max_fee: Float!, max_paths: Float!, out: [String!], request: String!): Boolean!
450450
pushBackup: Boolean!
451451
removePeer(publicKey: String): Boolean!
@@ -548,6 +548,17 @@ type OnChainBalance {
548548
pending: String!
549549
}
550550

551+
input OpenChannelParams {
552+
base_fee_mtokens: String
553+
chain_fee_tokens_per_vbyte: Float
554+
channel_size: Float
555+
fee_rate: Float
556+
give_tokens: Float = 0
557+
is_max_funding: Boolean
558+
is_private: Boolean
559+
partner_public_key: String!
560+
}
561+
551562
type OpenOrCloseChannel {
552563
transactionId: String!
553564
transactionOutputIndex: String!

src/client/src/graphql/mutations/__generated__/openChannel.generated.tsx

Lines changed: 4 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/client/src/graphql/mutations/openChannel.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,8 @@
11
import { gql } from '@apollo/client';
22

33
export const OPEN_CHANNEL = gql`
4-
mutation OpenChannel(
5-
$amount: Float!
6-
$partnerPublicKey: String!
7-
$tokensPerVByte: Float
8-
$isPrivate: Boolean
9-
$pushTokens: Float
10-
) {
11-
openChannel(
12-
amount: $amount
13-
partnerPublicKey: $partnerPublicKey
14-
tokensPerVByte: $tokensPerVByte
15-
isPrivate: $isPrivate
16-
pushTokens: $pushTokens
17-
) {
4+
mutation OpenChannel($input: OpenChannelParams!) {
5+
openChannel(input: $input) {
186
transactionId
197
transactionOutputIndex
208
}

src/client/src/graphql/types.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ export type MutationCloseChannelArgs = {
567567
};
568568

569569
export type MutationCreateAddressArgs = {
570-
type?: InputMaybe<Scalars['String']['input']>;
570+
type?: Scalars['String']['input'];
571571
};
572572

573573
export type MutationCreateBaseInvoiceArgs = {
@@ -648,11 +648,7 @@ export type MutationLnUrlWithdrawArgs = {
648648
};
649649

650650
export type MutationOpenChannelArgs = {
651-
amount: Scalars['Float']['input'];
652-
isPrivate?: InputMaybe<Scalars['Boolean']['input']>;
653-
partnerPublicKey: Scalars['String']['input'];
654-
pushTokens?: InputMaybe<Scalars['Float']['input']>;
655-
tokensPerVByte?: InputMaybe<Scalars['Float']['input']>;
651+
input: OpenChannelParams;
656652
};
657653

658654
export type MutationPayArgs = {
@@ -807,6 +803,17 @@ export type OnChainBalance = {
807803
pending: Scalars['String']['output'];
808804
};
809805

806+
export type OpenChannelParams = {
807+
base_fee_mtokens?: InputMaybe<Scalars['String']['input']>;
808+
chain_fee_tokens_per_vbyte?: InputMaybe<Scalars['Float']['input']>;
809+
channel_size?: InputMaybe<Scalars['Float']['input']>;
810+
fee_rate?: InputMaybe<Scalars['Float']['input']>;
811+
give_tokens?: InputMaybe<Scalars['Float']['input']>;
812+
is_max_funding?: InputMaybe<Scalars['Boolean']['input']>;
813+
is_private?: InputMaybe<Scalars['Boolean']['input']>;
814+
partner_public_key: Scalars['String']['input'];
815+
};
816+
810817
export type OpenOrCloseChannel = {
811818
__typename?: 'OpenOrCloseChannel';
812819
transactionId: Scalars['String']['output'];

src/client/src/views/home/quickActions/openChannel/OpenChannel.tsx

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ export const OpenChannelCard = ({
4848
const [fee, setFee] = useState(0);
4949
const [publicKey, setPublicKey] = useState(initialPublicKey);
5050
const [privateChannel, setPrivateChannel] = useState(false);
51+
const [isMaxFunding, setIsMaxFunding] = useState(false);
5152
const [type, setType] = useState('fee');
5253

54+
const [feeRate, setFeeRate] = useState<number | null>(null);
55+
const [baseFee, setBaseFee] = useState<number | null>(null);
56+
5357
const [openChannel, { loading }] = useOpenChannelMutation({
5458
onError: error => toast.error(getErrorContent(error)),
5559
onCompleted: () => {
@@ -59,7 +63,7 @@ export const OpenChannelCard = ({
5963
refetchQueries: ['GetChannels', 'GetPendingChannels'],
6064
});
6165

62-
const canOpen = publicKey !== '' && size > 0 && fee > 0;
66+
const canOpen = publicKey !== '' && (size > 0 || isMaxFunding) && fee > 0;
6367

6468
const pushAmount =
6569
pushType === 'none'
@@ -164,13 +168,57 @@ export const OpenChannelCard = ({
164168
/>
165169
)}
166170
<Separation />
171+
<InputWithDeco title={'Max Size'} noInput={true}>
172+
<MultiButton>
173+
{renderButton(
174+
() => {
175+
setIsMaxFunding(true);
176+
setSize(0);
177+
},
178+
'Yes',
179+
isMaxFunding
180+
)}
181+
{renderButton(() => setIsMaxFunding(false), 'No', !isMaxFunding)}
182+
</MultiButton>
183+
</InputWithDeco>
184+
{!isMaxFunding ? (
185+
<InputWithDeco
186+
title={'Channel Size'}
187+
value={size}
188+
placeholder={'Sats'}
189+
amount={size}
190+
inputType={'number'}
191+
inputCallback={value => setSize(Number(value))}
192+
/>
193+
) : null}
194+
<Separation />
195+
<InputWithDeco
196+
title={'Fee Rate'}
197+
value={feeRate}
198+
placeholder={'ppm'}
199+
amount={feeRate}
200+
inputType={'number'}
201+
inputCallback={value => {
202+
if (value == null) {
203+
setFeeRate(null);
204+
} else {
205+
setFeeRate(Number(value));
206+
}
207+
}}
208+
/>
167209
<InputWithDeco
168-
title={'Channel Size'}
169-
value={size}
170-
placeholder={'Sats'}
171-
amount={size}
210+
title={'Base Fee'}
211+
value={baseFee}
212+
placeholder={'msats'}
213+
amount={baseFee}
172214
inputType={'number'}
173-
inputCallback={value => setSize(Number(value))}
215+
inputCallback={value => {
216+
if (value == null) {
217+
setBaseFee(null);
218+
} else {
219+
setBaseFee(Number(value));
220+
}
221+
}}
174222
/>
175223
<Separation />
176224
{fetchFees && !dontShow && (
@@ -243,11 +291,16 @@ export const OpenChannelCard = ({
243291
onClick={() =>
244292
openChannel({
245293
variables: {
246-
amount: size,
247-
partnerPublicKey: publicKey || '',
248-
tokensPerVByte: fee,
249-
isPrivate: privateChannel,
250-
pushTokens: pushAmount,
294+
input: {
295+
channel_size: size,
296+
partner_public_key: publicKey || '',
297+
is_private: privateChannel,
298+
is_max_funding: isMaxFunding,
299+
give_tokens: pushAmount,
300+
chain_fee_tokens_per_vbyte: fee,
301+
base_fee_mtokens: baseFee == null ? undefined : baseFee + '',
302+
fee_rate: feeRate,
303+
},
251304
},
252305
})
253306
}

src/server/modules/api/channels/channels.resolver.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import { getChannelAge } from './channels.helpers';
1010
import {
1111
Channel,
1212
ClosedChannel,
13+
OpenChannelParams,
1314
OpenOrCloseChannel,
1415
PendingChannel,
1516
SingleChannel,
1617
UpdateRoutingFeesParams,
1718
} from './channels.types';
19+
import { GraphQLError } from 'graphql';
1820

1921
@Resolver()
2022
export class ChannelsResolver {
@@ -130,34 +132,54 @@ export class ChannelsResolver {
130132
@Mutation(() => OpenOrCloseChannel)
131133
async openChannel(
132134
@CurrentUser() user: UserId,
133-
@Args('amount') local_tokens: number,
134-
@Args('partnerPublicKey') partner_public_key: string,
135-
@Args('isPrivate', { nullable: true }) is_private: boolean,
136-
@Args('pushTokens', { nullable: true, defaultValue: 0 }) pushTokens: number,
137-
@Args('tokensPerVByte', { nullable: true })
138-
chain_fee_tokens_per_vbyte: number
135+
@Args('input') input: OpenChannelParams
139136
) {
137+
const {
138+
channel_size = 0,
139+
partner_public_key,
140+
is_private,
141+
is_max_funding,
142+
give_tokens = 0,
143+
chain_fee_tokens_per_vbyte,
144+
base_fee_mtokens,
145+
fee_rate,
146+
} = input;
147+
148+
if (!channel_size && !is_max_funding) {
149+
throw new GraphQLError('You need to specify a channel size.');
150+
}
151+
152+
this.logger.info('Starting opening channel attempt', { input });
153+
140154
let public_key = partner_public_key;
141155

142156
if (partner_public_key.indexOf('@') >= 0) {
157+
this.logger.info('Connecting to new peer', { partner_public_key });
158+
143159
const parts = partner_public_key.split('@');
144160
public_key = parts[0];
145161
await this.nodeService.addPeer(user.id, public_key, parts[1], false);
162+
163+
this.logger.info(`Connected to new peer`, { partner_public_key });
146164
}
147165

148166
const openParams = {
149-
is_private,
150-
local_tokens,
151-
chain_fee_tokens_per_vbyte,
167+
local_tokens: channel_size,
152168
partner_public_key: public_key,
153-
give_tokens: Math.min(pushTokens, local_tokens),
169+
...(is_private ? { is_private } : {}),
170+
...(give_tokens ? { give_tokens } : {}),
171+
...(chain_fee_tokens_per_vbyte ? { chain_fee_tokens_per_vbyte } : {}),
172+
...(is_max_funding ? { is_max_funding } : {}),
173+
...(base_fee_mtokens ? { base_fee_mtokens } : {}),
174+
...(fee_rate ? { fee_rate } : {}),
154175
};
155176

156-
this.logger.info('Opening channel with params', { openParams });
157-
158177
const info = await this.nodeService.openChannel(user.id, openParams);
159178

160-
this.logger.info('Channel opened');
179+
this.logger.info('Channel opened with params', {
180+
params: openParams,
181+
result: info,
182+
});
161183

162184
return {
163185
transactionId: info.transaction_id,

src/server/modules/api/channels/channels.types.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,23 @@ export class UpdateRoutingFeesParams {
262262
@Field({ nullable: true })
263263
min_htlc_mtokens?: string;
264264
}
265+
266+
@InputType()
267+
export class OpenChannelParams {
268+
@Field()
269+
partner_public_key: string;
270+
@Field({ nullable: true })
271+
channel_size: number;
272+
@Field({ nullable: true })
273+
is_private: boolean;
274+
@Field({ nullable: true })
275+
is_max_funding: boolean;
276+
@Field({ nullable: true, defaultValue: 0 })
277+
give_tokens: number;
278+
@Field({ nullable: true })
279+
chain_fee_tokens_per_vbyte: number;
280+
@Field({ nullable: true })
281+
base_fee_mtokens: string;
282+
@Field({ nullable: true })
283+
fee_rate: number;
284+
}

0 commit comments

Comments
 (0)