mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-10-05 11:18:24 +00:00
Uograde cashu-ts to 4.11
This commit is contained in:
@@ -0,0 +1,152 @@
|
|||||||
|
/**
|
||||||
|
* The cashu-ts contract that the websocket->poller fallbacks rest on.
|
||||||
|
*
|
||||||
|
* `_monitorSentProofs` (sendOperationApi), `_monitorAsyncMeltQuote`
|
||||||
|
* (transferOperationApi) and the mint-quote watcher (topupOperationApi) all
|
||||||
|
* subscribe over NUT-17 and fall back to a poller when the websocket cannot
|
||||||
|
* carry the update. The subscribe call failing is the easy half, and a plain
|
||||||
|
* try/catch covers it. The other half is an ESTABLISHED subscription dying
|
||||||
|
* later: mints and reverse proxies idle out long-lived sockets, and a sent
|
||||||
|
* token or a pending melt quote routinely outlives one.
|
||||||
|
*
|
||||||
|
* Up to cashu-ts 4.10 that case was UNREPORTABLE. `createSubscription` passed
|
||||||
|
* the error callback only to `addRpcListener`, which covers the subscribe RPC
|
||||||
|
* itself; `addSubListener(subId, callback)` took no error callback at all, so
|
||||||
|
* once the subscription was live nothing held a way to signal it. A socket
|
||||||
|
* close ran `stopMessageHandling()`, which drained the queue and told nobody.
|
||||||
|
* The subscription simply went quiet and the transaction hung.
|
||||||
|
*
|
||||||
|
* 4.11 (#1252) stores the error callback per subscription and fans it out from
|
||||||
|
* `stopMessageHandling(err)`. That is what lets the fallback start, and it is
|
||||||
|
* the entire reason the pollers in those three functions are hoisted out of
|
||||||
|
* the setup `catch` into a shared `startPoller()` reachable from both paths.
|
||||||
|
*
|
||||||
|
* If a future cashu-ts stops invoking the error callback on close, those three
|
||||||
|
* fallbacks go silent again with no other test failing. This pins it at the
|
||||||
|
* WSConnection level — the layer the `wallet.on.*` helpers are built on — so
|
||||||
|
* the assertion is about the library contract rather than our wiring.
|
||||||
|
*
|
||||||
|
* Deterministic and offline: the WebSocket implementation is injected.
|
||||||
|
*
|
||||||
|
* @jest-environment node
|
||||||
|
*/
|
||||||
|
import {WSConnection, injectWebSocketImpl} from '@cashu/cashu-ts'
|
||||||
|
|
||||||
|
type CloseInit = {code: number; reason: string; wasClean: boolean}
|
||||||
|
|
||||||
|
/** Minimal WebSocket double: opens next tick, acks `subscribe`, closes on demand. */
|
||||||
|
class FakeWebSocket {
|
||||||
|
static instances: FakeWebSocket[] = []
|
||||||
|
static OPEN = 1
|
||||||
|
|
||||||
|
onopen?: () => void
|
||||||
|
onclose?: (e: CloseInit) => void
|
||||||
|
onmessage?: (e: {data: string}) => void
|
||||||
|
onerror?: (e: unknown) => void
|
||||||
|
readyState = 0
|
||||||
|
sent: string[] = []
|
||||||
|
|
||||||
|
constructor(public url: string) {
|
||||||
|
FakeWebSocket.instances.push(this)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.readyState = FakeWebSocket.OPEN
|
||||||
|
this.onopen?.()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
send(raw: string) {
|
||||||
|
this.sent.push(raw)
|
||||||
|
const msg = JSON.parse(raw)
|
||||||
|
if (msg.method === 'subscribe') {
|
||||||
|
// The sub listener is only registered once this ack lands.
|
||||||
|
setTimeout(
|
||||||
|
() =>
|
||||||
|
this.onmessage?.({
|
||||||
|
data: JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
result: {status: 'OK', subId: msg.params.subId},
|
||||||
|
id: msg.id,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.readyState = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/** What a mint or proxy does to an idle connection. */
|
||||||
|
dropRemote(init: Partial<CloseInit> = {}) {
|
||||||
|
this.readyState = 3
|
||||||
|
this.onclose?.({code: 1006, reason: 'idle timeout', wasClean: false, ...init})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tick = () => new Promise(resolve => setTimeout(resolve, 5))
|
||||||
|
|
||||||
|
async function establishedSubscription() {
|
||||||
|
const ws = new WSConnection('wss://mint.test/v1/ws')
|
||||||
|
await ws.connect()
|
||||||
|
|
||||||
|
const updates: unknown[] = []
|
||||||
|
const errors: Error[] = []
|
||||||
|
ws.createSubscription(
|
||||||
|
{kind: 'proof_state', filters: ['deadbeef']} as never,
|
||||||
|
payload => updates.push(payload),
|
||||||
|
error => errors.push(error),
|
||||||
|
)
|
||||||
|
await tick()
|
||||||
|
|
||||||
|
const socket = FakeWebSocket.instances[FakeWebSocket.instances.length - 1]
|
||||||
|
return {ws, socket, updates, errors}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('an established NUT-17 subscription reports a socket close', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
FakeWebSocket.instances = []
|
||||||
|
injectWebSocketImpl(FakeWebSocket as never)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('PRECONDITION: the subscription is live before the socket drops', async () => {
|
||||||
|
const {ws, errors} = await establishedSubscription()
|
||||||
|
|
||||||
|
expect(ws.activeSubscriptions).toHaveLength(1)
|
||||||
|
expect(errors).toHaveLength(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('invokes the error callback when the mint drops the connection', async () => {
|
||||||
|
const {socket, errors} = await establishedSubscription()
|
||||||
|
|
||||||
|
socket.dropRemote()
|
||||||
|
await tick()
|
||||||
|
|
||||||
|
// This is the signal the three operation-api fallbacks start their
|
||||||
|
// poller from. Before 4.11 it never arrived and they hung instead.
|
||||||
|
expect(errors).toHaveLength(1)
|
||||||
|
expect(errors[0]).toBeInstanceOf(Error)
|
||||||
|
expect(errors[0].message).toMatch(/closed/i)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('drops the subscription so a later close cannot fire it twice', async () => {
|
||||||
|
const {ws, socket, errors} = await establishedSubscription()
|
||||||
|
|
||||||
|
socket.dropRemote()
|
||||||
|
await tick()
|
||||||
|
socket.dropRemote()
|
||||||
|
await tick()
|
||||||
|
|
||||||
|
expect(errors).toHaveLength(1)
|
||||||
|
expect(ws.activeSubscriptions).toHaveLength(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('reports a CLEAN close too — idle teardown is not a success signal', async () => {
|
||||||
|
const {socket, errors} = await establishedSubscription()
|
||||||
|
|
||||||
|
socket.dropRemote({code: 1000, reason: '', wasClean: true})
|
||||||
|
await tick()
|
||||||
|
|
||||||
|
expect(errors).toHaveLength(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
+2
-2
@@ -22,7 +22,7 @@
|
|||||||
"machine-translate": "npx @inlang/cli machine translate --project minibits.inlang"
|
"machine-translate": "npx @inlang/cli machine translate --project minibits.inlang"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cashu/cashu-ts": "^4.10.0",
|
"@cashu/cashu-ts": "^4.11.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^7.1.0",
|
"@fortawesome/fontawesome-svg-core": "^7.1.0",
|
||||||
"@fortawesome/free-brands-svg-icons": "^7.1.0",
|
"@fortawesome/free-brands-svg-icons": "^7.1.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^7.1.0",
|
"@fortawesome/free-regular-svg-icons": "^7.1.0",
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
"@react-navigation/native": "^7.1.18",
|
"@react-navigation/native": "^7.1.18",
|
||||||
"@react-navigation/native-stack": "^7.3.27",
|
"@react-navigation/native-stack": "^7.3.27",
|
||||||
"@react-navigation/stack": "^7.4.9",
|
"@react-navigation/stack": "^7.4.9",
|
||||||
"@scure/bip32": "^2.2.0",
|
"@scure/bip32": "^2.4.0",
|
||||||
"@scure/bip39": "2.0.1",
|
"@scure/bip39": "2.0.1",
|
||||||
"@sentry/react-native": "^7.7.0",
|
"@sentry/react-native": "^7.7.0",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/node_modules/@scure/bip32/index.js b/node_modules/@scure/bip32/index.js
|
diff --git a/node_modules/@scure/bip32/index.js b/node_modules/@scure/bip32/index.js
|
||||||
index 8e49612..d54da85 100644
|
index 49b54b8..a66540e 100644
|
||||||
--- a/node_modules/@scure/bip32/index.js
|
--- a/node_modules/@scure/bip32/index.js
|
||||||
+++ b/node_modules/@scure/bip32/index.js
|
+++ b/node_modules/@scure/bip32/index.js
|
||||||
@@ -28,6 +28,7 @@ import { ripemd160 } from '@noble/hashes/legacy.js';
|
@@ -28,6 +28,7 @@ import { ripemd160 } from '@noble/hashes/legacy.js';
|
||||||
@@ -10,7 +10,7 @@ index 8e49612..d54da85 100644
|
|||||||
const Point = /* @__PURE__ */ (() => secp.Point)();
|
const Point = /* @__PURE__ */ (() => secp.Point)();
|
||||||
const Fn = /* @__PURE__ */ (() => Point.Fn)();
|
const Fn = /* @__PURE__ */ (() => Point.Fn)();
|
||||||
const base58check = /* @__PURE__ */ createBase58check(sha256);
|
const base58check = /* @__PURE__ */ createBase58check(sha256);
|
||||||
@@ -102,7 +103,8 @@ export class HDKey {
|
@@ -112,7 +113,8 @@ export class HDKey {
|
||||||
throw new RangeError('HDKey: seed length must be between 128 and 512 bits; 256 bits is advised, got ' +
|
throw new RangeError('HDKey: seed length must be between 128 and 512 bits; 256 bits is advised, got ' +
|
||||||
seed.length);
|
seed.length);
|
||||||
}
|
}
|
||||||
@@ -20,13 +20,13 @@ index 8e49612..d54da85 100644
|
|||||||
const privateKey = I.slice(0, 32);
|
const privateKey = I.slice(0, 32);
|
||||||
const chainCode = I.slice(32);
|
const chainCode = I.slice(32);
|
||||||
return new HDKey({ versions, chainCode, privateKey });
|
return new HDKey({ versions, chainCode, privateKey });
|
||||||
@@ -225,7 +227,8 @@ export class HDKey {
|
@@ -248,7 +250,8 @@ export class HDKey {
|
||||||
// Normal child: serP(point(kpar)) || ser32(index)
|
// Normal child: serP(point(kpar)) || ser32(index)
|
||||||
data = concatBytes(this._publicKey, data);
|
data = concatBytes(this._publicKey, data);
|
||||||
}
|
}
|
||||||
- const out = _I || hmac(sha512, this.chainCode, data);
|
- const out = _I || hmac(sha512, this._chainCode, data);
|
||||||
+ //const out = _I || hmac(sha512, this.chainCode, data);
|
+ //const out = _I || hmac(sha512, this._chainCode, data);
|
||||||
+ const out = _I || new Uint8Array(quickCrypto.createHmac('sha512', this.chainCode).update(data).digest());
|
+ const out = _I || new Uint8Array(quickCrypto.createHmac('sha512', this._chainCode).update(data).digest());
|
||||||
abytes(out, 64);
|
abytes(out, 64);
|
||||||
const childTweak = out.slice(0, 32);
|
const childTweak = out.slice(0, 32);
|
||||||
const chainCode = out.slice(32);
|
const chainCode = out.slice(32);
|
||||||
@@ -739,6 +739,25 @@ async function _monitorSentProofs(params: {mintUrl: string; proofsToSend: CashuP
|
|||||||
const wsMint = new CashuMint(mintUrl)
|
const wsMint = new CashuMint(mintUrl)
|
||||||
const wsWallet = new CashuWallet(wsMint)
|
const wsWallet = new CashuWallet(wsMint)
|
||||||
|
|
||||||
|
// The websocket is the fast path; the poller is the fallback that has to run
|
||||||
|
// whenever it is not available. Two things must reach it: the subscribe failing
|
||||||
|
// outright, and an ESTABLISHED socket closing later — mints and proxies idle out
|
||||||
|
// long-lived subscriptions. cashu-ts reports the second case through the error
|
||||||
|
// callback (>= 4.11; before that an established subscription just went silent),
|
||||||
|
// so the fallback cannot live in the catch below — that catch has long since
|
||||||
|
// been left by then.
|
||||||
|
let settled = false
|
||||||
|
const startPoller = () => {
|
||||||
|
if (settled) return
|
||||||
|
settled = true
|
||||||
|
poller(
|
||||||
|
`syncStateWithMintPoller-${mintUrl}`,
|
||||||
|
WalletTask.syncStateWithMintQueueAwaitable,
|
||||||
|
{interval: 10 * 1000, maxPolls: 3, maxErrors: 1},
|
||||||
|
{proofsToSync, mintUrl, proofState: 'PENDING' as const},
|
||||||
|
).then(() => log.trace('[SendOperationApi]', 'polling completed', {mintUrl}))
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.trace('[SendOperationApi]', 'Subscribing to proofStateUpdates', {secret: proofsToSend[0]?.secret})
|
log.trace('[SendOperationApi]', 'Subscribing to proofStateUpdates', {secret: proofsToSend[0]?.secret})
|
||||||
const unsub = await wsWallet.on.proofStateUpdates(
|
const unsub = await wsWallet.on.proofStateUpdates(
|
||||||
@@ -747,21 +766,21 @@ async function _monitorSentProofs(params: {mintUrl: string; proofsToSend: CashuP
|
|||||||
log.trace(`[SendOperationApi] Websocket: proof state updated: ${proofState.state} with secret: ${proofsToSend[0].secret}`)
|
log.trace(`[SendOperationApi] Websocket: proof state updated: ${proofState.state} with secret: ${proofsToSend[0].secret}`)
|
||||||
if (proofState.state === CheckStateEnum.SPENT) {
|
if (proofState.state === CheckStateEnum.SPENT) {
|
||||||
WalletTask.syncStateWithMintQueueAwaitable({proofsToSync, mintUrl, proofState: 'PENDING'})
|
WalletTask.syncStateWithMintQueueAwaitable({proofsToSync, mintUrl, proofState: 'PENDING'})
|
||||||
|
settled = true
|
||||||
unsub()
|
unsub()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async (error: any) => {
|
async (error: any) => {
|
||||||
throw error
|
log.warn(
|
||||||
|
'[SendOperationApi] Proof state subscription closed, falling back to poller',
|
||||||
|
{mintUrl, error: error?.message},
|
||||||
|
)
|
||||||
|
startPoller()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
log.error(Err.NETWORK_ERROR, 'WebSocket subscription failed. Starting poller.', error.message)
|
log.error(Err.NETWORK_ERROR, 'WebSocket subscription failed. Starting poller.', error.message)
|
||||||
poller(
|
startPoller()
|
||||||
`syncStateWithMintPoller-${mintUrl}`,
|
|
||||||
WalletTask.syncStateWithMintQueueAwaitable,
|
|
||||||
{interval: 10 * 1000, maxPolls: 3, maxErrors: 1},
|
|
||||||
{proofsToSync, mintUrl, proofState: 'PENDING' as const},
|
|
||||||
).then(() => log.trace('[SendOperationApi]', 'polling completed', {mintUrl}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -585,6 +585,24 @@ async function _monitorMintQuote(params: {
|
|||||||
MintOperationService.enqueuePendingTopupCheck(tx)
|
MintOperationService.enqueuePendingTopupCheck(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The websocket is the fast path; the poller is the fallback that has to run
|
||||||
|
// whenever it is not available. Two things must reach it: the subscribe failing
|
||||||
|
// outright, and an ESTABLISHED socket closing later — mints and proxies idle out
|
||||||
|
// long-lived subscriptions. cashu-ts reports the second case through the error
|
||||||
|
// callback (>= 4.11; before that an established subscription just went silent),
|
||||||
|
// so the fallback cannot live in the catch below — that catch has long since
|
||||||
|
// been left by then.
|
||||||
|
let settled = false
|
||||||
|
const startPoller = () => {
|
||||||
|
if (settled) return
|
||||||
|
settled = true
|
||||||
|
poller(
|
||||||
|
`handlePendingTopupPoller-${paymentHash}`,
|
||||||
|
enqueueRefresh,
|
||||||
|
{interval: 10 * 1000, maxPolls: 6, maxErrors: 2},
|
||||||
|
).then(() => log.trace('[handlePendingTopupPoller] polling completed', {quote}))
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.trace('[TopupOperationApi]', 'Subscribing to mintQuotePaid', {quote})
|
log.trace('[TopupOperationApi]', 'Subscribing to mintQuotePaid', {quote})
|
||||||
const unsub = await wsWallet.on.mintQuotePaid(
|
const unsub = await wsWallet.on.mintQuotePaid(
|
||||||
@@ -598,10 +616,15 @@ async function _monitorMintQuote(params: {
|
|||||||
{transactionId, error: e.message},
|
{transactionId, error: e.message},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
settled = true
|
||||||
unsub()
|
unsub()
|
||||||
},
|
},
|
||||||
async (error: any) => {
|
async (error: any) => {
|
||||||
throw error
|
log.warn(
|
||||||
|
'[TopupOperationApi] Mint quote subscription closed, falling back to poller',
|
||||||
|
{quote, transactionId, error: error?.message},
|
||||||
|
)
|
||||||
|
startPoller()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@@ -610,11 +633,7 @@ async function _monitorMintQuote(params: {
|
|||||||
'[TopupOperationApi] WebSocket error for mint quote, starting poller.',
|
'[TopupOperationApi] WebSocket error for mint quote, starting poller.',
|
||||||
error.message,
|
error.message,
|
||||||
)
|
)
|
||||||
poller(
|
startPoller()
|
||||||
`handlePendingTopupPoller-${paymentHash}`,
|
|
||||||
enqueueRefresh,
|
|
||||||
{interval: 10 * 1000, maxPolls: 6, maxErrors: 2},
|
|
||||||
).then(() => log.trace('[handlePendingTopupPoller] polling completed', {quote}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1340,6 +1340,24 @@ async function _monitorAsyncMeltQuote(params: {
|
|||||||
const wsMint = new CashuMint(mintUrl)
|
const wsMint = new CashuMint(mintUrl)
|
||||||
const wsWallet = new CashuWallet(wsMint)
|
const wsWallet = new CashuWallet(wsMint)
|
||||||
|
|
||||||
|
// The websocket is the fast path; the poller is what actually resolves the tx
|
||||||
|
// when it is not available. Two things must reach it: the subscribe failing
|
||||||
|
// outright, and an ESTABLISHED socket closing later — mints and proxies idle out
|
||||||
|
// long-lived subscriptions, and a melt quote can stay pending for minutes.
|
||||||
|
// cashu-ts reports the second case through the error callback (>= 4.11; before
|
||||||
|
// that an established subscription just went silent), so the fallback cannot
|
||||||
|
// live in the catch below — that catch has long since been left by then.
|
||||||
|
let settled = false
|
||||||
|
const startPoller = () => {
|
||||||
|
if (settled) return
|
||||||
|
settled = true
|
||||||
|
poller(
|
||||||
|
`meltQuotePoller-${quoteId}`,
|
||||||
|
() => refresh(transactionId),
|
||||||
|
{interval: 15 * 1000, maxPolls: 8, maxErrors: 2},
|
||||||
|
).then(() => log.trace('[meltQuotePoller] polling completed', {quoteId}))
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.trace('[TransferOperationApi]', 'Subscribing to meltQuoteUpdates', {quoteId})
|
log.trace('[TransferOperationApi]', 'Subscribing to meltQuoteUpdates', {quoteId})
|
||||||
const unsub = await wsWallet.on.meltQuoteUpdates(
|
const unsub = await wsWallet.on.meltQuoteUpdates(
|
||||||
@@ -1357,11 +1375,16 @@ async function _monitorAsyncMeltQuote(params: {
|
|||||||
{transactionId, error: refreshError.message},
|
{transactionId, error: refreshError.message},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
settled = true
|
||||||
unsub()
|
unsub()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async (error: any) => {
|
async (error: any) => {
|
||||||
throw error
|
log.warn(
|
||||||
|
'[TransferOperationApi] Melt quote subscription closed, falling back to poller',
|
||||||
|
{quoteId, transactionId, error: error?.message},
|
||||||
|
)
|
||||||
|
startPoller()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@@ -1370,11 +1393,7 @@ async function _monitorAsyncMeltQuote(params: {
|
|||||||
'[TransferOperationApi] WebSocket error for async melt, starting poller.',
|
'[TransferOperationApi] WebSocket error for async melt, starting poller.',
|
||||||
error.message,
|
error.message,
|
||||||
)
|
)
|
||||||
poller(
|
startPoller()
|
||||||
`meltQuotePoller-${quoteId}`,
|
|
||||||
() => refresh(transactionId),
|
|
||||||
{interval: 15 * 1000, maxPolls: 8, maxErrors: 2},
|
|
||||||
).then(() => log.trace('[meltQuotePoller] polling completed', {quoteId}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2869,15 +2869,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@cashu/cashu-ts@npm:^4.10.0":
|
"@cashu/cashu-ts@npm:^4.11.0":
|
||||||
version: 4.10.0
|
version: 4.11.0
|
||||||
resolution: "@cashu/cashu-ts@npm:4.10.0"
|
resolution: "@cashu/cashu-ts@npm:4.11.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@noble/curves": ^2.2.0
|
"@noble/curves": ^2.4.0
|
||||||
"@noble/hashes": ^2.2.0
|
"@noble/hashes": ^2.4.0
|
||||||
"@scure/base": ^2.2.0
|
"@scure/base": ^2.4.0
|
||||||
"@scure/bip32": ^2.2.0
|
"@scure/bip32": ^2.4.0
|
||||||
checksum: 55994116585f64acf6078e000ca747e5d082d307779165c9a1aece0803a6d2f1d1c3d9c0c5616cb1b3df8ac12ca2175d03c42f59d08ef3df21ab13c79ecc6b79
|
checksum: 1adfa648fdb36bd6308e600535f6d1a1d258fbaeada371709e42a7aade425dd5ff0eb844bec09a29da79aad226ad7c4377fe3abcab6f8614e0371144ae4a2709
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -5449,12 +5449,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@noble/curves@npm:2.2.0, @noble/curves@npm:^2.2.0":
|
"@noble/curves@npm:2.4.0, @noble/curves@npm:^2.4.0":
|
||||||
version: 2.2.0
|
version: 2.4.0
|
||||||
resolution: "@noble/curves@npm:2.2.0"
|
resolution: "@noble/curves@npm:2.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@noble/hashes": 2.2.0
|
"@noble/hashes": 2.4.0
|
||||||
checksum: 2b6f02c18918578f528791644886f54333c67323f5ccefe10bf250f08760f63786b807390d8d5f8562c661e70dd3559ce8e51e1fe360118c8fd47071c2bd6991
|
checksum: 3e1d2a57efea01bd76cd2e0d711446b67ac4124988f4abe8b4b849f04a9d52b7fa1e7fa7d8ed94151ca31cb09c0bc7e00b77a057a7d99f114a0d45f8ead6d71e
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -5465,10 +5465,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@noble/hashes@npm:2.2.0, @noble/hashes@npm:^2.2.0":
|
"@noble/hashes@npm:2.4.0, @noble/hashes@npm:^2.4.0":
|
||||||
version: 2.2.0
|
version: 2.4.0
|
||||||
resolution: "@noble/hashes@npm:2.2.0"
|
resolution: "@noble/hashes@npm:2.4.0"
|
||||||
checksum: a8745fb5da57a73ddd3dd6d5ad45d156ea664be51ead5344ca1528f8e56ad0ba0720ec8adff3bda37c50c72a86a33a57332ec02c3fb8d2a2612f9c3e5e7079ab
|
checksum: 0eaf273e341c53ebf7de3e6dcc27755c2124da04152549a61580a525929844e05a7799aeeb9a6a46943cde59ff297ebe6d61968669b162577db188c62b948efe
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -6463,10 +6463,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@scure/base@npm:2.2.0, @scure/base@npm:^2.2.0":
|
"@scure/base@npm:2.4.0, @scure/base@npm:^2.4.0":
|
||||||
version: 2.2.0
|
version: 2.4.0
|
||||||
resolution: "@scure/base@npm:2.2.0"
|
resolution: "@scure/base@npm:2.4.0"
|
||||||
checksum: 2dd91f310765366e2dcb5e37709eb35ccd57d3f2f112d36232ca03fb8819c8764708f333ac40935fa719ff2e943bd50e1912ab43d212e44e807100d21f835f13
|
checksum: 95014a31c1c0fc8d70913031535060deac181aef10cd84cacbc0bd394db58df22fd35ce7b14a73d34e158b472094fd92e614613598aa03378ffeb8967b5b007c
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -6481,14 +6481,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@scure/bip32@npm:^2.2.0":
|
"@scure/bip32@npm:^2.4.0":
|
||||||
version: 2.2.0
|
version: 2.4.0
|
||||||
resolution: "@scure/bip32@npm:2.2.0"
|
resolution: "@scure/bip32@npm:2.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@noble/curves": 2.2.0
|
"@noble/curves": 2.4.0
|
||||||
"@noble/hashes": 2.2.0
|
"@noble/hashes": 2.4.0
|
||||||
"@scure/base": 2.2.0
|
"@scure/base": 2.4.0
|
||||||
checksum: 6cd0ddf603b739d3c24a13618fc246d409bbf0dffec22bc2c3c8e3e64271bb58c7078bea0b6ab9601fcfe881a969ee31e3074d478affe13a439d7527a0b68ecf
|
checksum: fabadcab4673e17c3702bca8037f847f0c6e90b7bc751424de740c26f5de432bac957716dbd16fb775005db1701fd6e220cf8adc17a46d5e355b7086969faf39
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -14762,7 +14762,7 @@ __metadata:
|
|||||||
"@babel/plugin-proposal-export-namespace-from": ^7.18.9
|
"@babel/plugin-proposal-export-namespace-from": ^7.18.9
|
||||||
"@babel/preset-env": ^7.25.3
|
"@babel/preset-env": ^7.25.3
|
||||||
"@babel/runtime": ^7.25.0
|
"@babel/runtime": ^7.25.0
|
||||||
"@cashu/cashu-ts": ^4.10.0
|
"@cashu/cashu-ts": ^4.11.0
|
||||||
"@expo/fingerprint": ^0.13.4
|
"@expo/fingerprint": ^0.13.4
|
||||||
"@fortawesome/fontawesome-svg-core": ^7.1.0
|
"@fortawesome/fontawesome-svg-core": ^7.1.0
|
||||||
"@fortawesome/free-brands-svg-icons": ^7.1.0
|
"@fortawesome/free-brands-svg-icons": ^7.1.0
|
||||||
@@ -14794,7 +14794,7 @@ __metadata:
|
|||||||
"@react-navigation/native": ^7.1.18
|
"@react-navigation/native": ^7.1.18
|
||||||
"@react-navigation/native-stack": ^7.3.27
|
"@react-navigation/native-stack": ^7.3.27
|
||||||
"@react-navigation/stack": ^7.4.9
|
"@react-navigation/stack": ^7.4.9
|
||||||
"@scure/bip32": ^2.2.0
|
"@scure/bip32": ^2.4.0
|
||||||
"@scure/bip39": 2.0.1
|
"@scure/bip39": 2.0.1
|
||||||
"@sentry/cli": ^2.56.0
|
"@sentry/cli": ^2.56.0
|
||||||
"@sentry/react-native": ^7.7.0
|
"@sentry/react-native": ^7.7.0
|
||||||
|
|||||||
Reference in New Issue
Block a user