Skip to content

Commit

Permalink
Rebased
Browse files Browse the repository at this point in the history
  • Loading branch information
rsercano committed Nov 9, 2020
2 parents 1dc4425 + f0b2ac9 commit 98770f0
Show file tree
Hide file tree
Showing 43 changed files with 1,070 additions and 865 deletions.
8 changes: 4 additions & 4 deletions docs/api.md

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

12 changes: 6 additions & 6 deletions lib/Xud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ class Xud extends EventEmitter {
nodeKey = await NodeKey.generate();
await nodeKey.toFile(nodeKeyPath);
}

// we need to initialize connext every time xud starts, even in noencrypt mode
// the call below is in lieu of the UnlockNode/CreateNode call flow
await this.swapClientManager.initConnext(
nodeKey.childSeed(SwapClientType.Connext),
);
} else if (this.rpcServer) {
this.rpcServer.grpcService.locked = true;
const initService = new InitService(this.swapClientManager, nodeKeyPath, nodeKeyExists, this.config.dbpath);
Expand Down Expand Up @@ -194,12 +200,6 @@ class Xud extends EventEmitter {
// wait for components to initialize in parallel
await Promise.all(initPromises);

// We initialize Connext separately because it
// requires a NodeKey.
await this.swapClientManager.initConnext(
nodeKey.childSeed(SwapClientType.Connext),
);

// initialize pool and start listening/connecting only once other components are initialized
await this.pool.init();

Expand Down
16 changes: 14 additions & 2 deletions lib/cli/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ const loadXudConfig = async (argv: Arguments<any>) => {
}
};

const getTlsCert = (certPath: string) => {
try {
return fs.readFileSync(certPath);
} catch (err) {
if (err.code === 'ENOENT') {
throw `tls cert could not be found at ${certPath}, it may take several seconds to be created on xud's first run`;
}

throw err;
}
};

/**
* A generic function to instantiate an XU client.
* @param argv the command line arguments
Expand All @@ -46,7 +58,7 @@ export const loadXudClient = async (argv: Arguments<any>) => {
await loadXudConfig(argv);

const certPath = argv.tlscertpath || path.join(argv.xudir, 'tls.cert');
const cert = fs.readFileSync(certPath);
const cert = getTlsCert(certPath);
const credentials = grpc.credentials.createSsl(cert);

return new XudClient(`${argv.rpchost}:${argv.rpcport}`, credentials);
Expand All @@ -56,7 +68,7 @@ export const loadXudInitClient = async (argv: Arguments<any>) => {
await loadXudConfig(argv);

const certPath = argv.tlscertpath || path.join(argv.xudir, 'tls.cert');
const cert = fs.readFileSync(certPath);
const cert = getTlsCert(certPath);
const credentials = grpc.credentials.createSsl(cert);

return new XudInitClient(`${argv.rpchost}:${argv.rpcport}`, credentials);
Expand Down
4 changes: 4 additions & 0 deletions lib/cli/commands/openchannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export const builder = (argv: Argv) => argv
.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>) => {
if (isNaN(argv.amount)) {
throw 'amount must be a number';
}

const request = new OpenChannelRequest();
if (argv.node_identifier) {
request.setNodeIdentifier(argv.node_identifier);
Expand Down
8 changes: 4 additions & 4 deletions lib/cli/commands/tradinglimits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const HEADERS = [
colors.blue('Currency'),
colors.blue('Max Buy'),
colors.blue('Max Sell'),
colors.blue('Reserved Outbound'),
colors.blue('Reserved Inbound'),
colors.blue('Reserved Buy'),
colors.blue('Reserved Sell'),
];

const formatTradingLimits = (tradingLimits: TradingLimitsResponse.AsObject) => {
Expand All @@ -23,8 +23,8 @@ const formatTradingLimits = (tradingLimits: TradingLimitsResponse.AsObject) => {
currency,
`${satsToCoinsStr(tradingLimit.maxBuy)}`,
`${satsToCoinsStr(tradingLimit.maxSell)}`,
`${satsToCoinsStr(tradingLimit.reservedOutbound)}`,
`${satsToCoinsStr(tradingLimit.reservedInbound)}`,
`${satsToCoinsStr(tradingLimit.reservedBuy)}`,
`${satsToCoinsStr(tradingLimit.reservedSell)}`,
);
formatted.push(row);
});
Expand Down
24 changes: 17 additions & 7 deletions lib/connextclient/ConnextClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class ConnextClient extends SwapClient {
public address?: string;
/** A map of currency symbols to token addresses. */
public tokenAddresses = new Map<string, string>();
public userIdentifier?: string;
/**
* A map of expected invoices by hash.
* This is equivalent to invoices of lnd with the difference
Expand Down Expand Up @@ -259,10 +260,6 @@ class ConnextClient extends SwapClient {
});
}

public totalOutboundAmount = (currency: string): number => {
return this.outboundAmounts.get(currency) || 0;
}

/**
* Checks whether we have a pending collateral request for the currency and,
* if one doesn't exist, starts a new request for the specified amount. Then
Expand All @@ -285,6 +282,10 @@ class ConnextClient extends SwapClient {
this.requestCollateralPromises.set(currency, requestCollateralPromise);
}

/**
* Checks whether there is sufficient inbound capacity to receive the specified amount
* and throws an error if there isn't, otherwise does nothing.
*/
public checkInboundCapacity = (inboundAmount: number, currency: string) => {
const inboundCapacity = this.inboundAmounts.get(currency) || 0;
if (inboundCapacity < inboundAmount) {
Expand Down Expand Up @@ -371,9 +372,9 @@ class ConnextClient extends SwapClient {
this.subscribeIncomingTransfer(),
this.subscribeDeposit(),
]);
const { userIdentifier } = config;
this.userIdentifier = config.userIdentifier;
this.emit('connectionVerified', {
newIdentifier: userIdentifier,
newIdentifier: this.userIdentifier,
});
this.setStatus(ClientStatus.ConnectionVerified);
} catch (err) {
Expand Down Expand Up @@ -768,7 +769,16 @@ class ConnextClient extends SwapClient {
if (!currency) {
throw errors.CURRENCY_MISSING;
}
const amount = units || (await this.getBalance(currency)).freeBalanceOffChain;
const { freeBalanceOffChain } = await this.getBalance(currency);
const availableUnits = Number(freeBalanceOffChain);
if (units && availableUnits < units) {
throw errors.INSUFFICIENT_BALANCE;
}
const amount = units || freeBalanceOffChain;

if (Number(amount) === 0) {
return []; // there is nothing to withdraw and no tx to return
}

const withdrawResponse = await this.sendRequest('/withdraw', 'POST', {
recipient: destination,
Expand Down
8 changes: 4 additions & 4 deletions lib/grpc/GrpcService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,8 @@ class GrpcService {
const tradingLimits = new xudrpc.TradingLimits();
tradingLimits.setMaxSell(tradingLimitsObj.maxSell);
tradingLimits.setMaxBuy(tradingLimitsObj.maxBuy);
tradingLimits.setReservedInbound(tradingLimitsObj.reservedInbound);
tradingLimits.setReservedOutbound(tradingLimitsObj.reservedOutbound);
tradingLimits.setReservedSell(tradingLimitsObj.reservedSell);
tradingLimits.setReservedBuy(tradingLimitsObj.reservedBuy);
limitsMap.set(currency, tradingLimits);
});
callback(null, response);
Expand Down Expand Up @@ -883,10 +883,10 @@ class GrpcService {

const cancelled$ = getCancelled$(call);

this.service.subscribeOrders(call.request.toObject(), (order?: Order, orderRemoval?: OrderPortion) => {
this.service.subscribeOrders(call.request.toObject(), (order?: ServiceOrder, orderRemoval?: OrderPortion) => {
const orderUpdate = new xudrpc.OrderUpdate();
if (order) {
orderUpdate.setOrder(createOrder(order));
orderUpdate.setOrder(createServiceOrder(order));
} else if (orderRemoval) {
const grpcOrderRemoval = new xudrpc.OrderRemoval();
grpcOrderRemoval.setPairId(orderRemoval.pairId);
Expand Down
4 changes: 3 additions & 1 deletion lib/grpc/getGrpcError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ const getGrpcError = (err: any) => {
case orderErrorCodes.CURRENCY_CANNOT_BE_REMOVED:
case orderErrorCodes.MARKET_ORDERS_NOT_ALLOWED:
case serviceErrorCodes.NOMATCHING_MODE_IS_REQUIRED:
case orderErrorCodes.INSUFFICIENT_OUTBOUND_BALANCE:
case swapErrorCodes.INSUFFICIENT_OUTBOUND_CAPACITY:
case swapErrorCodes.INSUFFICIENT_INBOUND_CAPACITY:
case orderErrorCodes.QUANTITY_ON_HOLD:
case swapErrorCodes.SWAP_CLIENT_NOT_FOUND:
case swapErrorCodes.SWAP_CLIENT_MISCONFIGURED:
case serviceErrorCodes.NO_CHANNELS_TO_CLOSE:
code = status.FAILED_PRECONDITION;
break;
case lndErrorCodes.UNAVAILABLE:
Expand Down
22 changes: 9 additions & 13 deletions lib/lndclient/LndClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ interface LndClient {

const MAXFEE = 0.03;
const BASE_MAX_CLIENT_WAIT_TIME = 6000;
const GRPC_CLIENT_OPTIONS = {
'grpc.ssl_target_name_override': 'localhost',
'grpc.default_authority': 'localhost',
};

/** A class representing a client to interact with lnd. */
class LndClient extends SwapClient {
Expand All @@ -62,7 +66,7 @@ class LndClient extends SwapClient {
private channelBackupSubscription?: ClientReadableStream<lndrpc.ChanBackupSnapshot>;
private invoiceSubscriptions = new Map<string, ClientReadableStream<lndrpc.Invoice>>();
private initRetryTimeout?: NodeJS.Timeout;
private _totalOutboundAmount = 0;
private totalOutboundAmount = 0;
private totalInboundAmount = 0;
private maxChannelOutboundAmount = 0;
private maxChannelInboundAmount = 0;
Expand Down Expand Up @@ -192,22 +196,14 @@ class LndClient extends SwapClient {
return this.chainIdentifier;
}

public totalOutboundAmount = () => {
return this._totalOutboundAmount;
}

public checkInboundCapacity = (_inboundAmount: number) => {
return; // we do not currently check inbound capacities for lnd
}

public setReservedInboundAmount = (_reservedInboundAmount: number) => {
return; // not currently used for lnd
}

/** Lnd specific procedure to mark the client as locked. */
private lock = () => {
if (!this.walletUnlocker) {
this.walletUnlocker = new WalletUnlockerClient(this.uri, this.credentials);
this.walletUnlocker = new WalletUnlockerClient(this.uri, this.credentials, GRPC_CLIENT_OPTIONS);
}
if (this.lightning) {
this.lightning.close();
Expand Down Expand Up @@ -466,7 +462,7 @@ class LndClient extends SwapClient {
}

this.logger.info(`trying to verify connection to lnd at ${this.uri}`);
this.lightning = new LightningClient(this.uri, this.credentials);
this.lightning = new LightningClient(this.uri, this.credentials, GRPC_CLIENT_OPTIONS);

try {
await this.waitForClientReady(this.lightning);
Expand Down Expand Up @@ -742,8 +738,8 @@ class LndClient extends SwapClient {
this.logger.debug(`new channel inbound capacity: ${maxInbound}`);
}

if (this._totalOutboundAmount !== totalOutboundAmount) {
this._totalOutboundAmount = totalOutboundAmount;
if (this.totalOutboundAmount !== totalOutboundAmount) {
this.totalOutboundAmount = totalOutboundAmount;
this.logger.debug(`new channel total outbound capacity: ${totalOutboundAmount}`);
}

Expand Down
47 changes: 20 additions & 27 deletions lib/orderbook/OrderBook.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import assert from 'assert';
import { EventEmitter } from 'events';
import { UnitConverter } from '../utils/UnitConverter';
import uuidv1 from 'uuid/v1';
import { SwapClientType, SwapFailureReason, SwapPhase, SwapRole } from '../constants/enums';
import { Models } from '../db/DB';
Expand All @@ -8,7 +9,6 @@ import Logger from '../Logger';
import { SwapFailedPacket, SwapRequestPacket } from '../p2p/packets';
import Peer from '../p2p/Peer';
import Pool from '../p2p/Pool';
import swapsErrors from '../swaps/errors';
import Swaps from '../swaps/Swaps';
import { SwapDeal, SwapFailure, SwapSuccess } from '../swaps/types';
import { pubKeyToAlias } from '../utils/aliasUtils';
Expand Down Expand Up @@ -121,7 +121,7 @@ class OrderBook extends EventEmitter {

const onOrderRemoved = (order: OwnOrder) => {
const { inboundCurrency, outboundCurrency, inboundAmount, outboundAmount } =
Swaps.calculateInboundOutboundAmounts(order.quantity, order.price, order.isBuy, order.pairId);
UnitConverter.calculateInboundOutboundAmounts(order.quantity, order.price, order.isBuy, order.pairId);
this.swaps.swapClientManager.subtractInboundReservedAmount(inboundCurrency, inboundAmount);
this.swaps.swapClientManager.subtractOutboundReservedAmount(outboundCurrency, outboundAmount);
};
Expand All @@ -130,7 +130,7 @@ class OrderBook extends EventEmitter {

this.on('ownOrder.added', (order) => {
const { inboundCurrency, outboundCurrency, inboundAmount, outboundAmount } =
Swaps.calculateInboundOutboundAmounts(order.quantity, order.price, order.isBuy, order.pairId);
UnitConverter.calculateInboundOutboundAmounts(order.quantity, order.price, order.isBuy, order.pairId);
this.swaps.swapClientManager.addInboundReservedAmount(inboundCurrency, inboundAmount);
this.swaps.swapClientManager.addOutboundReservedAmount(outboundCurrency, outboundAmount);
});
Expand Down Expand Up @@ -307,6 +307,11 @@ class OrderBook extends EventEmitter {
this.pairInstances.set(pairInstance.id, pairInstance);
this.addTradingPair(pairInstance.id);

this.pool.rawPeers().forEach(async (peer) => {
this.checkPeerCurrencies(peer);
await this.verifyPeerPairs(peer);
});

this.pool.updatePairs(this.pairIds);
return pairInstance;
}
Expand Down Expand Up @@ -335,7 +340,7 @@ class OrderBook extends EventEmitter {
}
const currencyInstance = await this.repository.addCurrency({ ...currency, decimalPlaces: currency.decimalPlaces || 8 });
this.currencyInstances.set(currencyInstance.id, currencyInstance);
this.swaps.swapClientManager.add(currencyInstance);
await this.swaps.swapClientManager.add(currencyInstance);
}

public removeCurrency = async (currencyId: string) => {
Expand All @@ -347,7 +352,6 @@ class OrderBook extends EventEmitter {
}
}
this.currencyInstances.delete(currencyId);
this.swaps.swapClientManager.remove(currencyId);
await currency.destroy();
} else {
throw errors.CURRENCY_DOES_NOT_EXIST(currencyId);
Expand All @@ -363,6 +367,11 @@ class OrderBook extends EventEmitter {
this.pairInstances.delete(pairId);
this.tradingPairs.delete(pairId);

this.pool.rawPeers().forEach(async (peer) => {
this.checkPeerCurrencies(peer);
await this.verifyPeerPairs(peer);
});

this.pool.updatePairs(this.pairIds);
return pair.destroy();
}
Expand Down Expand Up @@ -487,27 +496,7 @@ class OrderBook extends EventEmitter {
(order.isBuy ? tp.quoteAsk() : tp.quoteBid()) :
order.price;

const { outboundCurrency, inboundCurrency, outboundAmount, inboundAmount } =
Swaps.calculateInboundOutboundAmounts(order.quantity, price, order.isBuy, order.pairId);

// check if clients exists
const outboundSwapClient = this.swaps.swapClientManager.get(outboundCurrency);
const inboundSwapClient = this.swaps.swapClientManager.get(inboundCurrency);
if (!outboundSwapClient) {
throw swapsErrors.SWAP_CLIENT_NOT_FOUND(outboundCurrency);
}
if (!inboundSwapClient) {
throw swapsErrors.SWAP_CLIENT_NOT_FOUND(inboundCurrency);
}

// check if sufficient outbound channel capacity exists
const totalOutboundAmount = outboundSwapClient.totalOutboundAmount(outboundCurrency);
if (outboundAmount > totalOutboundAmount) {
throw errors.INSUFFICIENT_OUTBOUND_BALANCE(outboundCurrency, outboundAmount, totalOutboundAmount);
}

// check if sufficient inbound channel capacity exists
inboundSwapClient.checkInboundCapacity(inboundAmount, inboundCurrency);
await this.swaps.swapClientManager.checkSwapCapacities({ ...order, price });
}

let replacedOrderIdentifier: OrderIdentifier | undefined;
Expand Down Expand Up @@ -1022,7 +1011,11 @@ class OrderBook extends EventEmitter {
}

private removePeerPair = (peerPubKey: string, pairId: string) => {
const tp = this.getTradingPair(pairId);
const tp = this.tradingPairs.get(pairId);
if (!tp) {
return;
}

const orders = tp.removePeerOrders(peerPubKey);
orders.forEach((order) => {
this.emit('peerOrder.invalidation', order);
Expand Down
Loading

0 comments on commit 98770f0

Please sign in to comment.