From 7c76a3d2bf38cd2e39289be583cb6d27f508973b Mon Sep 17 00:00:00 2001 From: Offer Markovich Date: Sat, 29 Jun 2019 19:03:07 +0300 Subject: [PATCH] feat(swaps): prevent raiden from being first leg This prevents Raiden based currencies from being the first leg of a swap. It better calculates the maker CLTV by using a cltv-delta of 5760 for raiden. This is the first step towards a more robust approach. Co-authored-by: Daniel McNally --- lib/http/HttpService.ts | 1 + lib/raidenclient/RaidenClient.ts | 5 +++-- lib/swaps/SwapClientManager.ts | 4 ++-- lib/swaps/Swaps.ts | 32 +++++++++++++++++++++++++++++--- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/lib/http/HttpService.ts b/lib/http/HttpService.ts index bf204b790..75dc00b53 100644 --- a/lib/http/HttpService.ts +++ b/lib/http/HttpService.ts @@ -5,6 +5,7 @@ class HttpService { constructor(private service: Service) {} public resolveHashRaiden = async (resolveRequest: RaidenResolveRequest): Promise => { + // TODO: add reveal_timeout, settle time out, token, etc const secret = await this.service.resolveHash({ rHash: resolveRequest.secrethash.slice(2), amount: resolveRequest.amount, diff --git a/lib/raidenclient/RaidenClient.ts b/lib/raidenclient/RaidenClient.ts index f4ab6ca23..b63933a9e 100644 --- a/lib/raidenclient/RaidenClient.ts +++ b/lib/raidenclient/RaidenClient.ts @@ -33,7 +33,7 @@ async function parseResponseBody(res: http.IncomingMessage): Promise { */ class RaidenClient extends SwapClient { public readonly type = SwapClientType.Raiden; - public readonly cltvDelta: number = 1; + public readonly cltvDelta: number = 5760; public address?: string; /** A map of currency symbols to token addresses. */ public tokenAddresses = new Map(); @@ -151,8 +151,9 @@ class RaidenClient extends SwapClient { public getRoutes = async (_amount: number, _destination: string) => { // stub placeholder, query routes not currently implemented in raiden + // assume a fixed lock time of 100 Raiden's blocks return [{ - getTotalTimeLock: () => 1, + getTotalTimeLock: () => 101, }]; } diff --git a/lib/swaps/SwapClientManager.ts b/lib/swaps/SwapClientManager.ts index ca2cf5680..1f31daa39 100644 --- a/lib/swaps/SwapClientManager.ts +++ b/lib/swaps/SwapClientManager.ts @@ -10,11 +10,11 @@ import { Models } from '../db/DB'; import { SwapClientType } from '../constants/enums'; import { EventEmitter } from 'events'; -function isRaidenClient(swapClient: SwapClient): swapClient is RaidenClient { +export function isRaidenClient(swapClient: SwapClient): swapClient is RaidenClient { return (swapClient.type === SwapClientType.Raiden); } -function isLndClient(swapClient: SwapClient): swapClient is LndClient { +export function isLndClient(swapClient: SwapClient): swapClient is LndClient { return (swapClient.type === SwapClientType.Lnd); } diff --git a/lib/swaps/Swaps.ts b/lib/swaps/Swaps.ts index 3cc74b5b9..c54aee6d7 100644 --- a/lib/swaps/Swaps.ts +++ b/lib/swaps/Swaps.ts @@ -12,7 +12,7 @@ import { SwapDealInstance } from '../db/types'; import { SwapDeal, SwapSuccess, SanitySwap, ResolveRequest } from './types'; import { generatePreimageAndHash, setTimeoutPromise } from '../utils/utils'; import { PacketType } from '../p2p/packets'; -import SwapClientManager from './SwapClientManager'; +import SwapClientManager, { isRaidenClient } from './SwapClientManager'; import { errors } from './errors'; export type OrderToAccept = Pick & { @@ -433,6 +433,29 @@ class Swaps extends EventEmitter { const { makerCurrency, makerAmount, takerCurrency, takerAmount } = Swaps.calculateMakerTakerAmounts(quantity, price, isBuy, requestBody.pairId); + const makerSwapClient = this.swapClientManager.get(makerCurrency)!; + if (!makerSwapClient) { + await this.sendErrorToPeer({ + peer, + rHash, + failureReason: SwapFailureReason.SwapClientNotSetup, + errorMessage: 'Unsupported maker currency', + reqId: requestPacket.header.id, + }); + return false; + } + + if (isRaidenClient(makerSwapClient)) { + await this.sendErrorToPeer({ + peer, + rHash, + failureReason: SwapFailureReason.InvalidSwapRequest, + errorMessage: 'Raiden based tokens can not be first leg', + reqId: requestPacket.header.id, + }); + return false; + } + const takerSwapClient = this.swapClientManager.get(takerCurrency); if (!takerSwapClient) { await this.sendErrorToPeer({ @@ -558,7 +581,6 @@ class Swaps extends EventEmitter { return false; } - const makerSwapClient = this.swapClientManager.get(makerCurrency)!; try { await makerSwapClient.addInvoice(deal.rHash, deal.makerAmount, deal.makerCltvDelta); } catch (err) { @@ -681,12 +703,16 @@ class Swaps extends EventEmitter { let expectedAmount: number; let source: string; let destination: string; - + // TODO: check cltv value switch (deal.role) { case SwapRole.Maker: expectedAmount = deal.makerAmount; source = 'Taker'; destination = 'Maker'; + if (deal.makerCltvDelta! > 50 * 2) { + this.failDeal(deal, SwapFailureReason.InvalidResolveRequest, 'Wrong CLTV received on first leg'); + return false; + } break; case SwapRole.Taker: expectedAmount = deal.takerAmount;