Skip to content

Commit

Permalink
feat: show routing fees
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Jan 9, 2025
1 parent c76bd47 commit b1db75d
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 3 deletions.
32 changes: 32 additions & 0 deletions e2e/fees.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { expect, test } from "@playwright/test";

import { addReferral, getReferrals, setReferral } from "./utils";

const referral = "pro";

test.describe("Fees", () => {
test("should show routing fees", async ({ page }) => {
if (!(referral in (await getReferrals()))) {
await addReferral(referral);
}

const config = { maxRoutingFee: 0.001 };
await setReferral(referral, config);

await page.goto(`/?ref=${referral}`);

await page.locator(".arrow-down").first().click();
await page.getByTestId("select-BTC").click();
await page
.locator(
"div:nth-child(3) > .asset-wrap > .asset > .asset-selection > .arrow-down",
)
.click();
await page.getByTestId("select-LN").click();

const routingFees = page.getByTestId("routing-fee-limit");
await expect(routingFees).toHaveText(
`${config.maxRoutingFee * 100 * 10_000} ppm`,
);
});
});
30 changes: 30 additions & 0 deletions e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ const execCommand = async (command: string): Promise<string> => {
}
};

const boltzCli = async (command: string): Promise<string> => {
try {
const { stdout, stderr } = await execAsync(
`docker exec boltz-backend boltz-cli ${command}`,
{ shell: "/bin/bash" },
);

if (stderr) {
throw new Error(`Error executing command: ${stderr}`);
}

return stdout.trim();
} catch (error) {
console.error(`Failed to execute command: ${command}`, error);
throw error;
}
};

export const getBitcoinAddress = (): Promise<string> =>
execCommand("bitcoin-cli-sim-client getnewaddress");

Expand Down Expand Up @@ -64,6 +82,18 @@ export const generateInvoiceLnd = async (amount: number): Promise<string> => {
).payment_request as string;
};

export const addReferral = (name: string): Promise<string> =>
boltzCli(`addreferral ${name} 0`);

export const getReferrals = async (): Promise<Record<string, unknown>> =>
JSON.parse(await boltzCli(`getreferrals`)) as Record<string, unknown>;

export const setReferral = (
name: string,
config: Record<string, unknown>,
): Promise<string> =>
boltzCli(`setreferral ${name} '${JSON.stringify(config)}'`);

export const lookupInvoiceLnd = async (
invoice: string,
): Promise<{ state: string; r_preimage: string }> => {
Expand Down
23 changes: 22 additions & 1 deletion src/components/Fees.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BigNumber } from "bignumber.js";
import { createEffect } from "solid-js";
import { Show, createEffect, createSignal } from "solid-js";

import { LBTC } from "../consts/Assets";
import { SwapType } from "../consts/Enums";
Expand All @@ -19,6 +19,8 @@ import { formatAmount } from "../utils/denomination";
import { getPair } from "../utils/helper";
import Denomination from "./settings/Denomination";

const ppmFactor = 10_000;

// When sending to an unconfidential address, we need to add an extra
// confidential OP_RETURN output with 1 sat inside
const unconfidentialExtra = 5;
Expand Down Expand Up @@ -46,7 +48,15 @@ const Fees = () => {
addressValid() &&
!isConfidentialAddress(onchainAddress());

const [routingFee, setRoutingFee] = createSignal<number | undefined>(
undefined,
);

createEffect(() => {
// Reset routing fee when changing the pair
// (which might not be submarine and not set the signal)
setRoutingFee(undefined);

if (pairs()) {
const cfg = getPair(
pairs(),
Expand All @@ -61,6 +71,10 @@ const Fees = () => {

switch (swapType()) {
case SwapType.Submarine:
setRoutingFee(
(cfg as SubmarinePairTypeTaproot).fees
.maximalRoutingFee,
);
setMinerFee(
(cfg as SubmarinePairTypeTaproot).fees.minerFees,
);
Expand Down Expand Up @@ -148,6 +162,13 @@ const Fees = () => {
data-denominator={denomination()}
/>
</span>
<Show when={routingFee() !== undefined}>
<br />
{t("routing_fee_limit")}:{" "}
<span data-testid="routing-fee-limit">
{routingFee() * ppmFactor} ppm
</span>
</Show>
</label>
</div>
);
Expand Down
5 changes: 5 additions & 0 deletions src/i18n/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ const dict = {
refund_available_in: "Refund will be available in {{ blocks }} blocks",
no_wallet_connected: "No wallet connected",
no_lockup_transaction: "No lockup transaction found",
routing_fee_limit: "Routing fee limit",
},
de: {
language: "Deutsch",
Expand Down Expand Up @@ -468,6 +469,7 @@ const dict = {
refund_available_in: "Rückerstattung möglich in {{ blocks }} Blöcken",
no_wallet_connected: "Kein Wallet verbunden",
no_lockup_transaction: "Keine Lockup-Transaktion gefunden",
routing_fee_limit: "Routing Gebühr Limit",
},
es: {
language: "Español",
Expand Down Expand Up @@ -704,6 +706,7 @@ const dict = {
refund_available_in: "Reembolso disponible en {{ blocks }} bloques",
no_wallet_connected: "No hay monedero conectado",
no_lockup_transaction: "No se encontró ninguna transacción de lockup",
routing_fee_limit: "Límite de la tarifa de enrutamiento",
},
zh: {
language: "中文",
Expand Down Expand Up @@ -914,6 +917,7 @@ const dict = {
refund_available_in: "退款将分 {{ blocks }} 区块提供",
no_wallet_connected: "未连接钱包",
no_lockup_transaction: "未找到锁仓交易",
routing_fee_limit: "最大路由费用",
},
ja: {
language: "日本語",
Expand Down Expand Up @@ -1149,6 +1153,7 @@ const dict = {
refund_available_in: "返金は {{ blocks }} つのブロックに分かれる",
no_wallet_connected: "財布はつながっていない!",
no_lockup_transaction: "ロックアップトランザクションが見つかりません",
routing_fee_limit: "ルーティング料金の上限",
},
};

Expand Down
3 changes: 2 additions & 1 deletion src/utils/boltzClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ type SubmarinePairTypeTaproot = PairType & {
maximalZeroConf: number;
};
fees: {
percentage: number;
minerFees: number;
percentage: number;
maximalRoutingFee?: number;
};
};

Expand Down
8 changes: 7 additions & 1 deletion src/utils/denomination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const formatAmountDenomination = (

default: {
const chars = amount.toString().split("").reverse();
return chars
const formatted = chars
.reduce(
(acc, char, i) =>
i % 3 === 0 ? acc + " " + char : acc + char,
Expand All @@ -63,6 +63,12 @@ export const formatAmountDenomination = (
.split("")
.reverse()
.join("");

return (
formatted.includes(".") || formatted.includes(",")
? formatted.replaceAll(" .", ".").replaceAll(" ,", ",")
: formatted
).replaceAll(".", separator);
}
}
};
Expand Down
2 changes: 2 additions & 0 deletions tests/utils/denomination.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ describe("denomination utils", () => {
${Denomination.Btc} | ${1000} | ${"."} | ${"0.00001"}
${Denomination.Btc} | ${10000} | ${"."} | ${"0.0001"}
${Denomination.Btc} | ${10000} | ${","} | ${"0,0001"}
${Denomination.Sat} | ${0.12} | ${","} | ${"0,12"}
${Denomination.Sat} | ${0.24} | ${","} | ${"0,24"}
`(
"format $amount in $denomination with `$separator` separator",
({ denomination, amount, formatted, separator }) => {
Expand Down

0 comments on commit b1db75d

Please sign in to comment.