-
Notifications
You must be signed in to change notification settings - Fork 14
Feat: Add new balance breakdown apis #87
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
base: master
Are you sure you want to change the base?
Changes from all commits
6961965
a267a4e
c862e7a
23b1b67
6ab0e59
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,7 @@ import { | |
| type Proof, | ||
| type SerializedBlindedSignature, | ||
| } from '@cashu/cashu-ts'; | ||
| import type { CoreProof } from '../types'; | ||
| import type { CoreProof, BalanceBreakdown, BalancesBreakdownByMint } from '../types'; | ||
| import type { CounterService } from './CounterService'; | ||
| import type { ProofRepository } from '../repositories'; | ||
| import { EventBus } from '../events/EventBus'; | ||
|
|
@@ -268,7 +268,7 @@ export class ProofService { | |
| if (!mintUrl || mintUrl.trim().length === 0) { | ||
| throw new ProofValidationError('mintUrl is required'); | ||
| } | ||
| const proofs = await this.getReadyProofs(mintUrl); | ||
| const proofs = await this.proofRepository.getAvailableProofs(mintUrl); | ||
| return proofs.reduce((acc, proof) => acc + proof.amount, 0); | ||
| } | ||
|
|
||
|
|
@@ -280,6 +280,7 @@ export class ProofService { | |
| const proofs = await this.getAllReadyProofs(); | ||
| const balances: { [mintUrl: string]: number } = {}; | ||
| for (const proof of proofs) { | ||
| if (proof.usedByOperationId) continue; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
By skipping Useful? React with 👍 / 👎. |
||
| const mintUrl = proof.mintUrl; | ||
| const balance = balances[mintUrl] || 0; | ||
| balances[mintUrl] = balance + proof.amount; | ||
|
|
@@ -305,6 +306,67 @@ export class ProofService { | |
| return trustedBalances; | ||
| } | ||
|
|
||
| /** | ||
| * Gets detailed balance breakdown for a single mint. | ||
| * @param mintUrl - The URL of the mint | ||
| * @returns Balance breakdown with ready, reserved, and total amounts | ||
| */ | ||
| async getBalanceBreakdown(mintUrl: string): Promise<BalanceBreakdown> { | ||
| if (!mintUrl || mintUrl.trim().length === 0) { | ||
| throw new ProofValidationError('mintUrl is required'); | ||
| } | ||
| const proofs = await this.getReadyProofs(mintUrl); | ||
| let ready = 0; | ||
| let reserved = 0; | ||
| for (const proof of proofs) { | ||
| if (proof.usedByOperationId) { | ||
| reserved += proof.amount; | ||
| } else { | ||
| ready += proof.amount; | ||
| } | ||
| } | ||
| return { ready, reserved, total: ready + reserved }; | ||
| } | ||
|
|
||
| /** | ||
| * Gets detailed balance breakdown for all mints. | ||
| * @returns An object mapping mint URLs to their balance breakdowns | ||
| */ | ||
| async getBalancesBreakdown(): Promise<BalancesBreakdownByMint> { | ||
| const proofs = await this.getAllReadyProofs(); | ||
| const balances: BalancesBreakdownByMint = {}; | ||
| for (const proof of proofs) { | ||
| const mintUrl = proof.mintUrl; | ||
| const balance = balances[mintUrl] || { ready: 0, reserved: 0, total: 0 }; | ||
| if (proof.usedByOperationId) { | ||
| balance.reserved += proof.amount; | ||
| } else { | ||
| balance.ready += proof.amount; | ||
| } | ||
| balance.total = balance.ready + balance.reserved; | ||
| balances[mintUrl] = balance; | ||
| } | ||
| return balances; | ||
| } | ||
|
|
||
| /** | ||
| * Gets detailed balance breakdown for trusted mints only. | ||
| * @returns An object mapping trusted mint URLs to their balance breakdowns | ||
| */ | ||
| async getTrustedBalancesBreakdown(): Promise<BalancesBreakdownByMint> { | ||
| const balances = await this.getBalancesBreakdown(); | ||
| const trustedMints = await this.mintService.getAllTrustedMints(); | ||
| const trustedUrls = new Set(trustedMints.map((m) => m.mintUrl)); | ||
|
|
||
| const trustedBalances: BalancesBreakdownByMint = {}; | ||
| for (const [mintUrl, balance] of Object.entries(balances)) { | ||
| if (trustedUrls.has(mintUrl)) { | ||
| trustedBalances[mintUrl] = balance; | ||
| } | ||
| } | ||
| return trustedBalances; | ||
| } | ||
|
|
||
| async setProofState( | ||
| mintUrl: string, | ||
| secrets: string[], | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By skipping proofs with
usedByOperationIdhere,getBalances()now returns spendable-only amounts, but reservation/unreservation does not trigger the events that current React balance consumers subscribe to. I checkedpackages/react/src/lib/providers/Balance.tsxandpackages/react/src/lib/hooks/useTrustedBalance.ts: both refresh onproofs:saved/proofs:state-changed(and mint updates), whilereserveProofs/releaseProofsemitproofs:reserved/proofs:released. Duringsend.prepare(which reserves proofs without changing proof state), UI balances can remain stale and overstate spendable funds until a later unrelated event fires.Useful? React with 👍 / 👎.