Skip to content

Commit

Permalink
feat(rpc/connext): deposit & openchannel calls
Browse files Browse the repository at this point in the history
This refactors the `Deposit` and `OpenChannel` methods in `SwapClient`
to make them generic and applicable to Connext. It implements this
functionality for Connext, namely retrieiving an address for sending
funds on-chain to the Connext wallet and depositing those funds into
Connext channels.

It also refactors the `CloseChannel` call similarly, however the
Connext REST client does not currently implement a `/withdraw` endpoint
for taking funds out of Connext channels. This adds dummy code to
construct a withdraw payload and make a request.

Withdrawing coins from the on-chain Connext wallet is not currently
supported by the Connext client and so the `Withdraw` rpc call remains
specific to lnd.

Closes #1472. Closes #1473.
  • Loading branch information
sangaman committed May 27, 2020
1 parent 07c52ef commit 9d360b5
Show file tree
Hide file tree
Showing 24 changed files with 652 additions and 463 deletions.
6 changes: 4 additions & 2 deletions docs/api.md

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

35 changes: 26 additions & 9 deletions lib/cli/commands/closechannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,48 @@ import { Arguments, Argv } from 'yargs';
import { CloseChannelRequest } from '../../proto/xudrpc_pb';
import { callback, loadXudClient } from '../command';

export const command = 'closechannel <node_identifier> <currency> [--force]';
export const command = 'closechannel <currency> [node_identifier ] [--force]';

export const describe = 'close any payment channels with a peer';

export const builder = (argv: Argv) => argv
.positional('node_identifier', {
description: 'the node key or alias of the connected peer to close the channel with',
type: 'string',
})
.positional('currency', {
description: 'the ticker symbol for the currency',
type: 'string',
})
.option('node_identifier', {
description: 'the node key or alias of the connected peer to close the channel with',
type: 'string',
})
.option('force', {
type: 'boolean',
description: 'whether to force close if the peer is offline',
})
.example('$0 closechannel 028599d05b18c0c3f8028915a17d603416f7276c822b6b2d20e71a3502bd0f9e0b BTC', 'close BTC channels by node key')
.example('$0 closechannel CheeseMonkey BTC', 'close BTC channels by alias')
.example('$0 closechannel CheeseMonkey BTC --force', 'force close BTC channels by alias');
.option('destination', {
type: 'string',
description: 'the on-chain address to send funds extracted from the channel',
})
.option('amount', {
type: 'number',
description: 'for Connext only - the amount to extract from the channel',
})
.example('$0 closechannel BTC 028599d05b18c0c3f8028915a17d603416f7276c822b6b2d20e71a3502bd0f9e0b', 'close BTC channels by node key')
.example('$0 closechannel BTC CheeseMonkey', 'close BTC channels by alias')
.example('$0 closechannel BTC CheeseMonkey --force', 'force close BTC channels by alias')
.example('$0 closechannel ETH --amount 0.1', '[UNIMPLEMENTED] remove 0.1 ETH from a Connext channel');

export const handler = async (argv: Arguments<any>) => {
const request = new CloseChannelRequest();
request.setNodeIdentifier(argv.node_identifier);
if (argv.node_identifier) {
request.setNodeIdentifier(argv.node_identifier);
}
request.setCurrency(argv.currency.toUpperCase());
if (argv.destination) {
request.setDestination(argv.destination);
}
if (argv.amount) {
request.setAmount(argv.amount);
}
if (argv.force) {
request.setForce(argv.force);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/cli/commands/openchannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export const builder = (argv: Argv) => argv
})
.example('$0 openchannel BTC 0.1 028599d05b18c0c3f8028915a17d603416f7276c822b6b2d20e71a3502bd0f9e0b', 'open an 0.1 BTC channel by node key')
.example('$0 openchannel BTC 0.1 CheeseMonkey', 'open an 0.1 BTC channel by alias')
.example('$0 openchannel BTC 0.1 CheeseMonkey 0.05', 'open an 0.1 BTC channel by alias and push 0.05 to remote side');
.example('$0 openchannel BTC 0.1 CheeseMonkey 0.05', 'open an 0.1 BTC channel by alias and push 0.05 to remote side')
.example('$0 openchannel ETH 0.5', 'deposit 0.5 into an ETH Connext channel without specifying a remote node');

export const handler = async (argv: Arguments<any>) => {
const request = new OpenChannelRequest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Arguments, Argv } from 'yargs';
import { DepositRequest } from '../../proto/xudrpc_pb';
import { callback, loadXudClient } from '../command';

export const command = 'deposit <currency>';
export const command = 'walletdeposit <currency>';

export const describe = 'gets an address to deposit funds to xud';

Expand All @@ -16,5 +16,5 @@ export const builder = (argv: Argv) => argv
export const handler = async (argv: Arguments<any>) => {
const request = new DepositRequest();
request.setCurrency(argv.currency);
(await loadXudClient(argv)).deposit(request, callback(argv));
(await loadXudClient(argv)).walletDeposit(request, callback(argv));
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Arguments, Argv } from 'yargs';
import { WithdrawRequest } from '../../proto/xudrpc_pb';
import { callback, loadXudClient } from '../command';

export const command = 'withdraw [amount] [currency] [destination] [fee]';
export const command = 'walletwithdraw [amount] [currency] [destination] [fee]';

export const describe = 'withdraws on-chain funds from xud';

Expand Down Expand Up @@ -42,5 +42,5 @@ export const handler = async (argv: Arguments<any>) => {
request.setDestination(argv.destination);
request.setFee(argv.fee);

(await loadXudClient(argv)).withdraw(request, callback(argv));
(await loadXudClient(argv)).walletWithdraw(request, callback(argv));
};
37 changes: 21 additions & 16 deletions lib/connextclient/ConnextClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import SwapClient, {
SwapClientInfo,
PaymentStatus,
} from '../swaps/SwapClient';
import { SwapDeal } from '../swaps/types';
import { SwapDeal, CloseChannelParams, OpenChannelParams } from '../swaps/types';
import { UnitConverter } from '../utils/UnitConverter';
import errors, { errorCodes } from './errors';
import {
Expand Down Expand Up @@ -548,28 +548,33 @@ class ConnextClient extends SwapClient {
};
}

/**
* Deposits funds to a node
*/
public deposit = async (
{ currency, units }:
{ currency: string, units: number },
) => {
public deposit = async () => {
const clientConfig = await this.getClientConfig();
return clientConfig.signerAddress;
}

public openChannel = async ({ currency, units }: OpenChannelParams) => {
if (!currency) {
throw errors.CURRENCY_MISSING;
}
const assetId = this.getTokenAddress(currency);
await this.sendRequest('/deposit', 'POST', {
assetId,
amount: BigInt(units).toString(),
});
}

public async openChannel() {}

/**
* Closes a payment client.
* @param multisigAddress the address of the client to close
*/
public closeChannel = async (): Promise<void> => {
// not relevant for connext
public closeChannel = async ({ units, currency, destination }: CloseChannelParams): Promise<void> => {
if (!currency) {
throw errors.CURRENCY_MISSING;
}
const amount = units || (await this.channelBalance(currency)).balance;
// TODO: connext-api-client withdraw endpoint not currently implemented
await this.sendRequest('/withdraw', 'POST', {
recipient: destination,
amount: BigInt(amount).toString(),
assetId: this.tokenAddresses.get(currency),
});
}

/**
Expand Down
11 changes: 6 additions & 5 deletions lib/grpc/GrpcService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,25 +360,26 @@ class GrpcService {
}

/**
* See [[Service.deposit]]
* See [[Service.walletDeposit]]
*/
public deposit: grpc.handleUnaryCall<xudrpc.DepositRequest, xudrpc.DepositResponse> = async (call, callback) => {
public walletDeposit: grpc.handleUnaryCall<xudrpc.DepositRequest, xudrpc.DepositResponse> = async (call, callback) => {
if (!this.isReady(this.service, callback)) {
return;
}
try {
await this.service.deposit(call.request.toObject());
const address = await this.service.walletDeposit(call.request.toObject());
const response = new xudrpc.DepositResponse();
response.setAddress(address);
callback(null, response);
} catch (err) {
callback(getGrpcError(err), null);
}
}

/**
* See [[Service.withdraw]]
* See [[Service.walletWithdraw]]
*/
public withdraw: grpc.handleUnaryCall<xudrpc.WithdrawRequest, xudrpc.WithdrawResponse> = async (call, callback) => {
public walletWithdraw: grpc.handleUnaryCall<xudrpc.WithdrawRequest, xudrpc.WithdrawResponse> = async (call, callback) => {
if (!this.isReady(this.service, callback)) {
return;
}
Expand Down
38 changes: 31 additions & 7 deletions lib/lndclient/LndClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { LightningClient, WalletUnlockerClient } from '../proto/lndrpc_grpc_pb';
import * as lndrpc from '../proto/lndrpc_pb';
import swapErrors from '../swaps/errors';
import SwapClient, { ChannelBalance, ClientStatus, PaymentState, SwapClientInfo, TradingLimits } from '../swaps/SwapClient';
import { SwapDeal } from '../swaps/types';
import { SwapDeal, CloseChannelParams, OpenChannelParams } from '../swaps/types';
import { base64ToHex, hexToUint8Array } from '../utils/utils';
import errors from './errors';
import { Chain, ChannelCount, ClientMethods, LndClientConfig, LndInfo } from './types';
Expand Down Expand Up @@ -519,6 +519,11 @@ class LndClient extends SwapClient {
return this.unaryCall<lndrpc.ClosedChannelsRequest, lndrpc.ClosedChannelsResponse>('closedChannels', new lndrpc.ClosedChannelsRequest());
}

public deposit = async () => {
const depositAddress = await this.newAddress();
return depositAddress;
}

public withdraw = async ({ amount, destination, all = false, fee }: {
amount: number,
destination: string,
Expand Down Expand Up @@ -653,7 +658,7 @@ class LndClient extends SwapClient {
/**
* Gets a new address for the internal lnd wallet.
*/
public newAddress = async (addressType = lndrpc.AddressType.WITNESS_PUBKEY_HASH) => {
private newAddress = async (addressType = lndrpc.AddressType.WITNESS_PUBKEY_HASH) => {
const request = new lndrpc.NewAddressRequest();
request.setType(addressType);
const newAddressResponse = await this.unaryCall<lndrpc.NewAddressRequest, lndrpc.NewAddressResponse>('newAddress', request);
Expand Down Expand Up @@ -739,14 +744,17 @@ class LndClient extends SwapClient {
* Opens a channel given peerPubKey and amount.
*/
public openChannel = async (
{ peerIdentifier: peerPubKey, units, uris, pushUnits = 0 }:
{ peerIdentifier: string, units: number, uris?: string[], pushUnits?: number },
{ remoteIdentifier, units, uris, pushUnits = 0 }: OpenChannelParams,
): Promise<void> => {
if (!remoteIdentifier) {
// TODO: better handling for for unrecognized peers & force closing channels
throw new Error('peer not connected to swap client');
}
if (uris) {
await this.connectPeerAddresses(uris);
}

await this.openChannelSync(peerPubKey, units, pushUnits);
await this.openChannelSync(remoteIdentifier, units, pushUnits);
}

/**
Expand Down Expand Up @@ -1025,13 +1033,29 @@ class LndClient extends SwapClient {
}

/**
* Attempts to close an open channel.
* Closes any payment channels with a specified node.
*/
public closeChannel = (fundingTxId: string, outputIndex: number, force: boolean): Promise<void> => {
public closeChannel = async ({ remoteIdentifier, force = false }: CloseChannelParams) => {
const channels = (await this.listChannels()).getChannelsList();
const closePromises: Promise<void>[] = [];
channels.forEach((channel) => {
if (channel.getRemotePubkey() === remoteIdentifier) {
const [fundingTxId, outputIndex] = channel.getChannelPoint().split(':');
const closePromise = this.closeChannelSync(fundingTxId, Number(outputIndex), force);
closePromises.push(closePromise);
}
});
await Promise.all(closePromises);
}

/** A synchronous helper method for the closeChannel call */
public closeChannelSync = (fundingTxId: string, outputIndex: number, force: boolean): Promise<void> => {
return new Promise<void>((resolve, reject) => {
if (!this.lightning) {
throw(errors.UNAVAILABLE(this.currency, this.status));
}

// TODO: set delivery_address parameter after upgrading to 0.10+ lnd API proto definition
const request = new lndrpc.CloseChannelRequest();
const channelPoint = new lndrpc.ChannelPoint();
channelPoint.setFundingTxidStr(fundingTxId);
Expand Down
58 changes: 29 additions & 29 deletions lib/proto/xudrpc.swagger.json

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

Loading

0 comments on commit 9d360b5

Please sign in to comment.