feat: create organizedProofs function

test: organizedProofs function
This commit is contained in:
P. Reis 2025-02-23 21:06:34 -03:00
parent ac684194a0
commit 61cc7c335a
2 changed files with 158 additions and 2 deletions

View file

@ -5,7 +5,7 @@ import { assertEquals } from '@std/assert';
import { createTestDB, genEvent } from '@/test.ts'; import { createTestDB, genEvent } from '@/test.ts';
import { validateAndParseWallet } from '@/utils/cashu.ts'; import { organizeProofs, validateAndParseWallet } from '@/utils/cashu.ts';
Deno.test('validateAndParseWallet function returns valid data', async () => { Deno.test('validateAndParseWallet function returns valid data', async () => {
await using db = await createTestDB({ pure: true }); await using db = await createTestDB({ pure: true });
@ -51,3 +51,119 @@ Deno.test('validateAndParseWallet function returns valid data', async () => {
mints: ['https://mint.soul.com'], mints: ['https://mint.soul.com'],
}); });
}); });
Deno.test('organizeProofs function is working', async () => {
await using db = await createTestDB({ pure: true });
const store = db.store;
const sk = generateSecretKey();
const signer = new NSecSigner(sk);
const pubkey = await signer.getPublicKey();
const event1 = genEvent({
kind: 7375,
content: await signer.nip44.encrypt(
pubkey,
JSON.stringify({
mint: 'https://mint.soul.com',
proofs: [
{
id: '005c2502034d4f12',
amount: 25,
secret: 'z+zyxAVLRqN9lEjxuNPSyRJzEstbl69Jc1vtimvtkPg=',
C: '0241d98a8197ef238a192d47edf191a9de78b657308937b4f7dd0aa53beae72c46',
},
{
id: '005c2502034d4f12',
amount: 25,
secret: 'z+zyxAVLRqN9lEjxuNPSyRJzEstbl69Jc1vtimvtkPg=',
C: '0241d98a8197ef238a192d47edf191a9de78b657308937b4f7dd0aa53beae72c46',
},
{
id: '005c2502034d4f12',
amount: 25,
secret: 'z+zyxAVLRqN9lEjxuNPSyRJzEstbl69Jc1vtimvtkPg=',
C: '0241d98a8197ef238a192d47edf191a9de78b657308937b4f7dd0aa53beae72c46',
},
{
id: '005c2502034d4f12',
amount: 25,
secret: 'z+zyxAVLRqN9lEjxuNPSyRJzEstbl69Jc1vtimvtkPg=',
C: '0241d98a8197ef238a192d47edf191a9de78b657308937b4f7dd0aa53beae72c46',
},
],
del: [],
}),
),
}, sk);
await db.store.event(event1);
const proof1 = {
'id': '004f7adf2a04356c',
'amount': 1,
'secret': '6780378b186cf7ada639ce4807803ad5e4a71217688430512f35074f9bca99c0',
'C': '03f0dd8df04427c8c53e4ae9ce8eb91c4880203d6236d1d745c788a5d7a47aaff3',
'dleq': {
'e': 'bd22fcdb7ede1edb52b9b8c6e1194939112928e7b4fc0176325e7671fb2bd351',
's': 'a9ad015571a0e538d62966a16d2facf806fb956c746a3dfa41fa689486431c67',
'r': 'b283980e30bf5a31a45e5e296e93ae9f20bf3a140c884b3b4cd952dbecc521df',
},
};
const token1 = JSON.stringify({
mint: 'https://mint-fashion.com',
proofs: [proof1],
del: [],
});
const event2 = genEvent({
kind: 7375,
content: await signer.nip44.encrypt(
pubkey,
token1,
),
}, sk);
await db.store.event(event2);
const proof2 = {
'id': '004f7adf2a04356c',
'amount': 123,
'secret': '6780378b186cf7ada639ce4807803ad5e4a71217688430512f35074f9bca99c0',
'C': '03f0dd8df04427c8c53e4ae9ce8eb91c4880203d6236d1d745c788a5d7a47aaff3',
'dleq': {
'e': 'bd22fcdb7ede1edb52b9b8c6e1194939112928e7b4fc0176325e7671fb2bd351',
's': 'a9ad015571a0e538d62966a16d2facf806fb956c746a3dfa41fa689486431c67',
'r': 'b283980e30bf5a31a45e5e296e93ae9f20bf3a140c884b3b4cd952dbecc521df',
},
};
const token2 = JSON.stringify({
mint: 'https://mint-fashion.com',
proofs: [proof2],
del: [],
});
const event3 = genEvent({
kind: 7375,
content: await signer.nip44.encrypt(
pubkey,
token2,
),
}, sk);
await db.store.event(event3);
const unspentProofs = await store.query([{ kinds: [7375], authors: [pubkey] }]);
const organizedProofs = await organizeProofs(unspentProofs, signer);
assertEquals(organizedProofs, {
'https://mint.soul.com': {
totalBalance: 100,
[event1.id]: { event: event1, balance: 100 },
},
'https://mint-fashion.com': {
totalBalance: 124,
[event2.id]: { event: event2, balance: 1 },
[event3.id]: { event: event3, balance: 123 },
},
});
});

View file

@ -7,6 +7,7 @@ import { z } from 'zod';
import { errorJson } from '@/utils/log.ts'; import { errorJson } from '@/utils/log.ts';
import { isNostrId } from '@/utils.ts'; import { isNostrId } from '@/utils.ts';
import { tokenEventSchema } from '@/schemas/cashu.ts';
type Data = { type Data = {
wallet: NostrEvent; wallet: NostrEvent;
@ -99,4 +100,43 @@ async function validateAndParseWallet(
return { data: { wallet, nutzapInfo, privkey, p2pk, mints }, error: null }; return { data: { wallet, nutzapInfo, privkey, p2pk, mints }, error: null };
} }
export { validateAndParseWallet }; type OrganizedProofs = {
[mintUrl: string]: {
/** Total balance in this mint */
totalBalance: number;
/** Event id */
[eventId: string]: {
event: NostrEvent;
/** Total balance in this event */
balance: number;
} | number;
};
};
async function organizeProofs(
events: NostrEvent[],
signer: SetRequired<NostrSigner, 'nip44'>,
): Promise<OrganizedProofs> {
const organizedProofs: OrganizedProofs = {};
const pubkey = await signer.getPublicKey();
for (const event of events) {
const decryptedContent = await signer.nip44.decrypt(pubkey, event.content);
const { data: token, success } = n.json().pipe(tokenEventSchema).safeParse(decryptedContent);
if (!success) {
continue;
}
const { mint, proofs } = token;
const balance = proofs.reduce((prev, current) => prev + current.amount, 0);
if (!organizedProofs[mint]) {
organizedProofs[mint] = { totalBalance: 0 };
}
organizedProofs[mint] = { ...organizedProofs[mint], [event.id]: { event, balance } };
organizedProofs[mint].totalBalance += balance;
}
return organizedProofs;
}
export { organizeProofs, validateAndParseWallet };