Skip to content
This repository has been archived by the owner on Aug 28, 2019. It is now read-only.

Commit

Permalink
Merge pull request #78 from BoltzExchange/configurable-fee
Browse files Browse the repository at this point in the history
feat: new fee structure
  • Loading branch information
michael1011 authored Apr 2, 2019
2 parents 3afd072 + f7d76bd commit 5dbdd48
Show file tree
Hide file tree
Showing 17 changed files with 499 additions and 193 deletions.
8 changes: 7 additions & 1 deletion lib/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Config {
host: '127.0.0.1',
port: 9001,

interval: 15,
interval: 5,
};

this.boltz = {
Expand Down Expand Up @@ -90,16 +90,22 @@ class Config {
{
base: 'LTC',
quote: 'BTC',

fee: 1,
},
{
base: 'BTC',
quote: 'BTC',

fee: 0.5,
rate: 1,
},
{
base: 'LTC',
quote: 'LTC',

rate: 1,
fee: 0.5,
},
];
}
Expand Down
17 changes: 15 additions & 2 deletions lib/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,9 @@ export const getFeeSymbol = (pairId: string, orderSide: OrderSide, isReverse: bo
const { base, quote } = splitPairId(pairId);

if (isReverse) {
return orderSide === OrderSide.BUY ? quote : base;
} else {
return orderSide === OrderSide.BUY ? base : quote;
} else {
return orderSide === OrderSide.BUY ? quote : base;
}
};

Expand All @@ -216,3 +216,16 @@ export const getSuccessfulTrades = async (swapRepository: SwapRepository, revers
reverseSwaps,
};
};

/**
* Converts the reponse of the backend method "getFeeEstimation" to an object
*/
export const feeMapToObject = (feesMap: [string, number][]) => {
const response: any = {};

feesMap.forEach(([symbol, fee]) => {
response[symbol] = fee;
});

return response;
};
1 change: 0 additions & 1 deletion lib/api/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class Api {
private registerRoutes = (controller: Controller) => {
// GET requests
this.app.route('/getpairs').get(controller.getPairs);
this.app.route('/getlimits').get(controller.getLimits);
this.app.route('/getfeeestimation').get(controller.getFeeEstimation);

// POST requests
Expand Down
4 changes: 0 additions & 4 deletions lib/api/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ class Controller {
this.successResponse(res, this.service.getPairs());
}

public getLimits = async (_req: Request, res: Response) => {
this.successResponse(res, this.service.getLimits());
}

public getFeeEstimation = async (_req: Request, res: Response) => {
this.successResponse(res, await this.service.getFeeEstimation());
}
Expand Down
11 changes: 11 additions & 0 deletions lib/consts/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,14 @@ export type CurrencyConfig = {
minLocalBalance: number;
minRemoteBalance: number;
};

export type PairConfig = {
base: string;
quote: string;

// Percentage of the amount that will be charged as fee
fee?: number;

// If there is a hardcoded rate the CryptoCompare API will not be queried
rate?: number;
};
4 changes: 4 additions & 0 deletions lib/notifications/CommandHandler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Logger from '../Logger';
import Service from '../service/Service';
import DiscordClient from './DiscordClient';
import BoltzClient from '../boltz/BoltzClient';
Expand All @@ -22,6 +23,7 @@ class CommandHandler {
private commands: Map<string, CommandInfo>;

constructor(
private logger: Logger,
private service: Service,
private boltz: BoltzClient,
private discord: DiscordClient) {
Expand All @@ -44,7 +46,9 @@ class CommandHandler {
const commandInfo = this.commands.get(command.toLowerCase());

if (commandInfo) {
this.logger.silly(`Executing command: ${command}`);
await commandInfo.executor(args);

return;
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/notifications/NotificationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class NotificationProvider {
this.listenToService();

new CommandHandler(
this.logger,
this.service,
this.boltz,
this.discord,
Expand Down
54 changes: 54 additions & 0 deletions lib/rates/FeeProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Logger from '../Logger';
import { PairConfig } from '../consts/Types';
import BoltzClient from '../boltz/BoltzClient';
import { mapToObject, getPairId, feeMapToObject, stringify } from '../Utils';

class FeeProvider {
// A map between the symbols of the pairs and their percentage fees
public percentageFees = new Map<string, number>();

public static transactionSizes = {
normalClaim: 140,

reverseLockup: 153,
reverseClaim: 138,
};

constructor(private logger: Logger, private boltz: BoltzClient) {}

public init = (pairs: PairConfig[]) => {
pairs.forEach((pair) => {
// Set the configured fee or fallback to 1% if it is not defined
const percentage = pair.fee !== undefined ? pair.fee : 1;
this.percentageFees.set(getPairId(pair), percentage / 100);
});

this.logger.debug(`Prepared data for fee estimations: ${stringify(mapToObject(this.percentageFees))}`);
}

public getFee = async (pair: string, chainCurrency: string, amount: number, isReverse: boolean) => {
const feeReponse = await this.boltz.getFeeEstimation(chainCurrency);
const feeMap = feeMapToObject(feeReponse.feesMap);

const baseFee = this.getBaseFee(feeMap[chainCurrency], isReverse);

// Multiply the amount with the percentage fee or with 0 if there is no percentage fee for that pair
const percentageFee = Math.ceil((this.percentageFees.get(pair) || 0) * amount);

return baseFee + percentageFee;
}

private getBaseFee = (satPerVbyte: number, isReverse: boolean) => {
if (isReverse) {
// The lockup transaction which spends a P2WPKH output (possibly more but we assume a best case scenario here),
// locks up funds in a P2WSH swap and sends the change back to a P2WKH output has about 153 vbytes
return satPerVbyte * FeeProvider.transactionSizes.reverseLockup;
} else {
// The claim transaction which spends a nested SegWit swap output and
// sends it to a P2WPKH address has about 140 vbytes
return satPerVbyte * FeeProvider.transactionSizes.normalClaim;
}
}
}

export default FeeProvider;
Loading

0 comments on commit 5dbdd48

Please sign in to comment.