From c33f31fc8e4d1a1bd651ad914e64e762c93b03fa Mon Sep 17 00:00:00 2001 From: michael1011 Date: Fri, 22 Feb 2019 10:56:33 +0100 Subject: [PATCH] feat: add additional field for fee of swap --- lib/Boltz.ts | 6 +- lib/proto/boltzrpc_pb.d.ts | 8 +++ lib/proto/boltzrpc_pb.js | 134 ++++++++++++++++++++++++++----------- lib/service/Service.ts | 14 ++-- lib/swap/SwapManager.ts | 10 +-- lib/wallet/Wallet.ts | 3 +- proto/boltzrpc.proto | 16 +++-- 7 files changed, 132 insertions(+), 59 deletions(-) diff --git a/lib/Boltz.ts b/lib/Boltz.ts index 24d46bac..80b0984b 100644 --- a/lib/Boltz.ts +++ b/lib/Boltz.ts @@ -68,9 +68,9 @@ class Boltz { } public start = async () => { - const promises = [ - this.db.init(), - ]; + await this.db.init(); + + const promises: Promise[] = []; this.currencies.forEach((currency) => { promises.push(this.connectChainClient(currency.chainClient)); diff --git a/lib/proto/boltzrpc_pb.d.ts b/lib/proto/boltzrpc_pb.d.ts index 7418f31e..65e97d6d 100644 --- a/lib/proto/boltzrpc_pb.d.ts +++ b/lib/proto/boltzrpc_pb.d.ts @@ -650,6 +650,9 @@ export class CreateSwapRequest extends jspb.Message { getRate(): number; setRate(value: number): void; + getFee(): number; + setFee(value: number): void; + getInvoice(): string; setInvoice(value: string): void; @@ -679,6 +682,7 @@ export namespace CreateSwapRequest { quoteCurrency: string, orderSide: OrderSide, rate: number, + fee: number, invoice: string, refundPublicKey: string, outputType: OutputType, @@ -732,6 +736,9 @@ export class CreateReverseSwapRequest extends jspb.Message { getRate(): number; setRate(value: number): void; + getFee(): number; + setFee(value: number): void; + getClaimPublicKey(): string; setClaimPublicKey(value: string): void; @@ -758,6 +765,7 @@ export namespace CreateReverseSwapRequest { quoteCurrency: string, orderSide: OrderSide, rate: number, + fee: number, claimPublicKey: string, amount: number, timeoutBlockNumber: number, diff --git a/lib/proto/boltzrpc_pb.js b/lib/proto/boltzrpc_pb.js index 0f97d3fd..d66fec4d 100644 --- a/lib/proto/boltzrpc_pb.js +++ b/lib/proto/boltzrpc_pb.js @@ -4327,10 +4327,11 @@ proto.boltzrpc.CreateSwapRequest.toObject = function(includeInstance, msg) { quoteCurrency: jspb.Message.getFieldWithDefault(msg, 2, ""), orderSide: jspb.Message.getFieldWithDefault(msg, 3, 0), rate: +jspb.Message.getFieldWithDefault(msg, 4, 0.0), - invoice: jspb.Message.getFieldWithDefault(msg, 5, ""), - refundPublicKey: jspb.Message.getFieldWithDefault(msg, 6, ""), - outputType: jspb.Message.getFieldWithDefault(msg, 7, 0), - timeoutBlockNumber: jspb.Message.getFieldWithDefault(msg, 8, 0) + fee: jspb.Message.getFieldWithDefault(msg, 5, 0), + invoice: jspb.Message.getFieldWithDefault(msg, 6, ""), + refundPublicKey: jspb.Message.getFieldWithDefault(msg, 7, ""), + outputType: jspb.Message.getFieldWithDefault(msg, 8, 0), + timeoutBlockNumber: jspb.Message.getFieldWithDefault(msg, 9, 0) }; if (includeInstance) { @@ -4384,18 +4385,22 @@ proto.boltzrpc.CreateSwapRequest.deserializeBinaryFromReader = function(msg, rea msg.setRate(value); break; case 5: + var value = /** @type {number} */ (reader.readInt64()); + msg.setFee(value); + break; + case 6: var value = /** @type {string} */ (reader.readString()); msg.setInvoice(value); break; - case 6: + case 7: var value = /** @type {string} */ (reader.readString()); msg.setRefundPublicKey(value); break; - case 7: + case 8: var value = /** @type {!proto.boltzrpc.OutputType} */ (reader.readEnum()); msg.setOutputType(value); break; - case 8: + case 9: var value = /** @type {number} */ (reader.readInt64()); msg.setTimeoutBlockNumber(value); break; @@ -4456,31 +4461,38 @@ proto.boltzrpc.CreateSwapRequest.serializeBinaryToWriter = function(message, wri f ); } + f = message.getFee(); + if (f !== 0) { + writer.writeInt64( + 5, + f + ); + } f = message.getInvoice(); if (f.length > 0) { writer.writeString( - 5, + 6, f ); } f = message.getRefundPublicKey(); if (f.length > 0) { writer.writeString( - 6, + 7, f ); } f = message.getOutputType(); if (f !== 0.0) { writer.writeEnum( - 7, + 8, f ); } f = message.getTimeoutBlockNumber(); if (f !== 0) { writer.writeInt64( - 8, + 9, f ); } @@ -4548,62 +4560,77 @@ proto.boltzrpc.CreateSwapRequest.prototype.setRate = function(value) { /** - * optional string invoice = 5; + * optional int64 fee = 5; + * @return {number} + */ +proto.boltzrpc.CreateSwapRequest.prototype.getFee = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0)); +}; + + +/** @param {number} value */ +proto.boltzrpc.CreateSwapRequest.prototype.setFee = function(value) { + jspb.Message.setProto3IntField(this, 5, value); +}; + + +/** + * optional string invoice = 6; * @return {string} */ proto.boltzrpc.CreateSwapRequest.prototype.getInvoice = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, "")); }; /** @param {string} value */ proto.boltzrpc.CreateSwapRequest.prototype.setInvoice = function(value) { - jspb.Message.setProto3StringField(this, 5, value); + jspb.Message.setProto3StringField(this, 6, value); }; /** - * optional string refund_public_key = 6; + * optional string refund_public_key = 7; * @return {string} */ proto.boltzrpc.CreateSwapRequest.prototype.getRefundPublicKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, "")); + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, "")); }; /** @param {string} value */ proto.boltzrpc.CreateSwapRequest.prototype.setRefundPublicKey = function(value) { - jspb.Message.setProto3StringField(this, 6, value); + jspb.Message.setProto3StringField(this, 7, value); }; /** - * optional OutputType output_type = 7; + * optional OutputType output_type = 8; * @return {!proto.boltzrpc.OutputType} */ proto.boltzrpc.CreateSwapRequest.prototype.getOutputType = function() { - return /** @type {!proto.boltzrpc.OutputType} */ (jspb.Message.getFieldWithDefault(this, 7, 0)); + return /** @type {!proto.boltzrpc.OutputType} */ (jspb.Message.getFieldWithDefault(this, 8, 0)); }; /** @param {!proto.boltzrpc.OutputType} value */ proto.boltzrpc.CreateSwapRequest.prototype.setOutputType = function(value) { - jspb.Message.setProto3EnumField(this, 7, value); + jspb.Message.setProto3EnumField(this, 8, value); }; /** - * optional int64 timeout_block_number = 8; + * optional int64 timeout_block_number = 9; * @return {number} */ proto.boltzrpc.CreateSwapRequest.prototype.getTimeoutBlockNumber = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 8, 0)); + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 9, 0)); }; /** @param {number} value */ proto.boltzrpc.CreateSwapRequest.prototype.setTimeoutBlockNumber = function(value) { - jspb.Message.setProto3IntField(this, 8, value); + jspb.Message.setProto3IntField(this, 9, value); }; @@ -4881,9 +4908,10 @@ proto.boltzrpc.CreateReverseSwapRequest.toObject = function(includeInstance, msg quoteCurrency: jspb.Message.getFieldWithDefault(msg, 2, ""), orderSide: jspb.Message.getFieldWithDefault(msg, 3, 0), rate: +jspb.Message.getFieldWithDefault(msg, 4, 0.0), - claimPublicKey: jspb.Message.getFieldWithDefault(msg, 5, ""), - amount: jspb.Message.getFieldWithDefault(msg, 6, 0), - timeoutBlockNumber: jspb.Message.getFieldWithDefault(msg, 7, 0) + fee: jspb.Message.getFieldWithDefault(msg, 5, 0), + claimPublicKey: jspb.Message.getFieldWithDefault(msg, 6, ""), + amount: jspb.Message.getFieldWithDefault(msg, 7, 0), + timeoutBlockNumber: jspb.Message.getFieldWithDefault(msg, 8, 0) }; if (includeInstance) { @@ -4937,14 +4965,18 @@ proto.boltzrpc.CreateReverseSwapRequest.deserializeBinaryFromReader = function(m msg.setRate(value); break; case 5: + var value = /** @type {number} */ (reader.readInt64()); + msg.setFee(value); + break; + case 6: var value = /** @type {string} */ (reader.readString()); msg.setClaimPublicKey(value); break; - case 6: + case 7: var value = /** @type {number} */ (reader.readInt64()); msg.setAmount(value); break; - case 7: + case 8: var value = /** @type {number} */ (reader.readInt64()); msg.setTimeoutBlockNumber(value); break; @@ -5005,24 +5037,31 @@ proto.boltzrpc.CreateReverseSwapRequest.serializeBinaryToWriter = function(messa f ); } + f = message.getFee(); + if (f !== 0) { + writer.writeInt64( + 5, + f + ); + } f = message.getClaimPublicKey(); if (f.length > 0) { writer.writeString( - 5, + 6, f ); } f = message.getAmount(); if (f !== 0) { writer.writeInt64( - 6, + 7, f ); } f = message.getTimeoutBlockNumber(); if (f !== 0) { writer.writeInt64( - 7, + 8, f ); } @@ -5090,47 +5129,62 @@ proto.boltzrpc.CreateReverseSwapRequest.prototype.setRate = function(value) { /** - * optional string claim_public_key = 5; + * optional int64 fee = 5; + * @return {number} + */ +proto.boltzrpc.CreateReverseSwapRequest.prototype.getFee = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0)); +}; + + +/** @param {number} value */ +proto.boltzrpc.CreateReverseSwapRequest.prototype.setFee = function(value) { + jspb.Message.setProto3IntField(this, 5, value); +}; + + +/** + * optional string claim_public_key = 6; * @return {string} */ proto.boltzrpc.CreateReverseSwapRequest.prototype.getClaimPublicKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 6, "")); }; /** @param {string} value */ proto.boltzrpc.CreateReverseSwapRequest.prototype.setClaimPublicKey = function(value) { - jspb.Message.setProto3StringField(this, 5, value); + jspb.Message.setProto3StringField(this, 6, value); }; /** - * optional int64 amount = 6; + * optional int64 amount = 7; * @return {number} */ proto.boltzrpc.CreateReverseSwapRequest.prototype.getAmount = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 6, 0)); + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0)); }; /** @param {number} value */ proto.boltzrpc.CreateReverseSwapRequest.prototype.setAmount = function(value) { - jspb.Message.setProto3IntField(this, 6, value); + jspb.Message.setProto3IntField(this, 7, value); }; /** - * optional int64 timeout_block_number = 7; + * optional int64 timeout_block_number = 8; * @return {number} */ proto.boltzrpc.CreateReverseSwapRequest.prototype.getTimeoutBlockNumber = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0)); + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 8, 0)); }; /** @param {number} value */ proto.boltzrpc.CreateReverseSwapRequest.prototype.setTimeoutBlockNumber = function(value) { - jspb.Message.setProto3IntField(this, 7, value); + jspb.Message.setProto3IntField(this, 8, value); }; diff --git a/lib/service/Service.ts b/lib/service/Service.ts index dfa16aee..80ce3736 100644 --- a/lib/service/Service.ts +++ b/lib/service/Service.ts @@ -87,6 +87,9 @@ const argChecks = { VALID_FEE_PER_VBYTE: ({ satPerVbyte }: { satPerVbyte: number }) => { if (!(satPerVbyte > 0) || satPerVbyte % 1 !== 0) throw Errors.INVALID_ARGUMENT('sat per vbyte fee must be positive integer'); }, + VALID_FEE: ({ fee }: { fee: number }) => { + if (fee < 0 || fee % 1 !== 0) throw Errors.INVALID_ARGUMENT('fee must be a positive integer'); + }, }; class Service extends EventEmitter { @@ -298,14 +301,16 @@ class Service extends EventEmitter { * Creates a new Swap from the chain to Lightning */ public createSwap = async (args: { baseCurrency: string, quoteCurrency: string, orderSide: number, rate: number - invoice: string, refundPublicKey: string, outputType: number, timeoutBlockNumber: number}) => { + fee: number, invoice: string, refundPublicKey: string, outputType: number, timeoutBlockNumber: number}) => { argChecks.VALID_CURRENCY({ currency: args.baseCurrency }); argChecks.VALID_CURRENCY({ currency: args.quoteCurrency }); argChecks.VALID_OUTPUTTYPE(args); argChecks.HAS_INVOICE(args); argChecks.HAS_REFUNDPUBKEY(args); + argChecks.VALID_FEE(args); argChecks.VALID_RATE(args); argChecks.VALID_TIMEOUT(args); + argChecks.VALID_TIMEOUT(args); const { swapManager } = this.serviceComponents; @@ -315,18 +320,19 @@ class Service extends EventEmitter { const refundPublicKey = getHexBuffer(args.refundPublicKey); return await swapManager.createSwap(args.baseCurrency, args.quoteCurrency, orderSide, - args.rate, args.invoice, refundPublicKey, outputType, args.timeoutBlockNumber); + args.rate, args.fee, args.invoice, refundPublicKey, outputType, args.timeoutBlockNumber); } /** * Creates a new Swap from Lightning to the chain */ public createReverseSwap = async (args: { baseCurrency: string, quoteCurrency: string, orderSide: number, rate: number, - claimPublicKey: string, amount: number, timeoutBlockNumber: number}) => { + fee: number, claimPublicKey: string, amount: number, timeoutBlockNumber: number}) => { argChecks.VALID_CURRENCY({ currency: args.baseCurrency }); argChecks.VALID_CURRENCY({ currency: args.quoteCurrency }); argChecks.HAS_CLAIMPUBKEY(args); argChecks.VALID_RATE(args); + argChecks.VALID_FEE(args); argChecks.VALID_TIMEOUT(args); const { swapManager } = this.serviceComponents; @@ -335,7 +341,7 @@ class Service extends EventEmitter { const claimPublicKey = getHexBuffer(args.claimPublicKey); return await swapManager.createReverseSwap(args.baseCurrency, args.quoteCurrency, orderSide, args.rate, - claimPublicKey, args.amount, args.timeoutBlockNumber); + args.fee, claimPublicKey, args.amount, args.timeoutBlockNumber); } /** diff --git a/lib/swap/SwapManager.ts b/lib/swap/SwapManager.ts index 16fea67d..0bd4bae9 100644 --- a/lib/swap/SwapManager.ts +++ b/lib/swap/SwapManager.ts @@ -40,6 +40,7 @@ class SwapManager { * @param quoteCurrency quote currency ticker symbol * @param orderSide whether the order is a buy or sell one * @param rate conversion rate of base and quote currency + * @param fee additional amount that the user has to pay * @param invoice the invoice that should be paid * @param refundPublicKey public key of the keypair needed for claiming * @param outputType what kind of adress should be returned @@ -48,7 +49,7 @@ class SwapManager { * @returns an onchain address */ public createSwap = async (baseCurrency: string, quoteCurrency: string, orderSide: OrderSide, rate: number, - invoice: string, refundPublicKey: Buffer, outputType: OutputType, timeoutBlockNumber: number) => { + fee: number, invoice: string, refundPublicKey: Buffer, outputType: OutputType, timeoutBlockNumber: number) => { const { sendingCurrency, receivingCurrency } = this.getCurrencies(baseCurrency, quoteCurrency, orderSide); @@ -73,7 +74,7 @@ class SwapManager { const outputScript = encodeFunction(redeemScript); const address = receivingCurrency.wallet.encodeAddress(outputScript); - const expectedAmount = this.calculateExpectedAmount(numSatoshis, this.getRate(rate, orderSide)); + const expectedAmount = this.calculateExpectedAmount(numSatoshis + fee, this.getRate(rate, orderSide)); receivingCurrency.swaps.set(getHexString(outputScript), { invoice, @@ -101,6 +102,7 @@ class SwapManager { * @param quoteCurrency quote currency ticker symbol * @param orderSide whether the order is a buy or sell one * @param rate conversion rate of base and quote currency + * @param fee additional amount that the user has to pay * @param claimPublicKey public key of the keypair needed for claiming * @param amount amount of the invoice * @param timeoutBlockNumber after how many blocks the onchain script should time out @@ -108,7 +110,7 @@ class SwapManager { * @returns a Lightning invoice, the lockup transaction and its hash */ public createReverseSwap = async (baseCurrency: string, quoteCurrency: string, orderSide: OrderSide, rate: number, - claimPublicKey: Buffer, amount: number, timeoutBlockNumber: number) => { + fee: number, claimPublicKey: Buffer, amount: number, timeoutBlockNumber: number) => { const { sendingCurrency, receivingCurrency } = this.getCurrencies(baseCurrency, quoteCurrency, orderSide); @@ -132,7 +134,7 @@ class SwapManager { const outputScript = p2wshOutput(redeemScript); const address = sendingCurrency.wallet.encodeAddress(outputScript); - const sendingAmount = this.calculateExpectedAmount(amount, 1 / this.getRate(rate, orderSide)); + const sendingAmount = this.calculateExpectedAmount(amount - fee, 1 / this.getRate(rate, orderSide)); const { vout, transaction } = await sendingCurrency.wallet.sendToAddress(address, OutputType.Bech32, true, sendingAmount); this.logger.debug(`Sending ${sendingAmount} on ${sendingCurrency.symbol} to swap address ${address}: ${transaction.getId()}:${vout}`); diff --git a/lib/wallet/Wallet.ts b/lib/wallet/Wallet.ts index de306e14..6ad64be9 100644 --- a/lib/wallet/Wallet.ts +++ b/lib/wallet/Wallet.ts @@ -315,7 +315,8 @@ class Wallet { builder.addOutput(address, amount); // Send the value left of the UTXOs to a new change address - builder.addOutput(await this.getNewAddress(OutputType.Bech32), toSpendSum - (amount + fee)); + const changeAddress = await this.getNewAddress(OutputType.Bech32); + builder.addOutput(changeAddress, toSpendSum - (amount + fee)); // Sign the transaction toSpend.forEach((utxo, index) => { diff --git a/proto/boltzrpc.proto b/proto/boltzrpc.proto index 8424a65d..5ccb0f5c 100644 --- a/proto/boltzrpc.proto +++ b/proto/boltzrpc.proto @@ -167,10 +167,11 @@ message CreateSwapRequest { string quote_currency = 2; OrderSide order_side = 3; float rate = 4; - string invoice = 5; - string refund_public_key = 6; - OutputType output_type = 7; - int64 timeout_block_number = 8; + int64 fee = 5; + string invoice = 6; + string refund_public_key = 7; + OutputType output_type = 8; + int64 timeout_block_number = 9; } message CreateSwapResponse { string redeem_script = 1; @@ -184,10 +185,11 @@ message CreateReverseSwapRequest { string quote_currency = 2; OrderSide order_side = 3; float rate = 4; - string claim_public_key = 5; + int64 fee = 5; + string claim_public_key = 6; // Amount of the invoice that will be returned - int64 amount = 6; - int64 timeout_block_number = 7; + int64 amount = 7; + int64 timeout_block_number = 8; } message CreateReverseSwapResponse { string invoice = 1;