Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump @cashu/cashu-ts from 0.8.1 to 2.1.0 #92

Merged
merged 4 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 20 additions & 22 deletions components/cart-invoice-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
CashuWallet,
getEncodedToken,
Proof,
MintKeyset,
} from "@cashu/cashu-ts";
import {
constructGiftWrappedMessageEvent,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down
32 changes: 19 additions & 13 deletions components/messages/chat-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -128,15 +131,18 @@ export const ChatMessage = ({
}`}
>
<p className={`inline-block flex-wrap overflow-x-hidden break-all`}>
{messageEvent.content.includes("cashuA") &&
canDecodeToken &&
tokenAfterCashuA ? (
{cashuPrefix && canDecodeToken && tokenAfterCashuVersion ? (
<>
{renderMessageContent(contentBeforeCashuA)}
{renderMessageContent(contentBeforeCashu)}
<div className="flex items-center">
<ClaimButton token={tokenAfterCashuA} passphrase={passphrase} />
<ClaimButton
token={cashuPrefix + tokenAfterCashuVersion}
passphrase={passphrase}
/>
<ClipboardIcon
onClick={() => handleCopyToken("cashuA" + tokenAfterCashuA)}
onClick={() =>
handleCopyToken(cashuPrefix + tokenAfterCashuVersion)
}
className={`ml-2 mt-1 h-5 w-5 cursor-pointer text-light-text ${
copiedToClipboard ? "hidden" : ""
}`}
Expand Down
39 changes: 16 additions & 23 deletions components/product-invoice-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
CashuMint,
CashuWallet,
getEncodedToken,
MintKeyset,
Proof,
} from "@cashu/cashu-ts";
import {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down
114 changes: 62 additions & 52 deletions components/utility-components/claim-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -51,15 +43,15 @@ 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);
const [isPaid, setIsPaid] = useState(false);
const [isRedeemed, setIsRedeemed] = useState(false);
const [isRedeeming, setIsRedeeming] = useState(false);
const [wallet, setWallet] = useState<CashuWallet>();
const [proofs, setProofs] = useState([]);
const [proofs, setProofs] = useState<Proof[]>([]);
const [tokenMint, setTokenMint] = useState("");
const [tokenAmount, setTokenAmount] = useState(0);
const [formattedTokenAmount, setFormattedTokenAmount] = useState("");
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -126,11 +125,6 @@ export default function ClaimButton({
? sellerProfile.content.lud16
: "invalid",
);
setName(
sellerProfile && sellerProfile.content.name
? sellerProfile.content.name
: userNPub,
);
}, [profileContext, tokenMint]);

useEffect(() => {
Expand Down Expand Up @@ -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),
);
Expand Down Expand Up @@ -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);
Expand Down
Loading
Loading