Skip to content

Commit

Permalink
provide a way to create nuts of specific denomincation(s)
Browse files Browse the repository at this point in the history
  • Loading branch information
pablof7z committed Oct 21, 2024
1 parent 95beb5d commit 4351ec4
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/beige-news-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nostr-dev-kit/ndk-wallet": patch
---

provide a way to create nuts of specific denomincation(s)
7 changes: 6 additions & 1 deletion ndk-wallet/src/cashu/pay/nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import type { Proof } from "@cashu/cashu-ts";
import { CashuMint, CashuWallet } from "@cashu/cashu-ts";
import type { MintUrl } from "../mint/utils";
import type { NDKCashuPay } from "../pay";
import { chooseProofsForAmount, rollOverProofs } from "../proofs";
import { chooseProofsForAmount, chooseProofsForAmounts, rollOverProofs } from "../proofs";
import { NDKCashuWallet } from "../wallet";

export type NutPayment = { amount: number; unit: string; mints: MintUrl[]; p2pk?: string };

export async function mintNuts(this: NDKCashuWallet, amounts: number[], unit: string) {
return await chooseProofsForAmounts(amounts, this);
}

/**
* Generates proof to satisfy a payment.
* Note that this function doesn't send the proofs to the recipient.
Expand Down
80 changes: 79 additions & 1 deletion ndk-wallet/src/cashu/proofs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,84 @@ function chooseProofsForQuote(
return { ...res, quote };
}

export function chooseProofsForAmounts(amounts: number[], wallet: NDKCashuWallet): TokenSelection & { needsSwap: boolean } | undefined {
let missingAmounts: number[] = [...amounts];
let tokenSelection: TokenSelection = {
usedProofs: [],
movedProofs: [],
usedTokens: [],
mint: ""
};
const reset = () => {
tokenSelection = {
usedProofs: [],
movedProofs: [],
usedTokens: [],
mint: ""
};
missingAmounts = [...amounts];
}

// try to find all proofs from the same mint
for (const [mint, tokens] of Object.entries(wallet.mintTokens)) {
reset();
tokenSelection.mint = mint;

for (const token of tokens) {
let tokenUsed = false;
for (const proof of token.proofs) {
if (missingAmounts.includes(proof.amount)) {
missingAmounts.splice(missingAmounts.indexOf(proof.amount), 1);
tokenSelection.usedProofs.push(proof);
tokenUsed = true;
} else {
tokenSelection.movedProofs.push(proof);
}
}

if (tokenUsed) {
tokenSelection.usedTokens.push(token);
}
}

if (missingAmounts.length === 0) {
d("found all proofs using mint %s without having to swap", mint);
return { ...tokenSelection, needsSwap: false };
}
}

for (const [mint, tokens] of Object.entries(wallet.mintTokens)) {
reset();
tokenSelection.mint = mint;
let missingAmount = missingAmounts.reduce((a, b) => a + b, 0);

for (const token of tokens) {
let tokenUsed = false;
for (const proof of token.proofs) {
if (missingAmount > 0) {
missingAmount -= proof.amount;
tokenSelection.usedProofs.push(proof);
tokenUsed = true;
} else {
tokenSelection.movedProofs.push(proof);
}
}

if (tokenUsed) {
tokenSelection.usedTokens.push(token);
}

if (missingAmount <= 0) {
d("found all proofs using mint %s, will need to swap", mint);
return { ...tokenSelection, needsSwap: true };
}
}
}

d("could not find all proofs for the requested amounts");
return;
}

export type ROLL_OVER_RESULT = {
destroyedTokens: NDKCashuToken[],
createdToken: NDKCashuToken | undefined
Expand All @@ -130,7 +208,7 @@ export async function rollOverProofs(
const relaySet = wallet.relaySet;

if (proofs.usedTokens.length > 0) {
console.trace("rolling over proofs for mint %s %d tokens", mint, proofs.usedTokens.length);
// console.trace("rolling over proofs for mint %s %d tokens", mint, proofs.usedTokens.length);

const deleteEvent = new NDKEvent(wallet.event.ndk);
deleteEvent.kind = NDKKind.EventDeletion;
Expand Down
18 changes: 18 additions & 0 deletions ndk-wallet/src/cashu/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { checkTokenProofs } from "./validate.js";
import { NDKWallet, NDKWalletBalance, NDKWalletEvents, NDKWalletStatus } from "../wallet/index.js";
import { EventEmitter } from "tseep";
import { decrypt } from "./decrypt.js";
import { chooseProofsForAmounts, rollOverProofs } from "./proofs.js";

const d = createDebug("ndk-wallet:cashu:wallet");

Expand Down Expand Up @@ -98,6 +99,23 @@ export class NDKCashuWallet extends EventEmitter<NDKWalletEvents> implements NDK

public checkProofs = checkTokenProofs.bind(this);

async mintNuts(amounts: number[], unit: string) {
const tokenSelection = await chooseProofsForAmounts(amounts, this);
if (tokenSelection?.needsSwap) {
const wallet = new CashuWallet(new CashuMint(tokenSelection.mint));
const proofs = await wallet.send(0, tokenSelection.usedProofs, {
preference: amounts.map((a) => ({ amount: a, count: 1 })),
});

await rollOverProofs(tokenSelection, proofs.returnChange, tokenSelection.mint, this);

return proofs.send;
} else if (tokenSelection) {
await rollOverProofs(tokenSelection, [], tokenSelection.mint, this);
}
return tokenSelection?.usedProofs;
}

static async from(event: NDKEvent): Promise<NDKCashuWallet | undefined> {
if (!event.ndk) throw new Error("no ndk instance on event");
const wallet = new NDKCashuWallet(event.ndk, event);
Expand Down

0 comments on commit 4351ec4

Please sign in to comment.