UNPKG

@sangaman/xud

Version:
260 lines 11.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = require("events"); const errors_1 = __importDefault(require("./errors")); const packets = __importStar(require("../p2p/packets/types")); const enums_1 = require("../types/enums"); const crypto_1 = require("crypto"); /** Functions to check argument validity and throw [[INVALID_ARGUMENT]] when invalid. */ const argChecks = { HAS_HOST: ({ host }) => { if (host === '') throw errors_1.default.INVALID_ARGUMENT('host must be specified'); }, HAS_ORDER_ID: ({ orderId }) => { if (orderId === '') throw errors_1.default.INVALID_ARGUMENT('orderId must be specified'); }, HAS_NODE_PUB_KEY: ({ nodePubKey }) => { if (nodePubKey === '') throw errors_1.default.INVALID_ARGUMENT('nodePubKey must be specified'); }, HAS_PAIR_ID: ({ pairId }) => { if (pairId === '') throw errors_1.default.INVALID_ARGUMENT('pairId must be specified'); }, MAX_RESULTS_NOT_NEGATIVE: ({ maxResults }) => { if (maxResults < 0) throw errors_1.default.INVALID_ARGUMENT('maxResults cannot be negative'); }, NON_ZERO_QUANTITY: ({ quantity }) => { if (quantity === 0) throw errors_1.default.INVALID_ARGUMENT('quantity must not equal 0'); }, PRICE_NON_NEGATIVE: ({ price }) => { if (price < 0) throw errors_1.default.INVALID_ARGUMENT('price cannot be negative'); }, VALID_PORT: ({ port }) => { if (port < 1024 || port > 65535 || !Number.isInteger(port)) throw errors_1.default.INVALID_ARGUMENT('port must be an integer between 1024 and 65535'); }, }; /** Class containing the available RPC methods for XUD */ class Service extends events_1.EventEmitter { /** Create an instance of available RPC methods and bind all exposed functions. */ constructor(logger, components) { super(); this.logger = logger; /* * Cancel placed order from the orderbook. */ this.cancelOrder = (args) => __awaiter(this, void 0, void 0, function* () { const { orderId, pairId } = args; argChecks.HAS_ORDER_ID(args); argChecks.HAS_PAIR_ID(args); const { removed, globalId } = this.orderBook.removeOwnOrderByLocalId(pairId, orderId); if (removed) { this.pool.broadcastOrderInvalidation({ pairId, orderId: globalId, }); } return { canceled: removed }; }); /** * Connect to an XU node on a given host and port. */ this.connect = (args) => __awaiter(this, void 0, void 0, function* () { const { host, port, nodePubKey } = args; argChecks.HAS_NODE_PUB_KEY(args); argChecks.HAS_HOST(args); argChecks.VALID_PORT(args); const peer = yield this.pool.addOutbound({ host, port }, nodePubKey); return peer.getStatus(); }); /* * Disconnect from a connected peer XU node on a given host and port. */ this.disconnect = (args) => __awaiter(this, void 0, void 0, function* () { const { nodePubKey } = args; argChecks.HAS_NODE_PUB_KEY(args); yield this.pool.closePeer(nodePubKey); return 'success'; }); /** * Execute an atomic swap */ this.executeSwap = ({ targetAddress, payload }) => { let body; let takerPubKey; let takerCoin; let makerCoin; if (!payload) { return 'no payload provided'; } if (targetAddress) { return 'target address provided'; } if (!payload.role || payload.role.toUpperCase() !== 'TAKER') { return 'role, if provided, must be of "taker"'; } if (!payload.receivingToken || (payload.receivingToken.toUpperCase() !== 'BTC' && payload.receivingToken.toUpperCase() !== 'LTC')) { return 'receivingToken can only be LTC or BTC'; } switch (payload.receivingToken.toUpperCase()) { case 'BTC': takerPubKey = this.lndBtcClient.pubKey; takerCoin = enums_1.CurrencyType.BTC; makerCoin = enums_1.CurrencyType.LTC; break; case 'LTC': takerPubKey = this.lndLtcClient.pubKey; takerCoin = enums_1.CurrencyType.LTC; makerCoin = enums_1.CurrencyType.BTC; break; default: return 'Invalid receiving token'; } if (!takerPubKey) { return 'Taker\'s LND is not connected'; } body = { takerCoin, makerCoin, takerPubKey, takerDealId: crypto_1.randomBytes(32).toString('hex'), takerAmount: payload.receivingAmount, makerAmount: payload.sendingAmount, }; const deal = { myRole: enums_1.SwapDealRole.Taker, takerAmount: body.takerAmount, takerCoin: body.takerCoin, takerPubKey: body.takerPubKey, takerDealId: body.takerDealId, makerAmount: body.makerAmount, makerCoin: body.makerCoin, createTime: Date.now(), }; this.pool.swapDeals.add(deal); this.logger.debug(' swap deal: ' + JSON.stringify(deal)); this.logger.debug('sending to peer ' + payload.nodePubKey + ': ' + JSON.stringify(body)); const packet = new packets.DealRequest(body); const error = this.pool.sendToPeer(payload.nodePubKey, packet); if (error) { return error.message; } // Todo: wait for swap to complete and provide the preimage back to the caller return 'Success'; }; /** * Get general information about this Exchange Union node. */ this.getInfo = () => __awaiter(this, void 0, void 0, function* () { const pairIds = this.orderBook.pairIds; let peerOrdersCount = 0; let ownOrdersCount = 0; pairIds.forEach((pairId) => { const peerOrders = this.orderBook.getPeerOrders(pairId, 0); const ownOrders = this.orderBook.getOwnOrders(pairId, 0); peerOrdersCount += Object.keys(peerOrders.buyOrders).length + Object.keys(peerOrders.sellOrders).length; ownOrdersCount += Object.keys(ownOrders.buyOrders).length + Object.keys(ownOrders.sellOrders).length; }); const lndbtc = this.lndBtcClient.isDisabled() ? undefined : yield this.lndBtcClient.getLndInfo(); const lndltc = this.lndLtcClient.isDisabled() ? undefined : yield this.lndLtcClient.getLndInfo(); const raiden = this.raidenClient.isDisabled() ? undefined : yield this.raidenClient.getRaidenInfo(); return { lndbtc, lndltc, raiden, version: this.version, numPeers: this.pool.peerCount, numPairs: pairIds.length, orders: { peer: peerOrdersCount, own: ownOrdersCount, }, }; }); /** * Get a list of standing orders from the order book for a specified trading pair. */ this.getOrders = (args) => { const { pairId, maxResults } = args; argChecks.HAS_PAIR_ID(args); argChecks.MAX_RESULTS_NOT_NEGATIVE(args); const result = { peerOrders: this.orderBook.getPeerOrders(pairId, maxResults), ownOrders: this.orderBook.getOwnOrders(pairId, maxResults), }; return result; }; /** * Get the list of the order book's available pairs. * @returns A list of available trading pairs */ this.getPairs = () => { return this.orderBook.pairs; }; /** * Get information about currently connected peers. * @returns A list of connected peers with key information for each peer */ this.listPeers = () => { return this.pool.listPeers(); }; /** * Add an order to the order book. * If price is zero or unspecified a market order will get added. */ this.placeOrder = (args) => __awaiter(this, void 0, void 0, function* () { const { pairId, price, quantity, orderId } = args; argChecks.PRICE_NON_NEGATIVE(args); argChecks.NON_ZERO_QUANTITY(args); argChecks.HAS_PAIR_ID(args); const order = { pairId, price, quantity, localId: orderId, }; return price > 0 ? this.orderBook.addLimitOrder(order) : this.orderBook.addMarketOrder(order); }); /* * Subscribe to incoming peer orders. */ this.subscribePeerOrders = (callback) => __awaiter(this, void 0, void 0, function* () { this.orderBook.on('peerOrder.incoming', order => callback(order)); this.orderBook.on('peerOrder.invalidation', order => callback({ canceled: true, id: order.orderId, pairId: order.pairId, quantity: order.quantity, })); }); /* * Subscribe to executed swaps */ this.subscribeSwaps = (_callback) => __awaiter(this, void 0, void 0, function* () { }); this.shutdown = components.shutdown; this.orderBook = components.orderBook; this.lndBtcClient = components.lndBtcClient; this.lndLtcClient = components.lndLtcClient; this.raidenClient = components.raidenClient; this.pool = components.pool; this.config = components.config; this.version = components.version; } } exports.default = Service; //# sourceMappingURL=Service.js.map