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

Added MintInfo Class #209

Open
wants to merge 9 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
12 changes: 7 additions & 5 deletions src/CashuWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { createP2PKsecret, getSignedProofs } from '@cashu/crypto/modules/client/
import { type Proof as NUT11Proof, DLEQ } from '@cashu/crypto/modules/common/index';
import { SubscriptionCanceller } from './model/types/wallet/websocket.js';
import { verifyDLEQProof_reblind } from '@cashu/crypto/modules/client/NUT12';
import { MintInfo } from './model/MintInfo.js';
/**
* The default number of proofs per denomination to keep in a wallet.
*/
Expand All @@ -66,7 +67,7 @@ class CashuWallet {
private _keysets: Array<MintKeyset> = [];
private _seed: Uint8Array | undefined = undefined;
private _unit = DEFAULT_UNIT;
private _mintInfo: GetInfoResponse | undefined = undefined;
private _mintInfo: MintInfo | undefined = undefined;
private _denominationTarget = DEFAULT_DENOMINATION_TARGET;

mint: CashuMint;
Expand Down Expand Up @@ -102,7 +103,7 @@ class CashuWallet {
if (keys) keys.forEach((key: MintKeys) => this._keys.set(key.id, key));
if (options?.unit) this._unit = options?.unit;
if (options?.keysets) this._keysets = options.keysets;
if (options?.mintInfo) this._mintInfo = options.mintInfo;
if (options?.mintInfo) this._mintInfo = new MintInfo(options.mintInfo);
if (options?.denominationTarget) {
this._denominationTarget = options.denominationTarget;
}
Expand Down Expand Up @@ -134,7 +135,7 @@ class CashuWallet {
get keysets(): Array<MintKeyset> {
return this._keysets;
}
get mintInfo(): GetInfoResponse {
get mintInfo(): MintInfo {
if (!this._mintInfo) {
throw new Error('Mint info not loaded');
}
Expand All @@ -145,8 +146,9 @@ class CashuWallet {
* Get information about the mint
* @returns mint info
*/
async getMintInfo(): Promise<GetInfoResponse> {
this._mintInfo = await this.mint.getInfo();
async getMintInfo(): Promise<MintInfo> {
const infoRes = await this.mint.getInfo();
this._mintInfo = new MintInfo(infoRes);
return this._mintInfo;
}

Expand Down
90 changes: 90 additions & 0 deletions src/model/MintInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { GetInfoResponse, MPPMethod, SwapMethod, WebSocketSupport } from './types';

export class MintInfo {
private readonly mintInfo: GetInfoResponse;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we use _mintInfo to match other private fields?


constructor(info: GetInfoResponse) {
this.mintInfo = info;
}

isSupported(num: 4 | 5): { disabled: boolean; params: Array<SwapMethod> };
isSupported(num: 7 | 8 | 9 | 10 | 11 | 12 | 14): { supported: boolean };
isSupported(num: 17): { supported: boolean; params?: Array<WebSocketSupport> };
isSupported(num: 15): { supported: boolean; params?: Array<MPPMethod> };
isSupported(num: number) {
switch (num) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the cases be handled exhaustively so that unrecognized NUT numbers always resolve to false?
Or alternatively throw on unrecognized NUT number.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good point! I added a default case that throws. Throwing in this case makes more sense to me, because it makes clear that this NUT is unsupported by the client, not the mint

case 4:
case 5: {
return this.checkMintMelt(num);
}
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 14: {
return this.checkGenericNut(num);
}
case 17: {
return this.checkNut17();
}
case 15: {
return this.checkNut15();
}
}
}
private checkGenericNut(num: 7 | 8 | 9 | 10 | 11 | 12 | 14) {
if (this.mintInfo.nuts[num]?.supported) {
return { supported: true };
}
return { supported: false };
}
private checkMintMelt(num: 4 | 5) {
const mintMeltInfo = this.mintInfo.nuts[num];
if (mintMeltInfo && mintMeltInfo.methods.length > 0 && !mintMeltInfo.disabled) {
return { disabled: false, params: mintMeltInfo.methods };
}
return { disabled: true, params: mintMeltInfo.methods };
}
private checkNut17() {
if (this.mintInfo.nuts['17'] && this.mintInfo.nuts[17].supported.length > 0) {
Egge21M marked this conversation as resolved.
Show resolved Hide resolved
return { supported: true, params: this.mintInfo.nuts[17].supported };
}
return { supported: false };
}
private checkNut15() {
if (this.mintInfo.nuts['15'] && this.mintInfo.nuts[15].methods.length > 0) {
return { supported: true, params: this.mintInfo.nuts[15].methods };
}
return { supported: false };
}

get contact() {
return this.mintInfo.contact;
}

get description() {
return this.mintInfo.description;
}

get description_long() {
return this.mintInfo.description_long;
}

get name() {
return this.mintInfo.name;
}

get pubkey() {
return this.mintInfo.pubkey;
}

get version() {
return this.mintInfo.version;
}

get motd() {
return this.mintInfo.motd;
}
}
17 changes: 14 additions & 3 deletions test/wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { getDecodedToken } from '../src/utils.js';
import { Proof } from '@cashu/crypto/modules/common';
import { Server, WebSocket } from 'mock-socket';
import { injectWebSocketImpl } from '../src/ws.js';
import { MintInfo } from '../src/model/MintInfo.js';

injectWebSocketImpl(WebSocket);

Expand Down Expand Up @@ -68,8 +69,18 @@ describe('test info', () => {
{ method: 'twitter', info: '@me' },
{ method: 'nostr', info: 'npub1337' }
]);
expect(info.nuts?.['17']).toEqual({
supported: [
expect(info.isSupported(10)).toEqual({ supported: true });
expect(info.isSupported(5)).toEqual({
disabled: false,
params: [
{ method: 'bolt11', unit: 'sat' },
{ method: 'bolt11', unit: 'usd' },
{ method: 'bolt11', unit: 'eur' }
]
});
expect(info.isSupported(17)).toEqual({
supported: true,
params: [
{
method: 'bolt11',
unit: 'sat',
Expand All @@ -87,7 +98,7 @@ describe('test info', () => {
}
]
});
expect(info).toEqual(mintInfoResp);
expect(info).toEqual(new MintInfo(mintInfoResp));
});
test('test info with deprecated contact field', async () => {
// mintInfoRespDeprecated is the same as mintInfoResp but with the contact field in the old format
Expand Down
Loading