From e91d466d44b9862ca9bcf3d539d234b08565df78 Mon Sep 17 00:00:00 2001
From: Riccardo Balbo
Date: Thu, 22 Feb 2024 21:39:40 +0100
Subject: [PATCH 1/5] feat: implement stablesats for galoy connector #2730
---
.../TransactionsTable/TransactionModal.tsx | 9 +-
.../components/TransactionsTable/index.tsx | 9 +-
src/app/hooks/useTransactions.ts | 5 +
src/app/screens/Home/AllowanceView/index.tsx | 6 +
src/app/screens/Publishers/Detail/index.tsx | 7 +-
.../screens/connectors/ConnectGaloy/index.tsx | 37 ++++-
.../connectors/connector.interface.ts | 1 +
.../background-script/connectors/galoy.ts | 140 +++++++++++++-----
src/i18n/locales/en/translation.json | 8 +-
src/types.ts | 2 +
10 files changed, 175 insertions(+), 49 deletions(-)
diff --git a/src/app/components/TransactionsTable/TransactionModal.tsx b/src/app/components/TransactionsTable/TransactionModal.tsx
index 2f291f40b1..d0a2e9f869 100644
--- a/src/app/components/TransactionsTable/TransactionModal.tsx
+++ b/src/app/components/TransactionsTable/TransactionModal.tsx
@@ -31,7 +31,7 @@ export default function TransactionModal({
keyPrefix: "transactions_table",
});
const [showMoreFields, setShowMoreFields] = useState(false);
- const { getFormattedSats } = useSettings();
+ const { getFormattedSats, getFormattedInCurrency } = useSettings();
function toggleShowMoreFields() {
setShowMoreFields(!showMoreFields);
@@ -82,7 +82,12 @@ export default function TransactionModal({
)}
>
{transaction.type == "sent" ? "-" : "+"}{" "}
- {getFormattedSats(transaction.totalAmount)}
+ {!transaction.displayAmount
+ ? getFormattedSats(transaction.totalAmount)
+ : getFormattedInCurrency(
+ transaction.displayAmount[0],
+ transaction.displayAmount[1]
+ )}
{!!transaction.totalAmountFiat && (
diff --git a/src/app/components/TransactionsTable/index.tsx b/src/app/components/TransactionsTable/index.tsx
index a9ac5a8f7e..31376aaf8b 100644
--- a/src/app/components/TransactionsTable/index.tsx
+++ b/src/app/components/TransactionsTable/index.tsx
@@ -23,7 +23,7 @@ export default function TransactionsTable({
noResultMsg,
loading = false,
}: Props) {
- const { getFormattedSats } = useSettings();
+ const { getFormattedSats, getFormattedInCurrency } = useSettings();
const [modalOpen, setModalOpen] = useState(false);
const [transaction, setTransaction] = useState();
const { t } = useTranslation("components", {
@@ -93,7 +93,12 @@ export default function TransactionsTable({
)}
>
{type == "outgoing" ? "-" : "+"}{" "}
- {getFormattedSats(tx.totalAmount)}
+ {!tx.displayAmount
+ ? getFormattedSats(tx.totalAmount)
+ : getFormattedInCurrency(
+ tx.displayAmount[0],
+ tx.displayAmount[1]
+ )}
{!!tx.totalAmountFiat && (
diff --git a/src/app/hooks/useTransactions.ts b/src/app/hooks/useTransactions.ts
index 1d1f5cd001..f7b24d7377 100644
--- a/src/app/hooks/useTransactions.ts
+++ b/src/app/hooks/useTransactions.ts
@@ -27,6 +27,11 @@ export const useTransactions = () => {
);
for (const transaction of transactions) {
+ if (
+ transaction.displayAmount &&
+ transaction.displayAmount[1] === settings.currency
+ )
+ continue;
transaction.totalAmountFiat = settings.showFiat
? await getFormattedFiat(transaction.totalAmount)
: "";
diff --git a/src/app/screens/Home/AllowanceView/index.tsx b/src/app/screens/Home/AllowanceView/index.tsx
index 7f454498ae..74e88df054 100644
--- a/src/app/screens/Home/AllowanceView/index.tsx
+++ b/src/app/screens/Home/AllowanceView/index.tsx
@@ -53,6 +53,11 @@ const AllowanceView: FC = (props) => {
try {
// attach fiatAmount if enabled
for (const transaction of transactions) {
+ if (
+ transaction.displayAmount &&
+ transaction.displayAmount[1] === settings.currency
+ )
+ continue;
transaction.totalAmountFiat = showFiat
? await getFormattedFiat(transaction.totalAmount)
: "";
@@ -74,6 +79,7 @@ const AllowanceView: FC = (props) => {
transactions,
getFormattedFiat,
showFiat,
+ settings.currency,
]);
const hasBudget = +props.allowance.totalBudget > 0;
diff --git a/src/app/screens/Publishers/Detail/index.tsx b/src/app/screens/Publishers/Detail/index.tsx
index c0909df09e..25d235b277 100644
--- a/src/app/screens/Publishers/Detail/index.tsx
+++ b/src/app/screens/Publishers/Detail/index.tsx
@@ -43,6 +43,11 @@ function PublisherDetail() {
);
for (const payment of _transactions) {
+ if (
+ payment.displayAmount &&
+ payment.displayAmount[1] === settings.currency
+ )
+ continue;
payment.totalAmountFiat = settings.showFiat
? await getFormattedFiat(payment.totalAmount)
: "";
@@ -53,7 +58,7 @@ function PublisherDetail() {
console.error(e);
if (e instanceof Error) toast.error(`Error: ${e.message}`);
}
- }, [id, settings.showFiat, getFormattedFiat]);
+ }, [id, settings.showFiat, getFormattedFiat, settings.currency]);
useEffect(() => {
// Run once.
diff --git a/src/app/screens/connectors/ConnectGaloy/index.tsx b/src/app/screens/connectors/ConnectGaloy/index.tsx
index 1d5ede6e19..4b701475a8 100644
--- a/src/app/screens/connectors/ConnectGaloy/index.tsx
+++ b/src/app/screens/connectors/ConnectGaloy/index.tsx
@@ -1,5 +1,6 @@
import ConnectorForm from "@components/ConnectorForm";
import Input from "@components/form/Input";
+import Select from "@components/form/Select";
import ConnectionErrorToast from "@components/toasts/ConnectionErrorToast";
import fetchAdapter from "@vespaiach/axios-fetch-adapter";
import axios from "axios";
@@ -54,11 +55,16 @@ export default function ConnectGaloy(props: Props) {
});
const [loading, setLoading] = useState(false);
const [authToken, setAuthToken] = useState();
+ const [currency, setCurrency] = useState("BTC");
function handleAuthTokenChange(event: React.ChangeEvent) {
setAuthToken(event.target.value.trim());
}
+ function handleCurrencyChange(event: React.ChangeEvent) {
+ setCurrency(event.target.value);
+ }
+
async function loginWithAuthToken(event: React.FormEvent) {
event.preventDefault();
setLoading(true);
@@ -100,10 +106,10 @@ export default function ConnectGaloy(props: Props) {
} else {
// Find the BTC wallet and get its ID
const btcWallet = meData.data.me.defaultAccount.wallets.find(
- (w: Wallet) => w.walletCurrency === "BTC"
+ (w: Wallet) => w.walletCurrency === currency
);
const walletId = btcWallet.id;
- saveAccount({ headers, walletId });
+ saveAccount({ headers, walletId, currency });
}
} catch (e: unknown) {
console.error(e);
@@ -122,7 +128,11 @@ export default function ConnectGaloy(props: Props) {
}
}
- async function saveAccount(config: { headers: Headers; walletId: string }) {
+ async function saveAccount(config: {
+ headers: Headers;
+ walletId: string;
+ currency: string;
+ }) {
setLoading(true);
const account = {
@@ -132,6 +142,7 @@ export default function ConnectGaloy(props: Props) {
headers: config.headers,
walletId: config.walletId,
apiCompatibilityMode,
+ currency: config.currency,
},
connector: "galoy",
};
@@ -215,6 +226,26 @@ export default function ConnectGaloy(props: Props) {
}
+
+
+
+
+
+
+
);
}
diff --git a/src/extension/background-script/connectors/connector.interface.ts b/src/extension/background-script/connectors/connector.interface.ts
index 946ae6c5d2..f2bd79c506 100644
--- a/src/extension/background-script/connectors/connector.interface.ts
+++ b/src/extension/background-script/connectors/connector.interface.ts
@@ -30,6 +30,7 @@ export interface ConnectorTransaction {
settled: boolean;
settleDate: number;
totalAmount: number;
+ displayAmount?: [number, ACCOUNT_CURRENCIES];
type: "received" | "sent";
}
diff --git a/src/extension/background-script/connectors/galoy.ts b/src/extension/background-script/connectors/galoy.ts
index 72d5da616d..0d669c32b5 100644
--- a/src/extension/background-script/connectors/galoy.ts
+++ b/src/extension/background-script/connectors/galoy.ts
@@ -1,16 +1,17 @@
import fetchAdapter from "@vespaiach/axios-fetch-adapter";
import axios, { AxiosRequestConfig } from "axios";
import lightningPayReq from "bolt11";
+import { ACCOUNT_CURRENCIES, CURRENCIES } from "~/common/constants";
+import { getCurrencyRateWithCache } from "~/extension/background-script/actions/cache/getCurrencyRate";
import { Account } from "~/types";
-
import Connector, {
CheckPaymentArgs,
CheckPaymentResponse,
ConnectPeerResponse,
+ ConnectorTransaction,
GetBalanceResponse,
GetInfoResponse,
GetTransactionsResponse,
- ConnectorTransaction,
KeysendArgs,
MakeInvoiceArgs,
MakeInvoiceResponse,
@@ -20,12 +21,15 @@ import Connector, {
SignMessageResponse,
} from "./connector.interface";
+type GaloyCurrencies = Extract;
+
interface Config {
walletId: string;
url: string;
headers?: Headers; // optional for backward compatibility
apiCompatibilityMode?: boolean; // optional for backward compatibility
accessToken?: string; // only present in old connectors
+ currency?: GaloyCurrencies; // default is BTC
}
class Galoy implements Connector {
@@ -62,6 +66,14 @@ class Galoy implements Connector {
return Promise.resolve();
}
+ toFiatInt(amount: number, currency: GaloyCurrencies): number {
+ return Math.round(amount * 100);
+ }
+
+ toFiatFloat(amount: number, currency: GaloyCurrencies): number {
+ return amount / 100;
+ }
+
get supportedMethods() {
return [
"getInfo",
@@ -187,36 +199,50 @@ class Galoy implements Connector {
const targetWallet = wallets.find((w) => w.id === this.config.walletId);
if (targetWallet) {
- if (targetWallet.walletCurrency === "USD") {
- throw new Error("USD currency support is not yet implemented.");
+ if (targetWallet.walletCurrency !== (this.config.currency || "BTC")) {
+ throw new Error(
+ "Wallet currency does not match the account currency. " +
+ targetWallet.walletCurrency +
+ " != " +
+ (this.config.currency || "BTC")
+ );
}
- targetWallet.transactions.edges.forEach(
- (edge: { cursor: string; node: TransactionNode }) => {
- const tx = edge.node;
- // Determine transaction type based on the direction field
- const transactionType: "received" | "sent" =
- tx.direction === "RECEIVE" ? "received" : "sent";
- // Do not display a double negative if sent
- const absSettlementAmount = Math.abs(tx.settlementAmount);
- // Convert createdAt from UNIX timestamp to Date
- const createdAtDate = new Date(tx.createdAt * 1000);
-
- transactions.push({
- id: edge.cursor,
- memo: tx.memo,
- preimage:
- tx.settlementVia.preImage ||
- tx.settlementVia.paymentSecret ||
- "",
- payment_hash: tx.initiationVia.paymentHash || "",
- settled: tx.status === "SUCCESS",
- settleDate: createdAtDate.getTime(),
- totalAmount: absSettlementAmount, // Assuming this is in the correct unit
- type: transactionType,
- });
+ for (const edge of targetWallet.transactions.edges) {
+ const tx = edge.node;
+ // Determine transaction type based on the direction field
+ const transactionType: "received" | "sent" =
+ tx.direction === "RECEIVE" ? "received" : "sent";
+ const currency = targetWallet.walletCurrency || "BTC";
+ // Do not display a double negative if sent
+ let absSettlementAmount = Math.abs(tx.settlementAmount);
+ let displayAmount: [number, ACCOUNT_CURRENCIES] | undefined =
+ undefined;
+ if (currency !== "BTC") {
+ const rate = await getCurrencyRateWithCache(CURRENCIES[currency]);
+ absSettlementAmount = this.toFiatFloat(
+ absSettlementAmount,
+ currency
+ );
+ displayAmount = [absSettlementAmount, CURRENCIES[currency]];
+ absSettlementAmount = Math.floor(absSettlementAmount / rate);
}
- );
+
+ const createdAtDate = new Date(tx.createdAt * 1000);
+
+ transactions.push({
+ id: edge.cursor,
+ memo: tx.memo,
+ preimage:
+ tx.settlementVia.preImage || tx.settlementVia.paymentSecret || "",
+ payment_hash: tx.initiationVia.paymentHash || "",
+ settled: tx.status === "SUCCESS",
+ settleDate: createdAtDate.getTime(),
+ totalAmount: absSettlementAmount,
+ type: transactionType,
+ displayAmount,
+ });
+ }
}
hasNextPage = targetWallet?.transactions.pageInfo.hasNextPage || false;
@@ -255,12 +281,25 @@ class Galoy implements Connector {
(w: GaloyWallet) => w.id === this.config.walletId
);
if (targetWallet) {
- if (targetWallet.walletCurrency === "USD") {
- throw new Error("USD currency support is not yet implemented.");
+ if (targetWallet.walletCurrency !== (this.config.currency || "BTC")) {
+ throw new Error(
+ "Wallet currency does not match the account currency. " +
+ targetWallet.walletCurrency +
+ " != " +
+ (this.config.currency || "BTC")
+ );
}
+
+ const currency = targetWallet.walletCurrency;
+ const balance =
+ currency !== "BTC"
+ ? this.toFiatFloat(targetWallet.balance, currency)
+ : targetWallet.balance;
+
return {
data: {
- balance: targetWallet.balance,
+ balance,
+ currency,
},
};
} else {
@@ -419,8 +458,13 @@ class Galoy implements Connector {
if (wallet === undefined) {
throw new Error("Bad data received.");
}
- if (wallet.walletCurrency === "USD") {
- throw new Error("USD currency support is not yet implemented.");
+ if (wallet.walletCurrency !== (this.config.currency || "BTC")) {
+ throw new Error(
+ "Wallet currency does not match the account currency. " +
+ wallet.walletCurrency +
+ " != " +
+ (this.config.currency || "BTC")
+ );
}
const txEdges = wallet.transactions.edges;
@@ -453,10 +497,26 @@ class Galoy implements Connector {
}
async makeInvoice(args: MakeInvoiceArgs): Promise {
+ const mutationName =
+ this.config.currency == "USD" ? "LnUsdInvoiceCreate" : "lnInvoiceCreate";
+ const inputTypeName =
+ this.config.currency == "USD"
+ ? "LnUsdInvoiceCreateInput"
+ : "LnInvoiceCreateInput";
+ const fun =
+ this.config.currency == "USD" ? "lnUsdInvoiceCreate" : "lnInvoiceCreate";
+ const currency = this.config.currency || "BTC";
+
+ let amountSats = Number(args.amount);
+ if (currency !== "BTC") {
+ const rate = await getCurrencyRateWithCache(CURRENCIES[currency]);
+ amountSats = this.toFiatInt(amountSats * rate, currency);
+ }
+
const query = {
query: `
- mutation lnInvoiceCreate($input: LnInvoiceCreateInput!) {
- lnInvoiceCreate(input: $input) {
+ mutation ${mutationName}($input: ${inputTypeName}!) {
+ ${fun}(input: $input) {
invoice {
paymentRequest
paymentHash
@@ -472,21 +532,21 @@ class Galoy implements Connector {
variables: {
input: {
walletId: this.config.walletId,
- amount: args.amount,
+ amount: amountSats,
memo: args.memo,
},
},
};
return this.request(query).then(({ data, errors }) => {
- const errs = errors || data.lnInvoiceCreate.errors;
+ const errs = errors || data[fun].errors;
if (errs && errs.length) {
throw new Error(errs[0].message || JSON.stringify(errs));
}
return {
data: {
- paymentRequest: data.lnInvoiceCreate.invoice.paymentRequest,
- rHash: data.lnInvoiceCreate.invoice.paymentHash,
+ paymentRequest: data[fun].invoice.paymentRequest,
+ rHash: data[fun].invoice.paymentHash,
},
};
});
diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json
index 144b6e7e6b..6be1995561 100644
--- a/src/i18n/locales/en/translation.json
+++ b/src/i18n/locales/en/translation.json
@@ -228,7 +228,10 @@
},
"token": {
"label": "Enter your API key",
- "info": "To connect your wallet generate an API key in the <0>Blink Dashboard (dashboard.blink.sv)0>:
- log in with email or phone number if you are using Blink already
- if you have no account yet can create a new one by logging in with a phone number
- create a new key on the API Keys tab
- give it a Name and choose the Read and Write Scope
- leave the default no expiry or choose a long timeframe to avoid needing to reconnect your wallet periodically
- copy the key (starting with blink_ ) and paste it to the textbox below.
The integration currently only supports using the BTC wallet.
"
+ "info": "To connect your wallet generate an API key in the <0>Blink Dashboard (dashboard.blink.sv)0>:
- log in with email or phone number if you are using Blink already
- if you have no account yet can create a new one by logging in with a phone number
- create a new key on the API Keys tab
- give it a Name and choose the Read and Write Scope
- leave the default no expiry or choose a long timeframe to avoid needing to reconnect your wallet periodically
- copy the key (starting with blink_ ) and paste it to the textbox below.
"
+ },
+ "currency": {
+ "label": "Select wallet"
}
},
"bitcoin_jungle": {
@@ -239,6 +242,9 @@
"token": {
"label": "Enter your Access token",
"info": "The {{label}} integration with Alby is in alpha and only recommended for advanced users.
You can grab your Access token by going into the mobile app, clicking on the settings icon, and then tapping 3 times on the build number to open the developer menu.
The access token can be copied from here.
"
+ },
+ "currency": {
+ "label": "Select wallet"
}
},
"galoy": {
diff --git a/src/types.ts b/src/types.ts
index 6bc4f7f414..1d8cfc77fa 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -727,6 +727,7 @@ export type Transaction = {
preimage: string;
title: string | React.ReactNode;
totalAmount: Allowance["payments"][number]["totalAmount"];
+ displayAmount?: [number, ACCOUNT_CURRENCIES];
totalAmountFiat?: string;
totalFees?: Allowance["payments"][number]["totalFees"];
type?: "sent" | "received";
@@ -896,6 +897,7 @@ export interface Invoice {
settleDate: number;
totalAmount: number;
totalAmountFiat?: string;
+ displayAmount?: [number, ACCOUNT_CURRENCIES];
preimage: string;
paymentHash?: string;
custom_records?: ConnectorTransaction["custom_records"];
From 67127094ff98657771937b22ef5fc9a34fe3808f Mon Sep 17 00:00:00 2001
From: Riccardo Balbo
Date: Mon, 26 Feb 2024 18:59:31 +0100
Subject: [PATCH 2/5] fix: galoy connector defaults to BTC currency, create
sats denominated usd invoices, fix naming
---
.../background-script/connectors/galoy.ts | 65 +++++++++----------
1 file changed, 30 insertions(+), 35 deletions(-)
diff --git a/src/extension/background-script/connectors/galoy.ts b/src/extension/background-script/connectors/galoy.ts
index 0d669c32b5..8c116843e8 100644
--- a/src/extension/background-script/connectors/galoy.ts
+++ b/src/extension/background-script/connectors/galoy.ts
@@ -29,7 +29,7 @@ interface Config {
headers?: Headers; // optional for backward compatibility
apiCompatibilityMode?: boolean; // optional for backward compatibility
accessToken?: string; // only present in old connectors
- currency?: GaloyCurrencies; // default is BTC
+ currency: GaloyCurrencies; // default is BTC
}
class Galoy implements Connector {
@@ -47,6 +47,7 @@ class Galoy implements Connector {
config.apiCompatibilityMode !== undefined
? config.apiCompatibilityMode
: true,
+ currency: config.currency || "BTC",
};
}
@@ -66,11 +67,11 @@ class Galoy implements Connector {
return Promise.resolve();
}
- toFiatInt(amount: number, currency: GaloyCurrencies): number {
+ toFiatCents(amount: number): number {
return Math.round(amount * 100);
}
- toFiatFloat(amount: number, currency: GaloyCurrencies): number {
+ fromFiatCents(amount: number): number {
return amount / 100;
}
@@ -199,12 +200,12 @@ class Galoy implements Connector {
const targetWallet = wallets.find((w) => w.id === this.config.walletId);
if (targetWallet) {
- if (targetWallet.walletCurrency !== (this.config.currency || "BTC")) {
+ if (targetWallet.walletCurrency !== this.config.currency) {
throw new Error(
"Wallet currency does not match the account currency. " +
targetWallet.walletCurrency +
" != " +
- (this.config.currency || "BTC")
+ this.config.currency
);
}
@@ -213,17 +214,14 @@ class Galoy implements Connector {
// Determine transaction type based on the direction field
const transactionType: "received" | "sent" =
tx.direction === "RECEIVE" ? "received" : "sent";
- const currency = targetWallet.walletCurrency || "BTC";
+ const currency = targetWallet.walletCurrency;
// Do not display a double negative if sent
let absSettlementAmount = Math.abs(tx.settlementAmount);
let displayAmount: [number, ACCOUNT_CURRENCIES] | undefined =
undefined;
if (currency !== "BTC") {
const rate = await getCurrencyRateWithCache(CURRENCIES[currency]);
- absSettlementAmount = this.toFiatFloat(
- absSettlementAmount,
- currency
- );
+ absSettlementAmount = this.fromFiatCents(absSettlementAmount);
displayAmount = [absSettlementAmount, CURRENCIES[currency]];
absSettlementAmount = Math.floor(absSettlementAmount / rate);
}
@@ -281,19 +279,19 @@ class Galoy implements Connector {
(w: GaloyWallet) => w.id === this.config.walletId
);
if (targetWallet) {
- if (targetWallet.walletCurrency !== (this.config.currency || "BTC")) {
+ if (targetWallet.walletCurrency !== this.config.currency) {
throw new Error(
"Wallet currency does not match the account currency. " +
targetWallet.walletCurrency +
" != " +
- (this.config.currency || "BTC")
+ this.config.currency
);
}
const currency = targetWallet.walletCurrency;
const balance =
currency !== "BTC"
- ? this.toFiatFloat(targetWallet.balance, currency)
+ ? this.fromFiatCents(targetWallet.balance)
: targetWallet.balance;
return {
@@ -458,12 +456,12 @@ class Galoy implements Connector {
if (wallet === undefined) {
throw new Error("Bad data received.");
}
- if (wallet.walletCurrency !== (this.config.currency || "BTC")) {
+ if (wallet.walletCurrency !== this.config.currency) {
throw new Error(
"Wallet currency does not match the account currency. " +
wallet.walletCurrency +
" != " +
- (this.config.currency || "BTC")
+ this.config.currency
);
}
@@ -497,26 +495,22 @@ class Galoy implements Connector {
}
async makeInvoice(args: MakeInvoiceArgs): Promise {
- const mutationName =
- this.config.currency == "USD" ? "LnUsdInvoiceCreate" : "lnInvoiceCreate";
- const inputTypeName =
- this.config.currency == "USD"
- ? "LnUsdInvoiceCreateInput"
- : "LnInvoiceCreateInput";
- const fun =
- this.config.currency == "USD" ? "lnUsdInvoiceCreate" : "lnInvoiceCreate";
- const currency = this.config.currency || "BTC";
-
- let amountSats = Number(args.amount);
- if (currency !== "BTC") {
- const rate = await getCurrencyRateWithCache(CURRENCIES[currency]);
- amountSats = this.toFiatInt(amountSats * rate, currency);
- }
+ const isUSD = this.config.currency == "USD";
+ const mutationName = isUSD
+ ? "LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient"
+ : "LnInvoiceCreate";
+ const inputTypeName = isUSD
+ ? "LnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipientInput"
+ : "LnInvoiceCreateInput";
+ const invoiceCreateFunction = isUSD
+ ? "lnUsdInvoiceBtcDenominatedCreateOnBehalfOfRecipient"
+ : "lnInvoiceCreate";
+ const amountSats = Number(args.amount);
const query = {
query: `
mutation ${mutationName}($input: ${inputTypeName}!) {
- ${fun}(input: $input) {
+ ${invoiceCreateFunction}(input: $input) {
invoice {
paymentRequest
paymentHash
@@ -531,22 +525,23 @@ class Galoy implements Connector {
`,
variables: {
input: {
- walletId: this.config.walletId,
+ walletId: !isUSD ? this.config.walletId : undefined,
+ recipientWalletId: isUSD ? this.config.walletId : undefined,
amount: amountSats,
memo: args.memo,
},
},
};
return this.request(query).then(({ data, errors }) => {
- const errs = errors || data[fun].errors;
+ const errs = errors || data[invoiceCreateFunction].errors;
if (errs && errs.length) {
throw new Error(errs[0].message || JSON.stringify(errs));
}
return {
data: {
- paymentRequest: data[fun].invoice.paymentRequest,
- rHash: data[fun].invoice.paymentHash,
+ paymentRequest: data[invoiceCreateFunction].invoice.paymentRequest,
+ rHash: data[invoiceCreateFunction].invoice.paymentHash,
},
};
});
From cd0a67c032326ed2e38649a4a6e97bb629fa3a36 Mon Sep 17 00:00:00 2001
From: Riccardo Balbo
Date: Wed, 6 Mar 2024 11:52:24 +0100
Subject: [PATCH 3/5] fix: disable amount check for non btc balances
---
src/app/screens/Keysend/index.tsx | 6 +++++-
src/app/screens/LNURLPay/index.tsx | 5 ++++-
src/app/screens/SendToBitcoinAddress/index.tsx | 5 ++++-
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/src/app/screens/Keysend/index.tsx b/src/app/screens/Keysend/index.tsx
index 8f2cec79e7..0125d65015 100644
--- a/src/app/screens/Keysend/index.tsx
+++ b/src/app/screens/Keysend/index.tsx
@@ -39,7 +39,11 @@ function Keysend() {
const { t: tCommon } = useTranslation("common");
const amountMin = 1;
- const amountExceeded = +amountSat > (auth?.account?.balance || 0);
+
+ const amountExceeded =
+ (auth?.account?.currency || "BTC") !== "BTC"
+ ? false
+ : +amountSat > (auth?.account?.balance || 0);
const rangeExceeded = +amountSat < amountMin;
useEffect(() => {
diff --git a/src/app/screens/LNURLPay/index.tsx b/src/app/screens/LNURLPay/index.tsx
index e82f10f24c..fc900813d3 100644
--- a/src/app/screens/LNURLPay/index.tsx
+++ b/src/app/screens/LNURLPay/index.tsx
@@ -71,7 +71,10 @@ function LNURLPay() {
const amountMin = Math.floor(+details.minSendable / 1000);
const amountMax = Math.floor(+details.maxSendable / 1000);
- const amountExceeded = +valueSat > (auth?.account?.balance || 0);
+ const amountExceeded =
+ (auth?.account?.currency || "BTC") !== "BTC"
+ ? false
+ : +valueSat > (auth?.account?.balance || 0);
const rangeExceeded = +valueSat > amountMax || +valueSat < amountMin;
const [showMoreFields, setShowMoreFields] = useState(false);
diff --git a/src/app/screens/SendToBitcoinAddress/index.tsx b/src/app/screens/SendToBitcoinAddress/index.tsx
index fc18468154..df2e3903de 100644
--- a/src/app/screens/SendToBitcoinAddress/index.tsx
+++ b/src/app/screens/SendToBitcoinAddress/index.tsx
@@ -208,7 +208,10 @@ function SendToBitcoinAddress() {
const amountMin = 100_000;
const amountMax = 10_000_000;
- const amountExceeded = +amountSat > (auth?.account?.balance || 0);
+ const amountExceeded =
+ (auth?.account?.currency || "BTC") !== "BTC"
+ ? false
+ : +amountSat > (auth?.account?.balance || 0);
const rangeExceeded = +amountSat > amountMax || +amountSat < amountMin;
const timeEstimateAlert = {t("time_estimate")};
From 9d3e8de6f8ac7f0643fdec6ca695579ae347e7b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Aaron?=
Date: Wed, 13 Mar 2024 16:36:48 +0100
Subject: [PATCH 4/5] fix: remove obsolete code
---
src/app/screens/Home/AllowanceView/index.tsx | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/app/screens/Home/AllowanceView/index.tsx b/src/app/screens/Home/AllowanceView/index.tsx
index 74e88df054..7f454498ae 100644
--- a/src/app/screens/Home/AllowanceView/index.tsx
+++ b/src/app/screens/Home/AllowanceView/index.tsx
@@ -53,11 +53,6 @@ const AllowanceView: FC = (props) => {
try {
// attach fiatAmount if enabled
for (const transaction of transactions) {
- if (
- transaction.displayAmount &&
- transaction.displayAmount[1] === settings.currency
- )
- continue;
transaction.totalAmountFiat = showFiat
? await getFormattedFiat(transaction.totalAmount)
: "";
@@ -79,7 +74,6 @@ const AllowanceView: FC = (props) => {
transactions,
getFormattedFiat,
showFiat,
- settings.currency,
]);
const hasBudget = +props.allowance.totalBudget > 0;
From 8ae5ed3aa6257a681c4843e11e5e5578e0d02037 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Aaron?=
Date: Wed, 13 Mar 2024 16:46:50 +0100
Subject: [PATCH 5/5] fix: create helper for parsing invoices
---
src/common/utils/paymentRequest.ts | 9 +++++++++
src/extension/background-script/connectors/galoy.ts | 13 ++++++++++++-
src/extension/background-script/connectors/lnc.ts | 11 +++--------
src/extension/background-script/connectors/lnd.ts | 7 ++-----
4 files changed, 26 insertions(+), 14 deletions(-)
create mode 100644 src/common/utils/paymentRequest.ts
diff --git a/src/common/utils/paymentRequest.ts b/src/common/utils/paymentRequest.ts
new file mode 100644
index 0000000000..acc5d0c3d3
--- /dev/null
+++ b/src/common/utils/paymentRequest.ts
@@ -0,0 +1,9 @@
+import lightningPayReq from "bolt11";
+
+export function getPaymentRequestDescription(paymentRequest: string): string {
+ const decodedPaymentRequest = lightningPayReq.decode(paymentRequest);
+ const descriptionTag = decodedPaymentRequest.tags.find(
+ (tag) => tag.tagName === "description"
+ );
+ return descriptionTag ? descriptionTag.data.toString() : "";
+}
diff --git a/src/extension/background-script/connectors/galoy.ts b/src/extension/background-script/connectors/galoy.ts
index 8c116843e8..0f7ff6a79e 100644
--- a/src/extension/background-script/connectors/galoy.ts
+++ b/src/extension/background-script/connectors/galoy.ts
@@ -2,6 +2,7 @@ import fetchAdapter from "@vespaiach/axios-fetch-adapter";
import axios, { AxiosRequestConfig } from "axios";
import lightningPayReq from "bolt11";
import { ACCOUNT_CURRENCIES, CURRENCIES } from "~/common/constants";
+import { getPaymentRequestDescription } from "~/common/utils/paymentRequest";
import { getCurrencyRateWithCache } from "~/extension/background-script/actions/cache/getCurrencyRate";
import { Account } from "~/types";
import Connector, {
@@ -160,6 +161,7 @@ class Galoy implements Connector {
direction
initiationVia {
... on InitiationViaLn {
+ paymentRequest
paymentHash
}
}
@@ -191,6 +193,7 @@ class Galoy implements Connector {
};
const response = await this.request(query);
+
const errs = response.errors || response.data.me.errors;
if (errs && errs.length) {
throw new Error(errs[0].message || JSON.stringify(errs));
@@ -228,9 +231,16 @@ class Galoy implements Connector {
const createdAtDate = new Date(tx.createdAt * 1000);
+ let paymentRequestDescription = "";
+ if (!tx.memo && tx.initiationVia.paymentRequest) {
+ paymentRequestDescription = getPaymentRequestDescription(
+ tx.initiationVia.paymentRequest
+ );
+ }
+
transactions.push({
id: edge.cursor,
- memo: tx.memo,
+ memo: tx.memo || paymentRequestDescription,
preimage:
tx.settlementVia.preImage || tx.settlementVia.paymentSecret || "",
payment_hash: tx.initiationVia.paymentHash || "",
@@ -590,6 +600,7 @@ type TransactionNode = {
direction: string;
initiationVia: {
paymentHash?: string;
+ paymentRequest?: string;
};
settlementVia: {
preImage?: string;
diff --git a/src/extension/background-script/connectors/lnc.ts b/src/extension/background-script/connectors/lnc.ts
index c744dfacd7..fb93faee18 100644
--- a/src/extension/background-script/connectors/lnc.ts
+++ b/src/extension/background-script/connectors/lnc.ts
@@ -1,6 +1,5 @@
import { Invoice } from "@lightninglabs/lnc-core/dist/types/proto/lnd/lightning";
import LNC from "@lightninglabs/lnc-web";
-import lightningPayReq from "bolt11";
import Base64 from "crypto-js/enc-base64";
import Hex from "crypto-js/enc-hex";
import UTF8 from "crypto-js/enc-utf8";
@@ -10,6 +9,7 @@ import snakeCase from "lodash.snakecase";
import { encryptData } from "~/common/lib/crypto";
import utils from "~/common/lib/utils";
import { mergeTransactions } from "~/common/utils/helpers";
+import { getPaymentRequestDescription } from "~/common/utils/paymentRequest";
import { Account } from "~/types";
import state from "../state";
import Connector, {
@@ -301,14 +301,9 @@ class Lnc implements Connector {
const outgoingInvoices: ConnectorTransaction[] =
outgoingInvoicesResponse.payments.map(
(payment, index): ConnectorTransaction => {
- let memo = "Sent";
+ let memo = "";
if (payment.paymentRequest) {
- memo = (
- lightningPayReq
- .decode(payment.paymentRequest)
- .tags.find((tag) => tag.tagName === "description")?.data ||
- "Sent"
- ).toString();
+ memo = getPaymentRequestDescription(payment.paymentRequest);
}
return {
diff --git a/src/extension/background-script/connectors/lnd.ts b/src/extension/background-script/connectors/lnd.ts
index d6ab7e9824..75f376b3a8 100644
--- a/src/extension/background-script/connectors/lnd.ts
+++ b/src/extension/background-script/connectors/lnd.ts
@@ -1,4 +1,3 @@
-import lightningPayReq from "bolt11";
import Base64 from "crypto-js/enc-base64";
import Hex from "crypto-js/enc-hex";
import UTF8 from "crypto-js/enc-utf8";
@@ -8,6 +7,7 @@ import utils from "~/common/lib/utils";
import { Account } from "~/types";
import { mergeTransactions } from "~/common/utils/helpers";
+import { getPaymentRequestDescription } from "~/common/utils/paymentRequest";
import Connector, {
CheckPaymentArgs,
CheckPaymentResponse,
@@ -522,10 +522,7 @@ class Lnd implements Connector {
(payment, index): ConnectorTransaction => {
let description: string | undefined;
if (payment.payment_request) {
- description = lightningPayReq
- .decode(payment.payment_request)
- .tags.find((tag) => tag.tagName === "description")
- ?.data.toString();
+ description = getPaymentRequestDescription(payment.payment_request);
}
return {