Skip to content

Commit

Permalink
feat(Lightning): specify outgoing channel id (#111)
Browse files Browse the repository at this point in the history
allows users to choose which channel to pay through on lightning

see #108
  • Loading branch information
KayBeSee authored Nov 29, 2022
1 parent c7d2141 commit 30a9d7c
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 64 deletions.
9 changes: 5 additions & 4 deletions apps/electron/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
FundingPsbtVerify,
CloseChannelRequest,
Invoice,
QueryRoutesRequest
QueryRoutesRequest,
SendPaymentRequest
} from '@lily-technologies/lnrpc';

import {
Expand Down Expand Up @@ -385,12 +386,12 @@ ipcMain.on('/close-channel', async (event, args: CloseChannelRequest) => {

ipcMain.on(
'/lightning-send-payment',
async (event, args: { config: LightningConfig; paymentRequest: string }) => {
const { config, paymentRequest } = args;
async (event, args: { config: LightningConfig; options: SendPaymentRequest }) => {
const { config, options } = args;

console.log(`(${config.id}): Sending payment...`);
try {
LightningDataProvider.sendPayment(paymentRequest, (data) => {
LightningDataProvider.sendPayment(options, (data) => {
event.reply('/lightning-send-payment', data);
});
} catch (e) {
Expand Down
4 changes: 2 additions & 2 deletions apps/express/src/routes/lightning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ router.post('/close-channel', async (req, res) => {
});

router.post('/lightning-send-payment', async (req, res) => {
const { config, paymentRequest } = req.body;
const { config, options } = req.body;

console.log(`(${config.id}): Sending payment...`);
try {
LightningDataProvider.sendPayment(paymentRequest, (data) => {
LightningDataProvider.sendPayment(options, (data) => {
if (data.status === 2 || data.status === 3) {
res.send(data);
}
Expand Down
7 changes: 4 additions & 3 deletions apps/frontend/src/frontend-middleware/BasePlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import type {
QueryRoutesRequest,
QueryRoutesResponse,
GetInfoResponse,
ChannelBalanceResponse
ChannelBalanceResponse,
SendPaymentRequest
} from '@lily-technologies/lnrpc';

import { WalletInfo } from 'bitcoin-simple-rpc';
Expand Down Expand Up @@ -82,7 +83,7 @@ export interface PlatformInterface {
broadcastTransaction(txHex: string): Promise<string>;

sendLightningPayment(
paymentRequest: string,
options: SendPaymentRequest,
config: LightningConfig,
callback: (payment: Payment) => void
): void;
Expand Down Expand Up @@ -192,7 +193,7 @@ export abstract class BasePlatform implements PlatformInterface {
abstract broadcastTransaction(txHex: string): Promise<string>;

abstract sendLightningPayment(
paymentRequest: string,
options: SendPaymentRequest,
config: LightningConfig,
callback: (payment: Payment) => void
): void;
Expand Down
9 changes: 5 additions & 4 deletions apps/frontend/src/frontend-middleware/ElectronPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import type {
LookupInvoiceMsg,
Invoice,
QueryRoutesRequest,
QueryRoutesResponse
QueryRoutesResponse,
SendPaymentRequest
} from '@lily-technologies/lnrpc';

import { WalletInfo } from 'bitcoin-simple-rpc';
Expand Down Expand Up @@ -194,13 +195,13 @@ export class ElectronPlatform extends BasePlatform {
// Lightning

async sendLightningPayment(
paymentRequest: string,
options: SendPaymentRequest,
config: LightningConfig,
callback: (payment: Payment) => void
) {
window.ipcRenderer.send('/lightning-send-payment', {
paymentRequest: paymentRequest,
config: config
options,
config
});

window.ipcRenderer.on('/lightning-send-payment', async (_event: any, ...args: any) => {
Expand Down
9 changes: 5 additions & 4 deletions apps/frontend/src/frontend-middleware/WebPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import type {
LookupInvoiceMsg,
Invoice,
QueryRoutesRequest,
QueryRoutesResponse
QueryRoutesResponse,
SendPaymentRequest
} from '@lily-technologies/lnrpc';

import { WalletInfo } from 'bitcoin-simple-rpc';
Expand Down Expand Up @@ -214,13 +215,13 @@ export class WebPlatform extends BasePlatform {
// Lightning

async sendLightningPayment(
paymentRequest: string,
options: SendPaymentRequest,
config: LightningConfig,
callback: (payment: Payment) => void
) {
const { data } = await axios.post<Payment>(`/lightning-send-payment`, {
paymentRequest: paymentRequest,
config: config
options,
config
});

callback(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,33 @@ import { classNames } from 'src/utils/other';

interface Props {
alias: string;
capacity: number;
capacity: string;
status: 'active' | 'inactive' | 'pending';
onClick: () => void;
localBalance: string;
remoteBalance: string;
selected?: boolean;
}

const ChannelRow = ({ alias, capacity, status, onClick, localBalance, remoteBalance }: Props) => (
const ChannelRow = ({
alias,
capacity,
status,
onClick,
localBalance,
remoteBalance,
selected
}: Props) => (
<tr
className='group cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 flex flex-col md:flex-row justify-between items-center py-6 md:py-2 rounded-lg'
className={classNames(
'group cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 flex flex-col md:flex-row justify-between items-center py-6 md:py-2 rounded-lg px-2',
selected
? 'border-green-900/20 bg-green-100/40 hover:bg-green-50 dark:hover:bg-green-700 active:bg-green-500/25 dark:bg-green-800'
: ''
)}
onClick={() => onClick()}
>
<td className='py-2 px-4 rounded-l-2xl'>
<td className='py-2 px-2 rounded-l-2xl'>
<ChannelHeader className='text-gray-900 dark:text-gray-300'>{alias}</ChannelHeader>
<ChannelSubheader className='flex items-center'>
<span className='relative flex'>
Expand All @@ -35,7 +49,7 @@ const ChannelRow = ({ alias, capacity, status, onClick, localBalance, remoteBala
)}
></span>
</span>
<Unit value={capacity} />
<Unit value={Number(capacity)} />
</ChannelSubheader>
</td>

Expand All @@ -44,15 +58,15 @@ const ChannelRow = ({ alias, capacity, status, onClick, localBalance, remoteBala
<span className='flex-1 flex justify-end'>
<span
className='bg-blue-500 rounded-l-lg text-blue-50 dark:text-white text-xs font-bold text-right whitespace-nowrap px-2 py-2'
style={{ width: `${(Number(localBalance) / capacity) * 100}%` }}
style={{ width: `${(Number(localBalance) / Number(capacity)) * 100}%` }}
>
<Unit value={Number(localBalance)} />
</span>
</span>
<span className='flex-1 flex justify-start'>
<span
className='bg-green-500 rounded-r-lg text-green-50 dark:text-white text-xs font-bold whitespace-nowrap px-2 py-2'
style={{ width: `${(Number(remoteBalance) / capacity) * 100}%` }}
style={{ width: `${(Number(remoteBalance) / Number(capacity)) * 100}%` }}
>
<Unit value={Number(remoteBalance)} />
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const ChannelView = ({ currentAccount, setViewOpenChannelForm }: Props) => {
remoteBalance={channel.remoteBalance}
key={channel.channelPoint}
alias={channel.alias}
capacity={Number(channel.capacity)}
capacity={channel.capacity}
status={'pending'}
onClick={() => openInModal(<ChannelModal channel={channel} />)}
/>
Expand All @@ -69,7 +69,7 @@ const ChannelView = ({ currentAccount, setViewOpenChannelForm }: Props) => {
remoteBalance={channel.remoteBalance}
key={channel.channelPoint}
alias={channel.alias}
capacity={Number(channel.capacity)}
capacity={channel.capacity}
status={channel.active ? 'active' : 'inactive'}
onClick={() => openInModal(<ChannelModal channel={channel} />)}
/>
Expand Down
58 changes: 58 additions & 0 deletions apps/frontend/src/pages/Send/Lightning/ChannelSlideover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useContext, useState } from 'react';
import ChannelRow from 'src/pages/Lightning/Channels/ChannelView/ChannelRow';

import { AccountMapContext } from 'src/context';
import { LilyLightningAccount } from '@lily/types';

interface Props {
onSave: (outgoingChanId: string) => void;
onCancel: () => void;
onClear: () => void;
outgoingChanId: string;
}

export const ChannelSlideover = ({ onSave, outgoingChanId, onCancel, onClear }: Props) => {
const { currentAccount } = useContext(AccountMapContext);
const [pendingOutgoingChannelId, setPendingOutgoingChannelId] = useState(outgoingChanId);

return (
<div className='py-6 flex flex-col h-full'>
<h2 className='px-4 text-xl font-medium text-slate-900 dark:text-slate-100 pb-4 border-b border-slate-200 dark:border-slate-700'>
Select a channel
</h2>
<div className='px-2 py-2 flex-grow overflow-y-auto shadow-inner'>
{(currentAccount as LilyLightningAccount).channels.map((channel) => (
<ChannelRow
{...channel}
selected={pendingOutgoingChannelId === channel.chanId}
status={channel.active ? 'active' : 'inactive'}
onClick={() => setPendingOutgoingChannelId(channel.chanId)}
/>
))}
</div>

<div className='pt-4 border-t border-slate-200 dark:border-slate-700'>
<div className='text-right flex items-center justify-end px-4'>
<button
onClick={() => {
if (outgoingChanId) {
onClear();
} else {
onCancel();
}
}}
className='rounded-md border border-gray-300 bg-white py-2 px-4 text-sm font-medium text-blue-gray-900 shadow-sm hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-2'
>
{outgoingChanId ? 'Clear selection' : 'Cancel'}
</button>
<button
onClick={() => onSave(pendingOutgoingChannelId)}
className='ml-3 inline-flex justify-center disabled:opacity-50 disabled:cursor-not-allowed rounded-md border border-transparent bg-gray-800 dark:bg-slate-700 disabled:hover:bg-gray-800 dark:disabled:hover:bg-slate-700 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-gray-900 dark:hover:bg-slate-600 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-2'
>
Save
</button>
</div>
</div>
</div>
);
};
Loading

0 comments on commit 30a9d7c

Please sign in to comment.