Repository: BoltzExchange/boltz-web-app
Pull request #894: Add missing denominations
Author: login: kiocos
Created: 2025-04-09T01:50:12Z | Merged: 2025-04-13T08:57:26Z

Closes #749

This PR adds most denominations we were missing and fixes the formatting of existing ones.

Some denominations are still to be added on #313.

### Screenshots

![image](https://github.com/user-attachments/assets/1c30dcc2-843e-486c-a6b7-0a2e9876f0ec)

![image](https://github.com/user-attachments/assets/ee3fb621-4053-4c52-86b5-14fc3d2cf994)

![image](https://github.com/user-attachments/assets/9fa8e0dc-beac-4380-b402-ebbef187ffdf)



Linked issue #749: Add missing denomination (sats/btc symbol)
We are missing denominations practically everywhere right now. This issue is about adding a sats or btc symbol to all amounts at once via some sort of component.
Linked issue comments: user: login: kiocos
created_at: 2025-03-24T14:46:10Z
body: Will work on this one
author_association: MEMBER
user: login: kiocos
created_at: 2025-03-26T00:24:11Z
body: @kilrau would you consider this acceptable?

![Image](https://github.com/user-attachments/assets/5a4ebfb0-8e14-49f7-94a0-8ccaa1de8466)

Adding the ₿ symbol on the i18n strings won't be trivial because we have the symbols as SVGs and currently we don't have anything [like this](https://react.i18next.com/latest/trans-component) to interpolate the HTML and the translation string.

It's simple when there's no need for interpolation:

![Image](https://github.com/user-attachments/assets/b09f1a65-7fa9-48a4-9ac9-23a1e29da932)
author_association: MEMBER
user: login: kilrau
created_at: 2025-03-26T18:17:55Z
body: > @kilrau would you consider this acceptable?

Yes.


> It's simple when there's no need for interpolation:
> 
> ![Image](https://github.com/user-attachments/assets/b09f1a65-7fa9-48a4-9ac9-23a1e29da932)

Looks nice! Is that the ₿ Unicode or our SVG? Looks like the SVG and I think it's better to stick with SVG for both, as sats need the SVG. PS: let's go with `BTC` and `sats` (lowercase, plural) in the written form for strings.
author_association: MEMBER
user: login: kiocos
created_at: 2025-03-26T18:45:26Z
body: > Looks nice! Is that the ₿ Unicode or our SVG? Looks like the SVG and I think it's better to stick with SVG for both, as sats need the SVG. 

Yes, it's the SVG. 

>PS: let's go with `BTC` and `sats` (lowercase, plural) in the written form for strings.

Sounds good to me!
author_association: MEMBER
user: login: kilrau
created_at: 2025-04-07T09:07:33Z
body: Got a PR for this one?
author_association: MEMBER

Diff:
diff --git a/src/components/CreateButton.tsx b/src/components/CreateButton.tsx
index 400527864..84236e282 100644
--- a/src/components/CreateButton.tsx
+++ b/src/components/CreateButton.tsx
@@ -17,7 +17,7 @@ import { customDerivationPathRdns, useWeb3Signer } from "../context/Web3";
 import { GasNeededToClaim, getSmartWalletAddress } from "../rif/Signer";
 import type { Pairs } from "../utils/boltzClient";
 import { fetchBolt12Invoice, getPairs } from "../utils/boltzClient";
-import { formatAmount } from "../utils/denomination";
+import { formatAmount, formatDenomination } from "../utils/denomination";
 import { formatError } from "../utils/errors";
 import type { HardwareSigner } from "../utils/hardware/HadwareSigner";
 import { coalesceLn, isMobile } from "../utils/helper";
@@ -274,6 +274,7 @@ const CreateButton = () => {
                 minimum,
                 assetReceive,
                 bolt12Offer,
+                denomination,
             ],
             () => {
                 if (!online()) {
@@ -303,7 +304,10 @@ const CreateButton = () => {
                                 denomination(),
                                 separator(),
                             ),
-                            denomination: denomination(),
+                            denomination: formatDenomination(
+                                denomination(),
+                                assetSend(),
+                            ),
                         },
                     });
                     return;
diff --git a/src/pages/Create.tsx b/src/pages/Create.tsx
index 43f151c07..16102f1f8 100644
--- a/src/pages/Create.tsx
+++ b/src/pages/Create.tsx
@@ -25,6 +25,7 @@ import {
     calculateDigits,
     convertAmount,
     formatAmount,
+    formatDenomination,
     getValidationRegex,
 } from "../utils/denomination";
 import { isMobile } from "../utils/helper";
@@ -213,7 +214,7 @@ const Create = () => {
                     denomination(),
                     separator(),
                 ),
-                denomination: denomination(),
+                denomination: formatDenomination(denomination(), assetSend()),
             };
             const label = lessThanMin ? "minimum_amount" : "maximum_amount";
             const errorMsg = t(label, params);
@@ -322,29 +323,41 @@ const Create = () => {
             <div class="frame">
                 <SettingsCog />
                 <h2 data-testid="create-swap-title">{t("create_swap")}</h2>
-                <p>
-                    {t("create_swap_subline")} <br />
-                    {t("send")} {t("min")}:{" "}
-                    <span
-                        onClick={() => setAmount(minimum())}
-                        class="btn-small btn-light">
-                        {formatAmount(
-                            BigNumber(minimum()),
-                            denomination(),
-                            separator(),
-                        )}
-                    </span>{" "}
-                    {t("max")}:{" "}
-                    <span
-                        onClick={() => setAmount(maximum())}
-                        class="btn-small btn-light">
-                        {formatAmount(
-                            BigNumber(maximum()),
-                            denomination(),
-                            separator(),
-                        )}
-                    </span>{" "}
-                </p>
+                {t("create_swap_subline")} <br />
+                <span class="swap-limits">
+                    <span>
+                        {t("send")} {t("min")}:
+                        <span
+                            onClick={() => setAmount(minimum())}
+                            class="btn-small btn-light">
+                            {formatAmount(
+                                BigNumber(minimum()),
+                                denomination(),
+                                separator(),
+                            )}
+                        </span>
+                        <span
+                            class="denominator"
+                            data-denominator={denomination()}
+                        />
+                    </span>
+                    <span>
+                        {t("max")}
+                        <span
+                            onClick={() => setAmount(maximum())}
+                            class="btn-small btn-light">
+                            {formatAmount(
+                                BigNumber(maximum()),
+                                denomination(),
+                                separator(),
+                            )}
+                        </span>
+                        <span
+                            class="denominator"
+                            data-denominator={denomination()}
+                        />
+                    </span>
+                </span>
                 <div class="icons">
                     <div>
                         <Asset side={Side.Send} signal={assetSend} />
diff --git a/src/status/TransactionClaimed.tsx b/src/status/TransactionClaimed.tsx
index fd21d62ca..a7195ee63 100644
--- a/src/status/TransactionClaimed.tsx
+++ b/src/status/TransactionClaimed.tsx
@@ -10,7 +10,7 @@ import { SwapType } from "../consts/Enums";
 import { useGlobalContext } from "../context/Global";
 import { usePayContext } from "../context/Pay";
 import { getSubmarinePreimage } from "../utils/boltzClient";
-import { formatAmount } from "../utils/denomination";
+import { formatAmount, formatDenomination } from "../utils/denomination";
 import { formatError } from "../utils/errors";
 import { checkInvoicePreimage } from "../utils/invoice";
 import type { SubmarineSwap } from "../utils/swapCreator";
@@ -93,7 +93,10 @@ const TransactionClaimed = () => {
                             denomination(),
                             separator(),
                         ),
-                        denomination: denomination(),
+                        denomination: formatDenomination(
+                            denomination(),
+                            swap().assetReceive,
+                        ),
                     })}
                 </p>
                 <hr />
diff --git a/src/status/TransactionLockupFailed.tsx b/src/status/TransactionLockupFailed.tsx
index 7e65232e2..3d2c08778 100644
--- a/src/status/TransactionLockupFailed.tsx
+++ b/src/status/TransactionLockupFailed.tsx
@@ -40,17 +40,16 @@ const Amount = (props: { label: DictKey; amount: number }) => {
     return (
         <div>
             <div>{t(props.label)}</div>
-            <input
-                disabled
-                type="text"
-                placeholder="0"
-                inputMode={denomination() == "btc" ? "decimal" : "numeric"}
-                value={formatAmount(
-                    new BigNumber(props.amount),
-                    denomination(),
-                    separator(),
-                )}
-            />
+            <span>
+                {`${
+                    formatAmount(
+                        new BigNumber(props.amount),
+                        denomination(),
+                        separator(),
+                    ) || 0
+                }`}
+                <span class="denominator" data-denominator={denomination()} />
+            </span>
         </div>
     );
 };
diff --git a/src/style/index.scss b/src/style/index.scss
index 68de1f4ba..c3fb80a91 100644
--- a/src/style/index.scss
+++ b/src/style/index.scss
@@ -749,11 +749,26 @@ textarea {
     gap: 0.3rem;
 }
 
-.quote > div > input {
-    color: white;
+.quote > div > span {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 20rem;
+    padding: 7px 8px;
+    margin: 0;
+    text-align: center;
     font-size: 1.5rem;
     font-weight: 600;
-    text-align: center;
+    color: white;
+    background: rgba(0, 0, 0, 0.3);
+    border: 1px dashed rgba(255, 255, 255, 0.3);
+    border-radius: 10px;
+    box-sizing: border-box;
+    .denominator {
+        width: 15px;
+        height: 15px;
+        margin-left: 0.5rem;
+    }
 }
 
 header {
@@ -765,3 +780,8 @@ header {
     margin-bottom: 1rem;
     color: vars.$primary;
 }
+
+.swap-limits {
+    display: inline-flex;
+    gap: 0.8rem;
+}
diff --git a/tests/components/CreateButton.spec.tsx b/tests/components/CreateButton.spec.tsx
index ef1887988..794fa2cff 100644
--- a/tests/components/CreateButton.spec.tsx
+++ b/tests/components/CreateButton.spec.tsx
@@ -34,7 +34,7 @@ describe("CreateButton", () => {
         const btn = (await screen.findByText(
             i18n.en.minimum_amount
                 .replace("{{ amount }}", "50 000")
-                .replace("{{ denomination }}", "sat"),
+                .replace("{{ denomination }}", "sats"),
         )) as HTMLButtonElement;
         expect(btn).not.toBeUndefined();
         expect(btn.disabled).toBeTruthy();
diff --git a/tests/pages/Create.spec.tsx b/tests/pages/Create.spec.tsx
index e7b55c889..121256c5e 100644
--- a/tests/pages/Create.spec.tsx
+++ b/tests/pages/Create.spec.tsx
@@ -250,7 +250,7 @@ describe("Create", () => {
         });
 
         expect(createButton.disabled).toEqual(true);
-        expect(createButton.innerHTML).toEqual("Minimum amount is 50 000 sat");
+        expect(createButton.innerHTML).toEqual("Minimum amount is 50 000 sats");
     });
 
     test("should allow comma in pasted amounts", async () => {


Reviews:
user: login: kilrau
body: So in some places we use the symbols, in others it's written out as L-BTC/BTC/RBTC or sats? Feels inconsistent.

![image](https://github.com/user-attachments/assets/03eebfde-82b0-4b5c-ae44-41c04109c456)
![image](https://github.com/user-attachments/assets/42db19a8-4962-427b-95f0-469ea895c462)


state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-09T14:21:13Z
user: login: kilrau
body: It's fine actually, reads better written as "sats" or BTC" in a sentence. Was just genuinely interested in your argumentation beyond "it's technically difficult to make it work in strings" ;)

Tested a bit more, couldn't find any places that still miss denominations or broken UI. LGTM :tada: 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-10T10:39:26Z
user: login: michael1011
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-11T21:56:49Z
user: login: kiocos
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-12T17:05:15Z
user: login: michael1011
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-13T08:53:54Z

Review comments:
diff_hunk: @@ -303,7 +303,10 @@ const CreateButton = () => {
                                 denomination(),
                                 separator(),
                             ),
-                            denomination: denomination(),
+                            denomination: formatDenomination(
+                                denomination(),
+                                assetSend(),
+                            ),
path: src/components/CreateButton.tsx
user: login: michael1011
body: ![image](https://github.com/user-attachments/assets/acceb0ac-845c-4b66-953c-9a4eeb9c3c51)
That does not work
created_at: 2025-04-11T21:55:31Z
author_association: MEMBER
diff_hunk: @@ -303,7 +303,10 @@ const CreateButton = () => {
                                 denomination(),
                                 separator(),
                             ),
-                            denomination: denomination(),
+                            denomination: formatDenomination(
+                                denomination(),
+                                assetSend(),
+                            ),
path: src/components/CreateButton.tsx
user: login: kiocos
body: @michael1011 oh, I had it lacking reactivity.
Fixed it by passing `denomination` to the `on` function of the `createEffect` where this label is updated.

![image](https://github.com/user-attachments/assets/2f63cc0c-b238-4545-a0cd-63175f6e8091)
![image](https://github.com/user-attachments/assets/8996ba70-4b7d-4f33-a747-c7069919b139)

created_at: 2025-04-12T17:05:14Z
author_association: MEMBER

PR comments:
user: login: vercel[bot]
created_at: 2025-04-09T01:50:16Z
body: @kiocosta is attempting to deploy a commit to the **boltz** Team on [Vercel](https://vercel.com).

A member of the Team first needs to [authorize it](https://vercel.com/git/authorize?team=boltz&type=github&job=%7B%22headInfo%22%3A%7B%22sha%22%3A%226d117863cdb98a737cff3772bd2bf7eed9181aea%22%7D%2C%22id%22%3A%22QmddjXJKSumUPFPTMtRCE75qWAKSYz8Y5xf7hry5MQQZp4%22%2C%22org%22%3A%22BoltzExchange%22%2C%22prId%22%3A894%2C%22repo%22%3A%22boltz-web-app%22%7D).


author_association: NONE
user: login: kiocos
created_at: 2025-04-09T14:50:40Z
body: > So in some places we use the symbols, in others it's written out as L-BTC/BTC/RBTC or sats? Feels inconsistent.

Not sure if I like the ₿, sats or L-BTC symbol everywhere, mostly because I'm not sure that would be clear for all users (especially the sats symbol).

As I've said [here](https://github.com/BoltzExchange/boltz-web-app/issues/749#issuecomment-2752825003), interpolating symbols with i18n strings adds some complexity which I'm not sure it's worth it.

What do you have in mind?
₿ or sats symbol for some places AND just "BTC" or "sats" when strings are more convenient (replacing L-BTC with BTC in your first screenshot)?

author_association: MEMBER
user: login: kilrau
created_at: 2025-04-10T10:40:05Z
body: good from my side @michael1011 
author_association: MEMBER
user: login: vercel[bot]
created_at: 2025-04-11T11:19:04Z
body: [vc]: #e6bmv3vi+6lxEkCX2PImaeAkCJ0JpIfnhtvaJ80yKmQ=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ3ZWJhcHAiLCJyb290RGlyZWN0b3J5IjpudWxsLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vYm9sdHovd2ViYXBwL0VaNk1pUW5RaGdxcEU5ekE3ZXFCQUVZVzhjVUoiLCJwcmV2aWV3VXJsIjoid2ViYXBwLWdpdC1mb3JrLWtpb2Nvc3RhLWFkZC1kZW5vbWluYXRpb24tYm9sdHoudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCJ9LHsibmFtZSI6IndlYmFwcC1tYWlubmV0Iiwicm9vdERpcmVjdG9yeSI6bnVsbCwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2JvbHR6L3dlYmFwcC1tYWlubmV0LzJja3M3QVpNQVEzazgyQW5YTTEyUU5OTmkxYlQiLCJwcmV2aWV3VXJsIjoid2ViYXBwLW1haW5uZXQtZ2l0LWZvcmsta2lvY29zdGEtYWRkLWRlbm9taW5hdGlvbi1ib2x0ei52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIn1dfQ==
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Updated (UTC) |
| :--- | :----- | :------ | :------ |
| **webapp** | ✅ Ready ([Inspect](https://vercel.com/boltz/webapp/EZ6MiQnQhgqpE9zA7eqBAEYW8cUJ)) | [Visit Preview](https://webapp-git-fork-kiocosta-add-denomination-boltz.vercel.app) | Apr 13, 2025 8:47am |
| **webapp-mainnet** | ✅ Ready ([Inspect](https://vercel.com/boltz/webapp-mainnet/2cks7AZMAQ3k82AnXM12QNNNi1bT)) | [Visit Preview](https://webapp-mainnet-git-fork-kiocosta-add-denomination-boltz.vercel.app) | Apr 13, 2025 8:47am |



author_association: NONE