diff --git a/components/cart-invoice-card.tsx b/components/cart-invoice-card.tsx
index 1f0005e..452f57a 100644
--- a/components/cart-invoice-card.tsx
+++ b/components/cart-invoice-card.tsx
@@ -32,6 +32,7 @@ import {
CashuWallet,
getEncodedToken,
Proof,
+ MintKeyset,
} from "@cashu/cashu-ts";
import {
constructGiftWrappedMessageEvent,
@@ -520,16 +521,12 @@ export default function CartInvoiceCard({
while (true) {
try {
- const { proofs } = await wallet.requestTokens(newPrice, hash);
+ const proofs = await wallet.mintProofs(newPrice, hash);
// Encoded proofs can be spent at the mint
encoded = getEncodedToken({
- token: [
- {
- mint: mints[0],
- proofs,
- },
- ],
+ mint: mints[0],
+ proofs,
});
if (encoded) {
@@ -593,16 +590,14 @@ export default function CartInvoiceCard({
const title = product.title;
const pubkey = product.pubkey;
let tokenAmount = totalCostsInSats[pubkey];
- const tokenToSend = await wallet.send(tokenAmount, remainingProofs);
+ const { keep, send } = await wallet.send(tokenAmount, remainingProofs, {
+ includeFees: true,
+ });
let encodedTokenToSend = getEncodedToken({
- token: [
- {
- mint: mints[0],
- proofs: tokenToSend.send,
- },
- ],
+ mint: mints[0],
+ proofs: send,
});
- remainingProofs = tokenToSend.returnChange;
+ remainingProofs = keep;
let paymentMessage = "";
if (quantities[product.id] && quantities[product.id] > 1) {
if (userNPub) {
@@ -890,15 +885,17 @@ export default function CartInvoiceCard({
try {
const mint = new CashuMint(mints[0]);
const wallet = new CashuWallet(mint);
- const mintKeySetResponse = await mint.getKeySets();
- const mintKeySetIds = mintKeySetResponse?.keysets;
+ const mintKeySetIds = await wallet.getKeySets();
const filteredProofs = tokens.filter(
- (p: Proof) => mintKeySetIds?.includes(p.id),
+ (p: Proof) =>
+ mintKeySetIds?.some((keysetId: MintKeyset) => keysetId.id === p.id),
);
- const tokenToSend = await wallet.send(price, filteredProofs);
+ const { keep, send } = await wallet.send(price, filteredProofs, {
+ includeFees: true,
+ });
await sendTokens(
wallet,
- tokenToSend.send,
+ send,
shippingName ? shippingName : undefined,
shippingAddress ? shippingAddress : undefined,
shippingUnitNo ? shippingUnitNo : undefined,
@@ -910,9 +907,10 @@ export default function CartInvoiceCard({
contactType ? contactType : undefined,
contactInstructions ? contactInstructions : undefined,
);
- const changeProofs = tokenToSend?.returnChange;
+ const changeProofs = keep;
const remainingProofs = tokens.filter(
- (p: Proof) => !mintKeySetIds?.includes(p.id),
+ (p: Proof) =>
+ mintKeySetIds?.some((keysetId: MintKeyset) => keysetId.id !== p.id),
);
let proofArray;
if (changeProofs.length >= 1 && changeProofs) {
diff --git a/components/messages/chat-message.tsx b/components/messages/chat-message.tsx
index 011388c..57cfd22 100644
--- a/components/messages/chat-message.tsx
+++ b/components/messages/chat-message.tsx
@@ -6,10 +6,11 @@ import { getLocalStorageData } from "../utility/nostr-helper-functions";
import ClaimButton from "../utility-components/claim-button";
import { NostrMessageEvent } from "../../utils/types/types";
import { timeSinceMessageDisplayText } from "../../utils/messages/utils";
+import { getDecodedToken } from "@cashu/cashu-ts";
function isDecodableToken(token: string): boolean {
try {
- atob(token);
+ getDecodedToken(token);
return true;
} catch (e) {
return false;
@@ -65,14 +66,16 @@ export const ChatMessage = ({
}
}, [messageEvent]);
- const tokenAfterCashuA = messageEvent.content.includes("cashuA")
- ? messageEvent.content.split("cashuA")[1]
+ const cashuMatch = messageEvent.content.match(/cashu[A-Za-z]/);
+ const cashuPrefix = cashuMatch ? cashuMatch[0] : null;
+ const tokenAfterCashuVersion = cashuPrefix
+ ? messageEvent.content.split(cashuPrefix)[1]
: null;
- const canDecodeToken = tokenAfterCashuA
- ? isDecodableToken(tokenAfterCashuA)
+ const canDecodeToken = tokenAfterCashuVersion
+ ? isDecodableToken(cashuPrefix + tokenAfterCashuVersion)
: false;
- const contentBeforeCashuA = messageEvent.content.includes("cashuA")
- ? messageEvent.content.split("cashuA")[0]
+ const contentBeforeCashu = cashuPrefix
+ ? messageEvent.content.split(cashuPrefix)[0]
: messageEvent.content;
const { userPubkey } = getLocalStorageData();
@@ -128,15 +131,18 @@ export const ChatMessage = ({
}`}
>
- {messageEvent.content.includes("cashuA") &&
- canDecodeToken &&
- tokenAfterCashuA ? (
+ {cashuPrefix && canDecodeToken && tokenAfterCashuVersion ? (
<>
- {renderMessageContent(contentBeforeCashuA)}
+ {renderMessageContent(contentBeforeCashu)}
-
+
handleCopyToken("cashuA" + tokenAfterCashuA)}
+ onClick={() =>
+ handleCopyToken(cashuPrefix + tokenAfterCashuVersion)
+ }
className={`ml-2 mt-1 h-5 w-5 cursor-pointer text-light-text ${
copiedToClipboard ? "hidden" : ""
}`}
diff --git a/components/product-invoice-card.tsx b/components/product-invoice-card.tsx
index 4430136..7988602 100644
--- a/components/product-invoice-card.tsx
+++ b/components/product-invoice-card.tsx
@@ -31,6 +31,7 @@ import {
CashuMint,
CashuWallet,
getEncodedToken,
+ MintKeyset,
Proof,
} from "@cashu/cashu-ts";
import {
@@ -483,19 +484,12 @@ export default function ProductInvoiceCard({
while (true) {
try {
- const { proofs } = await wallet.requestTokens(newPrice, hash);
-
- // Encoded proofs can be spent at the mint
+ const proofs = await wallet.mintProofs(newPrice, hash);
encoded = getEncodedToken({
- token: [
- {
- mint: mints[0],
- proofs,
- },
- ],
+ mint: mints[0],
+ proofs,
});
-
- if (encoded) {
+ if (encoded !== "" && encoded !== undefined) {
await sendTokens(
encoded,
shippingName ? shippingName : undefined,
@@ -812,19 +806,17 @@ export default function ProductInvoiceCard({
try {
const mint = new CashuMint(mints[0]);
const wallet = new CashuWallet(mint);
- const mintKeySetResponse = await mint.getKeySets();
- const mintKeySetIds = mintKeySetResponse?.keysets;
+ const mintKeySetIds = await wallet.getKeySets();
const filteredProofs = tokens.filter(
- (p: Proof) => mintKeySetIds?.includes(p.id),
+ (p: Proof) =>
+ mintKeySetIds?.some((keysetId: MintKeyset) => keysetId.id === p.id),
);
- const tokenToSend = await wallet.send(price, filteredProofs);
+ const { keep, send } = await wallet.send(price, filteredProofs, {
+ includeFees: true,
+ });
const encodedSendToken = getEncodedToken({
- token: [
- {
- mint: mints[0],
- proofs: tokenToSend.send,
- },
- ],
+ mint: mints[0],
+ proofs: send,
});
await sendTokens(
encodedSendToken,
@@ -845,9 +837,10 @@ export default function ProductInvoiceCard({
.catch((error) => {
console.error(error);
});
- const changeProofs = tokenToSend?.returnChange;
+ const changeProofs = keep;
const remainingProofs = tokens.filter(
- (p: Proof) => !mintKeySetIds?.includes(p.id),
+ (p: Proof) =>
+ mintKeySetIds?.some((keysetId: MintKeyset) => keysetId.id !== p.id),
);
let proofArray;
if (changeProofs.length >= 1 && changeProofs) {
diff --git a/components/utility-components/claim-button.tsx b/components/utility-components/claim-button.tsx
index 5212436..d0821ca 100644
--- a/components/utility-components/claim-button.tsx
+++ b/components/utility-components/claim-button.tsx
@@ -25,23 +25,15 @@ import {
} from "../utility/nostr-helper-functions";
import { SHOPSTRBUTTONCLASSNAMES } from "../utility/STATIC-VARIABLES";
import { LightningAddress } from "@getalby/lightning-tools";
-import { CashuMint, CashuWallet, Proof } from "@cashu/cashu-ts";
+import {
+ CashuMint,
+ CashuWallet,
+ Proof,
+ getDecodedToken,
+} from "@cashu/cashu-ts";
import RedemptionModal from "./redemption-modal";
import { formatWithCommas } from "./display-monetary-info";
-function decodeBase64ToJson(base64: string): any {
- // Step 1: Decode the base64 string to a regular string
- const decodedString = atob(base64);
- // Step 2: Parse the decoded string as JSON
- try {
- const json = JSON.parse(decodedString);
- return json;
- } catch (error) {
- console.error("Error parsing JSON from base64", error);
- throw new Error("Invalid JSON format in base64 string.");
- }
-}
-
export default function ClaimButton({
token,
passphrase,
@@ -51,7 +43,7 @@ export default function ClaimButton({
}) {
const [lnurl, setLnurl] = useState("");
const profileContext = useContext(ProfileMapContext);
- const { userNPub, userPubkey } = getLocalStorageData();
+ const { userPubkey } = getLocalStorageData();
const [openClaimTypeModal, setOpenClaimTypeModal] = useState(false);
const [openRedemptionModal, setOpenRedemptionModal] = useState(false);
@@ -59,7 +51,7 @@ export default function ClaimButton({
const [isRedeemed, setIsRedeemed] = useState(false);
const [isRedeeming, setIsRedeeming] = useState(false);
const [wallet, setWallet] = useState();
- const [proofs, setProofs] = useState([]);
+ const [proofs, setProofs] = useState([]);
const [tokenMint, setTokenMint] = useState("");
const [tokenAmount, setTokenAmount] = useState(0);
const [formattedTokenAmount, setFormattedTokenAmount] = useState("");
@@ -77,15 +69,13 @@ export default function ClaimButton({
const { mints, tokens, history } = getLocalStorageData();
- const [name, setName] = useState("");
-
- const { theme, setTheme } = useTheme();
+ const { theme } = useTheme();
useEffect(() => {
- const decodedToken = decodeBase64ToJson(token);
- const mint = decodedToken.token[0].mint;
+ const decodedToken = getDecodedToken(token);
+ const mint = decodedToken.mint;
setTokenMint(mint);
- const proofs = decodedToken.token[0].proofs;
+ const proofs = decodedToken.proofs;
setProofs(proofs);
const newWallet = new CashuWallet(new CashuMint(mint));
setWallet(newWallet);
@@ -103,8 +93,17 @@ export default function ClaimButton({
const checkProofsSpent = async () => {
try {
if (proofs.length > 0) {
- const spentProofs = await wallet?.checkProofsSpent(proofs);
- if (spentProofs && spentProofs.length > 0) setIsRedeemed(true);
+ let proofsStates = await wallet?.checkProofsStates(proofs);
+ if (proofsStates) {
+ const spentYs = new Set(
+ proofsStates
+ .filter((state) => state.state === "SPENT")
+ .map((state) => state.Y),
+ );
+ if (spentYs.size > 0) {
+ setIsRedeemed(true);
+ }
+ }
}
} catch (error) {
console.error(error);
@@ -126,11 +125,6 @@ export default function ClaimButton({
? sellerProfile.content.lud16
: "invalid",
);
- setName(
- sellerProfile && sellerProfile.content.name
- ? sellerProfile.content.name
- : userNPub,
- );
}, [profileContext, tokenMint]);
useEffect(() => {
@@ -164,8 +158,15 @@ export default function ClaimButton({
setIsInvalidToken(false);
setIsRedeeming(true);
try {
- const spentProofs = await wallet?.checkProofsSpent(proofs);
- if (spentProofs?.length === 0) {
+ let proofsStates = await wallet?.checkProofsStates(proofs);
+ const spentYs = proofsStates
+ ? new Set(
+ proofsStates
+ .filter((state) => state.state === "SPENT")
+ .map((state) => state.Y),
+ )
+ : new Set();
+ if (spentYs.size === 0) {
const uniqueProofs = proofs.filter(
(proof: Proof) => !tokens.some((token: Proof) => token.C === proof.C),
);
@@ -223,28 +224,37 @@ export default function ClaimButton({
const newAmount = Math.floor(tokenAmount * 0.98 - 2);
const ln = new LightningAddress(lnurl);
try {
- await ln.fetch();
- const invoice = await ln.requestInvoice({ satoshi: newAmount });
- const invoicePaymentRequest = invoice.paymentRequest;
- const response = await wallet?.payLnInvoice(
- invoicePaymentRequest,
- proofs,
- );
- const changeProofs = response?.change;
- const changeAmount =
- Array.isArray(changeProofs) && changeProofs.length > 0
- ? changeProofs.reduce(
- (acc, current: Proof) => acc + current.amount,
- 0,
- )
- : 0;
- if (changeAmount >= 1 && changeProofs) {
- setClaimChangeAmount(changeAmount);
- setClaimChangeProofs(changeProofs);
+ if (wallet) {
+ await wallet.loadMint();
+ await ln.fetch();
+ const invoice = await ln.requestInvoice({ satoshi: newAmount });
+ const invoicePaymentRequest = invoice.paymentRequest;
+ const meltQuote = await wallet.createMeltQuote(invoicePaymentRequest);
+ if (meltQuote) {
+ const meltQuoteTotal = meltQuote.amount + meltQuote.fee_reserve;
+ const { keep, send } = await wallet.send(meltQuoteTotal, proofs, {
+ includeFees: true,
+ });
+ const meltResponse = await wallet.meltProofs(meltQuote, send);
+ const changeProofs = [...keep, ...meltResponse.change];
+ const changeAmount =
+ Array.isArray(changeProofs) && changeProofs.length > 0
+ ? changeProofs.reduce(
+ (acc, current: Proof) => acc + current.amount,
+ 0,
+ )
+ : 0;
+ if (changeAmount >= 1 && changeProofs) {
+ setClaimChangeAmount(changeAmount);
+ setClaimChangeProofs(changeProofs);
+ }
+ setIsPaid(true);
+ setOpenRedemptionModal(true);
+ setIsRedeeming(false);
+ }
+ } else {
+ throw new Error("Wallet not initialized");
}
- setIsPaid(true);
- setOpenRedemptionModal(true);
- setIsRedeeming(false);
} catch (error) {
console.log(error);
setIsPaid(false);
diff --git a/components/utility-components/redemption-modal.tsx b/components/utility-components/redemption-modal.tsx
index 89e6a06..4064157 100644
--- a/components/utility-components/redemption-modal.tsx
+++ b/components/utility-components/redemption-modal.tsx
@@ -41,7 +41,7 @@ export default function RedemptionModal({
changeMint: string;
}) {
const [showModal, setShowModal] = useState(false);
- const { userPubkey, relays } = getLocalStorageData();
+ const { userPubkey } = getLocalStorageData();
const [formattedChangeAmount, setFormattedChangeAmount] = useState("");
@@ -92,12 +92,8 @@ export default function RedemptionModal({
let decodedRandomPubkeyForReceiver = nip19.decode(randomNpubForReceiver);
let decodedRandomPrivkeyForReceiver = nip19.decode(randomNsecForReceiver);
let encodedChange = getEncodedToken({
- token: [
- {
- mint: changeMint,
- proofs: changeProofs,
- },
- ],
+ mint: changeMint,
+ proofs: changeProofs,
});
const paymentMessage = "Overpaid fee change: " + encodedChange;
let giftWrappedMessageEvent = await constructGiftWrappedMessageEvent(
diff --git a/components/wallet/mint-button.tsx b/components/wallet/mint-button.tsx
index 6caaf44..e7ba19f 100644
--- a/components/wallet/mint-button.tsx
+++ b/components/wallet/mint-button.tsx
@@ -129,7 +129,7 @@ const MintButton = ({ passphrase }: { passphrase?: string }) => {
) {
while (true) {
try {
- const { proofs } = await wallet.requestTokens(numSats, hash);
+ const proofs = await wallet.mintProofs(numSats, hash);
if (proofs) {
const proofArray = [...tokens, ...proofs];
diff --git a/components/wallet/pay-button.tsx b/components/wallet/pay-button.tsx
index 00caba5..0b5c4fe 100644
--- a/components/wallet/pay-button.tsx
+++ b/components/wallet/pay-button.tsx
@@ -23,7 +23,7 @@ import {
publishSpendingHistoryEvent,
} from "../utility/nostr-helper-functions";
import { SHOPSTRBUTTONCLASSNAMES } from "../utility/STATIC-VARIABLES";
-import { CashuMint, CashuWallet, Proof } from "@cashu/cashu-ts";
+import { CashuMint, CashuWallet, MintKeyset, Proof } from "@cashu/cashu-ts";
import { formatWithCommas } from "../utility-components/display-monetary-info";
import { CashuWalletContext } from "../../utils/context/context";
@@ -34,7 +34,7 @@ const PayButton = ({ passphrase }: { passphrase?: string }) => {
const [isRedeeming, setIsRedeeming] = useState(false);
// const [totalAmount, setTotalAmount] = useState(0);
- const [feeAmount, setFeeAmount] = useState("");
+ const [feeReserveAmount, setFeeReserveAmount] = useState("");
const { mints, tokens, history } = getLocalStorageData();
@@ -49,9 +49,6 @@ const PayButton = ({ passphrase }: { passphrase?: string }) => {
reset: payReset,
} = useForm();
- const getMint = () => new CashuMint(mints[0]);
- const getWallet = () => new CashuWallet(getMint());
-
useEffect(() => {
const walletEvent = walletContext.mostRecentWalletEvent;
if (walletEvent?.tags) {
@@ -73,20 +70,18 @@ const PayButton = ({ passphrase }: { passphrase?: string }) => {
};
const calculateFee = async (invoice: string) => {
- setFeeAmount("");
+ setFeeReserveAmount("");
if (invoice && /^lnbc/.test(invoice)) {
- const fee = await getWallet().getFee(invoice);
- if (fee) {
- setFeeAmount(formatWithCommas(fee, "sats"));
- // const invoiceValue = new Invoice({ invoice });
- // const { satoshi } = invoiceValue;
- // const total = satoshi + fee;
- // setTotalAmount(total);
+ const mint = new CashuMint(mints[0]);
+ const wallet = new CashuWallet(mint);
+ const meltQuote = await wallet?.createMeltQuote(invoice);
+ if (meltQuote) {
+ setFeeReserveAmount(formatWithCommas(meltQuote.fee_reserve, "sats"));
} else {
- setFeeAmount("");
+ setFeeReserveAmount("");
}
} else {
- setFeeAmount("");
+ setFeeReserveAmount("");
}
};
@@ -95,16 +90,19 @@ const PayButton = ({ passphrase }: { passphrase?: string }) => {
setPaymentFailed(false);
setIsRedeeming(true);
try {
- const mintKeySetResponse = await getMint().getKeySets();
- const mintKeySetIds = mintKeySetResponse?.keysets;
- const filteredProofs = tokens.filter(
- (p: Proof) => mintKeySetIds?.includes(p.id),
- );
- const response = await getWallet().payLnInvoice(
- invoiceString,
- filteredProofs,
+ const mint = new CashuMint(mints[0]);
+ const wallet = new CashuWallet(mint);
+ const mintKeySetIds = await wallet.getKeySets();
+ const filteredProofs = tokens.filter((p: Proof) =>
+ mintKeySetIds.some((keyset: MintKeyset) => keyset.id === p.id),
);
- const changeProofs = response?.change;
+ const meltQuote = await wallet.createMeltQuote(invoiceString);
+ const meltQuoteTotal = meltQuote.amount + meltQuote.fee_reserve;
+ const { keep, send } = await wallet.send(meltQuoteTotal, filteredProofs, {
+ includeFees: true,
+ });
+ const meltResponse = await wallet.meltProofs(meltQuote, send);
+ const changeProofs = [...keep, ...meltResponse.change];
const changeAmount =
Array.isArray(changeProofs) && changeProofs.length > 0
? changeProofs.reduce(
@@ -113,7 +111,8 @@ const PayButton = ({ passphrase }: { passphrase?: string }) => {
)
: 0;
const remainingProofs = tokens.filter(
- (p: Proof) => !mintKeySetIds?.includes(p.id),
+ (p: Proof) =>
+ mintKeySetIds?.some((keysetId: MintKeyset) => keysetId.id !== p.id),
);
let proofArray;
if (changeAmount >= 1 && changeProofs) {
@@ -235,9 +234,9 @@ const PayButton = ({ passphrase }: { passphrase?: string }) => {
onBlur={onBlur} // notify when input is touched/blur
value={value}
/>
- {feeAmount && (
+ {feeReserveAmount && (
- Estimated Fee: {feeAmount}
+ Fee Reserve: {feeReserveAmount}
)}
{/* {totalAmount && totalAmount >= 1 && (
diff --git a/components/wallet/receive-button.tsx b/components/wallet/receive-button.tsx
index 98e4f5d..008e03a 100644
--- a/components/wallet/receive-button.tsx
+++ b/components/wallet/receive-button.tsx
@@ -73,12 +73,16 @@ const ReceiveButton = ({ passphrase }: { passphrase?: string }) => {
setIsInvalidToken(false);
try {
const token = getDecodedToken(tokenString);
- const tokenEntry = token.token;
- const tokenMint = tokenEntry[0].mint;
- const tokenProofs = tokenEntry[0].proofs;
+ const tokenMint = token.mint;
+ const tokenProofs = token.proofs;
const wallet = new CashuWallet(new CashuMint(tokenMint));
- const spentProofs = await wallet?.checkProofsSpent(tokenProofs);
- if (spentProofs.length === 0) {
+ let proofsStates = await wallet.checkProofsStates(tokenProofs);
+ const spentYs = new Set(
+ proofsStates
+ .filter((state) => state.state === "SPENT")
+ .map((state) => state.Y),
+ );
+ if (spentYs.size === 0) {
const uniqueProofs = tokenProofs.filter(
(proof: Proof) => !tokens.some((token: Proof) => token.C === proof.C),
);
@@ -165,10 +169,10 @@ const ReceiveButton = ({ passphrase }: { passphrase?: string }) => {
rules={{
required: "A Cashu token string is required.",
validate: (value) =>
- /^(web\+cashu:\/\/|cashu:\/\/|cashu:|cashuA)/.test(
+ /^(web\+cashu:\/\/|cashu:\/\/|cashu:|cashu[a-zA-Z])/.test(
value,
) ||
- "The token must start with 'web+cashu://', 'cashu://', 'cashu:', or 'cashuA'.",
+ "The token must start with 'web+cashu://', 'cashu://', 'cashu:', or 'cashu' followed by a versioning letter.",
}}
render={({
field: { onChange, onBlur, value },
diff --git a/components/wallet/send-button.tsx b/components/wallet/send-button.tsx
index c825577..567e985 100644
--- a/components/wallet/send-button.tsx
+++ b/components/wallet/send-button.tsx
@@ -31,6 +31,7 @@ import {
CashuMint,
CashuWallet,
getEncodedToken,
+ MintKeyset,
Proof,
} from "@cashu/cashu-ts";
import { CashuWalletContext } from "../../utils/context/context";
@@ -81,25 +82,25 @@ const SendButton = ({ passphrase }: { passphrase?: string }) => {
try {
const mint = new CashuMint(mints[0]);
const wallet = new CashuWallet(mint);
- const mintKeySetResponse = await mint.getKeySets();
- const mintKeySetIds = mintKeySetResponse?.keysets;
+ const mintKeySetIds = await wallet.getKeySets();
const filteredProofs = tokens.filter(
- (p: Proof) => mintKeySetIds?.includes(p.id),
+ (p: Proof) =>
+ mintKeySetIds?.some((keysetId: MintKeyset) => keysetId.id === p.id),
);
- const tokenToSend = await wallet.send(numSats, filteredProofs);
+ let sendTotal = (numSats / 10) * 10;
+ const { keep, send } = await wallet.send(sendTotal, filteredProofs, {
+ includeFees: true,
+ });
const encodedSendToken = getEncodedToken({
- token: [
- {
- mint: mints[0],
- proofs: tokenToSend.send,
- },
- ],
+ mint: mints[0],
+ proofs: send,
});
setShowTokenCard(true);
setNewToken(encodedSendToken);
- const changeProofs = tokenToSend?.returnChange;
+ const changeProofs = keep;
const remainingProofs = tokens.filter(
- (p: Proof) => !mintKeySetIds?.includes(p.id),
+ (p: Proof) =>
+ mintKeySetIds?.some((keysetId: MintKeyset) => keysetId.id !== p.id),
);
let proofArray;
if (changeProofs.length >= 1 && changeProofs) {
diff --git a/components/wallet/transactions.tsx b/components/wallet/transactions.tsx
index 369f3a1..25b1900 100644
--- a/components/wallet/transactions.tsx
+++ b/components/wallet/transactions.tsx
@@ -27,7 +27,7 @@ const Transactions = () => {
// Set up polling with setInterval
const interval = setInterval(() => {
fetchAndUpdateTransactions();
- }, 1000); // Polling every 1000 milliseconds (1 seconds)
+ }, 2100); // Polling every 2100 milliseconds (2.1 seconds)
// Clean up on component unmount
return () => clearInterval(interval);
}, []);
diff --git a/package-lock.json b/package-lock.json
index a4ee92c..fac397b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@braintree/sanitize-url": "^7.1.0",
- "@cashu/cashu-ts": "^0.8.1",
+ "@cashu/cashu-ts": "^2.1.0",
"@getalby/lightning-tools": "^5.0.1",
"@heroicons/react": "^2.1.1",
"@itseasy21/react-elastic-carousel": "^0.12.3",
@@ -1831,16 +1831,168 @@
"integrity": "sha512-o+UlMLt49RvtCASlOMW0AkHnabN9wR9rwCCherxO0yG4Npy34GkvrAqdXQvrhNs+jh+gkK8gB8Lf05qL/O7KWg=="
},
"node_modules/@cashu/cashu-ts": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-0.8.1.tgz",
- "integrity": "sha512-36+e5jJagwhzxxSW+WcVnjuiQQIp/rCabqURyEIce//+L3LuQmQ2xC32WskPUmxSFKhN8Nnngsma/pH6XzTWkw==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-2.1.0.tgz",
+ "integrity": "sha512-qFfFz1dx9keJxumjk5FyTvI1j0Yp/P5LXDy0cGO4Xlp3WYKOI1nykNOTPd+bTY9vSkvIM+xuXRer9BtQxqHtwA==",
"license": "MIT",
"dependencies": {
- "@gandlaf21/bolt11-decode": "^3.0.6",
- "@noble/curves": "^1.0.0",
+ "@cashu/crypto": "^0.3.4",
+ "@noble/curves": "^1.3.0",
+ "@noble/hashes": "^1.3.3",
+ "@scure/bip32": "^1.3.3",
"buffer": "^6.0.3"
}
},
+ "node_modules/@cashu/cashu-ts/node_modules/@noble/curves": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.7.0.tgz",
+ "integrity": "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==",
+ "license": "MIT",
+ "dependencies": {
+ "@noble/hashes": "1.6.0"
+ },
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/cashu-ts/node_modules/@noble/curves/node_modules/@noble/hashes": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.0.tgz",
+ "integrity": "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/cashu-ts/node_modules/@noble/hashes": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.1.tgz",
+ "integrity": "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/cashu-ts/node_modules/@scure/base": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.1.tgz",
+ "integrity": "sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/cashu-ts/node_modules/@scure/bip32": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.0.tgz",
+ "integrity": "sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@noble/curves": "~1.7.0",
+ "@noble/hashes": "~1.6.0",
+ "@scure/base": "~1.2.1"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/crypto": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/@cashu/crypto/-/crypto-0.3.4.tgz",
+ "integrity": "sha512-mfv1Pj4iL1PXzUj9NKIJbmncCLMqYfnEDqh/OPxAX0nNBt6BOnVJJLjLWFlQeYxlnEfWABSNkrqPje1t5zcyhA==",
+ "license": "MIT",
+ "dependencies": {
+ "@noble/curves": "^1.6.0",
+ "@noble/hashes": "^1.5.0",
+ "@scure/bip32": "^1.5.0",
+ "@scure/bip39": "^1.4.0",
+ "buffer": "^6.0.3"
+ }
+ },
+ "node_modules/@cashu/crypto/node_modules/@noble/curves": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.7.0.tgz",
+ "integrity": "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==",
+ "license": "MIT",
+ "dependencies": {
+ "@noble/hashes": "1.6.0"
+ },
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/crypto/node_modules/@noble/curves/node_modules/@noble/hashes": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.0.tgz",
+ "integrity": "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/crypto/node_modules/@noble/hashes": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.1.tgz",
+ "integrity": "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/crypto/node_modules/@scure/base": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.1.tgz",
+ "integrity": "sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/crypto/node_modules/@scure/bip32": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.0.tgz",
+ "integrity": "sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@noble/curves": "~1.7.0",
+ "@noble/hashes": "~1.6.0",
+ "@scure/base": "~1.2.1"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@cashu/crypto/node_modules/@scure/bip39": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.0.tgz",
+ "integrity": "sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==",
+ "license": "MIT",
+ "dependencies": {
+ "@noble/hashes": "~1.6.0",
+ "@scure/base": "~1.2.1"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@@ -2034,16 +2186,6 @@
"tslib": "^2.4.0"
}
},
- "node_modules/@gandlaf21/bolt11-decode": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/@gandlaf21/bolt11-decode/-/bolt11-decode-3.0.6.tgz",
- "integrity": "sha512-KUcAK2b9or8J47hzNTM2A+xdU0jCGIL4oC4TDyUlRYMfS5dBVOh4ywg9r3TZD8C/eVx7r14Hp4F79CSDjyCWTQ==",
- "dependencies": {
- "bech32": "^1.1.2",
- "bn.js": "^4.11.8",
- "buffer": "^6.0.3"
- }
- },
"node_modules/@getalby/lightning-tools": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@getalby/lightning-tools/-/lightning-tools-5.0.1.tgz",
@@ -5836,12 +5978,8 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
- },
- "node_modules/bech32": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
- "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
+ ],
+ "license": "MIT"
},
"node_modules/big.js": {
"version": "5.2.2",
@@ -5864,11 +6002,6 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
- "node_modules/bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
- },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -5938,6 +6071,7 @@
"url": "https://feross.org/support"
}
],
+ "license": "MIT",
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
@@ -7948,7 +8082,8 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
+ ],
+ "license": "BSD-3-Clause"
},
"node_modules/ignore": {
"version": "5.2.4",
@@ -8951,6 +9086,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -13422,13 +13558,110 @@
"integrity": "sha512-o+UlMLt49RvtCASlOMW0AkHnabN9wR9rwCCherxO0yG4Npy34GkvrAqdXQvrhNs+jh+gkK8gB8Lf05qL/O7KWg=="
},
"@cashu/cashu-ts": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-0.8.1.tgz",
- "integrity": "sha512-36+e5jJagwhzxxSW+WcVnjuiQQIp/rCabqURyEIce//+L3LuQmQ2xC32WskPUmxSFKhN8Nnngsma/pH6XzTWkw==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@cashu/cashu-ts/-/cashu-ts-2.1.0.tgz",
+ "integrity": "sha512-qFfFz1dx9keJxumjk5FyTvI1j0Yp/P5LXDy0cGO4Xlp3WYKOI1nykNOTPd+bTY9vSkvIM+xuXRer9BtQxqHtwA==",
"requires": {
- "@gandlaf21/bolt11-decode": "^3.0.6",
- "@noble/curves": "^1.0.0",
+ "@cashu/crypto": "^0.3.4",
+ "@noble/curves": "^1.3.0",
+ "@noble/hashes": "^1.3.3",
+ "@scure/bip32": "^1.3.3",
"buffer": "^6.0.3"
+ },
+ "dependencies": {
+ "@noble/curves": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.7.0.tgz",
+ "integrity": "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==",
+ "requires": {
+ "@noble/hashes": "1.6.0"
+ },
+ "dependencies": {
+ "@noble/hashes": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.0.tgz",
+ "integrity": "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ=="
+ }
+ }
+ },
+ "@noble/hashes": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.1.tgz",
+ "integrity": "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w=="
+ },
+ "@scure/base": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.1.tgz",
+ "integrity": "sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ=="
+ },
+ "@scure/bip32": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.0.tgz",
+ "integrity": "sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==",
+ "requires": {
+ "@noble/curves": "~1.7.0",
+ "@noble/hashes": "~1.6.0",
+ "@scure/base": "~1.2.1"
+ }
+ }
+ }
+ },
+ "@cashu/crypto": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/@cashu/crypto/-/crypto-0.3.4.tgz",
+ "integrity": "sha512-mfv1Pj4iL1PXzUj9NKIJbmncCLMqYfnEDqh/OPxAX0nNBt6BOnVJJLjLWFlQeYxlnEfWABSNkrqPje1t5zcyhA==",
+ "requires": {
+ "@noble/curves": "^1.6.0",
+ "@noble/hashes": "^1.5.0",
+ "@scure/bip32": "^1.5.0",
+ "@scure/bip39": "^1.4.0",
+ "buffer": "^6.0.3"
+ },
+ "dependencies": {
+ "@noble/curves": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.7.0.tgz",
+ "integrity": "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==",
+ "requires": {
+ "@noble/hashes": "1.6.0"
+ },
+ "dependencies": {
+ "@noble/hashes": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.0.tgz",
+ "integrity": "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ=="
+ }
+ }
+ },
+ "@noble/hashes": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.1.tgz",
+ "integrity": "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w=="
+ },
+ "@scure/base": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.1.tgz",
+ "integrity": "sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ=="
+ },
+ "@scure/bip32": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.0.tgz",
+ "integrity": "sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==",
+ "requires": {
+ "@noble/curves": "~1.7.0",
+ "@noble/hashes": "~1.6.0",
+ "@scure/base": "~1.2.1"
+ }
+ },
+ "@scure/bip39": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.0.tgz",
+ "integrity": "sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==",
+ "requires": {
+ "@noble/hashes": "~1.6.0",
+ "@scure/base": "~1.2.1"
+ }
+ }
}
},
"@cspotcode/source-map-support": {
@@ -13597,16 +13830,6 @@
"tslib": "^2.4.0"
}
},
- "@gandlaf21/bolt11-decode": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/@gandlaf21/bolt11-decode/-/bolt11-decode-3.0.6.tgz",
- "integrity": "sha512-KUcAK2b9or8J47hzNTM2A+xdU0jCGIL4oC4TDyUlRYMfS5dBVOh4ywg9r3TZD8C/eVx7r14Hp4F79CSDjyCWTQ==",
- "requires": {
- "bech32": "^1.1.2",
- "bn.js": "^4.11.8",
- "buffer": "^6.0.3"
- }
- },
"@getalby/lightning-tools": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@getalby/lightning-tools/-/lightning-tools-5.0.1.tgz",
@@ -16469,11 +16692,6 @@
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
- "bech32": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
- "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
- },
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -16489,11 +16707,6 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
- "bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
- },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
diff --git a/package.json b/package.json
index 47e7b27..a86e1ff 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@braintree/sanitize-url": "^7.1.0",
- "@cashu/cashu-ts": "^0.8.1",
+ "@cashu/cashu-ts": "^2.1.0",
"@getalby/lightning-tools": "^5.0.1",
"@heroicons/react": "^2.1.1",
"@itseasy21/react-elastic-carousel": "^0.12.3",
diff --git a/pages/api/cashu/request-mint.ts b/pages/api/cashu/request-mint.ts
index 701f687..21e5eb0 100644
--- a/pages/api/cashu/request-mint.ts
+++ b/pages/api/cashu/request-mint.ts
@@ -14,7 +14,7 @@ const requestMint = async (req: NextApiRequest, res: NextApiResponse) => {
const wallet = new CashuWallet(new CashuMint(mintUrl));
- const { pr, hash } = await wallet.requestMint(total);
+ const { request, quote } = await wallet.createMintQuote(total);
const id = uuid();
@@ -23,9 +23,9 @@ const requestMint = async (req: NextApiRequest, res: NextApiResponse) => {
date_time: DateTime.now().toUTC().toSQL(),
total,
currency,
- hash,
+ hash: quote,
});
- return res.status(200).json({ pr, hash, id });
+ return res.status(200).json({ pr: request, hash: quote, id });
} catch (error) {
console.error(error);
return res.status(500).json({ error });
diff --git a/pages/api/metrics/post-invoice-status.ts b/pages/api/metrics/post-invoice-status.ts
index b068296..58b759e 100644
--- a/pages/api/metrics/post-invoice-status.ts
+++ b/pages/api/metrics/post-invoice-status.ts
@@ -42,7 +42,7 @@ const UpdateInvoice = async (req: NextApiRequest, res: NextApiResponse) => {
} = response[0];
try {
- await wallet.requestTokens(total, hash);
+ await wallet.mintProofs(total, hash);
} catch (error: any) {
console.error(error);
if (error.message.includes("quote already issued")) {
diff --git a/pages/api/nostr/fetch-service.ts b/pages/api/nostr/fetch-service.ts
index c954063..e1b012d 100644
--- a/pages/api/nostr/fetch-service.ts
+++ b/pages/api/nostr/fetch-service.ts
@@ -26,6 +26,7 @@ import {
} from "@/components/utility/product-parser-functions";
import { calculateWeightedScore } from "@/components/utility/review-parser-functions";
import { DeleteEvent } from "../../../pages/api/nostr/crud-service";
+import { hashToCurve } from "@cashu/crypto/modules/common";
function getUniqueProofs(proofs: Proof[]): Proof[] {
const uniqueProofs = new Set();
@@ -1048,6 +1049,7 @@ export const fetchCashuWallet = async (
}> => {
return new Promise(async function (resolve, reject) {
const { userPubkey, signInMethod, tokens } = getLocalStorageData();
+ const enc = new TextEncoder();
try {
let mostRecentWalletEvent: NostrEvent[] = [];
let proofEvents: any[] = [];
@@ -1201,15 +1203,21 @@ export const fetchCashuWallet = async (
let wallet = new CashuWallet(
new CashuMint(cashuWalletEventContent?.mint),
);
- let spentProofs = await wallet?.checkProofsSpent(
+ const Ys = cashuWalletEventContent?.proofs.map((p: Proof) =>
+ hashToCurve(enc.encode(p.secret)).toHex(true),
+ );
+ let proofsStates = await wallet?.checkProofsStates(
cashuWalletEventContent?.proofs,
);
- if (
- spentProofs &&
- spentProofs.length > 0 &&
- JSON.stringify(spentProofs) ===
- JSON.stringify(cashuWalletEventContent?.proofs)
- ) {
+ const spentYs = new Set(
+ proofsStates
+ .filter((state) => state.state === "SPENT")
+ .map((state) => state.Y),
+ );
+ const allYsMatch =
+ Ys.length === spentYs.size &&
+ Ys.every((y: string) => spentYs.has(y));
+ if (proofsStates && proofsStates.length > 0 && allYsMatch) {
await DeleteEvent([event.id], passphrase);
} else if (cashuWalletEventContent.proofs) {
let allProofs = [
@@ -1235,11 +1243,19 @@ export const fetchCashuWallet = async (
try {
let wallet = new CashuWallet(new CashuMint(mint));
if (cashuProofs.length > 0) {
- let spentProofs =
- await wallet?.checkProofsSpent(cashuProofs);
- if (spentProofs.length > 0) {
+ const Ys = cashuProofs.map((p: Proof) =>
+ hashToCurve(enc.encode(p.secret)).toHex(true),
+ );
+ let proofsStates =
+ await wallet?.checkProofsStates(cashuProofs);
+ const spentYs = new Set(
+ proofsStates
+ .filter((state) => state.state === "SPENT")
+ .map((state) => state.Y),
+ );
+ if (spentYs.size > 0) {
cashuProofs = cashuProofs.filter(
- (proof) => !spentProofs.includes(proof),
+ (proof, index) => !spentYs.has(Ys[index]),
);
}
}
diff --git a/pages/wallet/index.tsx b/pages/wallet/index.tsx
index b5f84b5..e9c2557 100644
--- a/pages/wallet/index.tsx
+++ b/pages/wallet/index.tsx
@@ -9,7 +9,7 @@ import ReceiveButton from "../../components/wallet/receive-button";
import SendButton from "../../components/wallet/send-button";
import PayButton from "../../components/wallet/pay-button";
import Transactions from "../../components/wallet/transactions";
-import { CashuMint, Proof } from "@cashu/cashu-ts";
+import { CashuMint, CashuWallet, MintKeyset, Proof } from "@cashu/cashu-ts";
import RequestPassphraseModal from "@/components/utility-components/request-passphrase-modal";
const Wallet = () => {
@@ -19,7 +19,8 @@ const Wallet = () => {
const [totalBalance, setTotalBalance] = useState(0);
const [walletBalance, setWalletBalance] = useState(0);
const [mint, setMint] = useState("");
- const [mintKeySetIds, setMintKeySetIds] = useState([]);
+ const [wallet, setWallet] = useState();
+ const [mintKeySetIds, setMintKeySetIds] = useState([]);
const router = useRouter();
const { signInMethod, mints, tokens } = getLocalStorageData();
@@ -30,20 +31,24 @@ const Wallet = () => {
}
}, [signInMethod, passphrase]);
+ useEffect(() => {
+ let currentMint = new CashuMint(mints[0]);
+ setMint(mints[0]);
+ let cashuWallet = new CashuWallet(currentMint);
+ setWallet(cashuWallet);
+ }, [mints]);
+
useEffect(() => {
const fetchLocalKeySet = async () => {
- if (mints && mints.length > 0) {
- const currentMint = new CashuMint(mints[0]);
- setMint(mints[0]);
- const mintKeySetResponse = await currentMint.getKeySets();
- const mintKeySet = mintKeySetResponse?.keysets;
- if (mintKeySet) {
- setMintKeySetIds(mintKeySet);
+ if (wallet) {
+ const mintKeySetIdsArray = await wallet.getKeySets();
+ if (mintKeySetIdsArray) {
+ setMintKeySetIds(mintKeySetIdsArray);
}
}
};
fetchLocalKeySet();
- }, [mints]);
+ }, [wallet]);
useEffect(() => {
// Function to fetch and update balances
@@ -57,7 +62,8 @@ const Wallet = () => {
}
if (mints && tokens && mintKeySetIds) {
const filteredProofs = tokens.filter(
- (p: Proof) => mintKeySetIds?.includes(p.id),
+ (p: Proof) =>
+ mintKeySetIds?.some((keysetId: MintKeyset) => keysetId.id === p.id),
);
let walletTotal =
filteredProofs && filteredProofs.length >= 1
@@ -71,7 +77,7 @@ const Wallet = () => {
// Set up polling with setInterval
const interval = setInterval(() => {
fetchAndUpdateBalances();
- }, 1000); // Polling every 1000 milliseconds (1 seconds)
+ }, 2100); // Polling every 2100 milliseconds (2.1 seconds)
// Clean up on component unmount
return () => clearInterval(interval);
}, [mintKeySetIds, mints, tokens]);