Skip to content

Commit

Permalink
chore: improve channel open (#550)
Browse files Browse the repository at this point in the history
  • Loading branch information
apotdevin committed Jul 25, 2023
1 parent accdc5e commit f63af91
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 69 deletions.
13 changes: 12 additions & 1 deletion schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ type Mutation {
lnUrlWithdraw(amount: Float!, callback: String!, description: String, k1: String!): String!
loginAmboss: Boolean!
logout: Boolean!
openChannel(amount: Float!, isPrivate: Boolean, partnerPublicKey: String!, pushTokens: Float = 0, tokensPerVByte: Float): OpenOrCloseChannel!
openChannel(input: OpenChannelParams!): OpenOrCloseChannel!
pay(max_fee: Float!, max_paths: Float!, out: [String!], request: String!): Boolean!
pushBackup: Boolean!
removePeer(publicKey: String): Boolean!
Expand Down Expand Up @@ -548,6 +548,17 @@ type OnChainBalance {
pending: String!
}

input OpenChannelParams {
base_fee_mtokens: String
chain_fee_tokens_per_vbyte: Float
channel_size: Float
fee_rate: Float
give_tokens: Float = 0
is_max_funding: Boolean
is_private: Boolean
partner_public_key: String!
}

type OpenOrCloseChannel {
transactionId: String!
transactionOutputIndex: String!
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions src/client/src/graphql/mutations/openChannel.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import { gql } from '@apollo/client';

export const OPEN_CHANNEL = gql`
mutation OpenChannel(
$amount: Float!
$partnerPublicKey: String!
$tokensPerVByte: Float
$isPrivate: Boolean
$pushTokens: Float
) {
openChannel(
amount: $amount
partnerPublicKey: $partnerPublicKey
tokensPerVByte: $tokensPerVByte
isPrivate: $isPrivate
pushTokens: $pushTokens
) {
mutation OpenChannel($input: OpenChannelParams!) {
openChannel(input: $input) {
transactionId
transactionOutputIndex
}
Expand Down
19 changes: 13 additions & 6 deletions src/client/src/graphql/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ export type MutationCloseChannelArgs = {
};

export type MutationCreateAddressArgs = {
type?: InputMaybe<Scalars['String']['input']>;
type?: Scalars['String']['input'];
};

export type MutationCreateBaseInvoiceArgs = {
Expand Down Expand Up @@ -648,11 +648,7 @@ export type MutationLnUrlWithdrawArgs = {
};

export type MutationOpenChannelArgs = {
amount: Scalars['Float']['input'];
isPrivate?: InputMaybe<Scalars['Boolean']['input']>;
partnerPublicKey: Scalars['String']['input'];
pushTokens?: InputMaybe<Scalars['Float']['input']>;
tokensPerVByte?: InputMaybe<Scalars['Float']['input']>;
input: OpenChannelParams;
};

export type MutationPayArgs = {
Expand Down Expand Up @@ -807,6 +803,17 @@ export type OnChainBalance = {
pending: Scalars['String']['output'];
};

export type OpenChannelParams = {
base_fee_mtokens?: InputMaybe<Scalars['String']['input']>;
chain_fee_tokens_per_vbyte?: InputMaybe<Scalars['Float']['input']>;
channel_size?: InputMaybe<Scalars['Float']['input']>;
fee_rate?: InputMaybe<Scalars['Float']['input']>;
give_tokens?: InputMaybe<Scalars['Float']['input']>;
is_max_funding?: InputMaybe<Scalars['Boolean']['input']>;
is_private?: InputMaybe<Scalars['Boolean']['input']>;
partner_public_key: Scalars['String']['input'];
};

export type OpenOrCloseChannel = {
__typename?: 'OpenOrCloseChannel';
transactionId: Scalars['String']['output'];
Expand Down
75 changes: 64 additions & 11 deletions src/client/src/views/home/quickActions/openChannel/OpenChannel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ export const OpenChannelCard = ({
const [fee, setFee] = useState(0);
const [publicKey, setPublicKey] = useState(initialPublicKey);
const [privateChannel, setPrivateChannel] = useState(false);
const [isMaxFunding, setIsMaxFunding] = useState(false);
const [type, setType] = useState('fee');

const [feeRate, setFeeRate] = useState<number | null>(null);
const [baseFee, setBaseFee] = useState<number | null>(null);

const [openChannel, { loading }] = useOpenChannelMutation({
onError: error => toast.error(getErrorContent(error)),
onCompleted: () => {
Expand All @@ -59,7 +63,7 @@ export const OpenChannelCard = ({
refetchQueries: ['GetChannels', 'GetPendingChannels'],
});

const canOpen = publicKey !== '' && size > 0 && fee > 0;
const canOpen = publicKey !== '' && (size > 0 || isMaxFunding) && fee > 0;

const pushAmount =
pushType === 'none'
Expand Down Expand Up @@ -164,13 +168,57 @@ export const OpenChannelCard = ({
/>
)}
<Separation />
<InputWithDeco title={'Max Size'} noInput={true}>
<MultiButton>
{renderButton(
() => {
setIsMaxFunding(true);
setSize(0);
},
'Yes',
isMaxFunding
)}
{renderButton(() => setIsMaxFunding(false), 'No', !isMaxFunding)}
</MultiButton>
</InputWithDeco>
{!isMaxFunding ? (
<InputWithDeco
title={'Channel Size'}
value={size}
placeholder={'Sats'}
amount={size}
inputType={'number'}
inputCallback={value => setSize(Number(value))}
/>
) : null}
<Separation />
<InputWithDeco
title={'Fee Rate'}
value={feeRate}
placeholder={'ppm'}
amount={feeRate}
inputType={'number'}
inputCallback={value => {
if (value == null) {
setFeeRate(null);
} else {
setFeeRate(Number(value));
}
}}
/>
<InputWithDeco
title={'Channel Size'}
value={size}
placeholder={'Sats'}
amount={size}
title={'Base Fee'}
value={baseFee}
placeholder={'msats'}
amount={baseFee}
inputType={'number'}
inputCallback={value => setSize(Number(value))}
inputCallback={value => {
if (value == null) {
setBaseFee(null);
} else {
setBaseFee(Number(value));
}
}}
/>
<Separation />
{fetchFees && !dontShow && (
Expand Down Expand Up @@ -243,11 +291,16 @@ export const OpenChannelCard = ({
onClick={() =>
openChannel({
variables: {
amount: size,
partnerPublicKey: publicKey || '',
tokensPerVByte: fee,
isPrivate: privateChannel,
pushTokens: pushAmount,
input: {
channel_size: size,
partner_public_key: publicKey || '',
is_private: privateChannel,
is_max_funding: isMaxFunding,
give_tokens: pushAmount,
chain_fee_tokens_per_vbyte: fee,
base_fee_mtokens: baseFee == null ? undefined : baseFee + '',
fee_rate: feeRate,
},
},
})
}
Expand Down
48 changes: 35 additions & 13 deletions src/server/modules/api/channels/channels.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { getChannelAge } from './channels.helpers';
import {
Channel,
ClosedChannel,
OpenChannelParams,
OpenOrCloseChannel,
PendingChannel,
SingleChannel,
UpdateRoutingFeesParams,
} from './channels.types';
import { GraphQLError } from 'graphql';

@Resolver()
export class ChannelsResolver {
Expand Down Expand Up @@ -130,34 +132,54 @@ export class ChannelsResolver {
@Mutation(() => OpenOrCloseChannel)
async openChannel(
@CurrentUser() user: UserId,
@Args('amount') local_tokens: number,
@Args('partnerPublicKey') partner_public_key: string,
@Args('isPrivate', { nullable: true }) is_private: boolean,
@Args('pushTokens', { nullable: true, defaultValue: 0 }) pushTokens: number,
@Args('tokensPerVByte', { nullable: true })
chain_fee_tokens_per_vbyte: number
@Args('input') input: OpenChannelParams
) {
const {
channel_size = 0,
partner_public_key,
is_private,
is_max_funding,
give_tokens = 0,
chain_fee_tokens_per_vbyte,
base_fee_mtokens,
fee_rate,
} = input;

if (!channel_size && !is_max_funding) {
throw new GraphQLError('You need to specify a channel size.');
}

this.logger.info('Starting opening channel attempt', { input });

let public_key = partner_public_key;

if (partner_public_key.indexOf('@') >= 0) {
this.logger.info('Connecting to new peer', { partner_public_key });

const parts = partner_public_key.split('@');
public_key = parts[0];
await this.nodeService.addPeer(user.id, public_key, parts[1], false);

this.logger.info(`Connected to new peer`, { partner_public_key });
}

const openParams = {
is_private,
local_tokens,
chain_fee_tokens_per_vbyte,
local_tokens: channel_size,
partner_public_key: public_key,
give_tokens: Math.min(pushTokens, local_tokens),
...(is_private ? { is_private } : {}),
...(give_tokens ? { give_tokens } : {}),
...(chain_fee_tokens_per_vbyte ? { chain_fee_tokens_per_vbyte } : {}),
...(is_max_funding ? { is_max_funding } : {}),
...(base_fee_mtokens ? { base_fee_mtokens } : {}),
...(fee_rate ? { fee_rate } : {}),
};

this.logger.info('Opening channel with params', { openParams });

const info = await this.nodeService.openChannel(user.id, openParams);

this.logger.info('Channel opened');
this.logger.info('Channel opened with params', {
params: openParams,
result: info,
});

return {
transactionId: info.transaction_id,
Expand Down
20 changes: 20 additions & 0 deletions src/server/modules/api/channels/channels.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,23 @@ export class UpdateRoutingFeesParams {
@Field({ nullable: true })
min_htlc_mtokens?: string;
}

@InputType()
export class OpenChannelParams {
@Field()
partner_public_key: string;
@Field({ nullable: true })
channel_size: number;
@Field({ nullable: true })
is_private: boolean;
@Field({ nullable: true })
is_max_funding: boolean;
@Field({ nullable: true, defaultValue: 0 })
give_tokens: number;
@Field({ nullable: true })
chain_fee_tokens_per_vbyte: number;
@Field({ nullable: true })
base_fee_mtokens: string;
@Field({ nullable: true })
fee_rate: number;
}

0 comments on commit f63af91

Please sign in to comment.