From c8054c3ad7384e7f660acb7ec57f472eb8ac698f Mon Sep 17 00:00:00 2001 From: starbackr-dev Date: Tue, 19 Mar 2024 22:44:32 -0400 Subject: [PATCH 01/50] Added unit field to CashuWallet unit field is required for v1 API to quote, mint and melt tokens based on unit=usd or others. Updated CashuWallet and test scripts related to that. --- src/CashuWallet.ts | 15 +++++++++------ test/integration.test.ts | 21 +++++++++++---------- test/request.test.ts | 4 ++-- test/wallet.test.ts | 37 +++++++++++++++++++------------------ 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 03521e20..e870eb03 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -36,20 +36,23 @@ import { bytesToHex } from '@noble/curves/abstract/utils'; class CashuWallet { private _keys = {} as MintKeys; private _keysetId = ''; + private _unit = 'sat'; mint: CashuMint; - unit = 'sat'; + /** * @param keys public keys from the mint * @param mint Cashu mint instance is used to make api calls */ - constructor(mint: CashuMint, keys?: MintKeys) { + constructor(mint: CashuMint, unit?:string, keys?: MintKeys) { this.mint = mint; + if (unit) this._unit = unit; if (keys) { this._keys = keys; // this._keysetId = deriveKeysetId(this._keys); this._keysetId = keys.id; + } } @@ -107,7 +110,7 @@ class CashuWallet { */ getMintQuote(amount: number) { const requestMintPayload: RequestMintPayload = { - unit: this.unit, + unit: this._unit, amount: amount } return this.mint.mintQuote(requestMintPayload); @@ -145,7 +148,7 @@ class CashuWallet { * @returns estimated Fee */ async getMeltQuote(invoice: string): Promise { - const meltQuote = await this.mint.meltQuote({ unit: this.unit, request: invoice }); + const meltQuote = await this.mint.meltQuote({ unit: this._unit, request: invoice }); return meltQuote; } /** @@ -189,7 +192,7 @@ class CashuWallet { meltQuote?: MeltQuoteResponse ): Promise { if (!meltQuote) { - meltQuote = await this.mint.meltQuote({ unit: this.unit, request: invoice }); + meltQuote = await this.mint.meltQuote({ unit: this._unit, request: invoice }); } return await this.meltTokens(meltQuote, proofsToSend); @@ -263,7 +266,7 @@ class CashuWallet { keyset, preference ); - const { signatures, error } = await CashuMint.split(tokenEntry.mint, payload); + const { signatures} = await CashuMint.split(tokenEntry.mint, payload); const newProofs = dhke.constructProofs( signatures, blindedMessages.rs, diff --git a/test/integration.test.ts b/test/integration.test.ts index f1c00580..faef690b 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -10,6 +10,7 @@ const externalInvoice = let request: Record | undefined; const mintUrl = 'http://localhost:3338'; +const unit = 'sats' describe('mint api', () => { test('get keys', async () => { @@ -32,13 +33,13 @@ describe('mint api', () => { }); test('request mint', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(100); expect(request).toBeDefined(); }); test('mint tokens', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(1337); expect(request).toBeDefined(); expect(request.request).toContain('lnbc1337'); @@ -49,7 +50,7 @@ describe('mint api', () => { }); test('get fee for local invoice', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(100); const fee = (await wallet.getMeltQuote(request.request)).fee_reserve; expect(fee).toBeDefined(); @@ -58,7 +59,7 @@ describe('mint api', () => { }); test('get fee for external invoice', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const fee = (await wallet.getMeltQuote(externalInvoice)).fee_reserve; expect(fee).toBeDefined(); // because external invoice, fee should be > 0 @@ -66,7 +67,7 @@ describe('mint api', () => { }); test('pay local invoice', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); @@ -94,7 +95,7 @@ describe('mint api', () => { }); test('pay external invoice', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(3000); const tokens = await wallet.mintTokens(3000, request.quote); @@ -120,7 +121,7 @@ describe('mint api', () => { }); test('test send tokens exact without previous split', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); @@ -133,7 +134,7 @@ describe('mint api', () => { }); test('test send tokens with change', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); @@ -146,7 +147,7 @@ describe('mint api', () => { }); test('receive tokens with previous split', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); @@ -161,7 +162,7 @@ describe('mint api', () => { }); test('receive tokens with previous mint', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const request = await wallet.getMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); const encoded = getEncodedToken({ diff --git a/test/request.test.ts b/test/request.test.ts index 14ff1616..38e77e03 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -31,7 +31,7 @@ describe('requests', () => { }; }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); await wallet.getMeltQuote(invoice); expect(request).toBeDefined(); @@ -51,7 +51,7 @@ describe('requests', () => { }; }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); setGlobalRequestOptions({ headers: { 'x-cashu': 'xyz-123-abc' } }); await wallet.getMeltQuote(invoice); diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 70a19efb..6e405936 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -11,6 +11,7 @@ const dummyKeysResp = { }; const mintUrl = 'http://localhost:3338'; const mint = new CashuMint(mintUrl); +const unit = 'sats'; const invoice = 'lnbc20u1p3u27nppp5pm074ffk6m42lvae8c6847z7xuvhyknwgkk7pzdce47grf2ksqwsdpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzpgxqyz5vqsp5sw6n7cztudpl5m5jv3z6dtqpt2zhd3q6dwgftey9qxv09w82rgjq9qyyssqhtfl8wv7scwp5flqvmgjjh20nf6utvv5daw5h43h69yqfwjch7wnra3cn94qkscgewa33wvfh7guz76rzsfg9pwlk8mqd27wavf2udsq3yeuju'; @@ -31,7 +32,7 @@ describe('test fees', () => { amount: 2000, fee_reserve: 20 }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const fee = await wallet.getMeltQuote(invoice); const amount = decode(invoice).sections[2].value / 1000; @@ -55,7 +56,7 @@ describe('receive', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const response: ReceiveResponse = await wallet.receive(tokenInput); @@ -91,7 +92,7 @@ describe('receive', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const token3sat = 'cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIjAwOWExZjI5MzI1M2U0MWUiLCAiYW1vdW50IjogMSwgInNlY3JldCI6ICJlN2MxYjc2ZDFiMzFlMmJjYTJiMjI5ZDE2MGJkZjYwNDZmMzNiYzQ1NzAyMjIzMDRiNjUxMTBkOTI2ZjdhZjg5IiwgIkMiOiAiMDM4OWNkOWY0Zjk4OGUzODBhNzk4OWQ0ZDQ4OGE3YzkxYzUyNzdmYjkzMDQ3ZTdhMmNjMWVkOGUzMzk2Yjg1NGZmIn0sIHsiaWQiOiAiMDA5YTFmMjkzMjUzZTQxZSIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogImRlNTVjMTVmYWVmZGVkN2Y5Yzk5OWMzZDRjNjJmODFiMGM2ZmUyMWE3NTJmZGVmZjZiMDg0Y2YyZGYyZjVjZjMiLCAiQyI6ICIwMmRlNDBjNTlkOTAzODNiODg1M2NjZjNhNGIyMDg2NGFjODNiYTc1OGZjZTNkOTU5ZGJiODkzNjEwMDJlOGNlNDcifV0sICJtaW50IjogImh0dHA6Ly9sb2NhbGhvc3Q6MzMzOCJ9XX0=' const response: ReceiveResponse = await wallet.receive(token3sat, [{ amount: 1, count: 3 }]); @@ -107,7 +108,7 @@ describe('receive', () => { test('test receive tokens already spent', async () => { const msg = 'tokens already spent. Secret: asdasdasd'; nock(mintUrl).post('/v1/split').reply(200, { detail: msg }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const { tokensWithErrors } = await wallet.receive(tokenInput); const t = tokensWithErrors!; @@ -124,7 +125,7 @@ describe('receive', () => { }); test('test receive could not verify proofs', async () => { nock(mintUrl).post('/v1/split').reply(200, { code: 0, error: 'could not verify proofs.' }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const { tokensWithErrors } = await wallet.receive(tokenInput); const t = tokensWithErrors!; @@ -154,7 +155,7 @@ describe('checkProofsSpent', () => { nock(mintUrl) .post('/v1/check') .reply(200, { spendable: [true] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet.checkProofsSpent(proofs); @@ -174,7 +175,7 @@ describe('payLnInvoice', () => { test('test payLnInvoice base case', async () => { nock(mintUrl).post('/v1/melt/quote/bolt11').reply(200, { quote: "quote_id", amount: 123, fee_reserve: 0 }); nock(mintUrl).post('/v1/melt/bolt11').reply(200, { paid: true, proof: '' }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet.payLnInvoice(invoice, proofs); @@ -204,7 +205,7 @@ describe('payLnInvoice', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet.payLnInvoice(invoice, [{ ...proofs[0], amount: 3 }]); @@ -214,7 +215,7 @@ describe('payLnInvoice', () => { }); test('test payLnInvoice bad resonse', async () => { nock(mintUrl).post('/v1/melt/quote/bolt11').reply(200, {}); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet.payLnInvoice(invoice, proofs).catch((e) => e); @@ -235,7 +236,7 @@ describe('requestTokens', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const { proofs } = await wallet.mintTokens(1, ''); @@ -246,7 +247,7 @@ describe('requestTokens', () => { }); test('test requestTokens bad resonse', async () => { nock(mintUrl).post('/v1/mint/bolt11').reply(200, {}); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet.mintTokens(1, '').catch((e) => e); @@ -275,7 +276,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet.send(1, proofs); @@ -302,7 +303,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet.send(1, [ { @@ -340,7 +341,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const overpayProofs = [ { @@ -388,7 +389,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const overpayProofs = [ { @@ -443,7 +444,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const overpayProofs = [ { @@ -483,7 +484,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet.send(2, proofs).catch((e) => e); @@ -491,7 +492,7 @@ describe('send', () => { }); test('test send bad response', async () => { nock(mintUrl).post('/v1/split').reply(200, {}); - const wallet = new CashuWallet(mint); + const wallet = new CashuWallet(mint, unit); const result = await wallet .send(1, [ From 559365fc5ded4928374971e4ee7b980810da6f16 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Mon, 25 Mar 2024 11:08:20 +0900 Subject: [PATCH 02/50] update readme --- README.md | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c7a52e81..675f4661 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Supported token formats: ## Usage -Go to the [docs](https://cashubtc.github.io/cashu-ts/docs) for detailed usage. +Go to the [docs](https://cashubtc.github.io/cashu-ts/docs) for detailed usage, or have a look at the [integration tests](./test/integration.test.ts) for examples on how to implement a wallet. ### Install @@ -52,26 +52,16 @@ Go to the [docs](https://cashubtc.github.io/cashu-ts/docs) for detailed usage. npm i @cashu/cashu-ts ``` -### Import +### Example ```typescript import { CashuMint, CashuWallet, getEncodedToken } from '@cashu/cashu-ts'; -const wallet = new CashuWallet(new CashuMint('{MINT_URL}')); +const mint = new CashuMint(mintUrl); +const wallet = new CashuWallet(mint); +const request = await wallet.getMintQuote(64); +const tokens = await wallet.mintTokens(64, request.quote); -const { pr, hash } = await wallet.requestMint(200); - -//pay this LN invoice -console.log({ pr }, { hash }); - -async function invoiceHasBeenPaid() { - const { proofs } = await wallet.requestTokens(200, hash); - //Encoded proofs can be spent at the mint - const encoded = getEncodedToken({ - token: [{ mint: '{MINT_URL}', proofs }] - }); - console.log(encoded); -} ``` ## Contribute From 499c449435419b3cf1ef84e75b6564ec7c34a0d0 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Mon, 25 Mar 2024 13:23:18 +0900 Subject: [PATCH 03/50] remove decode lnInvoice lib --- package-lock.json | 41 ----------------------------------------- package.json | 1 - src/index.ts | 10 +--------- src/utils.ts | 28 ---------------------------- test/utils.test.ts | 16 ---------------- test/wallet.test.ts | 3 +-- 6 files changed, 2 insertions(+), 97 deletions(-) diff --git a/package-lock.json b/package-lock.json index a57a4739..6d366d67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.9.0", "license": "MIT", "dependencies": { - "@gandlaf21/bolt11-decode": "^3.0.6", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", "@scure/bip32": "^1.3.3", @@ -818,16 +817,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@gandlaf21/bolt11-decode": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@gandlaf21/bolt11-decode/-/bolt11-decode-3.0.6.tgz", - "integrity": "sha512-KUcAK2b9or8J47hzNTM2A+xdU0jCGIL4oC4TDyUlRYMfS5dBVOh4ywg9r3TZD8C/eVx7r14Hp4F79CSDjyCWTQ==", - "dependencies": { - "bech32": "^1.1.2", - "bn.js": "^4.11.8", - "buffer": "^6.0.3" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -2086,16 +2075,6 @@ } ] }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" - }, - "node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -7020,16 +6999,6 @@ "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", "dev": true }, - "@gandlaf21/bolt11-decode": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@gandlaf21/bolt11-decode/-/bolt11-decode-3.0.6.tgz", - "integrity": "sha512-KUcAK2b9or8J47hzNTM2A+xdU0jCGIL4oC4TDyUlRYMfS5dBVOh4ywg9r3TZD8C/eVx7r14Hp4F79CSDjyCWTQ==", - "requires": { - "bech32": "^1.1.2", - "bn.js": "^4.11.8", - "buffer": "^6.0.3" - } - }, "@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -7979,16 +7948,6 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, - "bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" - }, - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", diff --git a/package.json b/package.json index f09c292b..dcf6d73f 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "typescript": "^5.0.4" }, "dependencies": { - "@gandlaf21/bolt11-decode": "^3.0.6", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", "@scure/bip32": "^1.3.3", diff --git a/src/index.ts b/src/index.ts index a321c040..f1c49f0b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,25 +2,17 @@ import { CashuMint } from './CashuMint.js'; import { CashuWallet } from './CashuWallet.js'; import { setGlobalRequestOptions } from './request.js'; import { generateNewMnemonic, deriveSeedFromMnemonic } from './secrets.js'; -import { getEncodedToken, getDecodedToken, deriveKeysetId, decodeInvoice } from './utils.js'; -import { decode } from '@gandlaf21/bolt11-decode'; +import { getEncodedToken, getDecodedToken, deriveKeysetId } from './utils.js'; export * from './model/types/index.js'; -/** - * @deprecated use decodeInvoice instead - */ -const getDecodedLnInvoice = decode; - export { CashuMint, CashuWallet, getDecodedToken, getEncodedToken, deriveKeysetId, - getDecodedLnInvoice, generateNewMnemonic, deriveSeedFromMnemonic, - decodeInvoice, setGlobalRequestOptions }; diff --git a/src/utils.ts b/src/utils.ts index d9d28b5f..2cef21dc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,8 +1,6 @@ -import { decode } from '@gandlaf21/bolt11-decode'; import { encodeBase64ToJson, encodeJsonToBase64 } from './base64.js'; import { AmountPreference, - InvoiceData, Keys, Proof, Token, @@ -191,32 +189,6 @@ export function joinUrls(...parts: Array): string { return parts.map((part) => part.replace(/(^\/+|\/+$)/g, '')).join('/'); } -export function decodeInvoice(bolt11Invoice: string): InvoiceData { - const invoiceData: InvoiceData = {} as InvoiceData; - const decodeResult = decode(bolt11Invoice); - invoiceData.paymentRequest = decodeResult.paymentRequest; - for (let i = 0; i < decodeResult.sections.length; i++) { - const decodedSection = decodeResult.sections[i]; - if (decodedSection.name === 'amount') { - invoiceData.amountInSats = Number(decodedSection.value) / 1000; - invoiceData.amountInMSats = Number(decodedSection.value); - } - if (decodedSection.name === 'timestamp') { - invoiceData.timestamp = decodedSection.value; - } - if (decodedSection.name === 'description') { - invoiceData.memo = decodedSection.value; - } - if (decodedSection.name === 'expiry') { - invoiceData.expiry = decodedSection.value; - } - if (decodedSection.name === 'payment_hash') { - invoiceData.paymentHash = decodedSection.value.toString('hex'); - } - } - return invoiceData; -} - export { bigIntStringify, bytesToNumber, diff --git a/test/utils.test.ts b/test/utils.test.ts index ade88d3b..ed7448b6 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -300,22 +300,6 @@ describe('test cleanToken', () => { }); }); -describe('test decodeInvoice', () => { - test('decoding a lightning invoice', async () => { - const invoice = - 'lnbc15u1p3xnhl2pp5jptserfk3zk4qy42tlucycrfwxhydvlemu9pqr93tuzlv9cc7g3sdqsvfhkcap3xyhx7un8cqzpgxqzjcsp5f8c52y2stc300gl6s4xswtjpc37hrnnr3c9wvtgjfuvqmpm35evq9qyyssqy4lgd8tj637qcjp05rdpxxykjenthxftej7a2zzmwrmrl70fyj9hvj0rewhzj7jfyuwkwcg9g2jpwtk3wkjtwnkdks84hsnu8xps5vsq4gj5hs'; - const invoiceData = utils.decodeInvoice(invoice); - expect(invoiceData.timestamp).toStrictEqual(1651105770); - expect(invoiceData.amountInMSats).toStrictEqual(1500000); - expect(invoiceData.amountInSats).toStrictEqual(1500); - expect(invoiceData.paymentHash).toStrictEqual( - '90570c8d3688ad5012aa5ff982606971ae46b3f9df0a100cb15f05f61718f223' - ); - expect(invoiceData.expiry).toStrictEqual(600); - expect(invoiceData.memo).toStrictEqual('bolt11.org'); - }); -}); - describe('test keyset derivation', () => { test('derive', () => { const keys = PUBKEYS; diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 0f80b859..e68ac5be 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -1,4 +1,3 @@ -import { decode } from '@gandlaf21/bolt11-decode'; import nock from 'nock'; import { CashuMint } from '../src/CashuMint.js'; import { CashuWallet } from '../src/CashuWallet.js'; @@ -41,7 +40,7 @@ describe('test fees', () => { const wallet = new CashuWallet(mint); const fee = await wallet.getMeltQuote(invoice); - const amount = decode(invoice).sections[2].value / 1000; + const amount = 2000; expect(fee.fee_reserve + amount).toEqual(2020); }); From d11117dae13194324e4b86cf3a536ee4178395e7 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Mon, 25 Mar 2024 14:36:52 +0900 Subject: [PATCH 04/50] migration guide --- migration-1.0.0.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 migration-1.0.0.md diff --git a/migration-1.0.0.md b/migration-1.0.0.md new file mode 100644 index 00000000..e4a1ae4f --- /dev/null +++ b/migration-1.0.0.md @@ -0,0 +1,93 @@ +# Version 1.0.0 Migration guide + +⚠️ Upgrading to version 1.0.0 will come with breaking changes! Please follow the migration guide for a smooth transition to the new version. + +## Context + +In Version 1.0.0 the api version of mints has been upgraded to `v1`. Please read the `v1` [v1 cleanup PR](https://github.com/cashubtc/nuts/pull/55) to understand more about how the API has changed. + +## Breaking changes + +### ⚠️ Important! When upgrading to this version, the `hash2curve` function and the `default secret format` have changed. This means deterministic secret derivation will produce NOT THE SAME SECRETS as before. When upgrading to this version, wallets that have been using deterministic secrets (seed phrase) must reset counters and then `self spend`/`refresh` all proofs, so that the backups continue working. + +--- + +### Decoding LN invoices + +**Removed LN invoice decode:** +Decoding LN invoices is no longer used inside the lib. + +**How to fix:** If you need to decode LN invoices, you can use +> npm i [@gandlaf21/bolt11-decode](https://www.npmjs.com/package/@gandlaf21/bolt11-decode) + +--- + +### `CashuWallet` interface changes + +**`requestMint(amount: number)` --> `getMintQuote(amount: number)`** +Now returns the following: + +```typescript +type MintQuoteResponse = { + request: string; + quote: string; +} +``` + +where `request` is the invoice to be paid, and `quote` is the identifier used to pass to `mintTokens()`. + +--- + +**`getMeltQuote(invoice: string)`** is now used to get fee estimation and conversion quotes instead of `getFee()` and returns: + +```typescript +type MeltQuoteResponse = { + quote: string; + amount: number; + fee_reserve: number; +} +``` +where `quote` is the identifier to pass to `meltTokens()` + +--- + +### Model changes + +**`MintKeys`--> `Keys`**: +`MintKeys` now include the `keys`, `id` and `unit` + +```typescript +type MintKeys = { + id: string; + unit: string; + keys: Keys; +}; + +type Keys = { [amount: number]: string }; + +``` +--- +**`MintKeyset`**: +Used to be a string array, but now contains the additional fields `active` and `unit` + +```typescript +type MintKeyset = { + id: string; + unit: string; + active: boolean; +}; +``` +--- +**`BlindedMessages`:** now include the field `id`, corresponding with the mints `keysetId` + +```typescript +type BlindedMessage { + amount: number; + B_: ProjPointType; + id: string; +} +``` +--- +### Pattern changes + +**removed `newKeys` from returns**: Functions no longer return `newKeys`. Wallets now specify the keyset they use in the BlindedMessage via the `id` field. \ No newline at end of file From 7e311ed924db0ef66481bffa2a634ce266ce00ef Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Mon, 25 Mar 2024 14:45:28 +0900 Subject: [PATCH 05/50] 1.0.0-rc.0 --- 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 6d366d67..3348abb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cashu/cashu-ts", - "version": "0.9.0", + "version": "1.0.0-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cashu/cashu-ts", - "version": "0.9.0", + "version": "1.0.0-rc.0", "license": "MIT", "dependencies": { "@noble/curves": "^1.3.0", diff --git a/package.json b/package.json index dcf6d73f..d2ecb4de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "0.9.0", + "version": "1.0.0-rc.0", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From 05175adc849eb92137261378b01788b0f22f3c6b Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Mon, 25 Mar 2024 14:46:34 +0900 Subject: [PATCH 06/50] 1.0.0-rc.1 --- 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 3348abb6..975ed1c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.0", + "version": "1.0.0-rc.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.0", + "version": "1.0.0-rc.1", "license": "MIT", "dependencies": { "@noble/curves": "^1.3.0", diff --git a/package.json b/package.json index d2ecb4de..5cab1bc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.0", + "version": "1.0.0-rc.1", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From 1b9a10f991dc9da2cb04e053c685e174693883ea Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 27 Mar 2024 09:38:13 +0900 Subject: [PATCH 07/50] fix unused restore payload --- src/CashuMint.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 32bbe16b..198aa1fe 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -326,9 +326,6 @@ class CashuMint { customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; - //TODO remove after fix - //@ts-expect-error temp fix - restorePayload.quote = ''; const data = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/restore'), method: 'POST', From aa0323553ea66b95ff1c004eee1f2efbc54f5938 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 27 Mar 2024 09:40:49 +0900 Subject: [PATCH 08/50] update mint image in int test pipeline --- .github/workflows/nutshell-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nutshell-integration.yml b/.github/workflows/nutshell-integration.yml index cf17cd90..8dafd40b 100644 --- a/.github/workflows/nutshell-integration.yml +++ b/.github/workflows/nutshell-integration.yml @@ -8,7 +8,7 @@ jobs: steps: - name: Pull and start mint run: | - docker run -d -p 3338:3338 --name nutshell -e MINT_LIGHTNING_BACKEND=FakeWallet -e MINT_LISTEN_HOST=0.0.0.0 -e MINT_LISTEN_PORT=3338 -e MINT_PRIVATE_KEY=TEST_PRIVATE_KEY cashubtc/nutshell:0.15.1 poetry run mint + docker run -d -p 3338:3338 --name nutshell -e MINT_LIGHTNING_BACKEND=FakeWallet -e MINT_LISTEN_HOST=0.0.0.0 -e MINT_LISTEN_PORT=3338 -e MINT_PRIVATE_KEY=TEST_PRIVATE_KEY cashubtc/nutshell:0.15.2 poetry run mint - name: Check running containers run: docker ps From c8f711c1e638308dc504c639d8c3f3adde76ba74 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 27 Mar 2024 09:58:13 +0900 Subject: [PATCH 09/50] fix pay external invoice integration test --- test/integration.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration.test.ts b/test/integration.test.ts index a24a5187..0c75747b 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -105,8 +105,8 @@ describe('mint api', () => { const response = await wallet.payLnInvoice(externalInvoice, sendResponse.send); expect(response).toBeDefined(); - // expect that we have received the fee back, since it was internal - expect(response.change.reduce((a, b) => a + b.amount, 0)).toBe(fee); + // expect that we have not received the fee back, since it was external + expect(response.change.reduce((a, b) => a + b.amount, 0)).toBeLessThan(fee); // check states of spent and kept proofs after payment const sentProofsSpent = await wallet.checkProofsSpent(sendResponse.send); From 03464ec059e7fe0f9cd5ab5521d7a20558a80507 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Thu, 28 Mar 2024 08:25:50 +0900 Subject: [PATCH 10/50] remove duplicate test ci runs, remove deprecated node version run --- .github/workflows/node.js.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 6b14853a..c47fd4ad 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: - node-version: [20.x, 16.x, 18.x] + node-version: [20.x, 18.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: From 3cb236d47694b881056a2fb1d9e7542e246b5b3b Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Thu, 28 Mar 2024 08:27:09 +0900 Subject: [PATCH 11/50] only run tests once --- .github/workflows/node.js.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index c47fd4ad..741a896b 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -3,7 +3,7 @@ name: Node.js CI -on: [push, pull_request] +on: [push] jobs: tests: @@ -11,7 +11,7 @@ jobs: strategy: matrix: - node-version: [20.x, 18.x] + node-version: [20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: From b07e864e9bf3fd113f3adcc4f9c08f6f05d67714 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Thu, 28 Mar 2024 09:23:43 +0900 Subject: [PATCH 12/50] fix keyset derivation --- src/utils.ts | 21 +++++++++----- test/consts.ts | 68 ++-------------------------------------------- test/utils.test.ts | 2 +- 3 files changed, 18 insertions(+), 73 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 2cef21dc..dd33d975 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -8,7 +8,7 @@ import { TokenV2 } from './model/types/index.js'; import { TOKEN_PREFIX, TOKEN_VERSION } from './utils/Constants.js'; -import { bytesToHex } from '@noble/curves/abstract/utils'; +import { bytesToHex, hexToBytes } from '@noble/curves/abstract/utils'; import { sha256 } from '@noble/hashes/sha256'; function splitAmount(value: number, amountPreference?: Array): Array { @@ -128,12 +128,19 @@ function handleTokens(token: string): Token { export function deriveKeysetId(keys: Keys) { const pubkeysConcat = Object.entries(keys) .sort((a, b) => +a[0] - +b[0]) - .map(([, pubKey]) => pubKey) - .join(''); - const hash = sha256(new TextEncoder().encode(pubkeysConcat)); - const hashHex = bytesToHex(hash); - return '00' + hashHex.slice(0, 14); -} + .map(([, pubKey]) => hexToBytes(pubKey)).reduce((prev,curr)=>mergeUInt8Arrays(prev,curr),new Uint8Array()) + const hash = sha256(pubkeysConcat); + const hashHex = Buffer.from(hash).toString('hex').slice(0, 14) + return '00' + hashHex +} + +function mergeUInt8Arrays(a1: Uint8Array, a2: Uint8Array): Uint8Array { + // sum of individual array lengths + const mergedArray = new Uint8Array(a1.length + a2.length); + mergedArray.set(a1); + mergedArray.set(a2, a1.length); + return mergedArray; + } /** * merge proofs from same mint, diff --git a/test/consts.ts b/test/consts.ts index a4dc2e61..f79a0652 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -1,66 +1,4 @@ export const PUBKEYS = { - '1': '0352d74be2366c43a3e2e88798b8e2d03c569ef09d22e02bb365f69a5210a1760b', - '2': '033b88748953acc5e6e3bd08c1c706eb7cb2ea91afd24a2a7f58ce1a5ea662f528', - '4': '0337290d84d9754e86b16e6908649548f54225038112d30d5dc5cdd03edca59b42', - '8': '030ffb1c6541e36c0ed7d64d2317f125a04126de38a9fddeabda860f9823a315b8', - '16': '035aaf89544bef31d420eba46b4f24bd1a26018883cbfafeec79ce7e61637bc593', - '32': '0219e43d08e6ce640c6cee70a5cb5946a967ec3b32207c8c7f465875356c0b3e7a', - '64': '039eca547db9d9709631038edbb287b06f7c591acb3a7a863cc027c5d0c5296524', - '128': '036d0d2fb209a5b43527a816ab7475151e2ec8b0b9535543c0aa2a9fab43c0e7c1', - '256': '0209d950bf0a545c7cd33cd3b76100ed008c1b62f49eb1627564aaedd1a05942c5', - '512': '02393187e1c1df39f08610d0af930d971c8d2474beb5a08e86a3de3359d3ab9320', - '1024': '02464f570d0413e918aebcb8d5734debd9368548bef4f36eb62637dd602e6253ea', - '2048': '02b3c7e26a17e20952e4ac8f58534217831fd9f4e3d3b1ee1c80908d4f1e1ee705', - '4096': '023f60d762c187210a9cd8de2dccd1d4e74594d4f489c194ea05c588cda978eacf', - '8192': '029df2cd59413e63b545be9c56f4b0dc4bbf663489bc3ab67eadde2772fbfd370c', - '16384': '034543746c6fce7ad3db341796356a71b4d3b7f6cb2908dea1f8c001b64761dd9b', - '32768': '035e642822cd59400058d402058c6c887f620ef7a9ba09ef815f26ba3f59118a8e', - '65536': '03d0fc713531149cf8b47b96ecec54f853e19ff47417d550cd7a1dbb654edff98a', - '131072': '023db71e398e641540202a2b429354f6d62cb25b0db2a8e0247ff8cdbb152b66c4', - '262144': '02f3edf578a999fd471d0651c95202efabbf9b8096d3fa81975e155979418197f3', - '524288': '03db113ce4b8c01a282ad6d89e594ca4e67cb0f2f9ceb218938aa9420f31085092', - '1048576': '02da6b3a16443b131a2fdc764106de83f50f6af5e0d648d49f808eb5913e841093', - '2097152': '02d6c7b6ba9c2d0ea5fa888de1616f2fc1a34c5e21df15bdf5a71c75aa510c07c9', - '4194304': '021d66e4ef4cbb0860483ac640723e231a55e63dad77bdc9ed3156dcada33f6cf3', - '8388608': '035064a5c497fdf8398bc3790304ac1efd86594f88ab65e04500168d5100291213', - '16777216': '03f4f7f2afe38bde4e59f50478473fbb0dfb6d869cf2e28400e91728301b774955', - '33554432': '02cb68adad06865f8a774ac73a83d20c6cf649b5ca766e41f6376bc391625d35f5', - '67108864': '028302c0995a8e1129b1a27152e3683112ee38902cbc6b04c5edbf804811f7898a', - '134217728': '02e67e852e6d0d9709a9e4ba164a812adef870f42d4bcc36d541a277da4acdfdb6', - '268435456': '0210276a3d3c6615bfa10f430b20fb51ff61591f7c4da6906f455b7f096673e689', - '536870912': '02abffa5e1f0036aabcca596d527720b62d4921a5df6ffccef52c801f8a4b1e0ab', - '1073741824': '03e07c92aa7ceab7e2c01adb7af77def101b7caa502795b9b8e30a8b53b39d7dad', - '2147483648': '0203786ad188ba2368fd4f44d24ec1cdc9736d757557946b9d4b2403ec7b116d29', - '4294967296': '02caa6c148adbbe3e6ae71d074770085c43624acd8107a40dc5e7929ef24b5bfaa', - '8589934592': '02a3879c0a6e4297654c109096559326b80ff70432fedcaa3673a2ae8742e4cb33', - '17179869184': '0212fd5125cb773ab2b8dbb304c1e5b9359fc75f0889e3073d5a411886f54f6d38', - '34359738368': '03797b244dee73204127223ca4d341a92e3a87d3f17e1c80fedcc5a336ff616a1e', - '68719476736': '03086982375f4097b2f4d00e1924b89d696352b874fec8bc76504347f51328671d', - '137438953472': '02b61f17e50dc9d0887d7b6953f97a520ea0796870e0bba51e05b7e2f495d9b806', - '274877906944': '02290f140f84512e0ba941e6f958833390d4495f161544b8bcf3241a0ead89de18', - '549755813888': '0310ee60086163731d7839a7bf2062e655ab2563871488429c8a67433f2373876d', - '1099511627776': '0212b293c4e0f9c2f1dac473077f2daa280cd6600ac3fb8789c1bccddc272054a1', - '2199023255552': '03e590752f1379fd09986b07ef4a14dfadf8bec5aacf4ec83f56990f2a07ec6656', - '4398046511104': '02ec77ebaa46fdaf0eca996865dcb8121f71c2a4d35e70135933f21c7f632e2f38', - '8796093022208': '038c5f43fa83c4dd84cadd22ec12df56de435eff713629d0706eae6f42741ce00e', - '17592186044416': '036ba077c8350e7dcfcb972a4087252e59cf1e74ea8cffbe0405143037f295f58e', - '35184372088832': '0279771f0d2971c35e93d0b22b3b42ce6b859141f1f72b215b51c7feff96e87cef', - '70368744177664': '03864a3ae9e3e3817c14d0635d2cd88b1130c3440e2473815c02121d26140b5b57', - '140737488355328': '029e7296b502ed49b32c0981790a159bbfb0c9a827fb1178295067810cf6e31921', - '281474976710656': '030024a03f98bd27743ccecb7d6e3204646415bed7cb7c1098aaebdeabb72d63b4', - '562949953421312': '0384fb48aa0b4e4a68f645c963ffaaf3de4a5561edeb486cba74daf1b93a02a04a', - '1125899906842624': '02ef5cf515cb8b7459b6a0d6f631013fbef0885718dc30f272397beb3643f5bfa3', - '2251799813685248': '02f944f0fef655d8c89f042460e15fd3c6d452a1e8cbac503b826893477656f9b2', - '4503599627370496': '0378b14720f73c27ecfe9051f07ae09051d69e077ac8849a66bd77a7965f2cc760', - '9007199254740992': '02a0c981d62cf945144724de11c9ca595aebbda8b6afb39a9faa7f4abcec3e6da8', - '18014398509481984': '0225ce53547e4f322a80fab97e5028ab78282b6f63f9528ca83108b47d8007cc72', - '36028797018963968': '0315a18f669aee0c983ca7fcd23d929b71cf6b6983d760a96e950d17a061d43a06', - '72057594037927936': '03d1877405fb8ba7f7767fd646d305afd566088e5742d47f45b7c38753ce4d1167', - '144115188075855872': '029bbf9e5c76d11096a2f5bd176917e21ca941e294081866895183a131ba4358e6', - '288230376151711744': '023cf13b9c1a5a242dbb15c63d5e397bc595a672f90e2046b59e036f786713d796', - '576460752303423488': '03a34759634b1615d33ce7da47ef18df738559f9b47d96cbda897810de86aa0a9c', - '1152921504606846976': '03d1d210b1d41cf860876260ad4761fc5daedfefcf1874d2a87386cfccfe689d65', - '2305843009213693952': '03d42abc9c05b8ae2ac926de932030e7aa6ec845eacd5ddcab589df5c779ffb3e4', - '4611686018427387904': '022e2acccc241b9936cedcd6447308c344ee4903798507bbb604ef81468fabf277', - '9223372036854775808': '027fd1b5d36ddf18de228b5f3bdf61bff8d94b5a2f7ddc44b117372d7436b178e3' -}; + "1": "02194603ffa36356f4a56b7df9371fc3192472351453ec7398b8da8117e7c3e104", "2": "03b0f36d6d47ce14df8a7be9137712c42bcdd960b19dd02f1d4a9703b1f31d7513", "4": "0366be6e026e42852498efb82014ca91e89da2e7a5bd3761bdad699fa2aec9fe09", "8": "0253de5237f189606f29d8a690ea719f74d65f617bb1cb6fbea34f2bc4f930016d", "16": "0217ff15bc0e183ae1745911bd84c761945a446fa27284eeb4a18220abc3a39eae", "32": "03c65d28721a9fe81e91e596fe1ab667e5ca0f8a9872d5376e34fd4f29501910a9", "64": "02cedd62d7518736ff0c172fdfc3079845affc13eed9427cb81988e6f184ca5530", "128": "03c03e0922d1efec034c06074553f87453322cb36a6d789e61cfd8786961d7b5bc", "256": "0296d2894191b73993621848544053d47df0b43e7a34b8bfd12f2deb5258cebe57", "512": "03405f14f5c507eedba8658ab6b79179a31722c4226680ba03c6508fef2d0cad46", "1024": "031c6cc53a5a19fdf6bcd311871209a1645afb9ff52ae00128e46d75073b42a376", "2048": "03a5e61e7aa6b0d6c314d577ec44d58a5f7e4149f762b05cdba519949b957adae6", "4096": "027e0d8bab3525843d3b7d6193ae88d211d505e097bf8810b1fa6a205f912efccf", "8192": "022c0f3a5274acc129ad567f64542e01e538818689bdc21f4bbaf88be729295771", "16384": "03ef1e94c645e56fa09f9cc9bc07469077c209552a0ce4dbdb4bf44981a7b9fa85", "32768": "0208b013c5a52987dd0323aef4cf0d48c941a4a9d2d76bb974cc59e4b41d26d47b", "65536": "02f881a2534ca06d0da485b4be5050883022235ea89e6ea81f43115ed6cdefb190", "131072": "03154dab4b35831536dd85d9bdf892c9839bf6958617619b31f4ca5748bf0dbf2a", "262144": "02edaaee84d297212ad0819ec923c40e958c208bd96d2abf76e4004455cfd4e365", "524288": "030a08fc4c9f4ca0125c73b62d036845e43f7bcffe38cb5f09cfe35a8e59e135e6", "1048576": "030288d91b21db418027f2902b39fd1712c5afd22b9a734f6021dc6829363dc7e9", "2097152": "0231a3cd012a916db6ee899dfcc0f31da6dacc4c3497b74dd937e0b85a72081913", "4194304": "03467db9a45f138bcb7a762d64cd6029cbdf4ed740b1851831ce380efe3bef913c", "8388608": "0234104b610749c0276105c84da30c2ff82d831768a7edc2c4131b02ebc3eb3ae2", "16777216": "02599c06e1f52f16eb7593886c56a43bc53a5451a728cdf246c188720d1d138173", "33554432": "035d7ecd096a6a703e052de84133fac77c1c33c8b37e72ccc3d8a9d770a163da5d", "67108864": "028c06896499c7b16719ae249f7e826cdabfb77cbc9ccc80c668830b1071f9f5f6", "134217728": "02c8ac5f30cf34e011bac12414d6fce384f5cf2cbd0aa6b21340f68c119c835241", "268435456": "0258094c7f26006eaaf00fc1fcb9950e591c578d2900108fa46e6b4961285fe914", "536870912": "03be658104ed6f3c3109e4ca33ce5e3d63e6f537a70d47084e83097f0906e50b32", "1073741824": "03de09651ec6ca86e505c8e800fdd3fcea5c80246702189f2457678273e8cea462", "2147483648": "020f2ed905d971c57893c5ca8af869de33987f11e14d8eedc475f33cc9b6387b9f", "4294967296": "03d9b0de71d3618d746c5366839da7a2f84b6c75d59849f54a19b076eb1b9c54ef", "8589934592": "036097d00a195fdd2899d1687c414b39f21bd7c112bddb9239c4f0d9af4ff27ab7", "17179869184": "03d8ffa01c9e4e4802b0899a2694612dafd6390b24f19a8bd19fc2abae5679f9cf", "34359738368": "031b8a21a0acd754137b2c6d780693b1ef4528da02a8a29d4bae04c20df69084f5", "68719476736": "026c81e4498ec4693f4030c40bb8d48db38a436d6a3aa0ea1263f92f3a40f9239a", "137438953472": "03a95f4b5736d6fba5678ae67716f874be26ae2c10044d84204f6e51e41aef97dd", "274877906944": "025792fc31361ca5202a1d1313512eee9ce83c86356fa5f7b9642d5416c53f2571", "549755813888": "03555f71d7e951e6b9c3113afe1f228855331db24b9805fc274b1b5e5d9e8d0f7c", "1099511627776": "029b1b433c98ed693d07f53157093386c7a63d54d752a4da00fc252b84afdb89e7", "2199023255552": "03b03bd1f346ebc1c84b315f0cd7c9ae7bb577617a447b085d5f896419f6214651", "4398046511104": "0248a3f5162755d65a79b2fa35e51aa50d51b00040c127b12badaf97d3de12ef04", "8796093022208": "02bf233b579a6b402886b706ff2fef5deed2bf53b3bd370844091f4b1cdaf688dc", "17592186044416": "03c1eb5422c58b8e3522355c3cc470ccb6b0add8e4b0d5aadd0412dadbaddb0096", "35184372088832": "026c9450a3afae0103766d7767193ac5a49669cbc85bdbefab04b9fa182e42d911", "70368744177664": "034688f63ed273e524f08a155ac00c54c5f85d941e45394695e7c345cc00bcfaa4", "140737488355328": "0331df7f9c1876cf57db9f0a29b5c50c6c2cff20fef5d8b4c17158332bb10e72fd", "281474976710656": "0230dd1dba84778a2302b0c50db29e9c4846bbad96a7c847d92ce084bffb45305e", "562949953421312": "02fd0386d1998cd76e45fc17d07ffe82015ad918f5d8e516406956e78fe38e3511", "1125899906842624": "03d3fbf9c2dc0ca0fa5bfc5ccad526a1305331b4a14637cc2ebe64d324a3fedc9e", "2251799813685248": "03d2e21a411422f04acf9fd7ce307f410d6642714232103f52e61edef99172188f", "4503599627370496": "022163656cb4a2369d3a7b1fab1599fef924150c3030ffed3fbc40fec6f984613a", "9007199254740992": "03d25547594eeaa261ed48ebd6794389706c6c47cccd167c44a322721f0d07b509", "18014398509481984": "027ed195fe4f4565d4cbcc8755de0aa6ccd5878efa13da9607191ac854c806390f", "36028797018963968": "0231d6bfb9f2414c5992e96615904beaa5af844d2214e9e14d24202059639ee0df", "72057594037927936": "03860470440f4f5a2488ee64bacd4e4a9eb0d50d2a1d6215167acb247025b566bb", "144115188075855872": "031055a11ecc825257788f065c247da1a84493c1438aa95c6f2a1dffc886eccd1a", "288230376151711744": "03bb3f9f774a1f2651a2cbe9f21954c637aec565807a61f5551d9109a7d1d17b6f", "576460752303423488": "032701bb051cfa46676da504c6967b5b7d3a70eb6499a9feaa71ffe629b0edac9a", "1152921504606846976": "0342f67cf3e82cde49ced155b7117f8d583ae8766bce4fd7aa170179ee43a0608e", "2305843009213693952": "0366c51883c60f37f3a74d05e725791efd98773eb143a98aa8808915b0ffe23c6d", "4611686018427387904": "020d25d8c67e59395983569cf5a7b86f13cccf95a7b4d374bc40ffac04c6437b86", "9223372036854775808": "023c84c0895cc0e827b348ea0a62951ca489a5e436f3ea7545f3c1d5f1bea1c866" +} + diff --git a/test/utils.test.ts b/test/utils.test.ts index ed7448b6..ccc34160 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -305,6 +305,6 @@ describe('test keyset derivation', () => { const keys = PUBKEYS; const keysetId = utils.deriveKeysetId(keys); console.log(keysetId); - expect(keysetId).toBe('00a627821fbe96e4'); + expect(keysetId).toBe('009a1f293253e41e'); }); }); From c36dd0189ee51fa1f176f8147f764b7e99525ff9 Mon Sep 17 00:00:00 2001 From: starbackr-dev Date: Thu, 28 Mar 2024 10:54:27 -0400 Subject: [PATCH 13/50] fixed issue with merge --- src/CashuWallet.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index b73432da..15e23c6a 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -40,7 +40,7 @@ import { wordlist } from '@scure/bip39/wordlists/english'; class CashuWallet { private _keys: MintKeys | undefined; private _seed: Uint8Array | undefined; - private _unit = 'sat'; + private _unit = 'sat'; mint: CashuMint; @@ -52,6 +52,7 @@ class CashuWallet { */ constructor(mint: CashuMint, unit?:string, keys?: MintKeys, mnemonicOrSeed?: string | Uint8Array) { this.mint = mint; + if (unit) this._unit = unit; if (keys) { this._keys = keys; } @@ -151,7 +152,7 @@ class CashuWallet { preference, counter ); - const { signatures, error } = await CashuMint.split(tokenEntry.mint, payload); + const { signatures } = await CashuMint.split(tokenEntry.mint, payload); const newProofs = dhke.constructProofs( signatures, blindedMessages.rs, From 45318302b95366c06a5b124c12c2c93e7fee4855 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Sat, 30 Mar 2024 09:23:41 +0900 Subject: [PATCH 14/50] format --- README.md | 1 - migration-1.0.0.md | 31 +++++++++++++-------- src/utils.ts | 18 ++++-------- test/consts.ts | 68 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 90 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 675f4661..62ad9740 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,6 @@ const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint); const request = await wallet.getMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); - ``` ## Contribute diff --git a/migration-1.0.0.md b/migration-1.0.0.md index e4a1ae4f..af164f60 100644 --- a/migration-1.0.0.md +++ b/migration-1.0.0.md @@ -14,10 +14,11 @@ In Version 1.0.0 the api version of mints has been upgraded to `v1`. Please read ### Decoding LN invoices -**Removed LN invoice decode:** -Decoding LN invoices is no longer used inside the lib. +**Removed LN invoice decode:** +Decoding LN invoices is no longer used inside the lib. + +**How to fix:** If you need to decode LN invoices, you can use -**How to fix:** If you need to decode LN invoices, you can use > npm i [@gandlaf21/bolt11-decode](https://www.npmjs.com/package/@gandlaf21/bolt11-decode) --- @@ -25,13 +26,13 @@ Decoding LN invoices is no longer used inside the lib. ### `CashuWallet` interface changes **`requestMint(amount: number)` --> `getMintQuote(amount: number)`** -Now returns the following: +Now returns the following: ```typescript type MintQuoteResponse = { - request: string; - quote: string; -} + request: string; + quote: string; +}; ``` where `request` is the invoice to be paid, and `quote` is the identifier used to pass to `mintTokens()`. @@ -45,8 +46,9 @@ type MeltQuoteResponse = { quote: string; amount: number; fee_reserve: number; -} +}; ``` + where `quote` is the identifier to pass to `meltTokens()` --- @@ -64,11 +66,12 @@ type MintKeys = { }; type Keys = { [amount: number]: string }; - ``` + --- + **`MintKeyset`**: -Used to be a string array, but now contains the additional fields `active` and `unit` +Used to be a string array, but now contains the additional fields `active` and `unit` ```typescript type MintKeyset = { @@ -77,17 +80,21 @@ type MintKeyset = { active: boolean; }; ``` + --- + **`BlindedMessages`:** now include the field `id`, corresponding with the mints `keysetId` -```typescript +```typescript type BlindedMessage { amount: number; B_: ProjPointType; id: string; } ``` + --- + ### Pattern changes -**removed `newKeys` from returns**: Functions no longer return `newKeys`. Wallets now specify the keyset they use in the BlindedMessage via the `id` field. \ No newline at end of file +**removed `newKeys` from returns**: Functions no longer return `newKeys`. Wallets now specify the keyset they use in the BlindedMessage via the `id` field. diff --git a/src/utils.ts b/src/utils.ts index dd33d975..1729b995 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,12 +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, TokenEntry, 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'; @@ -128,10 +121,11 @@ function handleTokens(token: string): Token { export function deriveKeysetId(keys: Keys) { const pubkeysConcat = Object.entries(keys) .sort((a, b) => +a[0] - +b[0]) - .map(([, pubKey]) => hexToBytes(pubKey)).reduce((prev,curr)=>mergeUInt8Arrays(prev,curr),new Uint8Array()) + .map(([, pubKey]) => hexToBytes(pubKey)) + .reduce((prev, curr) => mergeUInt8Arrays(prev, curr), new Uint8Array()); const hash = sha256(pubkeysConcat); - const hashHex = Buffer.from(hash).toString('hex').slice(0, 14) - return '00' + hashHex + const hashHex = Buffer.from(hash).toString('hex').slice(0, 14); + return '00' + hashHex; } function mergeUInt8Arrays(a1: Uint8Array, a2: Uint8Array): Uint8Array { @@ -140,7 +134,7 @@ function mergeUInt8Arrays(a1: Uint8Array, a2: Uint8Array): Uint8Array { mergedArray.set(a1); mergedArray.set(a2, a1.length); return mergedArray; - } +} /** * merge proofs from same mint, diff --git a/test/consts.ts b/test/consts.ts index f79a0652..5d840a8c 100644 --- a/test/consts.ts +++ b/test/consts.ts @@ -1,4 +1,66 @@ export const PUBKEYS = { - "1": "02194603ffa36356f4a56b7df9371fc3192472351453ec7398b8da8117e7c3e104", "2": "03b0f36d6d47ce14df8a7be9137712c42bcdd960b19dd02f1d4a9703b1f31d7513", "4": "0366be6e026e42852498efb82014ca91e89da2e7a5bd3761bdad699fa2aec9fe09", "8": "0253de5237f189606f29d8a690ea719f74d65f617bb1cb6fbea34f2bc4f930016d", "16": "0217ff15bc0e183ae1745911bd84c761945a446fa27284eeb4a18220abc3a39eae", "32": "03c65d28721a9fe81e91e596fe1ab667e5ca0f8a9872d5376e34fd4f29501910a9", "64": "02cedd62d7518736ff0c172fdfc3079845affc13eed9427cb81988e6f184ca5530", "128": "03c03e0922d1efec034c06074553f87453322cb36a6d789e61cfd8786961d7b5bc", "256": "0296d2894191b73993621848544053d47df0b43e7a34b8bfd12f2deb5258cebe57", "512": "03405f14f5c507eedba8658ab6b79179a31722c4226680ba03c6508fef2d0cad46", "1024": "031c6cc53a5a19fdf6bcd311871209a1645afb9ff52ae00128e46d75073b42a376", "2048": "03a5e61e7aa6b0d6c314d577ec44d58a5f7e4149f762b05cdba519949b957adae6", "4096": "027e0d8bab3525843d3b7d6193ae88d211d505e097bf8810b1fa6a205f912efccf", "8192": "022c0f3a5274acc129ad567f64542e01e538818689bdc21f4bbaf88be729295771", "16384": "03ef1e94c645e56fa09f9cc9bc07469077c209552a0ce4dbdb4bf44981a7b9fa85", "32768": "0208b013c5a52987dd0323aef4cf0d48c941a4a9d2d76bb974cc59e4b41d26d47b", "65536": "02f881a2534ca06d0da485b4be5050883022235ea89e6ea81f43115ed6cdefb190", "131072": "03154dab4b35831536dd85d9bdf892c9839bf6958617619b31f4ca5748bf0dbf2a", "262144": "02edaaee84d297212ad0819ec923c40e958c208bd96d2abf76e4004455cfd4e365", "524288": "030a08fc4c9f4ca0125c73b62d036845e43f7bcffe38cb5f09cfe35a8e59e135e6", "1048576": "030288d91b21db418027f2902b39fd1712c5afd22b9a734f6021dc6829363dc7e9", "2097152": "0231a3cd012a916db6ee899dfcc0f31da6dacc4c3497b74dd937e0b85a72081913", "4194304": "03467db9a45f138bcb7a762d64cd6029cbdf4ed740b1851831ce380efe3bef913c", "8388608": "0234104b610749c0276105c84da30c2ff82d831768a7edc2c4131b02ebc3eb3ae2", "16777216": "02599c06e1f52f16eb7593886c56a43bc53a5451a728cdf246c188720d1d138173", "33554432": "035d7ecd096a6a703e052de84133fac77c1c33c8b37e72ccc3d8a9d770a163da5d", "67108864": "028c06896499c7b16719ae249f7e826cdabfb77cbc9ccc80c668830b1071f9f5f6", "134217728": "02c8ac5f30cf34e011bac12414d6fce384f5cf2cbd0aa6b21340f68c119c835241", "268435456": "0258094c7f26006eaaf00fc1fcb9950e591c578d2900108fa46e6b4961285fe914", "536870912": "03be658104ed6f3c3109e4ca33ce5e3d63e6f537a70d47084e83097f0906e50b32", "1073741824": "03de09651ec6ca86e505c8e800fdd3fcea5c80246702189f2457678273e8cea462", "2147483648": "020f2ed905d971c57893c5ca8af869de33987f11e14d8eedc475f33cc9b6387b9f", "4294967296": "03d9b0de71d3618d746c5366839da7a2f84b6c75d59849f54a19b076eb1b9c54ef", "8589934592": "036097d00a195fdd2899d1687c414b39f21bd7c112bddb9239c4f0d9af4ff27ab7", "17179869184": "03d8ffa01c9e4e4802b0899a2694612dafd6390b24f19a8bd19fc2abae5679f9cf", "34359738368": "031b8a21a0acd754137b2c6d780693b1ef4528da02a8a29d4bae04c20df69084f5", "68719476736": "026c81e4498ec4693f4030c40bb8d48db38a436d6a3aa0ea1263f92f3a40f9239a", "137438953472": "03a95f4b5736d6fba5678ae67716f874be26ae2c10044d84204f6e51e41aef97dd", "274877906944": "025792fc31361ca5202a1d1313512eee9ce83c86356fa5f7b9642d5416c53f2571", "549755813888": "03555f71d7e951e6b9c3113afe1f228855331db24b9805fc274b1b5e5d9e8d0f7c", "1099511627776": "029b1b433c98ed693d07f53157093386c7a63d54d752a4da00fc252b84afdb89e7", "2199023255552": "03b03bd1f346ebc1c84b315f0cd7c9ae7bb577617a447b085d5f896419f6214651", "4398046511104": "0248a3f5162755d65a79b2fa35e51aa50d51b00040c127b12badaf97d3de12ef04", "8796093022208": "02bf233b579a6b402886b706ff2fef5deed2bf53b3bd370844091f4b1cdaf688dc", "17592186044416": "03c1eb5422c58b8e3522355c3cc470ccb6b0add8e4b0d5aadd0412dadbaddb0096", "35184372088832": "026c9450a3afae0103766d7767193ac5a49669cbc85bdbefab04b9fa182e42d911", "70368744177664": "034688f63ed273e524f08a155ac00c54c5f85d941e45394695e7c345cc00bcfaa4", "140737488355328": "0331df7f9c1876cf57db9f0a29b5c50c6c2cff20fef5d8b4c17158332bb10e72fd", "281474976710656": "0230dd1dba84778a2302b0c50db29e9c4846bbad96a7c847d92ce084bffb45305e", "562949953421312": "02fd0386d1998cd76e45fc17d07ffe82015ad918f5d8e516406956e78fe38e3511", "1125899906842624": "03d3fbf9c2dc0ca0fa5bfc5ccad526a1305331b4a14637cc2ebe64d324a3fedc9e", "2251799813685248": "03d2e21a411422f04acf9fd7ce307f410d6642714232103f52e61edef99172188f", "4503599627370496": "022163656cb4a2369d3a7b1fab1599fef924150c3030ffed3fbc40fec6f984613a", "9007199254740992": "03d25547594eeaa261ed48ebd6794389706c6c47cccd167c44a322721f0d07b509", "18014398509481984": "027ed195fe4f4565d4cbcc8755de0aa6ccd5878efa13da9607191ac854c806390f", "36028797018963968": "0231d6bfb9f2414c5992e96615904beaa5af844d2214e9e14d24202059639ee0df", "72057594037927936": "03860470440f4f5a2488ee64bacd4e4a9eb0d50d2a1d6215167acb247025b566bb", "144115188075855872": "031055a11ecc825257788f065c247da1a84493c1438aa95c6f2a1dffc886eccd1a", "288230376151711744": "03bb3f9f774a1f2651a2cbe9f21954c637aec565807a61f5551d9109a7d1d17b6f", "576460752303423488": "032701bb051cfa46676da504c6967b5b7d3a70eb6499a9feaa71ffe629b0edac9a", "1152921504606846976": "0342f67cf3e82cde49ced155b7117f8d583ae8766bce4fd7aa170179ee43a0608e", "2305843009213693952": "0366c51883c60f37f3a74d05e725791efd98773eb143a98aa8808915b0ffe23c6d", "4611686018427387904": "020d25d8c67e59395983569cf5a7b86f13cccf95a7b4d374bc40ffac04c6437b86", "9223372036854775808": "023c84c0895cc0e827b348ea0a62951ca489a5e436f3ea7545f3c1d5f1bea1c866" -} - + '1': '02194603ffa36356f4a56b7df9371fc3192472351453ec7398b8da8117e7c3e104', + '2': '03b0f36d6d47ce14df8a7be9137712c42bcdd960b19dd02f1d4a9703b1f31d7513', + '4': '0366be6e026e42852498efb82014ca91e89da2e7a5bd3761bdad699fa2aec9fe09', + '8': '0253de5237f189606f29d8a690ea719f74d65f617bb1cb6fbea34f2bc4f930016d', + '16': '0217ff15bc0e183ae1745911bd84c761945a446fa27284eeb4a18220abc3a39eae', + '32': '03c65d28721a9fe81e91e596fe1ab667e5ca0f8a9872d5376e34fd4f29501910a9', + '64': '02cedd62d7518736ff0c172fdfc3079845affc13eed9427cb81988e6f184ca5530', + '128': '03c03e0922d1efec034c06074553f87453322cb36a6d789e61cfd8786961d7b5bc', + '256': '0296d2894191b73993621848544053d47df0b43e7a34b8bfd12f2deb5258cebe57', + '512': '03405f14f5c507eedba8658ab6b79179a31722c4226680ba03c6508fef2d0cad46', + '1024': '031c6cc53a5a19fdf6bcd311871209a1645afb9ff52ae00128e46d75073b42a376', + '2048': '03a5e61e7aa6b0d6c314d577ec44d58a5f7e4149f762b05cdba519949b957adae6', + '4096': '027e0d8bab3525843d3b7d6193ae88d211d505e097bf8810b1fa6a205f912efccf', + '8192': '022c0f3a5274acc129ad567f64542e01e538818689bdc21f4bbaf88be729295771', + '16384': '03ef1e94c645e56fa09f9cc9bc07469077c209552a0ce4dbdb4bf44981a7b9fa85', + '32768': '0208b013c5a52987dd0323aef4cf0d48c941a4a9d2d76bb974cc59e4b41d26d47b', + '65536': '02f881a2534ca06d0da485b4be5050883022235ea89e6ea81f43115ed6cdefb190', + '131072': '03154dab4b35831536dd85d9bdf892c9839bf6958617619b31f4ca5748bf0dbf2a', + '262144': '02edaaee84d297212ad0819ec923c40e958c208bd96d2abf76e4004455cfd4e365', + '524288': '030a08fc4c9f4ca0125c73b62d036845e43f7bcffe38cb5f09cfe35a8e59e135e6', + '1048576': '030288d91b21db418027f2902b39fd1712c5afd22b9a734f6021dc6829363dc7e9', + '2097152': '0231a3cd012a916db6ee899dfcc0f31da6dacc4c3497b74dd937e0b85a72081913', + '4194304': '03467db9a45f138bcb7a762d64cd6029cbdf4ed740b1851831ce380efe3bef913c', + '8388608': '0234104b610749c0276105c84da30c2ff82d831768a7edc2c4131b02ebc3eb3ae2', + '16777216': '02599c06e1f52f16eb7593886c56a43bc53a5451a728cdf246c188720d1d138173', + '33554432': '035d7ecd096a6a703e052de84133fac77c1c33c8b37e72ccc3d8a9d770a163da5d', + '67108864': '028c06896499c7b16719ae249f7e826cdabfb77cbc9ccc80c668830b1071f9f5f6', + '134217728': '02c8ac5f30cf34e011bac12414d6fce384f5cf2cbd0aa6b21340f68c119c835241', + '268435456': '0258094c7f26006eaaf00fc1fcb9950e591c578d2900108fa46e6b4961285fe914', + '536870912': '03be658104ed6f3c3109e4ca33ce5e3d63e6f537a70d47084e83097f0906e50b32', + '1073741824': '03de09651ec6ca86e505c8e800fdd3fcea5c80246702189f2457678273e8cea462', + '2147483648': '020f2ed905d971c57893c5ca8af869de33987f11e14d8eedc475f33cc9b6387b9f', + '4294967296': '03d9b0de71d3618d746c5366839da7a2f84b6c75d59849f54a19b076eb1b9c54ef', + '8589934592': '036097d00a195fdd2899d1687c414b39f21bd7c112bddb9239c4f0d9af4ff27ab7', + '17179869184': '03d8ffa01c9e4e4802b0899a2694612dafd6390b24f19a8bd19fc2abae5679f9cf', + '34359738368': '031b8a21a0acd754137b2c6d780693b1ef4528da02a8a29d4bae04c20df69084f5', + '68719476736': '026c81e4498ec4693f4030c40bb8d48db38a436d6a3aa0ea1263f92f3a40f9239a', + '137438953472': '03a95f4b5736d6fba5678ae67716f874be26ae2c10044d84204f6e51e41aef97dd', + '274877906944': '025792fc31361ca5202a1d1313512eee9ce83c86356fa5f7b9642d5416c53f2571', + '549755813888': '03555f71d7e951e6b9c3113afe1f228855331db24b9805fc274b1b5e5d9e8d0f7c', + '1099511627776': '029b1b433c98ed693d07f53157093386c7a63d54d752a4da00fc252b84afdb89e7', + '2199023255552': '03b03bd1f346ebc1c84b315f0cd7c9ae7bb577617a447b085d5f896419f6214651', + '4398046511104': '0248a3f5162755d65a79b2fa35e51aa50d51b00040c127b12badaf97d3de12ef04', + '8796093022208': '02bf233b579a6b402886b706ff2fef5deed2bf53b3bd370844091f4b1cdaf688dc', + '17592186044416': '03c1eb5422c58b8e3522355c3cc470ccb6b0add8e4b0d5aadd0412dadbaddb0096', + '35184372088832': '026c9450a3afae0103766d7767193ac5a49669cbc85bdbefab04b9fa182e42d911', + '70368744177664': '034688f63ed273e524f08a155ac00c54c5f85d941e45394695e7c345cc00bcfaa4', + '140737488355328': '0331df7f9c1876cf57db9f0a29b5c50c6c2cff20fef5d8b4c17158332bb10e72fd', + '281474976710656': '0230dd1dba84778a2302b0c50db29e9c4846bbad96a7c847d92ce084bffb45305e', + '562949953421312': '02fd0386d1998cd76e45fc17d07ffe82015ad918f5d8e516406956e78fe38e3511', + '1125899906842624': '03d3fbf9c2dc0ca0fa5bfc5ccad526a1305331b4a14637cc2ebe64d324a3fedc9e', + '2251799813685248': '03d2e21a411422f04acf9fd7ce307f410d6642714232103f52e61edef99172188f', + '4503599627370496': '022163656cb4a2369d3a7b1fab1599fef924150c3030ffed3fbc40fec6f984613a', + '9007199254740992': '03d25547594eeaa261ed48ebd6794389706c6c47cccd167c44a322721f0d07b509', + '18014398509481984': '027ed195fe4f4565d4cbcc8755de0aa6ccd5878efa13da9607191ac854c806390f', + '36028797018963968': '0231d6bfb9f2414c5992e96615904beaa5af844d2214e9e14d24202059639ee0df', + '72057594037927936': '03860470440f4f5a2488ee64bacd4e4a9eb0d50d2a1d6215167acb247025b566bb', + '144115188075855872': '031055a11ecc825257788f065c247da1a84493c1438aa95c6f2a1dffc886eccd1a', + '288230376151711744': '03bb3f9f774a1f2651a2cbe9f21954c637aec565807a61f5551d9109a7d1d17b6f', + '576460752303423488': '032701bb051cfa46676da504c6967b5b7d3a70eb6499a9feaa71ffe629b0edac9a', + '1152921504606846976': '0342f67cf3e82cde49ced155b7117f8d583ae8766bce4fd7aa170179ee43a0608e', + '2305843009213693952': '0366c51883c60f37f3a74d05e725791efd98773eb143a98aa8808915b0ffe23c6d', + '4611686018427387904': '020d25d8c67e59395983569cf5a7b86f13cccf95a7b4d374bc40ffac04c6437b86', + '9223372036854775808': '023c84c0895cc0e827b348ea0a62951ca489a5e436f3ea7545f3c1d5f1bea1c866' +}; From e9a679e2cd38915661e54ee4b3f16266cbbb25ca Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Fri, 29 Mar 2024 15:58:23 +0900 Subject: [PATCH 15/50] pay to pubkey --- package-lock.json | 38 ++++++++- package.json | 4 +- src/CashuWallet.ts | 171 +++++++++++++++++++++++++++------------ test/base64.test.ts | 23 ++++++ test/integration.test.ts | 5 +- test/wallet.test.ts | 24 +++--- 6 files changed, 196 insertions(+), 69 deletions(-) diff --git a/package-lock.json b/package-lock.json index 975ed1c7..5a0252a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,13 @@ "version": "1.0.0-rc.1", "license": "MIT", "dependencies": { + "@gandlaf21/cashu-crypto": "^0.2.5", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", "@scure/bip32": "^1.3.3", "@scure/bip39": "^1.2.2", - "buffer": "^6.0.3" + "buffer": "^6.0.3", + "js-base64": "^3.7.7" }, "devDependencies": { "@types/jest": "^29.5.1", @@ -817,6 +819,18 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@gandlaf21/cashu-crypto": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@gandlaf21/cashu-crypto/-/cashu-crypto-0.2.5.tgz", + "integrity": "sha512-MvXHAKvNDREzTsHzK4M9LOsK3S/BwAtbyZ+myFkNFS68z9IhQVfUKP+lQgLXdiQdf5i64LQRkzLV+OpOXg6dHg==", + "dependencies": { + "@noble/curves": "^1.3.0", + "@noble/hashes": "^1.3.3", + "@scure/bip32": "^1.3.3", + "@scure/bip39": "^1.2.2", + "buffer": "^6.0.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -4692,6 +4706,11 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" + }, "node_modules/js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -6999,6 +7018,18 @@ "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", "dev": true }, + "@gandlaf21/cashu-crypto": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@gandlaf21/cashu-crypto/-/cashu-crypto-0.2.5.tgz", + "integrity": "sha512-MvXHAKvNDREzTsHzK4M9LOsK3S/BwAtbyZ+myFkNFS68z9IhQVfUKP+lQgLXdiQdf5i64LQRkzLV+OpOXg6dHg==", + "requires": { + "@noble/curves": "^1.3.0", + "@noble/hashes": "^1.3.3", + "@scure/bip32": "^1.3.3", + "@scure/bip39": "^1.2.2", + "buffer": "^6.0.3" + } + }, "@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -9847,6 +9878,11 @@ } } }, + "js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" + }, "js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", diff --git a/package.json b/package.json index 5cab1bc7..845c4e25 100644 --- a/package.json +++ b/package.json @@ -46,10 +46,12 @@ "typescript": "^5.0.4" }, "dependencies": { + "@gandlaf21/cashu-crypto": "^0.2.5", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", "@scure/bip32": "^1.3.3", "@scure/bip39": "^1.2.2", - "buffer": "^6.0.3" + "buffer": "^6.0.3", + "js-base64": "^3.7.7" } } diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index d5fd633d..4b3d8354 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -32,6 +32,9 @@ import { import { deriveBlindingFactor, deriveSecret, deriveSeedFromMnemonic } from './secrets.js'; import { validateMnemonic } from '@scure/bip39'; import { wordlist } from '@scure/bip39/wordlists/english'; +import { createP2PKsecret, getSignedProofs } from "@gandlaf21/cashu-crypto/modules/client/NUT11"; +import { serializeProof } from "@gandlaf21/cashu-crypto/modules/client"; +import { pointFromHex } from './DHKE'; /** * Class that represents a Cashu wallet. @@ -82,13 +85,19 @@ class CashuWallet { * @param {(string|Token)} token - Cashu token * @param preference optional preference for splitting proofs into specific amounts * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect + * @param pubkey? optionally locks ecash to pubkey. Will not be deterministic, even if counter is set! + * @param privkey? will create a signature on the @param token secrets if set * @returns New token with newly created proofs, token entries that had errors */ async receive( token: string | Token, - preference?: Array, - counter?: number - ): Promise { + options?: { + preference?: Array, + counter?: number, + pubkey?: string, + privkey?: string + } + ): Promise { let decodedToken: Array; if (typeof token === 'string') { decodedToken = cleanToken(getDecodedToken(token)).token; @@ -104,8 +113,12 @@ class CashuWallet { try { const { proofs, proofsWithError } = await this.receiveTokenEntry( tokenEntry, - preference, - counter + { + preference: options?.preference, + counter: options?.counter, + pubkey: options?.pubkey, + privkey: options?.privkey + } ); if (proofsWithError?.length) { tokenEntriesWithError.push(tokenEntry); @@ -128,17 +141,24 @@ class CashuWallet { * @param tokenEntry a single entry of a cashu token * @param preference optional preference for splitting proofs into specific amounts. * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect + * @param pubkey? optionally locks ecash to pubkey. Will not be deterministic, even if counter is set! + * @param privkey? will create a signature on the @param tokenEntry secrets if set * @returns New token entry with newly created proofs, proofs that had errors */ async receiveTokenEntry( tokenEntry: TokenEntry, - preference?: Array, - counter?: number + options?:{ + preference?: Array, + counter?: number, + pubkey?: string, + privkey?: string + } ): Promise { const proofsWithError: Array = []; const proofs: Array = []; try { const amount = tokenEntry.proofs.reduce((total, curr) => total + curr.amount, 0); + let preference = options?.preference if (!preference) { preference = getDefaultAmountPreference(amount); } @@ -148,7 +168,9 @@ class CashuWallet { tokenEntry.proofs, keys, preference, - counter + options?.counter, + options?.pubkey, + options?.privkey ); const { signatures, error } = await CashuMint.split(tokenEntry.mint, payload); const newProofs = dhke.constructProofs( @@ -176,16 +198,22 @@ class CashuWallet { * @param proofs proofs matching that amount * @param preference optional preference for splitting proofs into specific amounts. overrides amount param * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect + * @param pubkey? optionally locks ecash to pubkey. Will not be deterministic, even if counter is set! + * @param privkey? will create a signature on the @param proofs secrets if set * @returns promise of the change- and send-proofs */ async send( amount: number, proofs: Array, - preference?: Array, - counter?: number + options?:{ + preference?: Array, + counter?: number, + pubkey?: string, + privkey?: string + } ): Promise { - if (preference) { - amount = preference?.reduce((acc, curr) => acc + curr.amount * curr.count, 0); + if (options?.preference) { + amount = options?.preference?.reduce((acc, curr) => acc + curr.amount * curr.count, 0); } const keyset = await this.getKeys(); let amountAvailable = 0; @@ -203,14 +231,16 @@ class CashuWallet { if (amount > amountAvailable) { throw new Error('Not enough funds available'); } - if (amount < amountAvailable || preference) { + if (amount < amountAvailable || options?.preference || options?.pubkey) { const { amountKeep, amountSend } = this.splitReceive(amount, amountAvailable); const { payload, blindedMessages } = this.createSplitPayload( amountSend, proofsToSend, keyset, - preference, - counter + options?.preference, + options?.counter, + options?.pubkey, + options?.privkey ); const { signatures } = await this.mint.split(payload); const proofs = dhke.constructProofs( @@ -248,9 +278,11 @@ class CashuWallet { async restore( start: number, count: number, - keysetId?: string + options?: { + keysetId?: string + } ): Promise<{ proofs: Array }> { - const keys = await this.getKeys(keysetId); + const keys = await this.getKeys(options?.keysetId); if (!this._seed) { throw new Error('CashuWallet must be initialized with mnemonic to use restore'); } @@ -288,7 +320,9 @@ class CashuWallet { `could not initialize keys. No keyset with unit '${unit ? unit : 'sat'}' found` ); } - this._keys = keys; + if (!this._keys) { + this._keys = keys; + } } return this._keys; } @@ -315,16 +349,20 @@ class CashuWallet { async mintTokens( amount: number, quote: string, - keysetId?: string, - AmountPreference?: Array, - counter?: number + options?: { + keysetId?: string, + AmountPreference?: Array, + counter?: number, + pubkey?: string + } ): Promise<{ proofs: Array }> { - const keyset = await this.getKeys(keysetId); + const keyset = await this.getKeys(options?.keysetId); const { blindedMessages, secrets, rs } = this.createRandomBlindedMessages( amount, - keysetId ?? keyset.id, - AmountPreference, - counter + options?.keysetId ?? keyset.id, + options?.AmountPreference, + options?.counter, + options?.pubkey ); const postMintPayload: PostMintPayload = { outputs: blindedMessages, @@ -350,20 +388,24 @@ class CashuWallet { * Returns payment proof and change proofs * @param meltQuote ID of the melt quote * @param proofsToSend proofs to melt + * @param options.keysetId? optionally set keysetId for blank outputs for returned change. + * @param options.counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect * @returns */ async meltTokens( meltQuote: MeltQuoteResponse, proofsToSend: Array, - keysetId?: string, - counter?: number + options?: { + keysetId?: string, + counter?: number, + } ): Promise { - const keys = await this.getKeys(keysetId); + const keys = await this.getKeys(options?.keysetId); const { blindedMessages, secrets, rs } = this.createBlankOutputs( meltQuote.fee_reserve, keys.id, - counter + options?.counter ); const meltPayload: MeltPayload = { quote: meltQuote.quote, @@ -387,21 +429,23 @@ class CashuWallet { * @param invoice * @param proofsToSend the exact amount to send including fees * @param meltQuote melt quote for the invoice - * @param keysetId? optionally set keysetId for blank outputs for returned change. - * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect + * @param options.keysetId? optionally set keysetId for blank outputs for returned change. + * @param options.counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect * @returns */ async payLnInvoice( invoice: string, proofsToSend: Array, - meltQuote?: MeltQuoteResponse, - keysetId?: string, - counter?: number + meltQuote: MeltQuoteResponse, + options?:{ + keysetId?: string, + counter?: number + } ): Promise { if (!meltQuote) { meltQuote = await this.mint.meltQuote({ unit: this.unit, request: invoice }); } - return await this.meltTokens(meltQuote, proofsToSend, keysetId, counter); + return await this.meltTokens(meltQuote, proofsToSend, {keysetId:options?.keysetId, counter: options?.counter}); } /** @@ -409,21 +453,23 @@ class CashuWallet { * @param invoice Lightning invoice * @param token cashu token * @param meltQuote melt quote for the invoice - * @param keysetId? optionally set keysetId for blank outputs for returned change. - * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect + * @param options.keysetId? optionally set keysetId for blank outputs for returned change. + * @param options.counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect */ - payLnInvoiceWithToken( + async payLnInvoiceWithToken( invoice: string, token: string, - meltQuote?: MeltQuoteResponse, - keysetId?: string, - counter?: number + meltQuote: MeltQuoteResponse, + options?: { + keysetId?: string, + counter?: number + } ): Promise { const decodedToken = getDecodedToken(token); const proofs = decodedToken.token .filter((x) => x.mint === this.mint.mintUrl) .flatMap((t) => t.proofs); - return this.payLnInvoice(invoice, proofs, meltQuote, keysetId, counter); + return this.payLnInvoice(invoice, proofs, meltQuote, {keysetId: options?.keysetId, counter: options?.counter}); } /** @@ -432,6 +478,8 @@ class CashuWallet { * @param proofsToSend proofs to split* * @param preference optional preference for splitting proofs into specific amounts. overrides amount param * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect + * @param pubkey? optionally locks ecash to pubkey. Will not be deterministic, even if counter is set! + * @param privkey? will create a signature on the @param proofsToSend secrets if set * @returns */ private createSplitPayload( @@ -439,7 +487,9 @@ class CashuWallet { proofsToSend: Array, keyset: MintKeys, preference?: Array, - counter?: number + counter?: number, + pubkey?: string, + privkey?: string ): { payload: SplitPayload; blindedMessages: BlindedTransaction; @@ -458,8 +508,12 @@ class CashuWallet { amount, keyset.id, preference, - counter + counter, + pubkey ); + if (privkey) { + proofsToSend = getSignedProofs(proofsToSend.map((p)=>{return {amount:p.amount, C: pointFromHex(p.C), id: p.id, secret: new TextEncoder().encode(p.secret)}}), privkey).map(p=> serializeProof(p)) + } // join keepBlindedMessages and sendBlindedMessages const blindedMessages: BlindedTransaction = { @@ -480,7 +534,7 @@ class CashuWallet { } /** * returns proofs that are already spent (use for keeping wallet state clean) - * @param proofs (only the 'secret' field is required) + * @param proofs (only the 'Y' field is required) * @returns */ async checkProofsSpent(proofs: Array): Promise> { @@ -510,17 +564,20 @@ class CashuWallet { * Creates blinded messages for a given amount * @param amount amount to create blinded messages for * @param amountPreference optional preference for splitting proofs into specific amounts. overrides amount param + * @param keyksetId? override the keysetId derived from the current mintKeys with a custom one. This should be a keyset that was fetched from the `/keysets` endpoint * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect + * @param pubkey? optionally locks ecash to pubkey. Will not be deterministic, even if counter is set! * @returns blinded messages, secrets, rs, and amounts */ private createRandomBlindedMessages( amount: number, keysetId: string, amountPreference?: Array, - counter?: number + counter?: number, + pubkey?: string ): BlindedMessageData & { amounts: Array } { const amounts = splitAmount(amount, amountPreference); - return this.createBlindedMessages(amounts, keysetId, counter); + return this.createBlindedMessages(amounts, keysetId, counter, pubkey); } /** @@ -528,12 +585,14 @@ class CashuWallet { * @param amount array of amounts to create blinded messages for * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect * @param keyksetId? override the keysetId derived from the current mintKeys with a custom one. This should be a keyset that was fetched from the `/keysets` endpoint + * @param pubkey? optionally locks ecash to pubkey. Will not be deterministic, even if counter is set! * @returns blinded messages, secrets, rs, and amounts */ private createBlindedMessages( amounts: Array, keysetId: string, - counter?: number + counter?: number, + pubkey?: string ): BlindedMessageData & { amounts: Array } { // if we atempt to create deterministic messages without a _seed, abort. if (counter != undefined && !this._seed) { @@ -547,16 +606,21 @@ class CashuWallet { for (let i = 0; i < amounts.length; i++) { let deterministicR = undefined; let secretBytes = undefined; - if (this._seed && counter != undefined) { + if (pubkey) { + secretBytes = createP2PKsecret(pubkey) + } + else if (this._seed && counter != undefined) { secretBytes = deriveSecret(this._seed, keysetId, counter + i); deterministicR = bytesToNumber(deriveBlindingFactor(this._seed, keysetId, counter + i)); } else { secretBytes = randomBytes(32); } - const secretHex = bytesToHex(secretBytes); - const secret = new TextEncoder().encode(secretHex); - secrets.push(secret); - const { B_, r } = dhke.blindMessage(secret, deterministicR); + if (!pubkey) { + const secretHex = bytesToHex(secretBytes); + secretBytes = new TextEncoder().encode(secretHex); + } + secrets.push(secretBytes); + const { B_, r } = dhke.blindMessage(secretBytes, deterministicR); rs.push(r); const blindedMessage = new BlindedMessage(amounts[i], B_, keysetId); blindedMessages.push(blindedMessage.getSerializedBlindedMessage()); @@ -568,6 +632,7 @@ class CashuWallet { * Creates NUT-08 blank outputs (fee returns) for a given fee reserve * See: https://github.com/cashubtc/nuts/blob/main/08.md * @param feeReserve amount to cover with blank outputs + * @param keysetId mint keysetId * @param counter? optionally set counter to derive secret deterministically. CashuWallet class must be initialized with seed phrase to take effect * @returns blinded messages, secrets, and rs */ diff --git a/test/base64.test.ts b/test/base64.test.ts index 88ac080a..94540d58 100644 --- a/test/base64.test.ts +++ b/test/base64.test.ts @@ -72,4 +72,27 @@ describe('testing uint8 encoding', () => { expect(encodeBase64ToJson(base64url)).toStrictEqual(obj); expect(encodeJsonToBase64(obj)).toStrictEqual(base64url); }); + test('test script secret to from base64', () => { + const base64url = 'eyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6IjAwOWExZjI5MzI1M2U0MWUiLCJhbW91bnQiOjEsInNlY3JldCI6IltcIlAyUEtcIix7XCJub25jZVwiOlwiZDU2YWM4MzljMzdiZWRiNGM1MGIxODcxOTY1MDI2N2E2MWIzMTBlZjdhY2Q5ZWFjMzgwZmIxZmRmNmM1ZjkxNlwiLFwiZGF0YVwiOlwiYjM4Y2FjMmY0N2QzZWNjYjY0NmUxYmFiZDBiNDFlMzZhMTc5MmRlZjlhODU5ODRlNWZiZmVkZTU1ZjQ4Yjc4OVwifV0iLCJDIjoiMDM4YTcyZWRmNWRmN2M3ZmNiMTRhMDhjYjhiZDljODVlOTVkZmM0MzY4ZTU5YTk3OTRkZmI5OTAxZWEyZDIxNzI5In1dLCJtaW50IjoiaHR0cHM6Ly90ZXN0bnV0LmNhc2h1LnNwYWNlIn1dfQ'; + // const base64 = 'eyJ0ZXN0RGF0YSI6IvCfj7PvuI/wn4+z77iPIn0=' + const obj = { + "token": [ + { + "proofs": [ + { + "id": "009a1f293253e41e", + "amount": 1, + "secret": "[\"P2PK\",{\"nonce\":\"d56ac839c37bedb4c50b18719650267a61b310ef7acd9eac380fb1fdf6c5f916\",\"data\":\"b38cac2f47d3eccb646e1babd0b41e36a1792def9a85984e5fbfede55f48b789\"}]", + "C": "038a72edf5df7c7fcb14a08cb8bd9c85e95dfc4368e59a9794dfb9901ea2d21729" + } + ], + "mint": "https://testnut.cashu.space" + } + ] + }; + + expect(encodeBase64ToJson(base64url)).toStrictEqual(obj); + expect(encodeJsonToBase64(obj)).toStrictEqual(base64url); + }); + }); diff --git a/test/integration.test.ts b/test/integration.test.ts index 0c75747b..1fbee165 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -98,11 +98,12 @@ describe('mint api', () => { const request = await wallet.getMintQuote(3000); const tokens = await wallet.mintTokens(3000, request.quote); - const fee = (await wallet.getMeltQuote(externalInvoice)).fee_reserve; + const meltQuote = (await wallet.getMeltQuote(externalInvoice)); + const fee = meltQuote.fee_reserve expect(fee).toBeGreaterThan(0); const sendResponse = await wallet.send(2000 + fee, tokens.proofs); - const response = await wallet.payLnInvoice(externalInvoice, sendResponse.send); + const response = await wallet.payLnInvoice(externalInvoice, sendResponse.send, meltQuote); expect(response).toBeDefined(); // expect that we have not received the fee back, since it was external diff --git a/test/wallet.test.ts b/test/wallet.test.ts index e68ac5be..f2e1ec92 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -1,8 +1,9 @@ import nock from 'nock'; import { CashuMint } from '../src/CashuMint.js'; import { CashuWallet } from '../src/CashuWallet.js'; -import { ReceiveResponse } from '../src/model/types/index.js'; +import { MeltQuoteResponse, ReceiveResponse } from '../src/model/types/index.js'; import { cleanToken, getDecodedToken } from '../src/utils.js'; +import { AmountPreference } from '../src/model/types/index'; const dummyKeysResp = { keysets: [ @@ -129,7 +130,7 @@ describe('receive', () => { const wallet = new CashuWallet(mint); const token3sat = 'cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIjAwOWExZjI5MzI1M2U0MWUiLCAiYW1vdW50IjogMSwgInNlY3JldCI6ICJlN2MxYjc2ZDFiMzFlMmJjYTJiMjI5ZDE2MGJkZjYwNDZmMzNiYzQ1NzAyMjIzMDRiNjUxMTBkOTI2ZjdhZjg5IiwgIkMiOiAiMDM4OWNkOWY0Zjk4OGUzODBhNzk4OWQ0ZDQ4OGE3YzkxYzUyNzdmYjkzMDQ3ZTdhMmNjMWVkOGUzMzk2Yjg1NGZmIn0sIHsiaWQiOiAiMDA5YTFmMjkzMjUzZTQxZSIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogImRlNTVjMTVmYWVmZGVkN2Y5Yzk5OWMzZDRjNjJmODFiMGM2ZmUyMWE3NTJmZGVmZjZiMDg0Y2YyZGYyZjVjZjMiLCAiQyI6ICIwMmRlNDBjNTlkOTAzODNiODg1M2NjZjNhNGIyMDg2NGFjODNiYTc1OGZjZTNkOTU5ZGJiODkzNjEwMDJlOGNlNDcifV0sICJtaW50IjogImh0dHA6Ly9sb2NhbGhvc3Q6MzMzOCJ9XX0='; - const response: ReceiveResponse = await wallet.receive(token3sat, [{ amount: 1, count: 3 }]); + const response: ReceiveResponse = await wallet.receive(token3sat, {preference:[{ amount: 1, count: 3 }]}); expect(response.token.token).toHaveLength(1); expect(response.token.token[0].proofs).toHaveLength(3); @@ -217,8 +218,9 @@ describe('payLnInvoice', () => { .reply(200, { quote: 'quote_id', amount: 123, fee_reserve: 0 }); nock(mintUrl).post('/v1/melt/bolt11').reply(200, { paid: true, payment_preimage: '' }); const wallet = new CashuWallet(mint); + const meltQuote = await wallet.getMeltQuote("lnbcabbc") - const result = await wallet.payLnInvoice(invoice, proofs); + const result = await wallet.payLnInvoice(invoice, proofs,meltQuote); expect(result).toEqual({ isPaid: true, preimage: '', change: [] }); }); @@ -255,18 +257,17 @@ describe('payLnInvoice', () => { ] }); const wallet = new CashuWallet(mint); - - const result = await wallet.payLnInvoice(invoice, [{ ...proofs[0], amount: 3 }]); + const meltQuote = await wallet.getMeltQuote("lnbcabbc") + const result = await wallet.payLnInvoice(invoice, [{ ...proofs[0], amount: 3 }],meltQuote); expect(result.isPaid).toBe(true); expect(result.preimage).toBe('asd'); expect(result.change).toHaveLength(1); }); test('test payLnInvoice bad resonse', async () => { - nock(mintUrl).post('/v1/melt/quote/bolt11').reply(200, {}); + nock(mintUrl).post('/v1/melt/bolt11').reply(200, {}); const wallet = new CashuWallet(mint); - - const result = await wallet.payLnInvoice(invoice, proofs).catch((e) => e); + const result = await wallet.payLnInvoice(invoice, proofs, {} as MeltQuoteResponse).catch((e) => e); expect(result).toEqual(new Error('bad response')); }); @@ -454,7 +455,7 @@ describe('send', () => { C: '034268c0bd30b945adf578aca2dc0d1e26ef089869aaf9a08ba3a6da40fda1d8be' } ]; - const result = await wallet.send(4, overpayProofs, [{ amount: 1, count: 4 }]); + const result = await wallet.send(4, overpayProofs, {preference:[{ amount: 1, count: 4 }]}); expect(result.send).toHaveLength(4); expect(result.send[0]).toMatchObject({ amount: 1, id: '009a1f293253e41e' }); @@ -509,7 +510,7 @@ describe('send', () => { C: '034268c0bd30b945adf578aca2dc0d1e26ef089869aaf9a08ba3a6da40fda1d8be' } ]; - const result = await wallet.send(4, overpayProofs, [{ amount: 1, count: 3 }]); + const result = await wallet.send(4, overpayProofs, {preference:[{ amount: 1, count: 3 }]}); expect(result.send).toHaveLength(3); expect(result.send[0]).toMatchObject({ amount: 1, id: '009a1f293253e41e' }); @@ -572,8 +573,7 @@ describe('deterministic', () => { C: '034268c0bd30b945adf578aca2dc0d1e26ef089869aaf9a08ba3a6da40fda1d8be' } ], - undefined, - 1 + {counter: 1} ) .catch((e) => e); expect(result).toEqual( From 428b776ea8bbf619b81fdcef4c23f06806ebc57d Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Sat, 30 Mar 2024 09:20:53 +0900 Subject: [PATCH 16/50] update deps --- package-lock.json | 27 ++++++++------------------- package.json | 5 ++--- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5a0252a1..7acb928d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,12 @@ "version": "1.0.0-rc.1", "license": "MIT", "dependencies": { - "@gandlaf21/cashu-crypto": "^0.2.5", + "@gandlaf21/cashu-crypto": "^0.2.6", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", "@scure/bip32": "^1.3.3", "@scure/bip39": "^1.2.2", - "buffer": "^6.0.3", - "js-base64": "^3.7.7" + "buffer": "^6.0.3" }, "devDependencies": { "@types/jest": "^29.5.1", @@ -820,9 +819,9 @@ } }, "node_modules/@gandlaf21/cashu-crypto": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@gandlaf21/cashu-crypto/-/cashu-crypto-0.2.5.tgz", - "integrity": "sha512-MvXHAKvNDREzTsHzK4M9LOsK3S/BwAtbyZ+myFkNFS68z9IhQVfUKP+lQgLXdiQdf5i64LQRkzLV+OpOXg6dHg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@gandlaf21/cashu-crypto/-/cashu-crypto-0.2.6.tgz", + "integrity": "sha512-BwiaSAhk98XSgy+BXAeGNRLfjOh1CsGNQGi957wF7u+dfPH5EkOqnd7tnynmWi8yx0xdk0eF9EFwdKryjzEQrA==", "dependencies": { "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", @@ -4706,11 +4705,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/js-base64": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", - "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" - }, "node_modules/js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", @@ -7019,9 +7013,9 @@ "dev": true }, "@gandlaf21/cashu-crypto": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@gandlaf21/cashu-crypto/-/cashu-crypto-0.2.5.tgz", - "integrity": "sha512-MvXHAKvNDREzTsHzK4M9LOsK3S/BwAtbyZ+myFkNFS68z9IhQVfUKP+lQgLXdiQdf5i64LQRkzLV+OpOXg6dHg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@gandlaf21/cashu-crypto/-/cashu-crypto-0.2.6.tgz", + "integrity": "sha512-BwiaSAhk98XSgy+BXAeGNRLfjOh1CsGNQGi957wF7u+dfPH5EkOqnd7tnynmWi8yx0xdk0eF9EFwdKryjzEQrA==", "requires": { "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", @@ -9878,11 +9872,6 @@ } } }, - "js-base64": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", - "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" - }, "js-sdsl": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", diff --git a/package.json b/package.json index 845c4e25..c02c5baf 100644 --- a/package.json +++ b/package.json @@ -46,12 +46,11 @@ "typescript": "^5.0.4" }, "dependencies": { - "@gandlaf21/cashu-crypto": "^0.2.5", + "@gandlaf21/cashu-crypto": "^0.2.6", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", "@scure/bip32": "^1.3.3", "@scure/bip39": "^1.2.2", - "buffer": "^6.0.3", - "js-base64": "^3.7.7" + "buffer": "^6.0.3" } } From 31248c93c33ed3dc7c209b56280b35f729592112 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Sat, 30 Mar 2024 09:22:02 +0900 Subject: [PATCH 17/50] format --- src/CashuWallet.ts | 102 ++++++++++++++++++++++----------------- test/base64.test.ts | 31 ++++++------ test/integration.test.ts | 4 +- test/wallet.test.ts | 22 +++++---- 4 files changed, 88 insertions(+), 71 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 4b3d8354..75cb1770 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -32,8 +32,8 @@ import { import { deriveBlindingFactor, deriveSecret, deriveSeedFromMnemonic } from './secrets.js'; import { validateMnemonic } from '@scure/bip39'; import { wordlist } from '@scure/bip39/wordlists/english'; -import { createP2PKsecret, getSignedProofs } from "@gandlaf21/cashu-crypto/modules/client/NUT11"; -import { serializeProof } from "@gandlaf21/cashu-crypto/modules/client"; +import { createP2PKsecret, getSignedProofs } from '@gandlaf21/cashu-crypto/modules/client/NUT11'; +import { serializeProof } from '@gandlaf21/cashu-crypto/modules/client'; import { pointFromHex } from './DHKE'; /** @@ -92,12 +92,12 @@ class CashuWallet { async receive( token: string | Token, options?: { - preference?: Array, - counter?: number, - pubkey?: string, - privkey?: string + preference?: Array; + counter?: number; + pubkey?: string; + privkey?: string; } - ): Promise { + ): Promise { let decodedToken: Array; if (typeof token === 'string') { decodedToken = cleanToken(getDecodedToken(token)).token; @@ -111,15 +111,12 @@ class CashuWallet { continue; } try { - const { proofs, proofsWithError } = await this.receiveTokenEntry( - tokenEntry, - { - preference: options?.preference, - counter: options?.counter, - pubkey: options?.pubkey, - privkey: options?.privkey - } - ); + const { proofs, proofsWithError } = await this.receiveTokenEntry(tokenEntry, { + preference: options?.preference, + counter: options?.counter, + pubkey: options?.pubkey, + privkey: options?.privkey + }); if (proofsWithError?.length) { tokenEntriesWithError.push(tokenEntry); continue; @@ -147,18 +144,18 @@ class CashuWallet { */ async receiveTokenEntry( tokenEntry: TokenEntry, - options?:{ - preference?: Array, - counter?: number, - pubkey?: string, - privkey?: string + options?: { + preference?: Array; + counter?: number; + pubkey?: string; + privkey?: string; } ): Promise { const proofsWithError: Array = []; const proofs: Array = []; try { const amount = tokenEntry.proofs.reduce((total, curr) => total + curr.amount, 0); - let preference = options?.preference + let preference = options?.preference; if (!preference) { preference = getDefaultAmountPreference(amount); } @@ -205,11 +202,11 @@ class CashuWallet { async send( amount: number, proofs: Array, - options?:{ - preference?: Array, - counter?: number, - pubkey?: string, - privkey?: string + options?: { + preference?: Array; + counter?: number; + pubkey?: string; + privkey?: string; } ): Promise { if (options?.preference) { @@ -279,7 +276,7 @@ class CashuWallet { start: number, count: number, options?: { - keysetId?: string + keysetId?: string; } ): Promise<{ proofs: Array }> { const keys = await this.getKeys(options?.keysetId); @@ -350,10 +347,10 @@ class CashuWallet { amount: number, quote: string, options?: { - keysetId?: string, - AmountPreference?: Array, - counter?: number, - pubkey?: string + keysetId?: string; + AmountPreference?: Array; + counter?: number; + pubkey?: string; } ): Promise<{ proofs: Array }> { const keyset = await this.getKeys(options?.keysetId); @@ -396,8 +393,8 @@ class CashuWallet { meltQuote: MeltQuoteResponse, proofsToSend: Array, options?: { - keysetId?: string, - counter?: number, + keysetId?: string; + counter?: number; } ): Promise { const keys = await this.getKeys(options?.keysetId); @@ -437,15 +434,18 @@ class CashuWallet { invoice: string, proofsToSend: Array, meltQuote: MeltQuoteResponse, - options?:{ - keysetId?: string, - counter?: number + options?: { + keysetId?: string; + counter?: number; } ): Promise { if (!meltQuote) { meltQuote = await this.mint.meltQuote({ unit: this.unit, request: invoice }); } - return await this.meltTokens(meltQuote, proofsToSend, {keysetId:options?.keysetId, counter: options?.counter}); + return await this.meltTokens(meltQuote, proofsToSend, { + keysetId: options?.keysetId, + counter: options?.counter + }); } /** @@ -461,15 +461,18 @@ class CashuWallet { token: string, meltQuote: MeltQuoteResponse, options?: { - keysetId?: string, - counter?: number + keysetId?: string; + counter?: number; } ): Promise { const decodedToken = getDecodedToken(token); const proofs = decodedToken.token .filter((x) => x.mint === this.mint.mintUrl) .flatMap((t) => t.proofs); - return this.payLnInvoice(invoice, proofs, meltQuote, {keysetId: options?.keysetId, counter: options?.counter}); + return this.payLnInvoice(invoice, proofs, meltQuote, { + keysetId: options?.keysetId, + counter: options?.counter + }); } /** @@ -512,7 +515,17 @@ class CashuWallet { pubkey ); if (privkey) { - proofsToSend = getSignedProofs(proofsToSend.map((p)=>{return {amount:p.amount, C: pointFromHex(p.C), id: p.id, secret: new TextEncoder().encode(p.secret)}}), privkey).map(p=> serializeProof(p)) + proofsToSend = getSignedProofs( + proofsToSend.map((p) => { + return { + amount: p.amount, + C: pointFromHex(p.C), + id: p.id, + secret: new TextEncoder().encode(p.secret) + }; + }), + privkey + ).map((p) => serializeProof(p)); } // join keepBlindedMessages and sendBlindedMessages @@ -607,9 +620,8 @@ class CashuWallet { let deterministicR = undefined; let secretBytes = undefined; if (pubkey) { - secretBytes = createP2PKsecret(pubkey) - } - else if (this._seed && counter != undefined) { + secretBytes = createP2PKsecret(pubkey); + } else if (this._seed && counter != undefined) { secretBytes = deriveSecret(this._seed, keysetId, counter + i); deterministicR = bytesToNumber(deriveBlindingFactor(this._seed, keysetId, counter + i)); } else { diff --git a/test/base64.test.ts b/test/base64.test.ts index 94540d58..45a9b50b 100644 --- a/test/base64.test.ts +++ b/test/base64.test.ts @@ -73,26 +73,27 @@ describe('testing uint8 encoding', () => { expect(encodeJsonToBase64(obj)).toStrictEqual(base64url); }); test('test script secret to from base64', () => { - const base64url = 'eyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6IjAwOWExZjI5MzI1M2U0MWUiLCJhbW91bnQiOjEsInNlY3JldCI6IltcIlAyUEtcIix7XCJub25jZVwiOlwiZDU2YWM4MzljMzdiZWRiNGM1MGIxODcxOTY1MDI2N2E2MWIzMTBlZjdhY2Q5ZWFjMzgwZmIxZmRmNmM1ZjkxNlwiLFwiZGF0YVwiOlwiYjM4Y2FjMmY0N2QzZWNjYjY0NmUxYmFiZDBiNDFlMzZhMTc5MmRlZjlhODU5ODRlNWZiZmVkZTU1ZjQ4Yjc4OVwifV0iLCJDIjoiMDM4YTcyZWRmNWRmN2M3ZmNiMTRhMDhjYjhiZDljODVlOTVkZmM0MzY4ZTU5YTk3OTRkZmI5OTAxZWEyZDIxNzI5In1dLCJtaW50IjoiaHR0cHM6Ly90ZXN0bnV0LmNhc2h1LnNwYWNlIn1dfQ'; + const base64url = + 'eyJ0b2tlbiI6W3sicHJvb2ZzIjpbeyJpZCI6IjAwOWExZjI5MzI1M2U0MWUiLCJhbW91bnQiOjEsInNlY3JldCI6IltcIlAyUEtcIix7XCJub25jZVwiOlwiZDU2YWM4MzljMzdiZWRiNGM1MGIxODcxOTY1MDI2N2E2MWIzMTBlZjdhY2Q5ZWFjMzgwZmIxZmRmNmM1ZjkxNlwiLFwiZGF0YVwiOlwiYjM4Y2FjMmY0N2QzZWNjYjY0NmUxYmFiZDBiNDFlMzZhMTc5MmRlZjlhODU5ODRlNWZiZmVkZTU1ZjQ4Yjc4OVwifV0iLCJDIjoiMDM4YTcyZWRmNWRmN2M3ZmNiMTRhMDhjYjhiZDljODVlOTVkZmM0MzY4ZTU5YTk3OTRkZmI5OTAxZWEyZDIxNzI5In1dLCJtaW50IjoiaHR0cHM6Ly90ZXN0bnV0LmNhc2h1LnNwYWNlIn1dfQ'; // const base64 = 'eyJ0ZXN0RGF0YSI6IvCfj7PvuI/wn4+z77iPIn0=' const obj = { - "token": [ - { - "proofs": [ - { - "id": "009a1f293253e41e", - "amount": 1, - "secret": "[\"P2PK\",{\"nonce\":\"d56ac839c37bedb4c50b18719650267a61b310ef7acd9eac380fb1fdf6c5f916\",\"data\":\"b38cac2f47d3eccb646e1babd0b41e36a1792def9a85984e5fbfede55f48b789\"}]", - "C": "038a72edf5df7c7fcb14a08cb8bd9c85e95dfc4368e59a9794dfb9901ea2d21729" - } - ], - "mint": "https://testnut.cashu.space" - } + token: [ + { + proofs: [ + { + id: '009a1f293253e41e', + amount: 1, + secret: + '["P2PK",{"nonce":"d56ac839c37bedb4c50b18719650267a61b310ef7acd9eac380fb1fdf6c5f916","data":"b38cac2f47d3eccb646e1babd0b41e36a1792def9a85984e5fbfede55f48b789"}]', + C: '038a72edf5df7c7fcb14a08cb8bd9c85e95dfc4368e59a9794dfb9901ea2d21729' + } + ], + mint: 'https://testnut.cashu.space' + } ] - }; + }; expect(encodeBase64ToJson(base64url)).toStrictEqual(obj); expect(encodeJsonToBase64(obj)).toStrictEqual(base64url); }); - }); diff --git a/test/integration.test.ts b/test/integration.test.ts index 1fbee165..cffd71d7 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -98,8 +98,8 @@ describe('mint api', () => { const request = await wallet.getMintQuote(3000); const tokens = await wallet.mintTokens(3000, request.quote); - const meltQuote = (await wallet.getMeltQuote(externalInvoice)); - const fee = meltQuote.fee_reserve + const meltQuote = await wallet.getMeltQuote(externalInvoice); + const fee = meltQuote.fee_reserve; expect(fee).toBeGreaterThan(0); const sendResponse = await wallet.send(2000 + fee, tokens.proofs); diff --git a/test/wallet.test.ts b/test/wallet.test.ts index f2e1ec92..881c5c21 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -130,7 +130,9 @@ describe('receive', () => { const wallet = new CashuWallet(mint); const token3sat = 'cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIjAwOWExZjI5MzI1M2U0MWUiLCAiYW1vdW50IjogMSwgInNlY3JldCI6ICJlN2MxYjc2ZDFiMzFlMmJjYTJiMjI5ZDE2MGJkZjYwNDZmMzNiYzQ1NzAyMjIzMDRiNjUxMTBkOTI2ZjdhZjg5IiwgIkMiOiAiMDM4OWNkOWY0Zjk4OGUzODBhNzk4OWQ0ZDQ4OGE3YzkxYzUyNzdmYjkzMDQ3ZTdhMmNjMWVkOGUzMzk2Yjg1NGZmIn0sIHsiaWQiOiAiMDA5YTFmMjkzMjUzZTQxZSIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogImRlNTVjMTVmYWVmZGVkN2Y5Yzk5OWMzZDRjNjJmODFiMGM2ZmUyMWE3NTJmZGVmZjZiMDg0Y2YyZGYyZjVjZjMiLCAiQyI6ICIwMmRlNDBjNTlkOTAzODNiODg1M2NjZjNhNGIyMDg2NGFjODNiYTc1OGZjZTNkOTU5ZGJiODkzNjEwMDJlOGNlNDcifV0sICJtaW50IjogImh0dHA6Ly9sb2NhbGhvc3Q6MzMzOCJ9XX0='; - const response: ReceiveResponse = await wallet.receive(token3sat, {preference:[{ amount: 1, count: 3 }]}); + const response: ReceiveResponse = await wallet.receive(token3sat, { + preference: [{ amount: 1, count: 3 }] + }); expect(response.token.token).toHaveLength(1); expect(response.token.token[0].proofs).toHaveLength(3); @@ -218,9 +220,9 @@ describe('payLnInvoice', () => { .reply(200, { quote: 'quote_id', amount: 123, fee_reserve: 0 }); nock(mintUrl).post('/v1/melt/bolt11').reply(200, { paid: true, payment_preimage: '' }); const wallet = new CashuWallet(mint); - const meltQuote = await wallet.getMeltQuote("lnbcabbc") + const meltQuote = await wallet.getMeltQuote('lnbcabbc'); - const result = await wallet.payLnInvoice(invoice, proofs,meltQuote); + const result = await wallet.payLnInvoice(invoice, proofs, meltQuote); expect(result).toEqual({ isPaid: true, preimage: '', change: [] }); }); @@ -257,8 +259,8 @@ describe('payLnInvoice', () => { ] }); const wallet = new CashuWallet(mint); - const meltQuote = await wallet.getMeltQuote("lnbcabbc") - const result = await wallet.payLnInvoice(invoice, [{ ...proofs[0], amount: 3 }],meltQuote); + const meltQuote = await wallet.getMeltQuote('lnbcabbc'); + const result = await wallet.payLnInvoice(invoice, [{ ...proofs[0], amount: 3 }], meltQuote); expect(result.isPaid).toBe(true); expect(result.preimage).toBe('asd'); @@ -267,7 +269,9 @@ describe('payLnInvoice', () => { test('test payLnInvoice bad resonse', async () => { nock(mintUrl).post('/v1/melt/bolt11').reply(200, {}); const wallet = new CashuWallet(mint); - const result = await wallet.payLnInvoice(invoice, proofs, {} as MeltQuoteResponse).catch((e) => e); + const result = await wallet + .payLnInvoice(invoice, proofs, {} as MeltQuoteResponse) + .catch((e) => e); expect(result).toEqual(new Error('bad response')); }); @@ -455,7 +459,7 @@ describe('send', () => { C: '034268c0bd30b945adf578aca2dc0d1e26ef089869aaf9a08ba3a6da40fda1d8be' } ]; - const result = await wallet.send(4, overpayProofs, {preference:[{ amount: 1, count: 4 }]}); + const result = await wallet.send(4, overpayProofs, { preference: [{ amount: 1, count: 4 }] }); expect(result.send).toHaveLength(4); expect(result.send[0]).toMatchObject({ amount: 1, id: '009a1f293253e41e' }); @@ -510,7 +514,7 @@ describe('send', () => { C: '034268c0bd30b945adf578aca2dc0d1e26ef089869aaf9a08ba3a6da40fda1d8be' } ]; - const result = await wallet.send(4, overpayProofs, {preference:[{ amount: 1, count: 3 }]}); + const result = await wallet.send(4, overpayProofs, { preference: [{ amount: 1, count: 3 }] }); expect(result.send).toHaveLength(3); expect(result.send[0]).toMatchObject({ amount: 1, id: '009a1f293253e41e' }); @@ -573,7 +577,7 @@ describe('deterministic', () => { C: '034268c0bd30b945adf578aca2dc0d1e26ef089869aaf9a08ba3a6da40fda1d8be' } ], - {counter: 1} + { counter: 1 } ) .catch((e) => e); expect(result).toEqual( From 871d9777a8b1cc69bd9062b4702a27ed18ac65be Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Sat, 30 Mar 2024 13:20:34 +0900 Subject: [PATCH 18/50] edit migrations guide --- migration-1.0.0.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/migration-1.0.0.md b/migration-1.0.0.md index af164f60..fcc2d70f 100644 --- a/migration-1.0.0.md +++ b/migration-1.0.0.md @@ -25,6 +25,10 @@ Decoding LN invoices is no longer used inside the lib. ### `CashuWallet` interface changes +**optional parameters are now in an onpional `options?` Object** + +Utility functions now have an `options` object for optional parameters, instead of passing them directly + **`requestMint(amount: number)` --> `getMintQuote(amount: number)`** Now returns the following: From 18a1e1768767d5fe4e1a2fc57944b9e488de9f3a Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Sun, 31 Mar 2024 17:34:41 +0900 Subject: [PATCH 19/50] add p2pk integration test --- test/integration.test.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/integration.test.ts b/test/integration.test.ts index cffd71d7..ae24b041 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -3,6 +3,8 @@ import { CashuWallet } from '../src/CashuWallet.js'; import dns from 'node:dns'; import { deriveKeysetId, getEncodedToken } from '../src/utils.js'; +import { secp256k1 } from '@noble/curves/secp256k1'; +import { bytesToHex } from '@noble/curves/abstract/utils'; dns.setDefaultResultOrder('ipv4first'); const externalInvoice = @@ -173,4 +175,31 @@ describe('mint api', () => { expect(response.token).toBeDefined(); expect(response.tokensWithErrors).toBeUndefined(); }); + test('send and receive p2pk', async () => { + const mint = new CashuMint(mintUrl); + const wallet = new CashuWallet(mint); + + const privKeyAlice = secp256k1.utils.randomPrivateKey() + const pubKeyAlice = secp256k1.getPublicKey(privKeyAlice) + + const privKeyBob = secp256k1.utils.randomPrivateKey() + const pubKeyBob = secp256k1.getPublicKey(privKeyBob) + + const request = await wallet.getMintQuote(64); + const tokens = await wallet.mintTokens(64, request.quote); + + const {send} = await wallet.send(64, tokens.proofs, {pubkey: bytesToHex(pubKeyBob)}) + const encoded = getEncodedToken({ + token: [{ mint: mintUrl, proofs: send }] + }); + + const res = await wallet.receive(encoded,{privkey:bytesToHex(privKeyAlice)}).catch() + expect(res.token.token).toEqual([]) + expect(res.tokensWithErrors?.token.length).toBe(1) + + const { token } = await wallet.receive(encoded,{privkey:bytesToHex(privKeyBob)}) + + expect(token.token.map(t=>t.proofs).flat().reduce((curr,acc)=>{return curr+acc.amount},0)).toBe(64) + + }); }); From 4b0056d08bb9ab1457a8ad13e60daa2db8b07687 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 3 Apr 2024 21:08:09 +0900 Subject: [PATCH 20/50] format --- migration-1.0.0.md | 2 +- test/integration.test.ts | 36 +++++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/migration-1.0.0.md b/migration-1.0.0.md index fcc2d70f..f93966e8 100644 --- a/migration-1.0.0.md +++ b/migration-1.0.0.md @@ -27,7 +27,7 @@ Decoding LN invoices is no longer used inside the lib. **optional parameters are now in an onpional `options?` Object** -Utility functions now have an `options` object for optional parameters, instead of passing them directly +Utility functions now have an `options` object for optional parameters, instead of passing them directly **`requestMint(amount: number)` --> `getMintQuote(amount: number)`** Now returns the following: diff --git a/test/integration.test.ts b/test/integration.test.ts index ae24b041..2a1b4688 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -178,28 +178,34 @@ describe('mint api', () => { test('send and receive p2pk', async () => { const mint = new CashuMint(mintUrl); const wallet = new CashuWallet(mint); - - const privKeyAlice = secp256k1.utils.randomPrivateKey() - const pubKeyAlice = secp256k1.getPublicKey(privKeyAlice) - - const privKeyBob = secp256k1.utils.randomPrivateKey() - const pubKeyBob = secp256k1.getPublicKey(privKeyBob) - + + const privKeyAlice = secp256k1.utils.randomPrivateKey(); + const pubKeyAlice = secp256k1.getPublicKey(privKeyAlice); + + const privKeyBob = secp256k1.utils.randomPrivateKey(); + const pubKeyBob = secp256k1.getPublicKey(privKeyBob); + const request = await wallet.getMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); - - const {send} = await wallet.send(64, tokens.proofs, {pubkey: bytesToHex(pubKeyBob)}) + + const { send } = await wallet.send(64, tokens.proofs, { pubkey: bytesToHex(pubKeyBob) }); const encoded = getEncodedToken({ token: [{ mint: mintUrl, proofs: send }] }); - const res = await wallet.receive(encoded,{privkey:bytesToHex(privKeyAlice)}).catch() - expect(res.token.token).toEqual([]) - expect(res.tokensWithErrors?.token.length).toBe(1) + const res = await wallet.receive(encoded, { privkey: bytesToHex(privKeyAlice) }).catch(); + expect(res.token.token).toEqual([]); + expect(res.tokensWithErrors?.token.length).toBe(1); - const { token } = await wallet.receive(encoded,{privkey:bytesToHex(privKeyBob)}) + const { token } = await wallet.receive(encoded, { privkey: bytesToHex(privKeyBob) }); - expect(token.token.map(t=>t.proofs).flat().reduce((curr,acc)=>{return curr+acc.amount},0)).toBe(64) - + expect( + token.token + .map((t) => t.proofs) + .flat() + .reduce((curr, acc) => { + return curr + acc.amount; + }, 0) + ).toBe(64); }); }); From e7aafe1dd78d300cc1b217de067c8813d7c4480d Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 3 Apr 2024 21:21:47 +0900 Subject: [PATCH 21/50] 1.0.0-rc.2 --- 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 7acb928d..6dce2f4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "license": "MIT", "dependencies": { "@gandlaf21/cashu-crypto": "^0.2.6", diff --git a/package.json b/package.json index c02c5baf..ea6c6946 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From fb2d112cd10a51b87b89d1c9c6b674a18a32d2e0 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 3 Apr 2024 22:06:15 +0900 Subject: [PATCH 22/50] move use lib from @cashu namespace --- package.json | 2 +- src/CashuWallet.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c02c5baf..9632472b 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "typescript": "^5.0.4" }, "dependencies": { - "@gandlaf21/cashu-crypto": "^0.2.6", + "@cashu/crypto": "^0.2.6", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", "@scure/bip32": "^1.3.3", diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 75cb1770..4e4a8c56 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -32,8 +32,8 @@ import { import { deriveBlindingFactor, deriveSecret, deriveSeedFromMnemonic } from './secrets.js'; import { validateMnemonic } from '@scure/bip39'; import { wordlist } from '@scure/bip39/wordlists/english'; -import { createP2PKsecret, getSignedProofs } from '@gandlaf21/cashu-crypto/modules/client/NUT11'; -import { serializeProof } from '@gandlaf21/cashu-crypto/modules/client'; +import { createP2PKsecret, getSignedProofs } from '@cashu/crypto/modules/client/NUT11'; +import { serializeProof } from '@cashu/crypto/modules/client'; import { pointFromHex } from './DHKE'; /** From 220bd72e3138910b0f9e506df652070e25cbc809 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 3 Apr 2024 22:09:05 +0900 Subject: [PATCH 23/50] update lockfile --- package-lock.json | 50 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7acb928d..e09b4d25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0-rc.1", "license": "MIT", "dependencies": { - "@gandlaf21/cashu-crypto": "^0.2.6", + "@cashu/crypto": "^0.2.6", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.3", "@scure/bip32": "^1.3.3", @@ -695,6 +695,18 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "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==", + "dependencies": { + "@noble/curves": "^1.3.0", + "@noble/hashes": "^1.3.3", + "@scure/bip32": "^1.3.3", + "@scure/bip39": "^1.2.2", + "buffer": "^6.0.3" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -818,18 +830,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@gandlaf21/cashu-crypto": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@gandlaf21/cashu-crypto/-/cashu-crypto-0.2.6.tgz", - "integrity": "sha512-BwiaSAhk98XSgy+BXAeGNRLfjOh1CsGNQGi957wF7u+dfPH5EkOqnd7tnynmWi8yx0xdk0eF9EFwdKryjzEQrA==", - "dependencies": { - "@noble/curves": "^1.3.0", - "@noble/hashes": "^1.3.3", - "@scure/bip32": "^1.3.3", - "@scure/bip39": "^1.2.2", - "buffer": "^6.0.3" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -6921,6 +6921,18 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "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==", + "requires": { + "@noble/curves": "^1.3.0", + "@noble/hashes": "^1.3.3", + "@scure/bip32": "^1.3.3", + "@scure/bip39": "^1.2.2", + "buffer": "^6.0.3" + } + }, "@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -7012,18 +7024,6 @@ "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", "dev": true }, - "@gandlaf21/cashu-crypto": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@gandlaf21/cashu-crypto/-/cashu-crypto-0.2.6.tgz", - "integrity": "sha512-BwiaSAhk98XSgy+BXAeGNRLfjOh1CsGNQGi957wF7u+dfPH5EkOqnd7tnynmWi8yx0xdk0eF9EFwdKryjzEQrA==", - "requires": { - "@noble/curves": "^1.3.0", - "@noble/hashes": "^1.3.3", - "@scure/bip32": "^1.3.3", - "@scure/bip39": "^1.2.2", - "buffer": "^6.0.3" - } - }, "@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", From b810839158db3c0d0b3efdba3e984ef08c175a0a Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 3 Apr 2024 22:45:34 +0900 Subject: [PATCH 24/50] fix param typo --- src/CashuWallet.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 4e4a8c56..2de5a367 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -348,7 +348,7 @@ class CashuWallet { quote: string, options?: { keysetId?: string; - AmountPreference?: Array; + amountPreference?: Array; counter?: number; pubkey?: string; } @@ -357,7 +357,7 @@ class CashuWallet { const { blindedMessages, secrets, rs } = this.createRandomBlindedMessages( amount, options?.keysetId ?? keyset.id, - options?.AmountPreference, + options?.amountPreference, options?.counter, options?.pubkey ); From 5eed1a1e331d5af7fcbba4cee3ac764252275c4c Mon Sep 17 00:00:00 2001 From: gandlafbtc <123852829+gandlafbtc@users.noreply.github.com> Date: Thu, 4 Apr 2024 19:07:28 +0900 Subject: [PATCH 25/50] Update migration-1.0.0.md add missing function rename --- migration-1.0.0.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/migration-1.0.0.md b/migration-1.0.0.md index f93966e8..8c93f009 100644 --- a/migration-1.0.0.md +++ b/migration-1.0.0.md @@ -41,6 +41,8 @@ type MintQuoteResponse = { where `request` is the invoice to be paid, and `quote` is the identifier used to pass to `mintTokens()`. +**`requestTokens()` --> `mintTokens()`** + --- **`getMeltQuote(invoice: string)`** is now used to get fee estimation and conversion quotes instead of `getFee()` and returns: From 149d52c54203654e8e76bd4d37ebd623bbd22e80 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Wed, 3 Apr 2024 21:21:47 +0900 Subject: [PATCH 26/50] 1.0.0-rc.2 --- 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 e09b4d25..ff509ecb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "license": "MIT", "dependencies": { "@cashu/crypto": "^0.2.6", diff --git a/package.json b/package.json index 9632472b..ddf2c6d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From 2b334eae06652f97fd1a9749eacd92e94462ebed Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 5 Apr 2024 19:44:45 +0200 Subject: [PATCH 27/50] clarify comment --- src/CashuMint.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 198aa1fe..c7029900 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -29,7 +29,7 @@ class CashuMint { * @param _mintUrl requires mint URL to create this object * @param _customRequest if passed, use custom request implementation for network communication with the mint */ - constructor(private _mintUrl: string, private _customRequest?: typeof request) {} + constructor(private _mintUrl: string, private _customRequest?: typeof request) { } get mintUrl() { return this._mintUrl; @@ -119,7 +119,7 @@ class CashuMint { /** * Get the mints public keys * @param mintUrl - * @param keysetId optional param to get the keys for a specific keyset. If not specified, the keys from the active keyset are fetched + * @param keysetId optional param to get the keys for a specific keyset. If not specified, the keys from all active keysets are fetched * @param customRequest * @returns */ @@ -146,7 +146,7 @@ class CashuMint { } /** * Get the mints public keys - * @param keysetId optional param to get the keys for a specific keyset. If not specified, the keys from the active keyset are fetched + * @param keysetId optional param to get the keys for a specific keyset. If not specified, the keys from all active keysets are fetched * @returns the mints public keys */ async getKeys(keysetId?: string, mintUrl?: string): Promise { From fa903c98db80a1de5d99658644c21111ce269ef7 Mon Sep 17 00:00:00 2001 From: starbackr-dev Date: Sat, 6 Apr 2024 10:00:14 -0400 Subject: [PATCH 28/50] updated test scripts to fix fail --- test/request.test.ts | 1 + test/wallet.test.ts | 13 ++----------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/test/request.test.ts b/test/request.test.ts index 38e77e03..e931f6d1 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -5,6 +5,7 @@ import { setGlobalRequestOptions } from '../src/request.js'; let request: Record | undefined; const mintUrl = 'https://localhost:3338'; +const unit = 'sats'; const invoice = 'lnbc20u1p3u27nppp5pm074ffk6m42lvae8c6847z7xuvhyknwgkk7pzdce47grf2ksqwsdpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzpgxqyz5vqsp5sw6n7cztudpl5m5jv3z6dtqpt2zhd3q6dwgftey9qxv09w82rgjq9qyyssqhtfl8wv7scwp5flqvmgjjh20nf6utvv5daw5h43h69yqfwjch7wnra3cn94qkscgewa33wvfh7guz76rzsfg9pwlk8mqd27wavf2udsq3yeuju'; diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 41e11e64..865aad0d 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -129,7 +129,7 @@ describe('receive', () => { ] }); - const wallet = new CashuWallet(mint, mint); + const wallet = new CashuWallet(mint, unit); const token3sat = 'cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIjAwOWExZjI5MzI1M2U0MWUiLCAiYW1vdW50IjogMSwgInNlY3JldCI6ICJlN2MxYjc2ZDFiMzFlMmJjYTJiMjI5ZDE2MGJkZjYwNDZmMzNiYzQ1NzAyMjIzMDRiNjUxMTBkOTI2ZjdhZjg5IiwgIkMiOiAiMDM4OWNkOWY0Zjk4OGUzODBhNzk4OWQ0ZDQ4OGE3YzkxYzUyNzdmYjkzMDQ3ZTdhMmNjMWVkOGUzMzk2Yjg1NGZmIn0sIHsiaWQiOiAiMDA5YTFmMjkzMjUzZTQxZSIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogImRlNTVjMTVmYWVmZGVkN2Y5Yzk5OWMzZDRjNjJmODFiMGM2ZmUyMWE3NTJmZGVmZjZiMDg0Y2YyZGYyZjVjZjMiLCAiQyI6ICIwMmRlNDBjNTlkOTAzODNiODg1M2NjZjNhNGIyMDg2NGFjODNiYTc1OGZjZTNkOTU5ZGJiODkzNjEwMDJlOGNlNDcifV0sICJtaW50IjogImh0dHA6Ly9sb2NhbGhvc3Q6MzMzOCJ9XX0='; @@ -154,7 +154,7 @@ describe('receive', () => { const msg = 'tokens already spent. Secret: asdasdasd'; nock(mintUrl).post('/v1/swap').reply(200, { detail: msg }); - const wallet = new CashuWallet(mint, mint); + const wallet = new CashuWallet(mint, unit); const { tokensWithErrors } = await wallet.receive(tokenInput); @@ -175,10 +175,6 @@ describe('receive', () => { nock(mintUrl).post('/v1/split').reply(200, { code: 0, error: 'could not verify proofs.' }); const wallet = new CashuWallet(mint, unit); - nock(mintUrl).post('/v1/swap').reply(200, { code: 0, error: 'could not verify proofs.' }); - const wallet = new CashuWallet(mint, unit); - - const { tokensWithErrors } = await wallet.receive(tokenInput); const t = tokensWithErrors!; @@ -210,11 +206,6 @@ describe('checkProofsSpent', () => { .reply(200, { spendable: [true] }); const wallet = new CashuWallet(mint, unit); - .post('/v1/checkstate') - .reply(200, { states: [{ Y: 'asd', state: 'UNSPENT', witness: 'witness-asd' }] }); - const wallet = new CashuWallet(mint, unit); - - const result = await wallet.checkProofsSpent(proofs); expect(result).toStrictEqual([]); From 3012d26b466c5f82fae4364164a35914b14538d8 Mon Sep 17 00:00:00 2001 From: starbackr-dev Date: Sat, 6 Apr 2024 12:00:43 -0400 Subject: [PATCH 29/50] fixed wallet.test that got changed when merging. --- test/wallet.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 865aad0d..5ca056ab 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -201,9 +201,8 @@ describe('checkProofsSpent', () => { ]; test('test checkProofsSpent - get proofs that are NOT spendable', async () => { nock(mintUrl) - - .post('/v1/check') - .reply(200, { spendable: [true] }); + .post('/v1/checkstate') + .reply(200, { states: [{ Y: 'asd', state: 'UNSPENT', witness: 'witness-asd' }] }); const wallet = new CashuWallet(mint, unit); const result = await wallet.checkProofsSpent(proofs); @@ -212,6 +211,7 @@ describe('checkProofsSpent', () => { }); }); + describe('payLnInvoice', () => { const proofs = [ { From da910e17e0a88b7cc5333da1af4cbc2da844d3ac Mon Sep 17 00:00:00 2001 From: starbackr-dev Date: Sat, 6 Apr 2024 12:16:44 -0400 Subject: [PATCH 30/50] changed the unit field default to 'sat' instead of 'sats' --- test/integration.test.ts | 2 +- test/wallet.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration.test.ts b/test/integration.test.ts index 7a8d2d9a..e01dd266 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -12,7 +12,7 @@ const externalInvoice = let request: Record | undefined; const mintUrl = 'http://localhost:3338'; -const unit = 'sats' +const unit = 'sat' describe('mint api', () => { test('get keys', async () => { diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 5ca056ab..68517029 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -16,7 +16,7 @@ const dummyKeysResp = { }; const mintUrl = 'http://localhost:3338'; const mint = new CashuMint(mintUrl); -const unit = 'sats'; +const unit = 'sat'; const invoice = 'lnbc20u1p3u27nppp5pm074ffk6m42lvae8c6847z7xuvhyknwgkk7pzdce47grf2ksqwsdpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzpgxqyz5vqsp5sw6n7cztudpl5m5jv3z6dtqpt2zhd3q6dwgftey9qxv09w82rgjq9qyyssqhtfl8wv7scwp5flqvmgjjh20nf6utvv5daw5h43h69yqfwjch7wnra3cn94qkscgewa33wvfh7guz76rzsfg9pwlk8mqd27wavf2udsq3yeuju'; From b816dd3794cbf36c00048aca132472c68e07a1fa Mon Sep 17 00:00:00 2001 From: starbuilder <101296187+starbackr-dev@users.noreply.github.com> Date: Sat, 6 Apr 2024 12:37:34 -0400 Subject: [PATCH 31/50] Update node.js.yml - missing 'run' --- .github/workflows/node.js.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 741a896b..acf317e6 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -23,4 +23,4 @@ jobs: cache: 'npm' - run: npm ci - run: npm run compile - - run: npm test + - run: npm run test From c6588bac7a2545318ef3f3e5e1ea6b35f8c34b42 Mon Sep 17 00:00:00 2001 From: starbuilder <101296187+starbackr-dev@users.noreply.github.com> Date: Sat, 6 Apr 2024 12:45:43 -0400 Subject: [PATCH 32/50] Update node.js.yml - match to main branch --- .github/workflows/node.js.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index acf317e6..285e3196 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -6,12 +6,12 @@ name: Node.js CI on: [push] jobs: - tests: + build: runs-on: ubuntu-latest strategy: matrix: - node-version: [20.x] + node-version: [20.x, 16.x, 18.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: @@ -23,4 +23,4 @@ jobs: cache: 'npm' - run: npm ci - run: npm run compile - - run: npm run test + - run: npm test From a8b069df45df6ba36c0b3dc5e9f0cf9ccf6fceae Mon Sep 17 00:00:00 2001 From: starbuilder <101296187+starbackr-dev@users.noreply.github.com> Date: Sat, 6 Apr 2024 12:48:07 -0400 Subject: [PATCH 33/50] Update node.js.yml - switching node.js to 18.x --- .github/workflows/node.js.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 285e3196..8cdb2edf 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -6,12 +6,12 @@ name: Node.js CI on: [push] jobs: - build: + tests: runs-on: ubuntu-latest strategy: matrix: - node-version: [20.x, 16.x, 18.x] + node-version: [18.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: @@ -24,3 +24,4 @@ jobs: - run: npm ci - run: npm run compile - run: npm test + From cc3f59d43a3144554f6dfbda7fd1326dea842155 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:48:26 +0200 Subject: [PATCH 34/50] equalize mint and melt payload and request object names --- src/CashuMint.ts | 26 +++++++++++++------------- src/CashuWallet.ts | 12 ++++++------ src/model/types/index.ts | 8 ++++---- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index c7029900..7cbca2d4 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -7,13 +7,13 @@ import type { MintActiveKeys, MintAllKeysets, PostRestoreResponse, - RequestMintResponse, + MintQuoteResponse, SerializedBlindedMessage, SplitPayload, SplitResponse, - RequestMintPayload, - PostMintPayload, - PostMintResponse, + MintQuotePayload, + MintPayload, + MintResponse, PostRestorePayload, MeltQuotePayload, MeltQuoteResponse @@ -62,14 +62,14 @@ class CashuMint { */ public static async mintQuote( mintUrl: string, - requestMintPayload: RequestMintPayload, + MintQuotePayload: MintQuotePayload, customRequest?: typeof request - ): Promise { + ): Promise { const requestInstance = customRequest || request; - return requestInstance({ + return requestInstance({ endpoint: joinUrls(mintUrl, '/v1/mint/quote/bolt11'), method: 'POST', - requestBody: requestMintPayload + requestBody: MintQuotePayload }); } @@ -78,8 +78,8 @@ class CashuMint { * @param amount Amount requesting for mint. * @returns the mint will create and return a Lightning invoice for the specified amount */ - async mintQuote(requestMintPayload: RequestMintPayload): Promise { - return CashuMint.mintQuote(this._mintUrl, requestMintPayload, this._customRequest); + async mintQuote(MintQuotePayload: MintQuotePayload): Promise { + return CashuMint.mintQuote(this._mintUrl, MintQuotePayload, this._customRequest); } /** * Requests the mint to perform token minting after the LN invoice has been paid @@ -91,11 +91,11 @@ class CashuMint { */ public static async mint( mintUrl: string, - mintPayload: PostMintPayload, + mintPayload: MintPayload, customRequest?: typeof request ) { const requestInstance = customRequest || request; - const data = await requestInstance({ + const data = await requestInstance({ endpoint: joinUrls(mintUrl, '/v1/mint/bolt11'), method: 'POST', requestBody: mintPayload @@ -113,7 +113,7 @@ class CashuMint { * @param hash hash (id) used for by the mint to keep track of wether the invoice has been paid yet * @returns serialized blinded signatures */ - async mint(mintPayload: PostMintPayload) { + async mint(mintPayload: MintPayload) { return CashuMint.mint(this._mintUrl, mintPayload, this._customRequest); } /** diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 70f34a6d..19aea840 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -10,11 +10,11 @@ import { MeltQuoteResponse, MintKeys, MeltTokensResponse, - PostMintPayload, + MintPayload, Proof, ReceiveResponse, ReceiveTokenEntryResponse, - RequestMintPayload, + MintQuotePayload, SendResponse, SerializedBlindedMessage, SplitPayload, @@ -332,11 +332,11 @@ class CashuWallet { * @returns the mint will create and return a Lightning invoice for the specified amount */ async getMintQuote(amount: number) { - const requestMintPayload: RequestMintPayload = { + const MintQuotePayload: MintQuotePayload = { unit: this._unit, amount: amount }; - return await this.mint.mintQuote(requestMintPayload); + return await this.mint.mintQuote(MintQuotePayload); } /** @@ -363,11 +363,11 @@ class CashuWallet { options?.counter, options?.pubkey ); - const postMintPayload: PostMintPayload = { + const MintPayload: MintPayload = { outputs: blindedMessages, quote: quote }; - const { signatures } = await this.mint.mint(postMintPayload); + const { signatures } = await this.mint.mint(MintPayload); return { proofs: dhke.constructProofs(signatures, rs, secrets, keyset) }; diff --git a/src/model/types/index.ts b/src/model/types/index.ts index ed69683f..95f7d4e3 100644 --- a/src/model/types/index.ts +++ b/src/model/types/index.ts @@ -266,7 +266,7 @@ export type ApiError = { /** * Payload that needs to be sent to the mint when requesting a mint */ -export type RequestMintPayload = { +export type MintQuotePayload = { /** * Unit to be minted */ @@ -279,7 +279,7 @@ export type RequestMintPayload = { /** * Response from the mint after requesting a mint */ -export type RequestMintResponse = { +export type MintQuoteResponse = { request: string; quote: string; } & ApiError; @@ -287,7 +287,7 @@ export type RequestMintResponse = { /** * Payload that needs to be sent to the mint when requesting a mint */ -export type PostMintPayload = { +export type MintPayload = { /** * Quote ID received from the mint. */ @@ -300,7 +300,7 @@ export type PostMintPayload = { /** * Response from the mint after requesting a mint */ -export type PostMintResponse = { +export type MintResponse = { signatures: Array; } & ApiError; From 641e27e6910eec313b27507a8f747324a69cb8eb Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:49:26 +0200 Subject: [PATCH 35/50] npm run format --- src/CashuMint.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 7cbca2d4..8da6e62f 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -29,7 +29,7 @@ class CashuMint { * @param _mintUrl requires mint URL to create this object * @param _customRequest if passed, use custom request implementation for network communication with the mint */ - constructor(private _mintUrl: string, private _customRequest?: typeof request) { } + constructor(private _mintUrl: string, private _customRequest?: typeof request) {} get mintUrl() { return this._mintUrl; From 2b1a99fe9fe8d3f91ec62ef3702fe0f1b41e816d Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:52:46 +0200 Subject: [PATCH 36/50] fix replace with capitalized objects --- src/CashuMint.ts | 10 +++++----- src/CashuWallet.ts | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/CashuMint.ts b/src/CashuMint.ts index 8da6e62f..af19a0e3 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -29,7 +29,7 @@ class CashuMint { * @param _mintUrl requires mint URL to create this object * @param _customRequest if passed, use custom request implementation for network communication with the mint */ - constructor(private _mintUrl: string, private _customRequest?: typeof request) {} + constructor(private _mintUrl: string, private _customRequest?: typeof request) { } get mintUrl() { return this._mintUrl; @@ -62,14 +62,14 @@ class CashuMint { */ public static async mintQuote( mintUrl: string, - MintQuotePayload: MintQuotePayload, + mintQuotePayload: MintQuotePayload, customRequest?: typeof request ): Promise { const requestInstance = customRequest || request; return requestInstance({ endpoint: joinUrls(mintUrl, '/v1/mint/quote/bolt11'), method: 'POST', - requestBody: MintQuotePayload + requestBody: mintQuotePayload }); } @@ -78,8 +78,8 @@ class CashuMint { * @param amount Amount requesting for mint. * @returns the mint will create and return a Lightning invoice for the specified amount */ - async mintQuote(MintQuotePayload: MintQuotePayload): Promise { - return CashuMint.mintQuote(this._mintUrl, MintQuotePayload, this._customRequest); + async mintQuote(mintQuotePayload: MintQuotePayload): Promise { + return CashuMint.mintQuote(this._mintUrl, mintQuotePayload, this._customRequest); } /** * Requests the mint to perform token minting after the LN invoice has been paid diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 19aea840..56916918 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -332,11 +332,11 @@ class CashuWallet { * @returns the mint will create and return a Lightning invoice for the specified amount */ async getMintQuote(amount: number) { - const MintQuotePayload: MintQuotePayload = { + const mintQuotePayload: MintQuotePayload = { unit: this._unit, amount: amount }; - return await this.mint.mintQuote(MintQuotePayload); + return await this.mint.mintQuote(mintQuotePayload); } /** @@ -363,7 +363,7 @@ class CashuWallet { options?.counter, options?.pubkey ); - const MintPayload: MintPayload = { + const mintPayload: MintPayload = { outputs: blindedMessages, quote: quote }; From 33bac22c0f86fa2a8de6eb71f10235d6f35d9310 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Sat, 6 Apr 2024 11:26:29 +0900 Subject: [PATCH 37/50] import and typo fixes --- src/CashuWallet.ts | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 56916918..2931a95c 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -3,24 +3,24 @@ import { CashuMint } from './CashuMint.js'; import * as dhke from './DHKE.js'; import { BlindedMessage } from './model/BlindedMessage.js'; import { - AmountPreference, - BlindedMessageData, - BlindedTransaction, - MeltPayload, - MeltQuoteResponse, - MintKeys, - MeltTokensResponse, - MintPayload, - Proof, - ReceiveResponse, - ReceiveTokenEntryResponse, - MintQuotePayload, - SendResponse, - SerializedBlindedMessage, - SplitPayload, - CheckStateEnum, - Token, - TokenEntry + type AmountPreference, + type BlindedMessageData, + type BlindedTransaction, + type MeltPayload, + type MeltQuoteResponse, + type MintKeys, + type MeltTokensResponse, + type MintPayload, + type Proof, + type ReceiveResponse, + type ReceiveTokenEntryResponse, + type MintQuotePayload, + type SendResponse, + type SerializedBlindedMessage, + type SplitPayload, + type Token, + type TokenEntry, + CheckStateEnum } from './model/types/index.js'; import { bytesToNumber, @@ -367,7 +367,7 @@ class CashuWallet { outputs: blindedMessages, quote: quote }; - const { signatures } = await this.mint.mint(MintPayload); + const { signatures } = await this.mint.mint(mintPayload); return { proofs: dhke.constructProofs(signatures, rs, secrets, keyset) }; From c4ecba4106531dcb933a10f2afd2290f28586bf9 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Tue, 9 Apr 2024 09:55:27 +0900 Subject: [PATCH 38/50] format --- .github/workflows/node.js.yml | 1 - src/CashuMint.ts | 2 +- src/CashuWallet.ts | 12 ++++++++---- test/integration.test.ts | 2 +- test/request.test.ts | 2 +- test/wallet.test.ts | 15 +++------------ 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 8cdb2edf..8242752f 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -24,4 +24,3 @@ jobs: - run: npm ci - run: npm run compile - run: npm test - diff --git a/src/CashuMint.ts b/src/CashuMint.ts index af19a0e3..14919344 100644 --- a/src/CashuMint.ts +++ b/src/CashuMint.ts @@ -29,7 +29,7 @@ class CashuMint { * @param _mintUrl requires mint URL to create this object * @param _customRequest if passed, use custom request implementation for network communication with the mint */ - constructor(private _mintUrl: string, private _customRequest?: typeof request) { } + constructor(private _mintUrl: string, private _customRequest?: typeof request) {} get mintUrl() { return this._mintUrl; diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 2931a95c..f78a1bce 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -45,7 +45,6 @@ class CashuWallet { private _seed: Uint8Array | undefined; private _unit = 'sat'; mint: CashuMint; - /** * @param keys public keys from the mint @@ -53,9 +52,14 @@ class CashuWallet { * @param mnemonicOrSeed mnemonic phrase or Seed to initial derivation key for this wallets deterministic secrets. When the mnemonic is provided, the seed will be derived from it. * This can lead to poor performance, in which case the seed should be directly provided */ - constructor(mint: CashuMint, unit?:string, keys?: MintKeys, mnemonicOrSeed?: string | Uint8Array) { + constructor( + mint: CashuMint, + unit?: string, + keys?: MintKeys, + mnemonicOrSeed?: string | Uint8Array + ) { this.mint = mint; - if (unit) this._unit = unit; + if (unit) this._unit = unit; if (keys) { this._keys = keys; } @@ -332,7 +336,7 @@ class CashuWallet { * @returns the mint will create and return a Lightning invoice for the specified amount */ async getMintQuote(amount: number) { - const mintQuotePayload: MintQuotePayload = { + const mintQuotePayload: MintQuotePayload = { unit: this._unit, amount: amount }; diff --git a/test/integration.test.ts b/test/integration.test.ts index e01dd266..e8005121 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -12,7 +12,7 @@ const externalInvoice = let request: Record | undefined; const mintUrl = 'http://localhost:3338'; -const unit = 'sat' +const unit = 'sat'; describe('mint api', () => { test('get keys', async () => { diff --git a/test/request.test.ts b/test/request.test.ts index e931f6d1..f9692a42 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -5,7 +5,7 @@ import { setGlobalRequestOptions } from '../src/request.js'; let request: Record | undefined; const mintUrl = 'https://localhost:3338'; -const unit = 'sats'; +const unit = 'sats'; const invoice = 'lnbc20u1p3u27nppp5pm074ffk6m42lvae8c6847z7xuvhyknwgkk7pzdce47grf2ksqwsdpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzpgxqyz5vqsp5sw6n7cztudpl5m5jv3z6dtqpt2zhd3q6dwgftey9qxv09w82rgjq9qyyssqhtfl8wv7scwp5flqvmgjjh20nf6utvv5daw5h43h69yqfwjch7wnra3cn94qkscgewa33wvfh7guz76rzsfg9pwlk8mqd27wavf2udsq3yeuju'; diff --git a/test/wallet.test.ts b/test/wallet.test.ts index 68517029..f6218b47 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -132,8 +132,8 @@ describe('receive', () => { const wallet = new CashuWallet(mint, unit); const token3sat = 'cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIjAwOWExZjI5MzI1M2U0MWUiLCAiYW1vdW50IjogMSwgInNlY3JldCI6ICJlN2MxYjc2ZDFiMzFlMmJjYTJiMjI5ZDE2MGJkZjYwNDZmMzNiYzQ1NzAyMjIzMDRiNjUxMTBkOTI2ZjdhZjg5IiwgIkMiOiAiMDM4OWNkOWY0Zjk4OGUzODBhNzk4OWQ0ZDQ4OGE3YzkxYzUyNzdmYjkzMDQ3ZTdhMmNjMWVkOGUzMzk2Yjg1NGZmIn0sIHsiaWQiOiAiMDA5YTFmMjkzMjUzZTQxZSIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogImRlNTVjMTVmYWVmZGVkN2Y5Yzk5OWMzZDRjNjJmODFiMGM2ZmUyMWE3NTJmZGVmZjZiMDg0Y2YyZGYyZjVjZjMiLCAiQyI6ICIwMmRlNDBjNTlkOTAzODNiODg1M2NjZjNhNGIyMDg2NGFjODNiYTc1OGZjZTNkOTU5ZGJiODkzNjEwMDJlOGNlNDcifV0sICJtaW50IjogImh0dHA6Ly9sb2NhbGhvc3Q6MzMzOCJ9XX0='; - - const response: ReceiveResponse = await wallet.receive(token3sat, { + + const response: ReceiveResponse = await wallet.receive(token3sat, { preference: [{ amount: 1, count: 3 }] }); @@ -156,7 +156,6 @@ describe('receive', () => { nock(mintUrl).post('/v1/swap').reply(200, { detail: msg }); const wallet = new CashuWallet(mint, unit); - const { tokensWithErrors } = await wallet.receive(tokenInput); const t = tokensWithErrors!; @@ -171,7 +170,6 @@ describe('receive', () => { expect(/[0-9a-f]{64}/.test(t.token[0].proofs[0].secret)).toBe(true); }); test('test receive could not verify proofs', async () => { - nock(mintUrl).post('/v1/split').reply(200, { code: 0, error: 'could not verify proofs.' }); const wallet = new CashuWallet(mint, unit); @@ -211,7 +209,6 @@ describe('checkProofsSpent', () => { }); }); - describe('payLnInvoice', () => { const proofs = [ { @@ -222,16 +219,13 @@ describe('payLnInvoice', () => { } ]; test('test payLnInvoice base case', async () => { - - nock(mintUrl) .post('/v1/melt/quote/bolt11') .reply(200, { quote: 'quote_id', amount: 123, fee_reserve: 0 }); nock(mintUrl).post('/v1/melt/bolt11').reply(200, { paid: true, payment_preimage: '' }); const wallet = new CashuWallet(mint, unit); - const meltQuote = await wallet.getMeltQuote('lnbcabbc'); - + const meltQuote = await wallet.getMeltQuote('lnbcabbc'); const result = await wallet.payLnInvoice(invoice, proofs, meltQuote); @@ -274,13 +268,11 @@ describe('payLnInvoice', () => { const meltQuote = await wallet.getMeltQuote('lnbcabbc'); const result = await wallet.payLnInvoice(invoice, [{ ...proofs[0], amount: 3 }], meltQuote); - expect(result.isPaid).toBe(true); expect(result.preimage).toBe('asd'); expect(result.change).toHaveLength(1); }); test('test payLnInvoice bad resonse', async () => { - nock(mintUrl).post('/v1/melt/bolt11').reply(200, {}); const wallet = new CashuWallet(mint, unit); const result = await wallet @@ -559,7 +551,6 @@ describe('send', () => { expect(result).toEqual(new Error('Not enough funds available')); }); test('test send bad response', async () => { - nock(mintUrl).post('/v1/swap').reply(200, {}); const wallet = new CashuWallet(mint, unit); From 3c1ff1c67005388f986aae3a3e9ee8644b1e5bd8 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Tue, 9 Apr 2024 10:09:59 +0900 Subject: [PATCH 39/50] constructor options and set unit from keyset --- src/CashuWallet.ts | 28 ++++++++++++++++------------ test/integration.test.ts | 20 ++++++++++---------- test/request.test.ts | 4 ++-- test/wallet.test.ts | 36 ++++++++++++++++++------------------ 4 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index f78a1bce..110860eb 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -47,33 +47,37 @@ class CashuWallet { mint: CashuMint; /** - * @param keys public keys from the mint + * @param unit optionally set unit + * @param keys public keys from the mint. If set, it will override the unit with the keysets unit * @param mint Cashu mint instance is used to make api calls * @param mnemonicOrSeed mnemonic phrase or Seed to initial derivation key for this wallets deterministic secrets. When the mnemonic is provided, the seed will be derived from it. * This can lead to poor performance, in which case the seed should be directly provided */ constructor( mint: CashuMint, - unit?: string, - keys?: MintKeys, - mnemonicOrSeed?: string | Uint8Array + options?: { + unit?: string; + keys?: MintKeys; + mnemonicOrSeed?: string | Uint8Array; + } ) { this.mint = mint; - if (unit) this._unit = unit; - if (keys) { - this._keys = keys; + if (options?.unit) this._unit = options?.unit; + if (options?.keys) { + this._keys = options.keys; + this._unit = options.keys.unit; } - if (!mnemonicOrSeed) { + if (!options?.mnemonicOrSeed) { return; } - if (mnemonicOrSeed instanceof Uint8Array) { - this._seed = mnemonicOrSeed; + if (options?.mnemonicOrSeed instanceof Uint8Array) { + this._seed = options.mnemonicOrSeed; return; } - if (!validateMnemonic(mnemonicOrSeed, wordlist)) { + if (!validateMnemonic(options.mnemonicOrSeed, wordlist)) { throw new Error('Tried to instantiate with mnemonic, but mnemonic was invalid'); } - this._seed = deriveSeedFromMnemonic(mnemonicOrSeed); + this._seed = deriveSeedFromMnemonic(options.mnemonicOrSeed); } get keys(): MintKeys { diff --git a/test/integration.test.ts b/test/integration.test.ts index e8005121..6c96263f 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -35,13 +35,13 @@ describe('mint api', () => { }); test('request mint', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(100); expect(request).toBeDefined(); }); test('mint tokens', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(1337); expect(request).toBeDefined(); expect(request.request).toContain('lnbc1337'); @@ -52,7 +52,7 @@ describe('mint api', () => { }); test('get fee for local invoice', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(100); const fee = (await wallet.getMeltQuote(request.request)).fee_reserve; expect(fee).toBeDefined(); @@ -61,7 +61,7 @@ describe('mint api', () => { }); test('get fee for external invoice', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const fee = (await wallet.getMeltQuote(externalInvoice)).fee_reserve; expect(fee).toBeDefined(); // because external invoice, fee should be > 0 @@ -69,7 +69,7 @@ describe('mint api', () => { }); test('pay local invoice', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); @@ -97,7 +97,7 @@ describe('mint api', () => { }); test('pay external invoice', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(3000); const tokens = await wallet.mintTokens(3000, request.quote); @@ -124,7 +124,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 wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); @@ -137,7 +137,7 @@ describe('mint api', () => { }); test('test send tokens with change', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); @@ -150,7 +150,7 @@ describe('mint api', () => { }); test('receive tokens with previous split', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(100); const tokens = await wallet.mintTokens(100, request.quote); @@ -165,7 +165,7 @@ describe('mint api', () => { }); test('receive tokens with previous mint', async () => { const mint = new CashuMint(mintUrl); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const request = await wallet.getMintQuote(64); const tokens = await wallet.mintTokens(64, request.quote); const encoded = getEncodedToken({ diff --git a/test/request.test.ts b/test/request.test.ts index f9692a42..40c272dc 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -32,7 +32,7 @@ describe('requests', () => { }; }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); await wallet.getMeltQuote(invoice); expect(request).toBeDefined(); @@ -52,7 +52,7 @@ describe('requests', () => { }; }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); setGlobalRequestOptions({ headers: { 'x-cashu': 'xyz-123-abc' } }); await wallet.getMeltQuote(invoice); diff --git a/test/wallet.test.ts b/test/wallet.test.ts index f6218b47..27fcb722 100644 --- a/test/wallet.test.ts +++ b/test/wallet.test.ts @@ -39,7 +39,7 @@ describe('test fees', () => { amount: 2000, fee_reserve: 20 }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const fee = await wallet.getMeltQuote(invoice); const amount = 2000; @@ -63,7 +63,7 @@ describe('receive', () => { } ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const response: ReceiveResponse = await wallet.receive(tokenInput); @@ -129,7 +129,7 @@ describe('receive', () => { ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const token3sat = 'cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIjAwOWExZjI5MzI1M2U0MWUiLCAiYW1vdW50IjogMSwgInNlY3JldCI6ICJlN2MxYjc2ZDFiMzFlMmJjYTJiMjI5ZDE2MGJkZjYwNDZmMzNiYzQ1NzAyMjIzMDRiNjUxMTBkOTI2ZjdhZjg5IiwgIkMiOiAiMDM4OWNkOWY0Zjk4OGUzODBhNzk4OWQ0ZDQ4OGE3YzkxYzUyNzdmYjkzMDQ3ZTdhMmNjMWVkOGUzMzk2Yjg1NGZmIn0sIHsiaWQiOiAiMDA5YTFmMjkzMjUzZTQxZSIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogImRlNTVjMTVmYWVmZGVkN2Y5Yzk5OWMzZDRjNjJmODFiMGM2ZmUyMWE3NTJmZGVmZjZiMDg0Y2YyZGYyZjVjZjMiLCAiQyI6ICIwMmRlNDBjNTlkOTAzODNiODg1M2NjZjNhNGIyMDg2NGFjODNiYTc1OGZjZTNkOTU5ZGJiODkzNjEwMDJlOGNlNDcifV0sICJtaW50IjogImh0dHA6Ly9sb2NhbGhvc3Q6MzMzOCJ9XX0='; @@ -154,7 +154,7 @@ describe('receive', () => { const msg = 'tokens already spent. Secret: asdasdasd'; nock(mintUrl).post('/v1/swap').reply(200, { detail: msg }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const { tokensWithErrors } = await wallet.receive(tokenInput); const t = tokensWithErrors!; @@ -171,7 +171,7 @@ describe('receive', () => { }); test('test receive could not verify proofs', async () => { nock(mintUrl).post('/v1/split').reply(200, { code: 0, error: 'could not verify proofs.' }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const { tokensWithErrors } = await wallet.receive(tokenInput); const t = tokensWithErrors!; @@ -201,7 +201,7 @@ describe('checkProofsSpent', () => { nock(mintUrl) .post('/v1/checkstate') .reply(200, { states: [{ Y: 'asd', state: 'UNSPENT', witness: 'witness-asd' }] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const result = await wallet.checkProofsSpent(proofs); @@ -224,7 +224,7 @@ describe('payLnInvoice', () => { .reply(200, { quote: 'quote_id', amount: 123, fee_reserve: 0 }); nock(mintUrl).post('/v1/melt/bolt11').reply(200, { paid: true, payment_preimage: '' }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const meltQuote = await wallet.getMeltQuote('lnbcabbc'); const result = await wallet.payLnInvoice(invoice, proofs, meltQuote); @@ -264,7 +264,7 @@ describe('payLnInvoice', () => { ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const meltQuote = await wallet.getMeltQuote('lnbcabbc'); const result = await wallet.payLnInvoice(invoice, [{ ...proofs[0], amount: 3 }], meltQuote); @@ -274,7 +274,7 @@ describe('payLnInvoice', () => { }); test('test payLnInvoice bad resonse', async () => { nock(mintUrl).post('/v1/melt/bolt11').reply(200, {}); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const result = await wallet .payLnInvoice(invoice, proofs, {} as MeltQuoteResponse) .catch((e) => e); @@ -296,7 +296,7 @@ describe('requestTokens', () => { } ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const { proofs } = await wallet.mintTokens(1, ''); @@ -307,7 +307,7 @@ describe('requestTokens', () => { }); test('test requestTokens bad resonse', async () => { nock(mintUrl).post('/v1/mint/bolt11').reply(200, {}); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const result = await wallet.mintTokens(1, '').catch((e) => e); @@ -336,7 +336,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const result = await wallet.send(1, proofs); @@ -363,7 +363,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const result = await wallet.send(1, [ { @@ -401,7 +401,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const overpayProofs = [ { @@ -449,7 +449,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const overpayProofs = [ { @@ -504,7 +504,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const overpayProofs = [ { @@ -544,7 +544,7 @@ describe('send', () => { } ] }); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const result = await wallet.send(2, proofs).catch((e) => e); @@ -552,7 +552,7 @@ describe('send', () => { }); test('test send bad response', async () => { nock(mintUrl).post('/v1/swap').reply(200, {}); - const wallet = new CashuWallet(mint, unit); + const wallet = new CashuWallet(mint, { unit }); const result = await wallet .send(1, [ From 227444d7d70fe917a90b57f929724fcc1f72d463 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Tue, 9 Apr 2024 10:12:07 +0900 Subject: [PATCH 40/50] update migration guide --- migration-1.0.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration-1.0.0.md b/migration-1.0.0.md index 8c93f009..cbc8344b 100644 --- a/migration-1.0.0.md +++ b/migration-1.0.0.md @@ -25,7 +25,7 @@ Decoding LN invoices is no longer used inside the lib. ### `CashuWallet` interface changes -**optional parameters are now in an onpional `options?` Object** +**optional function AND constructor parameters are now in an onpional `options?` Object** Utility functions now have an `options` object for optional parameters, instead of passing them directly From 565badde2c68c34385e04458fc4974a6532cf220 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Tue, 9 Apr 2024 10:14:22 +0900 Subject: [PATCH 41/50] unit getter --- src/CashuWallet.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 110860eb..6d3a0b4e 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -80,6 +80,10 @@ class CashuWallet { this._seed = deriveSeedFromMnemonic(options.mnemonicOrSeed); } + get unit(): string { + return this._unit; + } + get keys(): MintKeys { if (!this._keys) { throw new Error('Keys are not set'); From 3d708fdebc366b6474516a42fb5e809beee94ee9 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Tue, 9 Apr 2024 10:17:36 +0900 Subject: [PATCH 42/50] 1.0.0-rc.3 --- 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 ff509ecb..75b02d00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "license": "MIT", "dependencies": { "@cashu/crypto": "^0.2.6", diff --git a/package.json b/package.json index ddf2c6d5..f2809bdb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From e462896e37ee9d907367e60d766bb1fb1e281be2 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Tue, 9 Apr 2024 10:23:46 +0900 Subject: [PATCH 43/50] add set unit to set keys --- src/CashuWallet.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index 6d3a0b4e..d19685c2 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -92,6 +92,7 @@ class CashuWallet { } set keys(keys: MintKeys) { this._keys = keys; + this._unit = keys.unit; } /** From eeb5708a2cee54bc1f242547747b61addfe3bd8f Mon Sep 17 00:00:00 2001 From: Kelbie Date: Tue, 9 Apr 2024 23:00:25 +0100 Subject: [PATCH 44/50] Update CashuWallet.ts --- src/CashuWallet.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index d19685c2..ca07c885 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -107,6 +107,7 @@ class CashuWallet { async receive( token: string | Token, options?: { + keysetId?: string; preference?: Array; counter?: number; pubkey?: string; @@ -127,6 +128,7 @@ class CashuWallet { } try { const { proofs, proofsWithError } = await this.receiveTokenEntry(tokenEntry, { + keysetId: options?.keysetId, preference: options?.preference, counter: options?.counter, pubkey: options?.pubkey, @@ -160,6 +162,7 @@ class CashuWallet { async receiveTokenEntry( tokenEntry: TokenEntry, options?: { + keysetId?: string; preference?: Array; counter?: number; pubkey?: string; @@ -174,7 +177,7 @@ class CashuWallet { if (!preference) { preference = getDefaultAmountPreference(amount); } - const keys = await this.getKeys(); + const keys = await this.getKeys(options?.keysetId); const { payload, blindedMessages } = this.createSplitPayload( amount, tokenEntry.proofs, @@ -218,6 +221,7 @@ class CashuWallet { amount: number, proofs: Array, options?: { + keysetId?: string; preference?: Array; counter?: number; pubkey?: string; @@ -227,7 +231,7 @@ class CashuWallet { if (options?.preference) { amount = options?.preference?.reduce((acc, curr) => acc + curr.amount * curr.count, 0); } - const keyset = await this.getKeys(); + const keyset = await this.getKeys(options?.keysetId); let amountAvailable = 0; const proofsToSend: Array = []; const proofsToKeep: Array = []; From 78099d0a9dd0b03530c3374214b97882ccf86a5f Mon Sep 17 00:00:00 2001 From: Kelbie Date: Tue, 9 Apr 2024 23:05:35 +0100 Subject: [PATCH 45/50] Update CashuWallet.ts --- src/CashuWallet.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index ca07c885..a8bbf8a3 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -107,7 +107,7 @@ class CashuWallet { async receive( token: string | Token, options?: { - keysetId?: string; + keysetId?: string; preference?: Array; counter?: number; pubkey?: string; @@ -128,7 +128,7 @@ class CashuWallet { } try { const { proofs, proofsWithError } = await this.receiveTokenEntry(tokenEntry, { - keysetId: options?.keysetId, + keysetId: options?.keysetId, preference: options?.preference, counter: options?.counter, pubkey: options?.pubkey, @@ -162,7 +162,7 @@ class CashuWallet { async receiveTokenEntry( tokenEntry: TokenEntry, options?: { - keysetId?: string; + keysetId?: string; preference?: Array; counter?: number; pubkey?: string; @@ -221,7 +221,7 @@ class CashuWallet { amount: number, proofs: Array, options?: { - keysetId?: string; + keysetId?: string; preference?: Array; counter?: number; pubkey?: string; @@ -231,7 +231,7 @@ class CashuWallet { if (options?.preference) { amount = options?.preference?.reduce((acc, curr) => acc + curr.amount * curr.count, 0); } - const keyset = await this.getKeys(options?.keysetId); + const keyset = await this.getKeys(options?.keysetId); let amountAvailable = 0; const proofsToSend: Array = []; const proofsToKeep: Array = []; From a2c23320074ac1472c287203bb9d07f653184ebe Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 17 Apr 2024 23:00:32 +0200 Subject: [PATCH 46/50] add unit to Token --- src/model/types/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/model/types/index.ts b/src/model/types/index.ts index 95f7d4e3..64de1356 100644 --- a/src/model/types/index.ts +++ b/src/model/types/index.ts @@ -388,6 +388,10 @@ export type Token = { * a message to send along with the token */ memo?: string; + /** + * the unit of the token + */ + unit?: string; }; /** * TokenEntry that stores proofs and mints From 935272cbf257ab812b99703dfae4797376d2d914 Mon Sep 17 00:00:00 2001 From: gudnuf Date: Fri, 19 Apr 2024 11:54:17 -0700 Subject: [PATCH 47/50] pass keysetId to `CashuWallet.send` + getKeys bug --- src/CashuWallet.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index d19685c2..fe6d5225 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -222,12 +222,13 @@ class CashuWallet { counter?: number; pubkey?: string; privkey?: string; + keysetId?: string; } ): Promise { if (options?.preference) { amount = options?.preference?.reduce((acc, curr) => acc + curr.amount * curr.count, 0); } - const keyset = await this.getKeys(); + const keyset = await this.getKeys(options?.keysetId); let amountAvailable = 0; const proofsToSend: Array = []; const proofsToKeep: Array = []; @@ -319,7 +320,7 @@ class CashuWallet { * Initialize the wallet with the mints public keys */ private async getKeys(keysetId?: string, unit?: string): Promise { - if (!this._keys || this._keys.id !== keysetId) { + if (!this._keys || (keysetId !== undefined && this._keys.id !== keysetId)) { const allKeys = await this.mint.getKeys(keysetId); let keys; if (keysetId) { From 90d692b555188c83c5f83508d521c9c1cdc03890 Mon Sep 17 00:00:00 2001 From: gudnuf Date: Fri, 19 Apr 2024 11:56:00 -0700 Subject: [PATCH 48/50] `meltQuote` optional in `CashuWallet.payLnInvoice` --- src/CashuWallet.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CashuWallet.ts b/src/CashuWallet.ts index fe6d5225..fa0397b5 100644 --- a/src/CashuWallet.ts +++ b/src/CashuWallet.ts @@ -449,7 +449,7 @@ class CashuWallet { async payLnInvoice( invoice: string, proofsToSend: Array, - meltQuote: MeltQuoteResponse, + meltQuote?: MeltQuoteResponse, options?: { keysetId?: string; counter?: number; From 0d59735cd659c45662d01a6ac374cdf9c38e7633 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Sat, 18 May 2024 19:12:28 +0900 Subject: [PATCH 49/50] 1.0.0-rc.4 --- 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 75b02d00..89a642c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.3", + "version": "1.0.0-rc.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.3", + "version": "1.0.0-rc.4", "license": "MIT", "dependencies": { "@cashu/crypto": "^0.2.6", diff --git a/package.json b/package.json index f2809bdb..8669695e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cashu/cashu-ts", - "version": "1.0.0-rc.3", + "version": "1.0.0-rc.4", "description": "cashu library for communicating with a cashu mint", "main": "dist/lib/es5/index.js", "module": "dist/lib/es6/index.js", From b60254ed2cef6281fd64102948b79adf21071619 Mon Sep 17 00:00:00 2001 From: gandlaf21 Date: Mon, 20 May 2024 11:51:06 +0900 Subject: [PATCH 50/50] format --- src/model/types/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model/types/index.ts b/src/model/types/index.ts index 64de1356..da3ac722 100644 --- a/src/model/types/index.ts +++ b/src/model/types/index.ts @@ -389,8 +389,8 @@ export type Token = { */ memo?: string; /** - * the unit of the token - */ + * the unit of the token + */ unit?: string; }; /**