From 706c2e0bea550ab80bb58cfca20922d0acdfd697 Mon Sep 17 00:00:00 2001 From: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:49:47 +0900 Subject: [PATCH 01/29] Update README.md --- README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c7a52e813..2b97628ac 100644 --- a/README.md +++ b/README.md @@ -78,4 +78,25 @@ async function invoiceHasBeenPaid() { Contributions are very welcome. -If you want to contribute, please open an Issue or a PR. +If you want to contribute, please open an Issue or a PR. +If you open a PR, please do so from the `development` branch as the base branch. + +### Version + +``` +* `main` +|\ +| * `staging` +| |\ +| | * `development` +| | |\ +| | | * `feature1` +| | | | +| | |/ +| | * +| | |\ `feature2` +| | | | +| | |/ +| |/ +|/ (create new version) +``` From bc6724aa0fae2454a338d22b85dd04c21b9ba6d3 Mon Sep 17 00:00:00 2001 From: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:50:38 +0900 Subject: [PATCH 02/29] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2b97628ac..0260c1801 100644 --- a/README.md +++ b/README.md @@ -94,8 +94,8 @@ If you open a PR, please do so from the `development` branch as the base branch. | | | | | | |/ | | * -| | |\ `feature2` -| | | | +| | |\ +| | | * `feature2` | | |/ | |/ |/ (create new version) From 4bb76a432f0b01589f95fa370ec5e0d78d0e70ae Mon Sep 17 00:00:00 2001 From: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> Date: Tue, 20 Feb 2024 12:08:10 +0900 Subject: [PATCH 03/29] Update README.md --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0260c1801..70ed88204 100644 --- a/README.md +++ b/README.md @@ -85,9 +85,15 @@ If you open a PR, please do so from the `development` branch as the base branch. ``` * `main` -|\ -| * `staging` -| |\ +|\ +|\ \ +| | * `hotfix` +| | +| * `staging` +| |\ +| |\ \ +| | | * `bugfix` +| | | | | * `development` | | |\ | | | * `feature1` From 53f015a2320c1037cbd9ec47cc8f98be566e3bf7 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:57:48 +0200 Subject: [PATCH 04/29] NUT-06: new info endpoint with monkeypatch for old format, see https://github.com/cashubtc/nuts/pull/117 --- src/CashuMint.ts | 18 +++++++++++++++++- src/CashuWallet.ts | 8 ++++++++ src/model/types/index.ts | 7 ++++++- test/wallet.test.ts | 21 +++++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index fc9873fb9..1c26dd13b 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -48,7 +48,23 @@ class CashuMint { customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; - return requestInstance({ endpoint: joinUrls(mintUrl, '/v1/info') }); + const data = await requestInstance({ + endpoint: joinUrls(mintUrl, '/v1/info') + }); + // BEGIN DEPRECATED + // Monkey patch old contact field ["email", "me@mail.com"] Array<[string, string]>; to new contact field [{method: "email", info: "me@mail.com"}] Array + // This is to maintain backwards compatibility with older versions of the mint + if (Array.isArray(data?.contact) && data?.contact.length > 0) { + data.contact = data.contact.map((contact: any) => { + if (Array.isArray(contact) && contact.length === 2 && typeof contact[0] === 'string' && typeof contact[1] === 'string') { + return { method: contact[0], info: contact[1] }; + } + return contact; + }); + } + // END DEPRECATED + + return data; } /** * fetches mints info at the /info endpoint diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 1d0712db0..db2884331 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -102,6 +102,14 @@ class CashuWallet { this._unit = keys.unit; } + /** + * Get information about the mint + * @returns mint info + */ + async getMintInfo() { + return this.mint.getInfo(); + } + /** * Receive an encoded or raw Cashu token (only supports single tokens. It will only process the first token in the token array) * @param {(string|Token)} token - Cashu token diff --git a/src/model/types/index.ts b/src/model/types/index.ts index 30b9d3a00..2ac83aa3b 100644 --- a/src/model/types/index.ts +++ b/src/model/types/index.ts @@ -473,6 +473,11 @@ export type BlindedMessageData = { rs: Array; }; +export type MintContactInfo = { + method: string; + info: string; +}; + /** * Response from mint at /info endpoint */ @@ -482,7 +487,7 @@ export type GetInfoResponse = { version: string; description?: string; description_long?: string; - contact: Array<[string, string]>; + contact: Array; nuts: { '4': { methods: Array; diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 9b575b36b..41a030b98 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -33,6 +33,27 @@ beforeEach(() => { nock(mintUrl).get('/v1/keys/009a1f293253e41e').reply(200, dummyKeysResp); }); +describe('test info', () => { + const mintInfoResp = JSON.parse('{"name":"Testnut mint","pubkey":"0296d0aa13b6a31cf0cd974249f28c7b7176d7274712c95a41c7d8066d3f29d679","version":"Nutshell/0.16.0","description":"Mint for testing Cashu wallets","description_long":"This mint usually runs the latest main branch of the nutshell repository. All your Lightning invoices will always be marked paid so that you can test minting and melting ecash via Lightning.","contact":[{"method":"email","info":"contact@me.com"},{"method":"twitter","info":"@me"},{"method":"nostr","info":"npub..."}],"motd":"This is a message of the day field. You should display this field to your users if the content changes!","nuts":{"4":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"5":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"7":{"supported":true},"8":{"supported":true},"9":{"supported":true},"10":{"supported":true},"11":{"supported":true},"12":{"supported":true},"17":[{"method":"bolt11","unit":"sat","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]},{"method":"bolt11","unit":"usd","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]}]}}'); + test('test info', async () => { + nock(mintUrl).get('/v1/info').reply(200, mintInfoResp); + const wallet = new CashuWallet(mint, { unit }); + + const info = await wallet.getMintInfo(); + expect(info.contact).toEqual([{ method: 'email', info: 'contact@me.com' }, { method: 'twitter', info: '@me' }, { method: 'nostr', info: 'npub...' }]); + expect(info).toEqual(mintInfoResp); + }); + test('test info with deprecated contact field', async () => { + // mintInfoRespDeprecated is the same as mintInfoResp but with the contact field in the old format + const mintInfoRespDeprecated = JSON.parse('{"name":"Testnut mint","pubkey":"0296d0aa13b6a31cf0cd974249f28c7b7176d7274712c95a41c7d8066d3f29d679","version":"Nutshell/0.16.0","description":"Mint for testing Cashu wallets","description_long":"This mint usually runs the latest main branch of the nutshell repository. All your Lightning invoices will always be marked paid so that you can test minting and melting ecash via Lightning.","contact":[["email","contact@me.com"],["twitter","@me"],["nostr","npub..."]],"motd":"This is a message of the day field. You should display this field to your users if the content changes!","nuts":{"4":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"5":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"7":{"supported":true},"8":{"supported":true},"9":{"supported":true},"10":{"supported":true},"11":{"supported":true},"12":{"supported":true},"17":[{"method":"bolt11","unit":"sat","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]},{"method":"bolt11","unit":"usd","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]}]}}'); + nock(mintUrl).get('/v1/info').reply(200, mintInfoRespDeprecated); + const wallet = new CashuWallet(mint, { unit }); + const info = await wallet.getMintInfo(); + expect(info.contact).toEqual([{ method: 'email', info: 'contact@me.com' }, { method: 'twitter', info: '@me' }, { method: 'nostr', info: 'npub...' }]); + expect(info).toEqual(mintInfoResp); + }); +}); + describe('test fees', () => { test('test melt quote fees', async () => { nock(mintUrl).get('/v1/melt/quote/bolt11/test').reply(200, { From 042bf2b5a6b6838a25f60e559e6ddcc9e37c1072 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:23:01 +0200 Subject: [PATCH 05/29] npm run format --- src/CashuMint.ts | 9 +++++++-- src/base64.ts | 4 ++-- test/wallet.test.ts | 20 ++++++++++++++++---- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 1c26dd13b..18d507ae5 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -51,12 +51,17 @@ class CashuMint { const data = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/info') }); - // BEGIN DEPRECATED + // BEGIN DEPRECATED // Monkey patch old contact field ["email", "me@mail.com"] Array<[string, string]>; to new contact field [{method: "email", info: "me@mail.com"}] Array // This is to maintain backwards compatibility with older versions of the mint if (Array.isArray(data?.contact) && data?.contact.length > 0) { data.contact = data.contact.map((contact: any) => { - if (Array.isArray(contact) && contact.length === 2 && typeof contact[0] === 'string' && typeof contact[1] === 'string') { + if ( + Array.isArray(contact) && + contact.length === 2 && + typeof contact[0] === 'string' && + typeof contact[1] === 'string' + ) { return { method: contact[0], info: contact[1] }; } return contact; diff --git a/src/base64.ts b/src/base64.ts index a84b9a974..7f1b09237 100644 --- a/src/base64.ts +++ b/src/base64.ts @@ -20,12 +20,12 @@ function encodeBase64ToJson(base64String: string): T { } function base64urlToBase64(str: string) { - return str.replace(/-/g, '+').replace(/_/g, '/').split('=')[0] + return str.replace(/-/g, '+').replace(/_/g, '/').split('=')[0]; // .replace(/./g, '='); } function base64urlFromBase64(str: string) { - return str.replace(/\+/g, '-').replace(/\//g, '_').split('=')[0] + return str.replace(/\+/g, '-').replace(/\//g, '_').split('=')[0]; // .replace(/=/g, '.'); } diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 41a030b98..3d3575883 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -34,22 +34,34 @@ beforeEach(() => { }); describe('test info', () => { - const mintInfoResp = JSON.parse('{"name":"Testnut mint","pubkey":"0296d0aa13b6a31cf0cd974249f28c7b7176d7274712c95a41c7d8066d3f29d679","version":"Nutshell/0.16.0","description":"Mint for testing Cashu wallets","description_long":"This mint usually runs the latest main branch of the nutshell repository. All your Lightning invoices will always be marked paid so that you can test minting and melting ecash via Lightning.","contact":[{"method":"email","info":"contact@me.com"},{"method":"twitter","info":"@me"},{"method":"nostr","info":"npub..."}],"motd":"This is a message of the day field. You should display this field to your users if the content changes!","nuts":{"4":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"5":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"7":{"supported":true},"8":{"supported":true},"9":{"supported":true},"10":{"supported":true},"11":{"supported":true},"12":{"supported":true},"17":[{"method":"bolt11","unit":"sat","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]},{"method":"bolt11","unit":"usd","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]}]}}'); + const mintInfoResp = JSON.parse( + '{"name":"Testnut mint","pubkey":"0296d0aa13b6a31cf0cd974249f28c7b7176d7274712c95a41c7d8066d3f29d679","version":"Nutshell/0.16.0","description":"Mint for testing Cashu wallets","description_long":"This mint usually runs the latest main branch of the nutshell repository. All your Lightning invoices will always be marked paid so that you can test minting and melting ecash via Lightning.","contact":[{"method":"email","info":"contact@me.com"},{"method":"twitter","info":"@me"},{"method":"nostr","info":"npub..."}],"motd":"This is a message of the day field. You should display this field to your users if the content changes!","nuts":{"4":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"5":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"7":{"supported":true},"8":{"supported":true},"9":{"supported":true},"10":{"supported":true},"11":{"supported":true},"12":{"supported":true},"17":[{"method":"bolt11","unit":"sat","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]},{"method":"bolt11","unit":"usd","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]}]}}' + ); test('test info', async () => { nock(mintUrl).get('/v1/info').reply(200, mintInfoResp); const wallet = new CashuWallet(mint, { unit }); const info = await wallet.getMintInfo(); - expect(info.contact).toEqual([{ method: 'email', info: 'contact@me.com' }, { method: 'twitter', info: '@me' }, { method: 'nostr', info: 'npub...' }]); + expect(info.contact).toEqual([ + { method: 'email', info: 'contact@me.com' }, + { method: 'twitter', info: '@me' }, + { method: 'nostr', info: 'npub...' } + ]); expect(info).toEqual(mintInfoResp); }); test('test info with deprecated contact field', async () => { // mintInfoRespDeprecated is the same as mintInfoResp but with the contact field in the old format - const mintInfoRespDeprecated = JSON.parse('{"name":"Testnut mint","pubkey":"0296d0aa13b6a31cf0cd974249f28c7b7176d7274712c95a41c7d8066d3f29d679","version":"Nutshell/0.16.0","description":"Mint for testing Cashu wallets","description_long":"This mint usually runs the latest main branch of the nutshell repository. All your Lightning invoices will always be marked paid so that you can test minting and melting ecash via Lightning.","contact":[["email","contact@me.com"],["twitter","@me"],["nostr","npub..."]],"motd":"This is a message of the day field. You should display this field to your users if the content changes!","nuts":{"4":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"5":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"7":{"supported":true},"8":{"supported":true},"9":{"supported":true},"10":{"supported":true},"11":{"supported":true},"12":{"supported":true},"17":[{"method":"bolt11","unit":"sat","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]},{"method":"bolt11","unit":"usd","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]}]}}'); + const mintInfoRespDeprecated = JSON.parse( + '{"name":"Testnut mint","pubkey":"0296d0aa13b6a31cf0cd974249f28c7b7176d7274712c95a41c7d8066d3f29d679","version":"Nutshell/0.16.0","description":"Mint for testing Cashu wallets","description_long":"This mint usually runs the latest main branch of the nutshell repository. All your Lightning invoices will always be marked paid so that you can test minting and melting ecash via Lightning.","contact":[["email","contact@me.com"],["twitter","@me"],["nostr","npub..."]],"motd":"This is a message of the day field. You should display this field to your users if the content changes!","nuts":{"4":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"5":{"methods":[{"method":"bolt11","unit":"sat"},{"method":"bolt11","unit":"usd"}],"disabled":false},"7":{"supported":true},"8":{"supported":true},"9":{"supported":true},"10":{"supported":true},"11":{"supported":true},"12":{"supported":true},"17":[{"method":"bolt11","unit":"sat","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]},{"method":"bolt11","unit":"usd","commands":["bolt11_melt_quote","proof_state","bolt11_mint_quote"]}]}}' + ); nock(mintUrl).get('/v1/info').reply(200, mintInfoRespDeprecated); const wallet = new CashuWallet(mint, { unit }); const info = await wallet.getMintInfo(); - expect(info.contact).toEqual([{ method: 'email', info: 'contact@me.com' }, { method: 'twitter', info: '@me' }, { method: 'nostr', info: 'npub...' }]); + expect(info.contact).toEqual([ + { method: 'email', info: 'contact@me.com' }, + { method: 'twitter', info: '@me' }, + { method: 'nostr', info: 'npub...' } + ]); expect(info).toEqual(mintInfoResp); }); }); From ff1f3163ac99c32b2d0f0b799da257ab86d2251c Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:07:37 +0200 Subject: [PATCH 06/29] contact field explicit type --- src/CashuMint.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 18d507ae5..a41b4a28c 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -16,7 +16,8 @@ import type { MintResponse, PostRestorePayload, MeltQuotePayload, - MeltQuoteResponse + MeltQuoteResponse, + MintContactInfo } from './model/types/index.js'; import request from './request.js'; import { isObj, joinUrls, sanitizeUrl } from './utils.js'; @@ -55,14 +56,14 @@ class CashuMint { // Monkey patch old contact field ["email", "me@mail.com"] Array<[string, string]>; to new contact field [{method: "email", info: "me@mail.com"}] Array // This is to maintain backwards compatibility with older versions of the mint if (Array.isArray(data?.contact) && data?.contact.length > 0) { - data.contact = data.contact.map((contact: any) => { + data.contact = data.contact.map((contact: MintContactInfo) => { if ( Array.isArray(contact) && contact.length === 2 && typeof contact[0] === 'string' && typeof contact[1] === 'string' ) { - return { method: contact[0], info: contact[1] }; + return { method: contact[0], info: contact[1] } as MintContactInfo; } return contact; }); From 00d3bc675228d14efc4252be2f7cce4c7907a628 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 14:00:16 +0200 Subject: [PATCH 07/29] add state enum changes of NUT-04 and NUT-05 --- src/CashuMint.ts | 45 ++++++++++++++++++++++++++++---------- src/CashuWallet.ts | 5 +++-- src/base64.ts | 4 ++-- src/legacy/nut-04.ts | 21 ++++++++++++++++++ src/legacy/nut-05.ts | 21 ++++++++++++++++++ src/model/types/index.ts | 47 +++++++++++++++++++++------------------- test/request.test.ts | 13 +++++++---- test/wallet.test.ts | 47 +++++++++++++++++++++++++++++++--------- 8 files changed, 151 insertions(+), 52 deletions(-) create mode 100644 src/legacy/nut-04.ts create mode 100644 src/legacy/nut-05.ts diff --git a/src/CashuMint.ts b/src/CashuMint.ts index fc9873fb9..e28635cf2 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -3,7 +3,6 @@ import type { CheckStateResponse, GetInfoResponse, MeltPayload, - MeltResponse, MintActiveKeys, MintAllKeysets, PostRestoreResponse, @@ -18,9 +17,17 @@ import type { MeltQuotePayload, MeltQuoteResponse } from './model/types/index.js'; +import { MeltQuoteState } from './model/types/index.js'; import request from './request.js'; import { isObj, joinUrls, sanitizeUrl } from './utils.js'; - +import { + MeltQuoteResponsePaidDeprecated, + handleMeltQuoteResponseDeprecated +} from './legacy/nut-05.js'; +import { + MintQuoteResponsePaidDeprecated, + handleMintQuoteResponseDeprecated +} from './legacy/nut-04.js'; /** * Class represents Cashu Mint API. This class contains Lower level functions that are implemented by CashuWallet. */ @@ -104,11 +111,13 @@ class CashuMint { customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; - return requestInstance({ + const response = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/mint/quote/bolt11'), method: 'POST', requestBody: mintQuotePayload }); + const data = handleMintQuoteResponseDeprecated(response); + return data; } /** * Requests a new mint quote from the mint. @@ -132,10 +141,13 @@ class CashuMint { customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; - return requestInstance({ + const response = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/mint/quote/bolt11', quote), method: 'GET' }); + + const data = handleMintQuoteResponseDeprecated(response); + return data; } /** * Gets an existing mint quote from the mint. @@ -192,12 +204,14 @@ class CashuMint { customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; - const data = await requestInstance({ + const response = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/melt/quote/bolt11'), method: 'POST', requestBody: meltQuotePayload }); + const data = handleMeltQuoteResponseDeprecated(response); + if ( !isObj(data) || typeof data?.amount !== 'number' || @@ -229,16 +243,20 @@ class CashuMint { customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; - const data = await requestInstance({ + const response = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/melt/quote/bolt11', quote), method: 'GET' }); + const data = handleMeltQuoteResponseDeprecated(response); + if ( !isObj(data) || typeof data?.amount !== 'number' || typeof data?.fee_reserve !== 'number' || - typeof data?.quote !== 'string' + typeof data?.quote !== 'string' || + typeof data?.state !== 'string' || + !Object.values(MeltQuoteState).includes(data.state) ) { throw new Error('bad response'); } @@ -265,9 +283,9 @@ class CashuMint { mintUrl: string, meltPayload: MeltPayload, customRequest?: typeof request - ): Promise { + ): Promise { const requestInstance = customRequest || request; - const data = await requestInstance({ + const data = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/melt/bolt11'), method: 'POST', requestBody: meltPayload @@ -275,8 +293,11 @@ class CashuMint { if ( !isObj(data) || - typeof data?.paid !== 'boolean' || - (data?.payment_preimage !== null && typeof data?.payment_preimage !== 'string') + typeof data?.amount !== 'number' || + typeof data?.fee_reserve !== 'number' || + typeof data?.quote !== 'string' || + typeof data?.state !== 'string' || + !Object.values(MeltQuoteState).includes(data.state) ) { throw new Error('bad response'); } @@ -288,7 +309,7 @@ class CashuMint { * @param meltPayload * @returns */ - async melt(meltPayload: MeltPayload): Promise { + async melt(meltPayload: MeltPayload): Promise { return CashuMint.melt(this._mintUrl, meltPayload, this._customRequest); } /** diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 1d0712db0..d872f53b7 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -19,7 +19,8 @@ import { type Token, type TokenEntry, CheckStateEnum, - SerializedBlindedSignature + SerializedBlindedSignature, + MeltQuoteState } from './model/types/index.js'; import { bytesToNumber, @@ -439,7 +440,7 @@ class CashuWallet { const meltResponse = await this.mint.melt(meltPayload); return { - isPaid: meltResponse.paid ?? false, + isPaid: meltResponse.state === MeltQuoteState.PAID, preimage: meltResponse.payment_preimage, change: meltResponse?.change ? this.constructProofs(meltResponse.change, rs, secrets, keys) diff --git a/src/base64.ts b/src/base64.ts index a84b9a974..7f1b09237 100644 --- a/src/base64.ts +++ b/src/base64.ts @@ -20,12 +20,12 @@ function encodeBase64ToJson(base64String: string): T { } function base64urlToBase64(str: string) { - return str.replace(/-/g, '+').replace(/_/g, '/').split('=')[0] + return str.replace(/-/g, '+').replace(/_/g, '/').split('=')[0]; // .replace(/./g, '='); } function base64urlFromBase64(str: string) { - return str.replace(/\+/g, '-').replace(/\//g, '_').split('=')[0] + return str.replace(/\+/g, '-').replace(/\//g, '_').split('=')[0]; // .replace(/=/g, '.'); } diff --git a/src/legacy/nut-04.ts b/src/legacy/nut-04.ts new file mode 100644 index 000000000..b1a5e8b9b --- /dev/null +++ b/src/legacy/nut-04.ts @@ -0,0 +1,21 @@ +import type { MintQuoteResponse } from '../model/types/index.js'; +import { MintQuoteState } from '../model/types/index.js'; + +export type MintQuoteResponsePaidDeprecated = { + paid?: boolean; +}; + +export function handleMintQuoteResponseDeprecated( + response: MintQuoteResponse & MintQuoteResponsePaidDeprecated +): MintQuoteResponse { + // if the response MeltQuoteResponse has a "paid" flag, we monkey patch it to the state enum + if (!response.state) { + console.warn( + "Deprecated field 'paid' found in MintQuoteResponse. Update NUT-04 of mint: https://github.com/cashubtc/nuts/pull/141)" + ); + } + if (typeof response.paid === 'boolean') { + response.state = response.paid ? MintQuoteState.PAID : MintQuoteState.UNPAID; + } + return response; +} diff --git a/src/legacy/nut-05.ts b/src/legacy/nut-05.ts new file mode 100644 index 000000000..7c13fc0a5 --- /dev/null +++ b/src/legacy/nut-05.ts @@ -0,0 +1,21 @@ +import type { MeltQuoteResponse } from '../model/types/index.js'; +import { MeltQuoteState } from '../model/types/index.js'; + +export type MeltQuoteResponsePaidDeprecated = { + paid?: boolean; +}; + +export function handleMeltQuoteResponseDeprecated( + response: MeltQuoteResponse & MeltQuoteResponsePaidDeprecated +): MeltQuoteResponse { + // if the response MeltQuoteResponse has a "paid" flag, we monkey patch it to the state enum + if (!response.state) { + console.warn( + "Deprecated field 'paid' found in MeltQuoteResponse. Update NUT-05 of mint: https://github.com/cashubtc/nuts/pull/136)" + ); + } + if (typeof response.paid === 'boolean') { + response.state = response.paid ? MeltQuoteState.PAID : MeltQuoteState.UNPAID; + } + return response; +} diff --git a/src/model/types/index.ts b/src/model/types/index.ts index 30b9d3a00..e09a0f096 100644 --- a/src/model/types/index.ts +++ b/src/model/types/index.ts @@ -146,6 +146,12 @@ export type MeltQuotePayload = { request: string; }; +export enum MeltQuoteState { + UNPAID = 'UNPAID', + PENDING = 'PENDING', + PAID = 'PAID' +} + /** * Response from the mint after requesting a melt quote */ @@ -163,13 +169,21 @@ export type MeltQuoteResponse = { */ fee_reserve: number; /** - * Whether the quote has been paid. + * State of the melt quote */ - paid: boolean; + state: MeltQuoteState; /** * Timestamp of when the quote expires */ expiry: number; + /** + * preimage of the paid invoice. is null if it the invoice has not been paid yet. can be null, depending on which LN-backend the mint uses + */ + payment_preimage: string | null; + /** + * Return/Change from overpaid fees. This happens due to Lighting fee estimation being inaccurate + */ + change?: Array; } & ApiError; /** @@ -190,24 +204,6 @@ export type MeltPayload = { outputs: Array; }; -/** - * Response from the mint after paying a lightning invoice (melt) - */ -export type MeltResponse = { - /** - * if false, the proofs have not been invalidated and the payment can be tried later again with the same proofs - */ - paid: boolean; - /** - * preimage of the paid invoice. can be null, depending on which LN-backend the mint uses - */ - payment_preimage: string | null; - /** - * Return/Change from overpaid fees. This happens due to Lighting fee estimation being inaccurate - */ - change?: Array; -} & ApiError; - /** * Response after paying a Lightning invoice */ @@ -280,6 +276,13 @@ export type MintQuotePayload = { */ amount: number; }; + +export enum MintQuoteState { + UNPAID = 'UNPAID', + PAID = 'PAID', + ISSUED = 'ISSUED' +} + /** * Response from the mint after requesting a mint */ @@ -293,9 +296,9 @@ export type MintQuoteResponse = { */ quote: string; /** - * Whether the quote has been paid. + * State of the mint quote */ - paid: boolean; + state: MintQuoteState; /** * Timestamp of when the quote expires */ diff --git a/test/request.test.ts b/test/request.test.ts index bdb6d30dc..d57d31bee 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -2,6 +2,7 @@ import nock from 'nock'; import { CashuMint } from '../src/CashuMint.js'; import { CashuWallet } from '../src/CashuWallet.js'; import { setGlobalRequestOptions } from '../src/request.js'; +import { MeltQuoteResponse } from '../src/model/types/index.js'; let request: Record | undefined; const mintUrl = 'https://localhost:3338'; @@ -29,8 +30,10 @@ describe('requests', () => { return { quote: 'test_melt_quote_id', amount: 2000, - fee_reserve: 20 - }; + fee_reserve: 20, + payment_preimage: null, + state: 'UNPAID' + } as MeltQuoteResponse; }); const wallet = new CashuWallet(mint, { unit }); @@ -49,8 +52,10 @@ describe('requests', () => { return { quote: 'test_melt_quote_id', amount: 2000, - fee_reserve: 20 - }; + fee_reserve: 20, + payment_preimage: null, + state: 'UNPAID' + } as MeltQuoteResponse; }); const wallet = new CashuWallet(mint, { unit }); diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 9b575b36b..2de6aeffc 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -35,11 +35,15 @@ beforeEach(() => { describe('test fees', () => { test('test melt quote fees', async () => { - nock(mintUrl).get('/v1/melt/quote/bolt11/test').reply(200, { - quote: 'test_melt_quote_id', - amount: 2000, - fee_reserve: 20 - }); + nock(mintUrl) + .get('/v1/melt/quote/bolt11/test') + .reply(200, { + quote: 'test_melt_quote_id', + amount: 2000, + fee_reserve: 20, + payment_preimage: null, + state: 'UNPAID' + } as MeltQuoteResponse); const wallet = new CashuWallet(mint, { unit }); const fee = await wallet.getMeltQuote('test'); @@ -187,15 +191,29 @@ describe('payLnInvoice', () => { test('test payLnInvoice base case', async () => { nock(mintUrl) .get('/v1/melt/quote/bolt11/test') - .reply(200, { quote: 'quote_id', amount: 123, fee_reserve: 0 }); - nock(mintUrl).post('/v1/melt/bolt11').reply(200, { paid: true, payment_preimage: '' }); + .reply(200, { + quote: 'test_melt_quote_id', + amount: 2000, + fee_reserve: 20, + payment_preimage: null, + state: 'PAID' + } as MeltQuoteResponse); + nock(mintUrl) + .post('/v1/melt/bolt11') + .reply(200, { + quote: 'test_melt_quote_id', + amount: 2000, + fee_reserve: 20, + payment_preimage: null, + state: 'PAID' + } as MeltQuoteResponse); const wallet = new CashuWallet(mint, { unit }); const meltQuote = await wallet.getMeltQuote('test'); const result = await wallet.payLnInvoice(invoice, proofs, meltQuote); - expect(result).toEqual({ isPaid: true, preimage: '', change: [] }); + expect(result).toEqual({ isPaid: true, preimage: null, change: [] }); }); test('test payLnInvoice change', async () => { nock.cleanAll(); @@ -215,12 +233,21 @@ describe('payLnInvoice', () => { }); nock(mintUrl) .get('/v1/melt/quote/bolt11/test') - .reply(200, { quote: 'quote_id', amount: 123, fee_reserve: 2 }); + .reply(200, { + quote: 'test_melt_quote_id', + amount: 2000, + fee_reserve: 20, + payment_preimage: 'asd', + state: 'PAID' + } as MeltQuoteResponse); nock(mintUrl) .post('/v1/melt/bolt11') .reply(200, { - paid: true, + quote: 'test_melt_quote_id', + amount: 2000, + fee_reserve: 20, payment_preimage: 'asd', + state: 'PAID', change: [ { id: '009a1f293253e41e', From a247b7fcc3aaac0c07056e5e8100f641ffd24ca1 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:25:12 +0200 Subject: [PATCH 08/29] console log instead of warnings --- src/legacy/nut-04.ts | 4 ++-- src/legacy/nut-05.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/legacy/nut-04.ts b/src/legacy/nut-04.ts index b1a5e8b9b..c12343bdb 100644 --- a/src/legacy/nut-04.ts +++ b/src/legacy/nut-04.ts @@ -10,8 +10,8 @@ export function handleMintQuoteResponseDeprecated( ): MintQuoteResponse { // if the response MeltQuoteResponse has a "paid" flag, we monkey patch it to the state enum if (!response.state) { - console.warn( - "Deprecated field 'paid' found in MintQuoteResponse. Update NUT-04 of mint: https://github.com/cashubtc/nuts/pull/141)" + console.log( + "Field 'state' not found in MintQuoteResponse. Update NUT-04 of mint: https://github.com/cashubtc/nuts/pull/141)" ); } if (typeof response.paid === 'boolean') { diff --git a/src/legacy/nut-05.ts b/src/legacy/nut-05.ts index 7c13fc0a5..7337d3c7d 100644 --- a/src/legacy/nut-05.ts +++ b/src/legacy/nut-05.ts @@ -10,8 +10,8 @@ export function handleMeltQuoteResponseDeprecated( ): MeltQuoteResponse { // if the response MeltQuoteResponse has a "paid" flag, we monkey patch it to the state enum if (!response.state) { - console.warn( - "Deprecated field 'paid' found in MeltQuoteResponse. Update NUT-05 of mint: https://github.com/cashubtc/nuts/pull/136)" + console.log( + "Field 'state' not found in MeltQuoteResponse. Update NUT-05 of mint: https://github.com/cashubtc/nuts/pull/136)" ); } if (typeof response.paid === 'boolean') { From ef8111f625bf3a21e8363e2df8002a753ece50dc Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:43:11 +0200 Subject: [PATCH 09/29] fix errors in test --- src/CashuMint.ts | 7 +++---- src/legacy/nut-04.ts | 8 ++++---- src/legacy/nut-05.ts | 8 ++++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index e28635cf2..318de2262 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -285,17 +285,16 @@ class CashuMint { customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; - const data = await requestInstance({ + const response = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/melt/bolt11'), method: 'POST', requestBody: meltPayload }); + const data = handleMeltQuoteResponseDeprecated(response); + if ( !isObj(data) || - typeof data?.amount !== 'number' || - typeof data?.fee_reserve !== 'number' || - typeof data?.quote !== 'string' || typeof data?.state !== 'string' || !Object.values(MeltQuoteState).includes(data.state) ) { diff --git a/src/legacy/nut-04.ts b/src/legacy/nut-04.ts index c12343bdb..63ab349c4 100644 --- a/src/legacy/nut-04.ts +++ b/src/legacy/nut-04.ts @@ -10,12 +10,12 @@ export function handleMintQuoteResponseDeprecated( ): MintQuoteResponse { // if the response MeltQuoteResponse has a "paid" flag, we monkey patch it to the state enum if (!response.state) { - console.log( + console.warn( "Field 'state' not found in MintQuoteResponse. Update NUT-04 of mint: https://github.com/cashubtc/nuts/pull/141)" ); - } - if (typeof response.paid === 'boolean') { - response.state = response.paid ? MintQuoteState.PAID : MintQuoteState.UNPAID; + if (typeof response.paid === 'boolean') { + response.state = response.paid ? MintQuoteState.PAID : MintQuoteState.UNPAID; + } } return response; } diff --git a/src/legacy/nut-05.ts b/src/legacy/nut-05.ts index 7337d3c7d..ccc6582e5 100644 --- a/src/legacy/nut-05.ts +++ b/src/legacy/nut-05.ts @@ -10,12 +10,12 @@ export function handleMeltQuoteResponseDeprecated( ): MeltQuoteResponse { // if the response MeltQuoteResponse has a "paid" flag, we monkey patch it to the state enum if (!response.state) { - console.log( + console.warn( "Field 'state' not found in MeltQuoteResponse. Update NUT-05 of mint: https://github.com/cashubtc/nuts/pull/136)" ); - } - if (typeof response.paid === 'boolean') { - response.state = response.paid ? MeltQuoteState.PAID : MeltQuoteState.UNPAID; + if (typeof response.paid === 'boolean') { + response.state = response.paid ? MeltQuoteState.PAID : MeltQuoteState.UNPAID; + } } return response; } From 18855eb0f35a0bfc30e45d57dc3d7e63bdb5921c Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:52:30 +0200 Subject: [PATCH 10/29] refactor depercated contact handler --- src/CashuMint.ts | 22 +++------------------- src/legacy/nut-06.ts | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 19 deletions(-) create mode 100644 src/legacy/nut-06.ts diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 9e33b81f9..92981ef8b 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -29,6 +29,7 @@ import { MintQuoteResponsePaidDeprecated, handleMintQuoteResponseDeprecated } from './legacy/nut-04.js'; +import { handeMintInfoContactFieldDeprecated } from './legacy/nut-06.js'; /** * Class represents Cashu Mint API. This class contains Lower level functions that are implemented by CashuWallet. */ @@ -56,27 +57,10 @@ class CashuMint { customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; - const data = await requestInstance({ + const response = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/info') }); - // BEGIN DEPRECATED - // Monkey patch old contact field ["email", "me@mail.com"] Array<[string, string]>; to new contact field [{method: "email", info: "me@mail.com"}] Array - // This is to maintain backwards compatibility with older versions of the mint - if (Array.isArray(data?.contact) && data?.contact.length > 0) { - data.contact = data.contact.map((contact: MintContactInfo) => { - if ( - Array.isArray(contact) && - contact.length === 2 && - typeof contact[0] === 'string' && - typeof contact[1] === 'string' - ) { - return { method: contact[0], info: contact[1] } as MintContactInfo; - } - return contact; - }); - } - // END DEPRECATED - + const data = handeMintInfoContactFieldDeprecated(response); return data; } /** diff --git a/src/legacy/nut-06.ts b/src/legacy/nut-06.ts new file mode 100644 index 000000000..8540292b0 --- /dev/null +++ b/src/legacy/nut-06.ts @@ -0,0 +1,21 @@ +import type { MintContactInfo, GetInfoResponse } from '../model/types/index.js'; + +export function handeMintInfoContactFieldDeprecated(data: GetInfoResponse) { + // Monkey patch old contact field ["email", "me@mail.com"] Array<[string, string]>; to new contact field [{method: "email", info: "me@mail.com"}] Array + // This is to maintain backwards compatibility with older versions of the mint + if (Array.isArray(data?.contact) && data?.contact.length > 0) { + data.contact = data.contact.map((contact: MintContactInfo) => { + if ( + Array.isArray(contact) && + contact.length === 2 && + typeof contact[0] === 'string' && + typeof contact[1] === 'string' + ) { + return { method: contact[0], info: contact[1] } as MintContactInfo; + } + console.warn("Mint returned deprecated 'contact' field. Update NUT-06: https://github.com/cashubtc/nuts/pull/117"); + return contact; + }); + } + return data; +} \ No newline at end of file From a752c0d97ac5482d7a4cbe2b997bae6b1b353cca Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:52:45 +0200 Subject: [PATCH 11/29] typo --- src/CashuMint.ts | 4 ++-- src/legacy/nut-06.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 92981ef8b..3cb6ef7af 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -29,7 +29,7 @@ import { MintQuoteResponsePaidDeprecated, handleMintQuoteResponseDeprecated } from './legacy/nut-04.js'; -import { handeMintInfoContactFieldDeprecated } from './legacy/nut-06.js'; +import { handleMintInfoContactFieldDeprecated } from './legacy/nut-06.js'; /** * Class represents Cashu Mint API. This class contains Lower level functions that are implemented by CashuWallet. */ @@ -60,7 +60,7 @@ class CashuMint { const response = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/info') }); - const data = handeMintInfoContactFieldDeprecated(response); + const data = handleMintInfoContactFieldDeprecated(response); return data; } /** diff --git a/src/legacy/nut-06.ts b/src/legacy/nut-06.ts index 8540292b0..f685046bc 100644 --- a/src/legacy/nut-06.ts +++ b/src/legacy/nut-06.ts @@ -1,6 +1,6 @@ import type { MintContactInfo, GetInfoResponse } from '../model/types/index.js'; -export function handeMintInfoContactFieldDeprecated(data: GetInfoResponse) { +export function handleMintInfoContactFieldDeprecated(data: GetInfoResponse) { // Monkey patch old contact field ["email", "me@mail.com"] Array<[string, string]>; to new contact field [{method: "email", info: "me@mail.com"}] Array // This is to maintain backwards compatibility with older versions of the mint if (Array.isArray(data?.contact) && data?.contact.length > 0) { From 70e93f47518883467c866967656cfcb831a9bc7c Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:54:53 +0200 Subject: [PATCH 12/29] npm run format --- src/legacy/nut-06.ts | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/legacy/nut-06.ts b/src/legacy/nut-06.ts index f685046bc..ded610490 100644 --- a/src/legacy/nut-06.ts +++ b/src/legacy/nut-06.ts @@ -1,21 +1,23 @@ import type { MintContactInfo, GetInfoResponse } from '../model/types/index.js'; export function handleMintInfoContactFieldDeprecated(data: GetInfoResponse) { - // Monkey patch old contact field ["email", "me@mail.com"] Array<[string, string]>; to new contact field [{method: "email", info: "me@mail.com"}] Array - // This is to maintain backwards compatibility with older versions of the mint - if (Array.isArray(data?.contact) && data?.contact.length > 0) { - data.contact = data.contact.map((contact: MintContactInfo) => { - if ( - Array.isArray(contact) && - contact.length === 2 && - typeof contact[0] === 'string' && - typeof contact[1] === 'string' - ) { - return { method: contact[0], info: contact[1] } as MintContactInfo; - } - console.warn("Mint returned deprecated 'contact' field. Update NUT-06: https://github.com/cashubtc/nuts/pull/117"); - return contact; - }); - } - return data; -} \ No newline at end of file + // Monkey patch old contact field ["email", "me@mail.com"] Array<[string, string]>; to new contact field [{method: "email", info: "me@mail.com"}] Array + // This is to maintain backwards compatibility with older versions of the mint + if (Array.isArray(data?.contact) && data?.contact.length > 0) { + data.contact = data.contact.map((contact: MintContactInfo) => { + if ( + Array.isArray(contact) && + contact.length === 2 && + typeof contact[0] === 'string' && + typeof contact[1] === 'string' + ) { + return { method: contact[0], info: contact[1] } as MintContactInfo; + } + console.warn( + "Mint returned deprecated 'contact' field. Update NUT-06: https://github.com/cashubtc/nuts/pull/117" + ); + return contact; + }); + } + return data; +} From 559080d7282cfbc929b9591ce009c741395f01d0 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:59:42 +0200 Subject: [PATCH 13/29] Format checker in gihtub pipeline --- .github/workflows/format.yml | 21 +++++++++++++++++++++ package.json | 1 + 2 files changed, 22 insertions(+) create mode 100644 .github/workflows/format.yml diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 000000000..53bac82dc --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,21 @@ +name: Format Check + +on: [push] + +jobs: + tests: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm run check-format diff --git a/package.json b/package.json index 4d45351be..2f15c9fbd 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "dev": "tsc --watch", "lint": "eslint --ext .js,.ts . --fix", "format": "prettier --write .", + "check-format": "prettier --check .", "typedoc": "typedoc src/index.ts" }, "keywords": [ From 0952172ba6dfcdc0fc17227272aafd24705eeddd Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:00:07 +0200 Subject: [PATCH 14/29] test format mismatch, should fail --- src/CashuMint.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 318de2262..4c6281e21 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -51,6 +51,8 @@ class CashuMint { * @param customRequest */ public static async getInfo( + + mintUrl: string, customRequest?: typeof request ): Promise { From 097f7ec9f5307d3d771bd1ff9d15b8e6610f0f33 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:01:40 +0200 Subject: [PATCH 15/29] install dep[s --- .github/workflows/format.yml | 5 ++++- src/CashuMint.ts | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 53bac82dc..2cd51ebd3 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -18,4 +18,7 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: 'npm' - - run: npm run check-format + - name: Install dependencies + run: npm install + - name: Check format + run: npm run check-format diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 4c6281e21..318de2262 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -51,8 +51,6 @@ class CashuMint { * @param customRequest */ public static async getInfo( - - mintUrl: string, customRequest?: typeof request ): Promise { From f34276cab717572d2fa7b8e636dbb51b529dde57 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:02:25 +0200 Subject: [PATCH 16/29] fix format, should succeed --- .github/workflows/format.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 2cd51ebd3..db5f86b07 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -19,6 +19,6 @@ jobs: node-version: ${{ matrix.node-version }} cache: 'npm' - name: Install dependencies - run: npm install + run: npm install - name: Check format run: npm run check-format From 46a53f5de839d973632f9ed574439f2d230ea692 Mon Sep 17 00:00:00 2001 From: KraXen72 Date: Tue, 16 Jul 2024 16:41:37 +0200 Subject: [PATCH 17/29] improve type definitions for GetInfoResponse --- src/model/types/index.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/model/types/index.ts b/src/model/types/index.ts index e94c993ec..61be3ea83 100644 --- a/src/model/types/index.ts +++ b/src/model/types/index.ts @@ -473,6 +473,18 @@ export type BlindedMessageData = { rs: Array; }; +/** core NUT4(mint)/5(melt) entry */ +export type CoreNUTEntry = { + methods: SwapMethod[]; + disabled: boolean; +} +/** Partial multi-path payments NUT entry */ +export type NUT15Entry = { + method: string, + unit: string, + mpp: boolean +} + /** * Response from mint at /info endpoint */ @@ -484,14 +496,8 @@ export type GetInfoResponse = { description_long?: string; contact: Array<[string, string]> & Array<{method: string, info: string}>; nuts: { - '4': { - methods: Array; - disabled: boolean; - }; - '5': { - methods: Array; - disabled: boolean; - }; + '4': CoreNUTEntry; + '5': CoreNUTEntry; '7'?: { supported: boolean; }; @@ -513,6 +519,7 @@ export type GetInfoResponse = { '13'?: { supported: boolean; }; + '15'?: NUT15Entry }; motd?: string; }; From aba81e5c2d78c2cc3bd82cb71526b7b987bff36b Mon Sep 17 00:00:00 2001 From: KraXen72 Date: Tue, 16 Jul 2024 16:46:54 +0200 Subject: [PATCH 18/29] fix definition of NUT15Entry in GetInfoResponse --- src/model/types/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/types/index.ts b/src/model/types/index.ts index 61be3ea83..46ea72ce5 100644 --- a/src/model/types/index.ts +++ b/src/model/types/index.ts @@ -519,7 +519,7 @@ export type GetInfoResponse = { '13'?: { supported: boolean; }; - '15'?: NUT15Entry + '15'?: NUT15Entry[] }; motd?: string; }; From 53c1af36adf4be1e16460f1f35c239c73160bb70 Mon Sep 17 00:00:00 2001 From: Egge Date: Fri, 5 Jul 2024 11:24:17 +0200 Subject: [PATCH 19/29] updated naming on mint / melt --- src/CashuMint.ts | 12 ++++++------ src/CashuWallet.ts | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 3cb6ef7af..ba3f4f660 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -111,7 +111,7 @@ class CashuMint { * @param customRequest * @returns the mint will create and return a new mint quote containing a payment request for the specified amount and unit */ - public static async mintQuote( + public static async postMintQuote( mintUrl: string, mintQuotePayload: MintQuotePayload, customRequest?: typeof request @@ -130,8 +130,8 @@ class CashuMint { * @param mintQuotePayload Payload for creating a new mint quote * @returns the mint will create and return a new mint quote containing a payment request for the specified amount and unit */ - async mintQuote(mintQuotePayload: MintQuotePayload): Promise { - return CashuMint.mintQuote(this._mintUrl, mintQuotePayload, this._customRequest); + async postMintQuote(mintQuotePayload: MintQuotePayload): Promise { + return CashuMint.postMintQuote(this._mintUrl, mintQuotePayload, this._customRequest); } /** @@ -204,7 +204,7 @@ class CashuMint { * @param MeltQuotePayload * @returns */ - public static async meltQuote( + public static async postMeltQuote( mintUrl: string, meltQuotePayload: MeltQuotePayload, customRequest?: typeof request @@ -233,8 +233,8 @@ class CashuMint { * @param MeltQuotePayload * @returns */ - async meltQuote(meltQuotePayload: MeltQuotePayload): Promise { - return CashuMint.meltQuote(this._mintUrl, meltQuotePayload, this._customRequest); + async postMeltQuote(meltQuotePayload: MeltQuotePayload): Promise { + return CashuMint.postMeltQuote(this._mintUrl, meltQuotePayload, this._customRequest); } /** diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 7b25ab34c..ae8292fff 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -341,12 +341,12 @@ class CashuWallet { * @param amount Amount requesting for mint. * @returns the mint will return a mint quote with a Lightning invoice for minting tokens of the specified amount and unit */ - async mintQuote(amount: number) { + async createMintQuote(amount: number) { const mintQuotePayload: MintQuotePayload = { unit: this._unit, amount: amount }; - return await this.mint.mintQuote(mintQuotePayload); + return await this.mint.postMintQuote(mintQuotePayload); } /** @@ -354,7 +354,7 @@ class CashuWallet { * @param quote Quote ID * @returns the mint will create and return a Lightning invoice for the specified amount */ - async getMintQuote(quote: string) { + async checkMintQuote(quote: string) { return await this.mint.getMintQuote(quote); } @@ -397,12 +397,12 @@ class CashuWallet { * @param invoice LN invoice that needs to get a fee estimate * @returns the mint will create and return a melt quote for the invoice with an amount and fee reserve */ - async meltQuote(invoice: string): Promise { + async createMeltQuote(invoice: string): Promise { const meltQuotePayload: MeltQuotePayload = { unit: this._unit, request: invoice }; - const meltQuote = await this.mint.meltQuote(meltQuotePayload); + const meltQuote = await this.mint.postMeltQuote(meltQuotePayload); return meltQuote; } @@ -411,7 +411,7 @@ class CashuWallet { * @param quote ID of the melt quote * @returns the mint will return an existing melt quote */ - async getMeltQuote(quote: string): Promise { + async checkMeltQuote(quote: string): Promise { const meltQuote = await this.mint.getMeltQuote(quote); return meltQuote; } @@ -476,7 +476,7 @@ class CashuWallet { } ): Promise { if (!meltQuote) { - meltQuote = await this.mint.meltQuote({ unit: this._unit, request: invoice }); + meltQuote = await this.mint.postMeltQuote({ unit: this._unit, request: invoice }); } return await this.meltTokens(meltQuote, proofsToSend, { keysetId: options?.keysetId, From c5b509a2611270a2de291d58cf5fe0963c625786 Mon Sep 17 00:00:00 2001 From: Egge Date: Fri, 5 Jul 2024 11:24:26 +0200 Subject: [PATCH 20/29] updated tests / all green --- test/integration.test.ts | 36 ++++++++++++++++++------------------ test/request.test.ts | 4 ++-- test/wallet.test.ts | 6 +++--- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/test/integration.test.ts b/test/integration.test.ts index 5776334a4..bb43f253d 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -36,15 +36,15 @@ describe('mint api', () => { test('request mint', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(100); + const request = await wallet.createMintQuote(100); expect(request).toBeDefined(); - const mintQuote = await wallet.getMintQuote(request.quote); + const mintQuote = await wallet.checkMintQuote(request.quote); expect(mintQuote).toBeDefined(); }); test('mint tokens', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(1337); + const request = await wallet.createMintQuote(1337); expect(request).toBeDefined(); expect(request.request).toContain('lnbc1337'); const tokens = await wallet.mintTokens(1337, request.quote); @@ -55,8 +55,8 @@ describe('mint api', () => { test('get fee for local invoice', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(100); - const fee = (await wallet.meltQuote(request.request)).fee_reserve; + const request = await wallet.createMintQuote(100); + const fee = (await wallet.createMeltQuote(request.request)).fee_reserve; expect(fee).toBeDefined(); // because local invoice, fee should be 0 expect(fee).toBe(0); @@ -64,7 +64,7 @@ describe('mint api', () => { test('get fee for external invoice', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const fee = (await wallet.meltQuote(externalInvoice)).fee_reserve; + const fee = (await wallet.createMeltQuote(externalInvoice)).fee_reserve; expect(fee).toBeDefined(); // because external invoice, fee should be > 0 expect(fee).toBeGreaterThan(0); @@ -72,17 +72,17 @@ describe('mint api', () => { test('pay local invoice', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(100); + const request = await wallet.createMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); // expect no fee because local invoice - const mintQuote = await wallet.mintQuote(10); - const quote = await wallet.meltQuote(mintQuote.request); + const mintQuote = await wallet.createMintQuote(10); + const quote = await wallet.createMeltQuote(mintQuote.request); const fee = quote.fee_reserve; expect(fee).toBe(0); // get the quote from the mint - const quote_ = await wallet.getMeltQuote(quote.quote); + const quote_ = await wallet.checkMeltQuote(quote.quote); expect(quote_).toBeDefined(); const sendResponse = await wallet.send(10, tokens.proofs); @@ -104,15 +104,15 @@ describe('mint api', () => { test('pay external invoice', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(3000); + const request = await wallet.createMintQuote(3000); const tokens = await wallet.mintTokens(3000, request.quote); - const meltQuote = await wallet.meltQuote(externalInvoice); + const meltQuote = await wallet.createMeltQuote(externalInvoice); const fee = meltQuote.fee_reserve; expect(fee).toBeGreaterThan(0); // get the quote from the mint - const quote_ = await wallet.getMeltQuote(meltQuote.quote); + const quote_ = await wallet.checkMeltQuote(meltQuote.quote); expect(quote_).toBeDefined(); const sendResponse = await wallet.send(2000 + fee, tokens.proofs); @@ -135,7 +135,7 @@ describe('mint api', () => { test('test send tokens exact without previous split', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(64); + const request = await wallet.createMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); const sendResponse = await wallet.send(64, tokens.proofs); @@ -148,7 +148,7 @@ describe('mint api', () => { test('test send tokens with change', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(100); + const request = await wallet.createMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); const sendResponse = await wallet.send(10, tokens.proofs); @@ -161,7 +161,7 @@ describe('mint api', () => { test('receive tokens with previous split', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(100); + const request = await wallet.createMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); const sendResponse = await wallet.send(10, tokens.proofs); @@ -174,7 +174,7 @@ describe('mint api', () => { test('receive tokens with previous mint', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint, { unit }); - const request = await wallet.mintQuote(64); + const request = await wallet.createMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); const encoded = getEncodedToken({ token: [{ mint: mintUrl, proofs: tokens.proofs }] @@ -192,7 +192,7 @@ describe('mint api', () => { const privKeyBob = secp256k1.utils.randomPrivateKey(); const pubKeyBob = secp256k1.getPublicKey(privKeyBob); - const request = await wallet.mintQuote(64); + const request = await wallet.createMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); const { send } = await wallet.send(64, tokens.proofs, { pubkey: bytesToHex(pubKeyBob) }); diff --git a/test/request.test.ts b/test/request.test.ts index d57d31bee..5ff7bcd24 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -37,7 +37,7 @@ describe('requests', () => { }); const wallet = new CashuWallet(mint, { unit }); - await wallet.getMeltQuote('test'); + await wallet.checkMeltQuote('test'); expect(request).toBeDefined(); // expect(request!['content-type']).toContain('application/json'); @@ -61,7 +61,7 @@ describe('requests', () => { const wallet = new CashuWallet(mint, { unit }); setGlobalRequestOptions({ headers: { 'x-cashu': 'xyz-123-abc' } }); - await wallet.getMeltQuote('test'); + await wallet.checkMeltQuote('test'); expect(request).toBeDefined(); expect(request!['x-cashu']).toContain('xyz-123-abc'); diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 3cc6032c9..b8bd97d86 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -79,7 +79,7 @@ describe('test fees', () => { } as MeltQuoteResponse); const wallet = new CashuWallet(mint, { unit }); - const fee = await wallet.getMeltQuote('test'); + const fee = await wallet.checkMeltQuote('test'); const amount = 2000; expect(fee.fee_reserve + amount).toEqual(2020); @@ -242,7 +242,7 @@ describe('payLnInvoice', () => { } as MeltQuoteResponse); const wallet = new CashuWallet(mint, { unit }); - const meltQuote = await wallet.getMeltQuote('test'); + const meltQuote = await wallet.checkMeltQuote('test'); const result = await wallet.payLnInvoice(invoice, proofs, meltQuote); @@ -291,7 +291,7 @@ describe('payLnInvoice', () => { }); const wallet = new CashuWallet(mint, { unit }); - const meltQuote = await wallet.getMeltQuote('test'); + const meltQuote = await wallet.checkMeltQuote('test'); const result = await wallet.payLnInvoice(invoice, [{ ...proofs[0], amount: 3 }], meltQuote); expect(result.isPaid).toBe(true); From 13c115fa9b21d453943d839eda1e1ddf5e0c11b8 Mon Sep 17 00:00:00 2001 From: Egge Date: Mon, 15 Jul 2024 13:38:50 +0200 Subject: [PATCH 21/29] updated migration doc --- migration-1.0.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration-1.0.0.md b/migration-1.0.0.md index 5489fb816..2f42612d0 100644 --- a/migration-1.0.0.md +++ b/migration-1.0.0.md @@ -33,7 +33,7 @@ To reduce complexity, simplify error handling and to prepare for token V4, this Utility functions now have an `options` object for optional parameters, instead of passing them directly -**`requestMint(amount: number)` --> `mintQuote(amount: number)`** +**`requestMint(amount: number)` --> `createMintQuote(amount: number)`** Now returns the following: ```typescript @@ -51,7 +51,7 @@ where `request` is the invoice to be paid, and `quote` is the identifier used to --- -**`getMeltQuote(invoice: string)`** is now used to get fee estimation and conversion quotes instead of `getFee()` and returns: +**`createMeltQuote(invoice: string)`** is now used to get fee estimation and conversion quotes instead of `getFee()` and returns: ```typescript type MeltQuoteResponse = { From 4ce07168dbc1c92692dfe59ea955b39b448f8961 Mon Sep 17 00:00:00 2001 From: Egge Date: Tue, 16 Jul 2024 16:49:58 +0200 Subject: [PATCH 22/29] mint and wallet same naming --- src/CashuMint.ts | 24 ++++++++++++------------ src/CashuWallet.ts | 10 +++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index ba3f4f660..3729ae028 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -111,7 +111,7 @@ class CashuMint { * @param customRequest * @returns the mint will create and return a new mint quote containing a payment request for the specified amount and unit */ - public static async postMintQuote( + public static async createMintQuote( mintUrl: string, mintQuotePayload: MintQuotePayload, customRequest?: typeof request @@ -130,8 +130,8 @@ class CashuMint { * @param mintQuotePayload Payload for creating a new mint quote * @returns the mint will create and return a new mint quote containing a payment request for the specified amount and unit */ - async postMintQuote(mintQuotePayload: MintQuotePayload): Promise { - return CashuMint.postMintQuote(this._mintUrl, mintQuotePayload, this._customRequest); + async createMintQuote(mintQuotePayload: MintQuotePayload): Promise { + return CashuMint.createMintQuote(this._mintUrl, mintQuotePayload, this._customRequest); } /** @@ -141,7 +141,7 @@ class CashuMint { * @param customRequest * @returns the mint will create and return a Lightning invoice for the specified amount */ - public static async getMintQuote( + public static async checkMintQuote( mintUrl: string, quote: string, customRequest?: typeof request @@ -160,8 +160,8 @@ class CashuMint { * @param quote Quote ID * @returns the mint will create and return a Lightning invoice for the specified amount */ - async getMintQuote(quote: string): Promise { - return CashuMint.getMintQuote(this._mintUrl, quote, this._customRequest); + async checkMintQuote(quote: string): Promise { + return CashuMint.checkMintQuote(this._mintUrl, quote, this._customRequest); } /** @@ -204,7 +204,7 @@ class CashuMint { * @param MeltQuotePayload * @returns */ - public static async postMeltQuote( + public static async createMeltQuote( mintUrl: string, meltQuotePayload: MeltQuotePayload, customRequest?: typeof request @@ -233,8 +233,8 @@ class CashuMint { * @param MeltQuotePayload * @returns */ - async postMeltQuote(meltQuotePayload: MeltQuotePayload): Promise { - return CashuMint.postMeltQuote(this._mintUrl, meltQuotePayload, this._customRequest); + async createMeltQuote(meltQuotePayload: MeltQuotePayload): Promise { + return CashuMint.createMeltQuote(this._mintUrl, meltQuotePayload, this._customRequest); } /** @@ -243,7 +243,7 @@ class CashuMint { * @param quote Quote ID * @returns */ - public static async getMeltQuote( + public static async checkMeltQuote( mintUrl: string, quote: string, customRequest?: typeof request @@ -274,8 +274,8 @@ class CashuMint { * @param quote Quote ID * @returns */ - async getMeltQuote(quote: string): Promise { - return CashuMint.getMeltQuote(this._mintUrl, quote, this._customRequest); + async checkMeltQuote(quote: string): Promise { + return CashuMint.checkMeltQuote(this._mintUrl, quote, this._customRequest); } /** diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index ae8292fff..23a31fae7 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -346,7 +346,7 @@ class CashuWallet { unit: this._unit, amount: amount }; - return await this.mint.postMintQuote(mintQuotePayload); + return await this.mint.createMintQuote(mintQuotePayload); } /** @@ -355,7 +355,7 @@ class CashuWallet { * @returns the mint will create and return a Lightning invoice for the specified amount */ async checkMintQuote(quote: string) { - return await this.mint.getMintQuote(quote); + return await this.mint.checkMintQuote(quote); } /** @@ -402,7 +402,7 @@ class CashuWallet { unit: this._unit, request: invoice }; - const meltQuote = await this.mint.postMeltQuote(meltQuotePayload); + const meltQuote = await this.mint.createMeltQuote(meltQuotePayload); return meltQuote; } @@ -412,7 +412,7 @@ class CashuWallet { * @returns the mint will return an existing melt quote */ async checkMeltQuote(quote: string): Promise { - const meltQuote = await this.mint.getMeltQuote(quote); + const meltQuote = await this.mint.checkMeltQuote(quote); return meltQuote; } @@ -476,7 +476,7 @@ class CashuWallet { } ): Promise { if (!meltQuote) { - meltQuote = await this.mint.postMeltQuote({ unit: this._unit, request: invoice }); + meltQuote = await this.mint.createMeltQuote({ unit: this._unit, request: invoice }); } return await this.meltTokens(meltQuote, proofsToSend, { keysetId: options?.keysetId, From 4909e396d2ac9432ca6fb8052f1267bb93ae1cf4 Mon Sep 17 00:00:00 2001 From: Egge Date: Tue, 16 Jul 2024 16:58:16 +0200 Subject: [PATCH 23/29] 1.0.0-rc.10 --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 13e09e24e..fec4573a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -696,9 +696,9 @@ "dev": true }, "node_modules/@cashu/crypto": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@cashu/crypto/-/crypto-0.2.6.tgz", - "integrity": "sha512-qjytcY26MRntG6nJc9U2tSeDw+BApKQaIch58POjEiTuc7MbIxgR/l/xU5NzXa/nGrSLdNZQwl/o5RQDhc2otw==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@cashu/crypto/-/crypto-0.2.7.tgz", + "integrity": "sha512-1aaDfUjiHNXoJqg8nW+341TLWV9W28DsVNXJUKcHL0yAmwLs5+56SSnb8LLDJzPamLVoYL0U0bda91klAzptig==", "dependencies": { "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", @@ -6922,9 +6922,9 @@ "dev": true }, "@cashu/crypto": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@cashu/crypto/-/crypto-0.2.6.tgz", - "integrity": "sha512-qjytcY26MRntG6nJc9U2tSeDw+BApKQaIch58POjEiTuc7MbIxgR/l/xU5NzXa/nGrSLdNZQwl/o5RQDhc2otw==", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@cashu/crypto/-/crypto-0.2.7.tgz", + "integrity": "sha512-1aaDfUjiHNXoJqg8nW+341TLWV9W28DsVNXJUKcHL0yAmwLs5+56SSnb8LLDJzPamLVoYL0U0bda91klAzptig==", "requires": { "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", diff --git a/package.json b/package.json index 4d45351be..918b37cbf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.9", + "version": "1.0.0-rc.10", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From 9d425359158837b71243780d9fafba74b685df2e Mon Sep 17 00:00:00 2001 From: KraXen72 Date: Tue, 16 Jul 2024 16:59:10 +0200 Subject: [PATCH 24/29] implement nut17 type defs --- src/model/types/index.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/model/types/index.ts b/src/model/types/index.ts index 46ea72ce5..121f7f67d 100644 --- a/src/model/types/index.ts +++ b/src/model/types/index.ts @@ -485,6 +485,13 @@ export type NUT15Entry = { mpp: boolean } +/** Websockets NUT entry */ +export type NUT17Entry = { + method: string, + unit: string, + commands: string[] +} + /** * Response from mint at /info endpoint */ @@ -519,7 +526,8 @@ export type GetInfoResponse = { '13'?: { supported: boolean; }; - '15'?: NUT15Entry[] + '15'?: NUT15Entry[], + '17'?: { supported?: NUT17Entry[] } }; motd?: string; }; From 142d671e8ae9418bb6457de0b5d6813316e49db3 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 16 Jul 2024 17:03:27 +0200 Subject: [PATCH 25/29] remove unused import --- src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index 3485bec73..48a2a00cd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ import { encodeBase64ToJson, encodeJsonToBase64 } from './base64.js'; -import { AmountPreference, Keys, Proof, Token, TokenEntry, TokenV2 } from './model/types/index.js'; +import { AmountPreference, Keys, Proof, Token, TokenV2 } from './model/types/index.js'; import { TOKEN_PREFIX, TOKEN_VERSION } from './utils/Constants.js'; import { bytesToHex, hexToBytes } from '@noble/curves/abstract/utils'; import { sha256 } from '@noble/hashes/sha256'; From ce81a59d602d59eaddef039f42309ffef735d109 Mon Sep 17 00:00:00 2001 From: Egge Date: Tue, 16 Jul 2024 17:32:30 +0200 Subject: [PATCH 26/29] 1.0.0-rc.11 --- README.md | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 79071cb99..75244c600 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,8 @@ const tokens = await wallet.mintTokens(64, mintQuote.quote); Contributions are very welcome. -If you want to contribute, please open an Issue or a PR. -If you open a PR, please do so from the `development` branch as the base branch. +If you want to contribute, please open an Issue or a PR. +If you open a PR, please do so from the `development` branch as the base branch. ### Version @@ -80,17 +80,17 @@ If you open a PR, please do so from the `development` branch as the base branch. | | * `hotfix` | | | * `staging` -| |\ +| |\ | |\ \ | | | * `bugfix` | | | -| | * `development` -| | |\ +| | * `development` +| | |\ | | | * `feature1` | | | | | | |/ | | * -| | |\ +| | |\ | | | * `feature2` | | |/ | |/ diff --git a/package.json b/package.json index 1e9cbe34b..744b0a78b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.10", + "version": "1.0.0-rc.11", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From 4e3869b36a0247ce56524a62898cb5b89a50157c Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 17 Jul 2024 09:43:55 +0900 Subject: [PATCH 27/29] audit fix deps --- package-lock.json | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index fec4573a7..6f93ce615 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.9", + "version": "1.0.0-rc.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.9", + "version": "1.0.0-rc.11", "license": "MIT", "dependencies": { "@cashu/crypto": "^0.2.6", @@ -2099,12 +2099,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3344,10 +3345,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3932,6 +3934,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5878,6 +5881,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -7984,12 +7988,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browserslist": { @@ -8885,9 +8889,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" From 7c95ca4b142b9c4370a611fbe5fda830ad4cec73 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 17 Jul 2024 09:44:05 +0900 Subject: [PATCH 28/29] 1.0.0-rc.12 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6f93ce615..973669c62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.11", + "version": "1.0.0-rc.12", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.11", + "version": "1.0.0-rc.12", "license": "MIT", "dependencies": { "@cashu/crypto": "^0.2.6", diff --git a/package.json b/package.json index 744b0a78b..f7b58aa05 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.11", + "version": "1.0.0-rc.12", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From 4797c05ee42fc97444a20dd01c8842af0f5b61a2 Mon Sep 17 00:00:00 2001 From: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> Date: Wed, 17 Jul 2024 21:46:26 +0900 Subject: [PATCH 29/29] Update version.yml change version build trigger to "released" --- .github/workflows/version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index eae242f56..23bca05db 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -4,7 +4,7 @@ permissions: id-token: write on: release: - types: [published] + types: [released] jobs: build: runs-on: ubuntu-latest