Skip to content

Commit

Permalink
Merge pull request #3 from diamondhands-dev/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
yuyaogawa authored Jan 18, 2023
2 parents 9bcf0dc + ae50190 commit 1884da8
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 5 deletions.
3 changes: 3 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ otpsecretpath = "/home/boltz/.boltz/otpSecret.dat"
# - Kraken
# - Poloniex
# - "fee": percentage of the swapped amount that should be charged as fee
# - "swapInFee" (optional): percentage of the swapped in amount that should be charged as fee
# "fee" is applied if this is not configured

[[pairs]]
base = "LTC"
Expand All @@ -109,6 +111,7 @@ base = "LTC"
quote = "LTC"
rate = 1
fee = 0.5
swapInFee = 1.0
timeoutDelta = 300

# The array "currencies" configures the chain and LND clients for the "pairs"
Expand Down
2 changes: 2 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
jinja2<3.1.0
Markdown<3.2
1 change: 1 addition & 0 deletions lib/consts/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export type PairConfig = {

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

// If there is a hardcoded rate the APIs of the exchanges will not be queried
rate?: number;
Expand Down
15 changes: 15 additions & 0 deletions lib/rates/FeeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type MinerFees = {
class FeeProvider {
// A map between the symbols of the pairs and their percentage fees
public percentageFees = new Map<string, number>();
public percentageSwapInFees = new Map<string, number>();

public minerFees = new Map<string, MinerFees>();

Expand Down Expand Up @@ -65,6 +66,9 @@ class FeeProvider {
}

this.percentageFees.set(getPairId(pair), percentage / 100);

const percentageSwapIn = pair.swapInFee !== undefined ? pair.swapInFee : 0;
this.percentageSwapInFees.set(getPairId(pair), percentageSwapIn / 100);
});

this.logger.debug(`Prepared data for fee estimations: ${stringify(mapToObject(this.percentageFees))}`);
Expand All @@ -74,6 +78,10 @@ class FeeProvider {
return this.percentageFees.get(pair) || 0;
};

public getPercentageSwapInFee = (pair: string): number => {
return this.percentageSwapInFees.get(pair) || 0;
};

public getFees = (
pair: string,
rate: number,
Expand All @@ -83,18 +91,25 @@ class FeeProvider {
): {
baseFee: number,
percentageFee: number,
percentageSwapInFee: number,
} => {
let percentageFee = this.getPercentageFee(pair);
let percentageSwapInFee = this.getPercentageSwapInFee(pair);

if (percentageFee !== 0) {
percentageFee = percentageFee * amount * rate;
}

if (percentageSwapInFee !== 0) {
percentageSwapInFee = percentageSwapInFee * amount * rate;
}

const { base, quote } = splitPairId(pair);
const chainCurrency = getChainCurrency(base, quote, orderSide, type !== BaseFeeType.NormalClaim);

return {
percentageFee: Math.ceil(percentageFee),
percentageSwapInFee: Math.ceil(percentageSwapInFee),
baseFee: this.getBaseFee(chainCurrency, type),
};
};
Expand Down
9 changes: 9 additions & 0 deletions lib/rates/RateProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type PairType = {
};
fees: {
percentage: number;
swapInFee: number;
minerFees: {
baseAsset: MinerFees,
quoteAsset: MinerFees,
Expand Down Expand Up @@ -64,6 +65,7 @@ class RateProvider {

// A copy of the "percentageFees" Map in the FeeProvider but all values are multiplied with 100
private percentageFees = new Map<string, number>();
private percentageSwapInFees = new Map<string, number>();

private timer!: any;

Expand All @@ -83,6 +85,11 @@ class RateProvider {
this.percentageFees.set(pair, percentage * 100);
});

this.feeProvider.percentageSwapInFees.forEach((swapInFee, pair) => {
// Multiply with 100 to get the percentage
this.percentageSwapInFees.set(pair, swapInFee * 100);
});

await this.updateMinerFees();

pairs.forEach((pair) => {
Expand All @@ -99,6 +106,7 @@ class RateProvider {
limits: this.getLimits(id, pair.base, pair.quote, pair.rate),
fees: {
percentage: this.percentageFees.get(id)!,
swapInFee: this.percentageSwapInFees.get(id)!,
minerFees: {
baseAsset: emptyMinerFees,
quoteAsset: emptyMinerFees,
Expand Down Expand Up @@ -189,6 +197,7 @@ class RateProvider {
hash: '',
fees: {
percentage: this.percentageFees.get(pairId)!,
swapInFee: this.percentageSwapInFees.get(pairId)!,
minerFees: {
baseAsset: this.feeProvider.minerFees.get(base)!,
quoteAsset: this.feeProvider.minerFees.get(quote)!,
Expand Down
19 changes: 14 additions & 5 deletions lib/service/Service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,9 +674,13 @@ class Service {

const rate = getRate(swap.rate!, swap.orderSide, false);

const percentageFee = this.rateProvider.feeProvider.getPercentageFee(swap.pair);
let percentageFee = this.rateProvider.feeProvider.getPercentageFee(swap.pair);
const percentageSwapInFee = this.rateProvider.feeProvider.getPercentageSwapInFee(swap.pair);
const baseFee = this.rateProvider.feeProvider.getBaseFee(onchainCurrency, BaseFeeType.NormalClaim);

if (percentageSwapInFee !== 0) {
percentageFee = percentageSwapInFee;
}
const invoiceAmount = this.calculateInvoiceAmount(swap.orderSide, rate, swap.onchainAmount, baseFee, percentageFee);

this.verifyAmount(swap.pair, rate, invoiceAmount, swap.orderSide, false);
Expand Down Expand Up @@ -730,22 +734,27 @@ class Service {

this.verifyAmount(swap.pair, rate, invoiceAmount, swap.orderSide, false);

const { baseFee, percentageFee } = this.rateProvider.feeProvider.getFees(
const { baseFee, percentageFee, percentageSwapInFee } = this.rateProvider.feeProvider.getFees(
swap.pair,
rate,
swap.orderSide,
invoiceAmount,
BaseFeeType.NormalClaim,
);
const expectedAmount = Math.floor(invoiceAmount * rate) + baseFee + percentageFee;

let serviceFee = percentageFee;
if (percentageSwapInFee !== 0) {
serviceFee = percentageSwapInFee;
}
const expectedAmount = Math.floor(invoiceAmount * rate) + baseFee + serviceFee;

if (swap.onchainAmount && expectedAmount > swap.onchainAmount) {
const maxInvoiceAmount = this.calculateInvoiceAmount(
swap.orderSide,
rate,
swap.onchainAmount,
baseFee,
this.rateProvider.feeProvider.getPercentageFee(swap.pair),
Math.max(this.rateProvider.feeProvider.getPercentageFee(swap.pair),this.rateProvider.feeProvider.getPercentageSwapInFee(swap.pair)),
);

throw Errors.INVALID_INVOICE_AMOUNT(maxInvoiceAmount);
Expand All @@ -757,7 +766,7 @@ class Service {
swap,
invoice,
expectedAmount,
percentageFee,
serviceFee,
acceptZeroConf,
this.eventHandler.emitSwapInvoiceSet,
);
Expand Down
5 changes: 5 additions & 0 deletions test/unit/rates/FeeProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@ describe('FeeProvider', () => {
base: 'LTC',
quote: 'BTC',
fee: 2,
swapInFee: -1,
},
{
base: 'BTC',
quote: 'BTC',
fee: 0,
swapInFee: -1,
},
{
base: 'LTC',
quote: 'LTC',

// The FeeProvider should set this to 1
fee: undefined,
swapInFee: undefined,
},
]);

Expand Down Expand Up @@ -112,11 +115,13 @@ describe('FeeProvider', () => {
expect(feeProvider.getFees('LTC/BTC', 2, OrderSide.BUY, amount, BaseFeeType.NormalClaim)).toEqual({
baseFee: 6120,
percentageFee: 4000000,
percentageSwapInFee: -2000000,
});

expect(feeProvider.getFees('LTC/BTC', 2, OrderSide.BUY, amount, BaseFeeType.ReverseLockup)).toEqual({
baseFee: 459,
percentageFee: 4000000,
percentageSwapInFee: -2000000,
});
});

Expand Down
14 changes: 14 additions & 0 deletions test/unit/rates/RateProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ const percentageFees = new Map<string, number>([
['BTC/BTC', 0.005],
]);

const percentageSwapInFees = new Map<string, number>([
['LTC/BTC', 0.01],
['BTC/BTC', -0.01],
]);

const minerFees = new Map<string, MinerFees>([
[
'BTC',
Expand Down Expand Up @@ -70,6 +75,7 @@ jest.mock('../../../lib/rates/FeeProvider', () => {
return {
minerFees,
percentageFees,
percentageSwapInFees,
getBaseFee: mockGetBaseFee,
updateMinerFees: mockUpdateMinerFees,
};
Expand Down Expand Up @@ -196,6 +202,14 @@ describe('RateProvider', () => {
});
});

test('should get percentage fees for swapin', () => {
const { pairs } = rateProvider;

percentageSwapInFees.forEach((_, pairId) => {
expect(pairs.get(pairId)!.fees.swapInFee).toEqual(percentageSwapInFees.get(pairId)! * 100);
});
});

test('should get miner fees', () => {
const { pairs } = rateProvider;

Expand Down
7 changes: 7 additions & 0 deletions test/unit/service/Service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ const mockInitFeeProvider = jest.fn().mockReturnValue(undefined);
const mockGetFees = jest.fn().mockReturnValue({
baseFee: 1,
percentageFee: 1,
percentageSwapInFee: 0,
});

const mockGetBaseFeeResult = 320;
Expand All @@ -248,12 +249,16 @@ const mockGetBaseFee = jest.fn().mockReturnValue(mockGetBaseFeeResult);
const mockGetPercentageFeeResult = 0.02;
const mockGetPercentageFee = jest.fn().mockReturnValue(mockGetPercentageFeeResult);

const mockGetPercentageSwapInFeeResult = 0.02;
const mockGetPercentageSwapInFee = jest.fn().mockReturnValue(mockGetPercentageSwapInFeeResult);

jest.mock('../../../lib/rates/FeeProvider', () => {
return jest.fn().mockImplementation(() => ({
init: mockInitFeeProvider,
getFees: mockGetFees,
getBaseFee: mockGetBaseFee,
getPercentageFee: mockGetPercentageFee,
getPercentageSwapInFee: mockGetPercentageSwapInFee,
}));
});

Expand Down Expand Up @@ -965,6 +970,7 @@ describe('Service', () => {
})).rejects.toEqual(Errors.SWAP_WITH_PREIMAGE_EXISTS());
});

// TODO: Add anohter test for swapInFee
test('should get swap rates', async () => {
const id = 'id';

Expand Down Expand Up @@ -993,6 +999,7 @@ describe('Service', () => {
await expect(service.getSwapRates(id)).rejects.toEqual(Errors.SWAP_NOT_FOUND(id));
});

// TODO: Add anohter test for swapInFee
test('should set invoices of swaps', async () => {
mockGetSwapResult = {
id: 'invoiceId',
Expand Down

0 comments on commit 1884da8

Please sign in to comment.