mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-10-05 19:28:26 +00:00
v3 broken
This commit is contained in:
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
019b98cc-e66d-7947-b6a6-e253c1830c03
|
|
||||||
@@ -8,7 +8,46 @@ const { withSentryConfig } = require("@sentry/react-native/metro");
|
|||||||
* @type {import('@react-native/metro-config').MetroConfig}
|
* @type {import('@react-native/metro-config').MetroConfig}
|
||||||
*/
|
*/
|
||||||
const config = {
|
const config = {
|
||||||
|
resolver: {
|
||||||
|
// Ensure Metro can resolve .cjs files (CommonJS modules)
|
||||||
|
sourceExts: ['jsx', 'js', 'ts', 'tsx', 'json', 'cjs'],
|
||||||
|
// Workaround for Unicode character issues in @noble/curves
|
||||||
|
// Files with Greek letters (β, α) cause "Property β does not exist" errors in Hermes
|
||||||
|
/*resolveRequest: (context, moduleName, platform) => {
|
||||||
|
// Force cashu-ts to use pre-built CJS bundle
|
||||||
|
if (moduleName === '@cashu/cashu-ts') {
|
||||||
|
return {
|
||||||
|
filePath: context.resolveRequest(context, '@cashu/cashu-ts/lib/cashu-ts.cjs', platform).filePath,
|
||||||
|
type: 'sourceFile',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block problematic @noble/curves files that contain Unicode characters
|
||||||
|
// Allow only essential modules needed for secp256k1
|
||||||
|
if (moduleName.startsWith('@noble/curves/')) {
|
||||||
|
const allowed = [
|
||||||
|
'secp256k1',
|
||||||
|
'abstract/modular',
|
||||||
|
'abstract/weierstrass',
|
||||||
|
'_shortw_utils',
|
||||||
|
'utils'
|
||||||
|
];
|
||||||
|
const isAllowed = allowed.some(path => moduleName.includes(path));
|
||||||
|
|
||||||
|
if (!isAllowed) {
|
||||||
|
// Return empty stub for blocked imports (contains Unicode chars incompatible with Hermes)
|
||||||
|
const stubPath = require('path').resolve(__dirname, 'node_modules/.metro-stub.js');
|
||||||
|
return {
|
||||||
|
filePath: stubPath,
|
||||||
|
type: 'sourceFile',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default resolution
|
||||||
|
return context.resolveRequest(context, moduleName, platform);
|
||||||
|
},*/
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withSentryConfig(mergeConfig(getDefaultConfig(__dirname), config));
|
module.exports = withSentryConfig(mergeConfig(getDefaultConfig(__dirname), config));
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "minibits_wallet",
|
"name": "minibits_wallet",
|
||||||
"version": "0.3.4-beta.13",
|
"version": "0.3.4-beta.14",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android:clean": "cd android && ./gradlew clean",
|
"android:clean": "cd android && ./gradlew clean",
|
||||||
@@ -21,7 +21,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": "minibits-cash/cashu-ts#e97b1a4ee9a7ddbb1468302c6996a9d6d3efcb6f",
|
"@cashu/cashu-ts": "3.2.2",
|
||||||
"@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",
|
||||||
|
|||||||
@@ -1,53 +1,36 @@
|
|||||||
diff --git a/node_modules/@scure/bip32/index.ts b/node_modules/@scure/bip32/index.ts
|
diff --git a/node_modules/@scure/bip32/lib/esm/index.js b/node_modules/@scure/bip32/lib/esm/index.js
|
||||||
index 0c9c91c..14c9ae2 100644
|
index ea306d0..c0ed23e 100644
|
||||||
--- a/node_modules/@scure/bip32/index.ts
|
--- a/node_modules/@scure/bip32/lib/esm/index.js
|
||||||
+++ b/node_modules/@scure/bip32/index.ts
|
+++ b/node_modules/@scure/bip32/lib/esm/index.js
|
||||||
@@ -25,6 +25,7 @@ import { bytesToHex, concatBytes, createView, hexToBytes, utf8ToBytes } from '@n
|
@@ -25,6 +25,8 @@ import { bytesToHex, concatBytes, createView, hexToBytes, utf8ToBytes } from '@n
|
||||||
import { secp256k1 as secp } from '@noble/curves/secp256k1';
|
import { secp256k1 as secp } from '@noble/curves/secp256k1';
|
||||||
import { mod } from '@noble/curves/abstract/modular';
|
import { mod } from '@noble/curves/abstract/modular';
|
||||||
import { createBase58check } from '@scure/base';
|
import { createBase58check } from '@scure/base';
|
||||||
+import QuickCrypto from 'react-native-quick-crypto';
|
+import quickCrypto from 'react-native-quick-crypto'
|
||||||
|
+
|
||||||
const Point = secp.ProjectivePoint;
|
const Point = secp.ProjectivePoint;
|
||||||
const base58check = createBase58check(sha256);
|
const base58check = createBase58check(sha256);
|
||||||
@@ -114,7 +115,8 @@ export class HDKey {
|
function bytesToNumber(bytes) {
|
||||||
seed.length
|
@@ -89,7 +91,9 @@ export class HDKey {
|
||||||
);
|
throw new Error('HDKey: seed length must be between 128 and 512 bits; 256 bits is advised, got ' +
|
||||||
}
|
seed.length);
|
||||||
- const I = hmac(sha512, MASTER_SECRET, seed);
|
}
|
||||||
+ // const I = hmac(sha512, MASTER_SECRET, seed);
|
- const I = hmac(sha512, MASTER_SECRET, seed);
|
||||||
+ const I = new Uint8Array(QuickCrypto.createHmac('sha512', MASTER_SECRET).update(seed).digest());
|
+ // const I = hmac(sha512, MASTER_SECRET, seed);
|
||||||
return new HDKey({
|
+ console.log('[bip32.fromMasterSeed] Using ESM quickCrypto HMAC');
|
||||||
versions,
|
+ const I = new Uint8Array(quickCrypto.createHmac('sha512', MASTER_SECRET).update(seed).digest());
|
||||||
chainCode: I.slice(32),
|
return new HDKey({
|
||||||
@@ -237,7 +239,8 @@ export class HDKey {
|
versions,
|
||||||
// Normal child: serP(point(kpar)) || ser32(index)
|
chainCode: I.slice(32),
|
||||||
data = concatBytes(this.pubKey, data);
|
@@ -206,7 +210,10 @@ export class HDKey {
|
||||||
}
|
// Normal child: serP(point(kpar)) || ser32(index)
|
||||||
- const I = hmac(sha512, this.chainCode, data);
|
data = concatBytes(this.pubKey, data);
|
||||||
+ //const I = hmac(sha512, this.chainCode, data);
|
}
|
||||||
+ const I = new Uint8Array(QuickCrypto.createHmac('sha512', this.chainCode).update(data).digest())
|
- const I = hmac(sha512, this.chainCode, data);
|
||||||
const childTweak = bytesToNumber(I.slice(0, 32));
|
+ // const I = hmac(sha512, this.chainCode, data);
|
||||||
const chainCode = I.slice(32);
|
+ console.log('[bip32.deriveChild] Using ESM quickCrypto HMAC');
|
||||||
if (!secp.utils.isValidPrivateKey(childTweak)) {
|
+ const I = new Uint8Array(quickCrypto.createHmac('sha512', this.chainCode).update(data).digest())
|
||||||
diff --git a/node_modules/@scure/bip32/package.json b/node_modules/@scure/bip32/package.json
|
+
|
||||||
index e866fba..6389575 100644
|
const childTweak = bytesToNumber(I.slice(0, 32));
|
||||||
--- a/node_modules/@scure/bip32/package.json
|
const chainCode = I.slice(32);
|
||||||
+++ b/node_modules/@scure/bip32/package.json
|
if (!secp.utils.isValidPrivateKey(childTweak)) {
|
||||||
@@ -6,15 +6,8 @@
|
|
||||||
"index.ts",
|
|
||||||
"./lib"
|
|
||||||
],
|
|
||||||
- "main": "./lib/index.js",
|
|
||||||
- "module": "./lib/esm/index.js",
|
|
||||||
+ "main": "./index.ts",
|
|
||||||
"types": "./lib/index.d.ts",
|
|
||||||
- "exports": {
|
|
||||||
- ".": {
|
|
||||||
- "import": "./lib/esm/index.js",
|
|
||||||
- "require": "./lib/index.js"
|
|
||||||
- }
|
|
||||||
- },
|
|
||||||
"dependencies": {
|
|
||||||
"@noble/curves": "~1.8.1",
|
|
||||||
"@noble/hashes": "~1.7.1",
|
|
||||||
|
|||||||
@@ -1,5 +1,26 @@
|
|||||||
|
diff --git a/node_modules/@scure/bip39/esm/index.js b/node_modules/@scure/bip39/esm/index.js
|
||||||
|
index d5734b0..deb1491 100644
|
||||||
|
--- a/node_modules/@scure/bip39/esm/index.js
|
||||||
|
+++ b/node_modules/@scure/bip39/esm/index.js
|
||||||
|
@@ -32,6 +32,7 @@ import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
|
||||||
|
import { sha256, sha512 } from '@noble/hashes/sha2';
|
||||||
|
import { abytes, anumber, randomBytes } from '@noble/hashes/utils';
|
||||||
|
import { utils as baseUtils } from '@scure/base';
|
||||||
|
+import quickCrypto from 'react-native-quick-crypto'
|
||||||
|
// Japanese wordlist
|
||||||
|
const isJapanese = (wordlist) => wordlist[0] === '\u3042\u3044\u3053\u304f\u3057\u3093';
|
||||||
|
// Normalization replaces equivalent sequences of characters
|
||||||
|
@@ -157,5 +158,7 @@ export function mnemonicToSeed(mnemonic, passphrase = '') {
|
||||||
|
* // new Uint8Array([...64 bytes])
|
||||||
|
*/
|
||||||
|
export function mnemonicToSeedSync(mnemonic, passphrase = '') {
|
||||||
|
- return pbkdf2(sha512, normalize(mnemonic).nfkd, psalt(passphrase), { c: 2048, dkLen: 64 });
|
||||||
|
+ console.log('[bip39.mnemonicToSeedSync] Using ESM quickCrypto PBKDF2 Sync');
|
||||||
|
+ return new Uint8Array(quickCrypto.pbkdf2Sync(normalize(mnemonic).nfkd, psalt(passphrase), 2048, 64, 'sha512'));
|
||||||
|
+ //return pbkdf2(sha512, normalize(mnemonic).nfkd, psalt(passphrase), { c: 2048, dkLen: 64 });
|
||||||
|
}
|
||||||
diff --git a/node_modules/@scure/bip39/src/index.ts b/node_modules/@scure/bip39/src/index.ts
|
diff --git a/node_modules/@scure/bip39/src/index.ts b/node_modules/@scure/bip39/src/index.ts
|
||||||
index 4284c3e..6ff83b2 100644
|
index 4284c3e..71e39e9 100644
|
||||||
--- a/node_modules/@scure/bip39/src/index.ts
|
--- a/node_modules/@scure/bip39/src/index.ts
|
||||||
+++ b/node_modules/@scure/bip39/src/index.ts
|
+++ b/node_modules/@scure/bip39/src/index.ts
|
||||||
@@ -33,6 +33,7 @@ import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
|
@@ -33,6 +33,7 @@ import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
|
||||||
@@ -16,7 +37,7 @@ index 4284c3e..6ff83b2 100644
|
|||||||
export function mnemonicToSeedSync(mnemonic: string, passphrase = ''): Uint8Array {
|
export function mnemonicToSeedSync(mnemonic: string, passphrase = ''): Uint8Array {
|
||||||
- return pbkdf2(sha512, normalize(mnemonic).nfkd, psalt(passphrase), { c: 2048, dkLen: 64 });
|
- return pbkdf2(sha512, normalize(mnemonic).nfkd, psalt(passphrase), { c: 2048, dkLen: 64 });
|
||||||
+ // return pbkdf2(sha512, normalize(mnemonic).nfkd, psalt(passphrase), { c: 2048, dkLen: 64 });
|
+ // return pbkdf2(sha512, normalize(mnemonic).nfkd, psalt(passphrase), { c: 2048, dkLen: 64 });
|
||||||
+
|
+ console.log('[mnemonicToSeedSync] Using TS quickCrypto PBKDF2 Sync');
|
||||||
+ const updated = new Uint8Array(QuickCrypto.pbkdf2Sync(normalize(mnemonic).nfkd, psalt(passphrase), 2048, 64, 'sha512'));
|
+ const updated = new Uint8Array(QuickCrypto.pbkdf2Sync(normalize(mnemonic).nfkd, psalt(passphrase), 2048, 64, 'sha512'));
|
||||||
+ // console.log('[@scure.bip39.mnemonicToSeedSync] Patched to use QuickCrypto.pbkdf2Sync')
|
+ // console.log('[@scure.bip39.mnemonicToSeedSync] Patched to use QuickCrypto.pbkdf2Sync')
|
||||||
+ return updated
|
+ return updated
|
||||||
|
|||||||
+7
-6
@@ -97,6 +97,12 @@ function App() {
|
|||||||
|
|
||||||
if (isInternetReachable === true) {
|
if (isInternetReachable === true) {
|
||||||
|
|
||||||
|
if(userSettingsStore.isOnboarded === false) {
|
||||||
|
log.trace('[App] User not onboarded → new install, skipping device re-enrollment')
|
||||||
|
setIsDeviceAuthenticated(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if(authStore.isRefreshTokenExpired) {
|
if(authStore.isRefreshTokenExpired) {
|
||||||
log.trace('[App] Network is online and refresh token expired → attempting device re-enrollment')
|
log.trace('[App] Network is online and refresh token expired → attempting device re-enrollment')
|
||||||
|
|
||||||
@@ -110,12 +116,7 @@ function App() {
|
|||||||
|
|
||||||
log.trace('[App] Device re-enrollment successful')
|
log.trace('[App] Device re-enrollment successful')
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.name !== Err.NOTFOUND_ERROR) {
|
log.error('[App] Device re-enrollment failed', { message: e.message })
|
||||||
log.error('[App] Device re-enrollment failed', { message: e.message })
|
|
||||||
} else {
|
|
||||||
// Expected on fresh install
|
|
||||||
userSettingsStore.setIsOnboarded(false)
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
// Always unblock the app
|
// Always unblock the app
|
||||||
setIsDeviceAuthenticated(true)
|
setIsDeviceAuthenticated(true)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { View, ScrollView, LayoutAnimation, Platform, UIManager, ViewStyle } fro
|
|||||||
import { BottomModal, Button, Icon, ListItem, Text } from '../components'
|
import { BottomModal, Button, Icon, ListItem, Text } from '../components'
|
||||||
import AppError, { Err } from '../utils/AppError'
|
import AppError, { Err } from '../utils/AppError'
|
||||||
import { spacing, useThemeColor, colors } from '../theme'
|
import { spacing, useThemeColor, colors } from '../theme'
|
||||||
import { isObj } from '@cashu/cashu-ts/src/utils'
|
import { CashuUtils } from '../services/cashu/cashuUtils'
|
||||||
import JSONTree from 'react-native-json-tree'
|
import JSONTree from 'react-native-json-tree'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import { useStores } from '../models'
|
import { useStores } from '../models'
|
||||||
@@ -85,7 +85,7 @@ export const ErrorModal: FC<ErrorModalProps> = function ({ error }) {
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{error.params && isObj(error.params) && (
|
{error.params && CashuUtils.isObj(error.params) && (
|
||||||
<>
|
<>
|
||||||
{isParamsVisible ? (
|
{isParamsVisible ? (
|
||||||
<>
|
<>
|
||||||
|
|||||||
+2
-2
@@ -4,7 +4,7 @@ import {
|
|||||||
type GetInfoResponse,
|
type GetInfoResponse,
|
||||||
type MintKeys as CashuMintKeys,
|
type MintKeys as CashuMintKeys,
|
||||||
type MintKeyset as CashuMintKeyset,
|
type MintKeyset as CashuMintKeyset,
|
||||||
CashuMint,
|
Mint as CashuMint,
|
||||||
} from '@cashu/cashu-ts'
|
} from '@cashu/cashu-ts'
|
||||||
import {colors, getRandomIconColor} from '../theme'
|
import {colors, getRandomIconColor} from '../theme'
|
||||||
import { log } from '../services'
|
import { log } from '../services'
|
||||||
@@ -16,7 +16,7 @@ import { generateId } from '../utils/utils'
|
|||||||
import { Proof } from './Proof'
|
import { Proof } from './Proof'
|
||||||
import { CashuProof, CashuUtils } from '../services/cashu/cashuUtils'
|
import { CashuProof, CashuUtils } from '../services/cashu/cashuUtils'
|
||||||
|
|
||||||
|
ß
|
||||||
export type MintBalance = {
|
export type MintBalance = {
|
||||||
mintUrl: string
|
mintUrl: string
|
||||||
balances: {
|
balances: {
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ import {
|
|||||||
import {log} from '../services/logService'
|
import {log} from '../services/logService'
|
||||||
import AppError, { Err } from '../utils/AppError'
|
import AppError, { Err } from '../utils/AppError'
|
||||||
import {
|
import {
|
||||||
CashuMint,
|
Mint as CashuMint,
|
||||||
|
GetKeysetsResponse,
|
||||||
|
GetKeysResponse,
|
||||||
MintActiveKeys,
|
MintActiveKeys,
|
||||||
MintAllKeysets,
|
MintAllKeysets,
|
||||||
type MintKeys as CashuMintKeys,
|
type MintKeys as CashuMintKeys,
|
||||||
@@ -124,8 +126,8 @@ export const MintsStoreModel = types
|
|||||||
|
|
||||||
const newMint = new CashuMint(mintUrl)
|
const newMint = new CashuMint(mintUrl)
|
||||||
// get fresh keysets
|
// get fresh keysets
|
||||||
const keySetResult: MintAllKeysets = yield newMint.getKeySets()
|
const keySetResult: GetKeysetsResponse = yield newMint.getKeySets()
|
||||||
const keysResult: MintActiveKeys = yield newMint.getKeys()
|
const keysResult: GetKeysResponse = yield newMint.getKeys()
|
||||||
const {keysets} = keySetResult
|
const {keysets} = keySetResult
|
||||||
const {keysets: keys} = keysResult
|
const {keysets: keys} = keysResult
|
||||||
|
|
||||||
|
|||||||
@@ -321,6 +321,14 @@ import {
|
|||||||
Database.updateProofsMintUrl(currentMintUrl, updatedMintUrl)
|
Database.updateProofsMintUrl(currentMintUrl, updatedMintUrl)
|
||||||
log.trace('[updateMintUrl] Updated mint URL in proofs')
|
log.trace('[updateMintUrl] Updated mint URL in proofs')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Action for importing proofs from backup without validation or side effects
|
||||||
|
importProofs(proofs: Proof[]) {
|
||||||
|
for (const proof of proofs) {
|
||||||
|
self.proofs.put(ProofModel.create(proof))
|
||||||
|
}
|
||||||
|
log.trace('[importProofs]', `Imported ${proofs.length} proofs from backup`)
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// ───────────────────── DERIVED VIEWS ─────────────────────
|
// ───────────────────── DERIVED VIEWS ─────────────────────
|
||||||
|
|||||||
+80
-43
@@ -1,20 +1,20 @@
|
|||||||
import {Instance, SnapshotOut, types, flow, getRoot, getSnapshot} from 'mobx-state-tree'
|
import {Instance, SnapshotOut, types, flow, getRoot, getSnapshot} from 'mobx-state-tree'
|
||||||
import {
|
import {
|
||||||
CashuMint,
|
Mint as CashuMint,
|
||||||
CashuWallet,
|
Wallet as CashuWallet,
|
||||||
MeltQuoteResponse,
|
MeltQuoteBolt11Response,
|
||||||
setGlobalRequestOptions,
|
setGlobalRequestOptions,
|
||||||
type MintKeys,
|
type MintKeys,
|
||||||
type MintKeyset,
|
type MintKeyset,
|
||||||
MintAllKeysets,
|
|
||||||
MintActiveKeys,
|
|
||||||
Token,
|
Token,
|
||||||
MeltProofsResponse,
|
MeltProofsResponse,
|
||||||
CheckStateEnum,
|
CheckStateEnum,
|
||||||
OutputAmounts,
|
GetKeysetsResponse,
|
||||||
MintQuoteResponse,
|
GetKeysResponse,
|
||||||
|
MintQuoteBolt11Response,
|
||||||
|
type ProofState,
|
||||||
|
type OperationCounters,
|
||||||
} from '@cashu/cashu-ts'
|
} from '@cashu/cashu-ts'
|
||||||
import { isObj } from '@cashu/cashu-ts/src/utils'
|
|
||||||
import { JS_BUNDLE_VERSION } from '@env'
|
import { JS_BUNDLE_VERSION } from '@env'
|
||||||
import {KeyChain, MinibitsClient, WalletKeys} from '../services'
|
import {KeyChain, MinibitsClient, WalletKeys} from '../services'
|
||||||
import {log} from '../services/logService'
|
import {log} from '../services/logService'
|
||||||
@@ -25,7 +25,6 @@ import { Proof } from './Proof'
|
|||||||
|
|
||||||
import { InFlightRequest, Mint } from './Mint'
|
import { InFlightRequest, Mint } from './Mint'
|
||||||
import { getRootStore } from './helpers/getRootStore'
|
import { getRootStore } from './helpers/getRootStore'
|
||||||
import { getUnixTime } from 'date-fns/getUnixTime'
|
|
||||||
|
|
||||||
//refresh
|
//refresh
|
||||||
/*
|
/*
|
||||||
@@ -43,7 +42,6 @@ export type ReceiveParams = {
|
|||||||
token: string | Token,
|
token: string | Token,
|
||||||
options?: {
|
options?: {
|
||||||
keysetId?: string;
|
keysetId?: string;
|
||||||
outputAmounts?: OutputAmounts;
|
|
||||||
proofsWeHave?: Array<CashuProof>;
|
proofsWeHave?: Array<CashuProof>;
|
||||||
counter?: number;
|
counter?: number;
|
||||||
pubkey?: string;
|
pubkey?: string;
|
||||||
@@ -57,7 +55,6 @@ export type SendParams = {
|
|||||||
amount: number,
|
amount: number,
|
||||||
proofs: Array<CashuProof>,
|
proofs: Array<CashuProof>,
|
||||||
options?: {
|
options?: {
|
||||||
outputAmounts?: OutputAmounts;
|
|
||||||
proofsWeHave?: Array<CashuProof>;
|
proofsWeHave?: Array<CashuProof>;
|
||||||
counter?: number;
|
counter?: number;
|
||||||
pubkey?: string;
|
pubkey?: string;
|
||||||
@@ -76,7 +73,6 @@ export type MintParams = {
|
|||||||
quote: string,
|
quote: string,
|
||||||
options?: {
|
options?: {
|
||||||
keysetId?: string;
|
keysetId?: string;
|
||||||
outputAmounts?: OutputAmounts;
|
|
||||||
proofsWeHave?: Array<CashuProof>;
|
proofsWeHave?: Array<CashuProof>;
|
||||||
counter?: number;
|
counter?: number;
|
||||||
pubkey?: string;
|
pubkey?: string;
|
||||||
@@ -85,7 +81,7 @@ export type MintParams = {
|
|||||||
|
|
||||||
|
|
||||||
export type MeltParams = {
|
export type MeltParams = {
|
||||||
meltQuote: MeltQuoteResponse,
|
meltQuote: MeltQuoteBolt11Response,
|
||||||
proofsToSend: Array<CashuProof>,
|
proofsToSend: Array<CashuProof>,
|
||||||
options?: {
|
options?: {
|
||||||
keysetId?: string;
|
keysetId?: string;
|
||||||
@@ -208,7 +204,7 @@ export const WalletStoreModel = types
|
|||||||
const mint = self.mints.find(m => m.mintUrl === mintUrl)
|
const mint = self.mints.find(m => m.mintUrl === mintUrl)
|
||||||
|
|
||||||
if (mint) {
|
if (mint) {
|
||||||
return mint
|
return mint as CashuMint
|
||||||
}
|
}
|
||||||
|
|
||||||
setGlobalRequestOptions({
|
setGlobalRequestOptions({
|
||||||
@@ -255,7 +251,7 @@ export const WalletStoreModel = types
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
// syncs mint model in wallet state and returns cashu-ts mint class instance
|
// syncs mint model in wallet state and returns cashu-ts mint class instance
|
||||||
const cashuMint = yield self.getMint(mintUrl)
|
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
||||||
|
|
||||||
// get uptodate mint model from wallet state
|
// get uptodate mint model from wallet state
|
||||||
const mintInstance = self.getMintModelInstance(mintUrl)
|
const mintInstance = self.getMintModelInstance(mintUrl)
|
||||||
@@ -315,7 +311,7 @@ export const WalletStoreModel = types
|
|||||||
|
|
||||||
if (seedWallet) {
|
if (seedWallet) {
|
||||||
log.trace('[WalletStore.getWallet]', 'Returning CACHED cashuWallet instance with seed', {mintUrl})
|
log.trace('[WalletStore.getWallet]', 'Returning CACHED cashuWallet instance with seed', {mintUrl})
|
||||||
return seedWallet
|
return seedWallet as CashuWallet
|
||||||
}
|
}
|
||||||
|
|
||||||
const seed = yield self.getCachedSeed()
|
const seed = yield self.getCachedSeed()
|
||||||
@@ -324,13 +320,13 @@ export const WalletStoreModel = types
|
|||||||
unit,
|
unit,
|
||||||
keys: mintInstance.keys,
|
keys: mintInstance.keys,
|
||||||
keysets: mintInstance.keysets,
|
keysets: mintInstance.keysets,
|
||||||
|
keysetId: walletKeys.id,
|
||||||
bip39seed: seed
|
bip39seed: seed
|
||||||
})
|
})
|
||||||
|
|
||||||
// Load uptodate mint info to wallet.mintInfo (NUTS support etc)
|
// Load uptodate mint info to wallet.mintInfo (NUTS support etc)
|
||||||
yield newSeedWallet.getMintInfo()
|
yield newSeedWallet.loadMint()
|
||||||
|
|
||||||
newSeedWallet.keysetId = walletKeys.id
|
|
||||||
self.seedWallets.push(newSeedWallet)
|
self.seedWallets.push(newSeedWallet)
|
||||||
|
|
||||||
log.trace('[WalletStore.getWallet]', 'Returning NEW cashuWallet instance with seed', {mintUrl})
|
log.trace('[WalletStore.getWallet]', 'Returning NEW cashuWallet instance with seed', {mintUrl})
|
||||||
@@ -352,10 +348,10 @@ export const WalletStoreModel = types
|
|||||||
unit,
|
unit,
|
||||||
keys: mintInstance.keys,
|
keys: mintInstance.keys,
|
||||||
keysets: mintInstance.keysets,
|
keysets: mintInstance.keysets,
|
||||||
|
keysetId: walletKeys.id,
|
||||||
bip39seed: undefined
|
bip39seed: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
newWallet.keysetId = walletKeys.id
|
|
||||||
self.wallets.push(newWallet)
|
self.wallets.push(newWallet)
|
||||||
|
|
||||||
log.trace('[WalletStore.getWallet]', 'Returning NEW cashuWallet instance', {mintUrl})
|
log.trace('[WalletStore.getWallet]', 'Returning NEW cashuWallet instance', {mintUrl})
|
||||||
@@ -365,7 +361,7 @@ export const WalletStoreModel = types
|
|||||||
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {keysets} = yield cashuMint.getKeySets() as Promise<MintAllKeysets> // all keysets
|
const {keysets} = yield cashuMint.getKeySets() as Promise<GetKeysetsResponse> // all keysets
|
||||||
return keysets as MintKeyset[]
|
return keysets as MintKeyset[]
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
let message = 'Could not connect to the selected mint.'
|
let message = 'Could not connect to the selected mint.'
|
||||||
@@ -377,7 +373,7 @@ export const WalletStoreModel = types
|
|||||||
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {keysets} = yield cashuMint.getKeys() as Promise<MintActiveKeys> // all active keys
|
const {keysets} = yield cashuMint.getKeys() as Promise<GetKeysResponse> // all active keys
|
||||||
return keysets as MintKeys[]
|
return keysets as MintKeys[]
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
let message = 'Could not connect to the selected mint.'
|
let message = 'Could not connect to the selected mint.'
|
||||||
@@ -449,7 +445,7 @@ export const WalletStoreModel = types
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cashuWallet.mintInfo.nuts['19'] && !options?.inFlightRequest) {
|
if(cashuWallet.getMintInfo().nuts['19'] && !options?.inFlightRequest) {
|
||||||
currentCounter.addInFlightRequest(transactionId, receiveParams)
|
currentCounter.addInFlightRequest(transactionId, receiveParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +536,7 @@ export const WalletStoreModel = types
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cashuWallet.mintInfo.nuts['19'] && !options?.inFlightRequest) {
|
if(cashuWallet.getMintInfo().nuts['19'] && !options?.inFlightRequest) {
|
||||||
currentCounter.addInFlightRequest(transactionId, sendParams)
|
currentCounter.addInFlightRequest(transactionId, sendParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,7 +593,27 @@ export const WalletStoreModel = types
|
|||||||
log.trace('[WalletStore.getProofsStatesFromMint] start', {mintUrl, unit})
|
log.trace('[WalletStore.getProofsStatesFromMint] start', {mintUrl, unit})
|
||||||
|
|
||||||
const cashuWallet: CashuWallet = yield self.getWallet(mintUrl, unit, {withSeed: false})
|
const cashuWallet: CashuWallet = yield self.getWallet(mintUrl, unit, {withSeed: false})
|
||||||
const proofsByState: {[key in CheckStateEnum]: CashuProof[]} = yield cashuWallet.checkProofsStates(proofs)
|
|
||||||
|
// v3.x returns ProofState[] array, not grouped by state
|
||||||
|
const proofStatesArray: ProofState[] = yield cashuWallet.checkProofsStates(proofs)
|
||||||
|
|
||||||
|
// Transform array into grouped structure expected by the rest of the code
|
||||||
|
// Map proof states back to original proofs using secret matching
|
||||||
|
const proofsByState: {[key in CheckStateEnum]: CashuProof[]} = {
|
||||||
|
SPENT: [],
|
||||||
|
PENDING: [],
|
||||||
|
UNSPENT: []
|
||||||
|
}
|
||||||
|
|
||||||
|
// proofStatesArray is returned in the same order as input proofs
|
||||||
|
for (let i = 0; i < proofStatesArray.length; i++) {
|
||||||
|
const proofState = proofStatesArray[i]
|
||||||
|
const originalProof = proofs[i]
|
||||||
|
|
||||||
|
if (originalProof) {
|
||||||
|
proofsByState[proofState.state].push(originalProof as CashuProof)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.trace('[WalletStore.getProofsStatesFromMint]', {mintUrl, proofsByState})
|
log.trace('[WalletStore.getProofsStatesFromMint]', {mintUrl, proofsByState})
|
||||||
|
|
||||||
@@ -625,7 +641,7 @@ export const WalletStoreModel = types
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const cashuMint = yield self.getMint(mintUrl)
|
const cashuMint = yield self.getMint(mintUrl)
|
||||||
const mintQuoteResponse: MintQuoteResponse = yield cashuMint.createMintQuote({
|
const mintQuoteResponse: MintQuoteBolt11Response = yield cashuMint.createMintQuoteBolt11({
|
||||||
unit,
|
unit,
|
||||||
amount,
|
amount,
|
||||||
description
|
description
|
||||||
@@ -657,7 +673,7 @@ export const WalletStoreModel = types
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
||||||
const quoteResponse: MintQuoteResponse = yield cashuMint.checkMintQuote(
|
const quoteResponse: MintQuoteBolt11Response = yield cashuMint.checkMintQuoteBolt11(
|
||||||
quote
|
quote
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -700,7 +716,7 @@ export const WalletStoreModel = types
|
|||||||
throw new AppError(Err.VALIDATION_ERROR, 'Missing mint instance', {mintUrl})
|
throw new AppError(Err.VALIDATION_ERROR, 'Missing mint instance', {mintUrl})
|
||||||
}
|
}
|
||||||
|
|
||||||
const cashuWallet = yield self.getWallet(
|
const cashuWallet: CashuWallet = yield self.getWallet(
|
||||||
mintUrl,
|
mintUrl,
|
||||||
unit,
|
unit,
|
||||||
{
|
{
|
||||||
@@ -717,29 +733,51 @@ export const WalletStoreModel = types
|
|||||||
|
|
||||||
log.debug('[WalletStore.mintProofs] counter', currentCounter.counter)
|
log.debug('[WalletStore.mintProofs] counter', currentCounter.counter)
|
||||||
|
|
||||||
|
// Sync wallet's internal counter with our stored counter (v3.x)
|
||||||
|
yield cashuWallet.counters.advanceToAtLeast(cashuWallet.keysetId, currentCounter.counter)
|
||||||
|
|
||||||
const mintParams: MintParams = options?.inFlightRequest?.request || {
|
const mintParams: MintParams = options?.inFlightRequest?.request || {
|
||||||
amount,
|
amount,
|
||||||
quote: mintQuote,
|
quote: mintQuote,
|
||||||
options: {
|
options: {
|
||||||
keysetId: cashuWallet.keysetId,
|
keysetId: cashuWallet.keysetId
|
||||||
counter: currentCounter.counter
|
// Note: counter is no longer passed in v3.x, wallet manages it internally
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cashuWallet.mintInfo.nuts['19'] && !options?.inFlightRequest) {
|
if(cashuWallet.getMintInfo().nuts['19'] && !options?.inFlightRequest) {
|
||||||
currentCounter.addInFlightRequest(transactionId, mintParams)
|
currentCounter.addInFlightRequest(transactionId, mintParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reservedCounters: OperationCounters | undefined = undefined
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const proofs = yield cashuWallet.mintProofs(
|
const proofs = yield cashuWallet.mintProofsBolt11(
|
||||||
mintParams.amount,
|
mintParams.amount,
|
||||||
mintParams.quote,
|
mintParams.quote,
|
||||||
mintParams.options
|
{
|
||||||
|
keysetId: mintParams.options?.keysetId,
|
||||||
|
onCountersReserved: (info) => {
|
||||||
|
reservedCounters = info as OperationCounters
|
||||||
|
log.debug('[mintProofsBolt11] Counters reserved', info)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
currentCounter.removeInFlightRequest(transactionId)
|
currentCounter.removeInFlightRequest(transactionId)
|
||||||
|
|
||||||
|
// Update our counter to match what the wallet used (v3.x)
|
||||||
|
if (reservedCounters) {
|
||||||
|
currentCounter.counter = reservedCounters.next
|
||||||
|
log.debug('[mintProofs] Updated counter', {
|
||||||
|
keysetId: reservedCounters.keysetId,
|
||||||
|
start: reservedCounters.start,
|
||||||
|
count: reservedCounters.count,
|
||||||
|
next: reservedCounters.next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
log.debug('[mintProofs]', {amount: mintParams.amount, quote: mintParams.quote, proofs})
|
log.debug('[mintProofs]', {amount: mintParams.amount, quote: mintParams.quote, proofs})
|
||||||
|
|
||||||
return proofs
|
return proofs
|
||||||
@@ -770,8 +808,8 @@ export const WalletStoreModel = types
|
|||||||
encodedInvoice: string,
|
encodedInvoice: string,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const cashuMint = yield self.getMint(mintUrl)
|
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
||||||
const lightningQuote: MeltQuoteResponse = yield cashuMint.createMeltQuote({
|
const lightningQuote: MeltQuoteBolt11Response = yield cashuMint.createMeltQuoteBolt11({
|
||||||
unit,
|
unit,
|
||||||
request: encodedInvoice
|
request: encodedInvoice
|
||||||
})
|
})
|
||||||
@@ -797,7 +835,7 @@ export const WalletStoreModel = types
|
|||||||
payLightningMelt: flow(function* payLightningMelt(
|
payLightningMelt: flow(function* payLightningMelt(
|
||||||
mintUrl: string,
|
mintUrl: string,
|
||||||
unit: MintUnit,
|
unit: MintUnit,
|
||||||
meltQuote: MeltQuoteResponse, // invoice is stored by mint by quote
|
meltQuote: MeltQuoteBolt11Response, // invoice is stored by mint by quote
|
||||||
proofsToMeltFrom: Proof[],
|
proofsToMeltFrom: Proof[],
|
||||||
transactionId: number,
|
transactionId: number,
|
||||||
options?: {
|
options?: {
|
||||||
@@ -849,13 +887,13 @@ export const WalletStoreModel = types
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cashuWallet.mintInfo.nuts['19'] && !options?.inFlightRequest) {
|
if(cashuWallet.getMintInfo().nuts['19'] && !options?.inFlightRequest) {
|
||||||
currentCounter.addInFlightRequest(transactionId, meltParams)
|
currentCounter.addInFlightRequest(transactionId, meltParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const meltResponse: MeltProofsResponse = yield cashuWallet.meltProofs(
|
const meltResponse = yield cashuWallet.meltProofsBolt11(
|
||||||
meltParams.meltQuote,
|
meltParams.meltQuote,
|
||||||
meltParams.proofsToSend,
|
meltParams.proofsToSend,
|
||||||
meltParams.options
|
meltParams.options
|
||||||
@@ -865,7 +903,7 @@ export const WalletStoreModel = types
|
|||||||
|
|
||||||
log.trace('[payLightningMelt]', {meltResponse})
|
log.trace('[payLightningMelt]', {meltResponse})
|
||||||
// we normalize naming of returned parameters
|
// we normalize naming of returned parameters
|
||||||
return meltResponse
|
return meltResponse as MeltProofsResponse
|
||||||
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if(!e.message.toLowerCase().includes('timeout') &&
|
if(!e.message.toLowerCase().includes('timeout') &&
|
||||||
@@ -896,7 +934,7 @@ export const WalletStoreModel = types
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
const cashuMint: CashuMint = yield self.getMint(mintUrl)
|
||||||
const quoteResponse: MeltQuoteResponse = yield cashuMint.checkMeltQuote(
|
const quoteResponse: MeltQuoteBolt11Response = yield cashuMint.checkMeltQuoteBolt11(
|
||||||
quote
|
quote
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -920,7 +958,7 @@ export const WalletStoreModel = types
|
|||||||
}),
|
}),
|
||||||
recoverMeltQuoteChange: flow(function* recoverMeltQuoteChange(
|
recoverMeltQuoteChange: flow(function* recoverMeltQuoteChange(
|
||||||
mintUrl: string,
|
mintUrl: string,
|
||||||
meltQuote: MeltQuoteResponse,
|
meltQuote: MeltQuoteBolt11Response,
|
||||||
transactionId: number
|
transactionId: number
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
@@ -991,11 +1029,10 @@ export const WalletStoreModel = types
|
|||||||
unit: 'sat', // just use default unit as we restore by keyset
|
unit: 'sat', // just use default unit as we restore by keyset
|
||||||
keys: cashuMint.keys,
|
keys: cashuMint.keys,
|
||||||
keysets: cashuMint.keysets,
|
keysets: cashuMint.keysets,
|
||||||
|
keysetId,
|
||||||
bip39seed: seed
|
bip39seed: seed
|
||||||
})
|
})
|
||||||
|
|
||||||
seedWallet.keysetId = keysetId
|
|
||||||
|
|
||||||
const count = Math.abs(indexTo - indexFrom)
|
const count = Math.abs(indexTo - indexFrom)
|
||||||
|
|
||||||
const {proofs} = yield seedWallet.restore(
|
const {proofs} = yield seedWallet.restore(
|
||||||
@@ -1011,7 +1048,7 @@ export const WalletStoreModel = types
|
|||||||
proofs: proofs || [] as Proof[]
|
proofs: proofs || [] as Proof[]
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
throw new AppError(Err.MINT_ERROR, isObj(e.message) ? JSON.stringify(e.message) : e.message, {mintUrl})
|
throw new AppError(Err.MINT_ERROR, CashuUtils.isObj(e.message) ? JSON.stringify(e.message) : e.message, {mintUrl})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
getMintInfo: flow(function* getMintInfo(mintUrl: string) {
|
getMintInfo: flow(function* getMintInfo(mintUrl: string) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import { MintsStoreSnapshot } from '../models/MintsStore'
|
|||||||
import { ContactsStoreSnapshot } from '../models/ContactsStore'
|
import { ContactsStoreSnapshot } from '../models/ContactsStore'
|
||||||
import { CashuMint, MintActiveKeys } from '@cashu/cashu-ts'
|
import { CashuMint, MintActiveKeys } from '@cashu/cashu-ts'
|
||||||
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
||||||
import { Proof, ProofModel } from '../models/Proof'
|
import { Proof } from '../models/Proof'
|
||||||
|
|
||||||
type Props = StaticScreenProps<undefined>
|
type Props = StaticScreenProps<undefined>
|
||||||
|
|
||||||
@@ -199,11 +199,7 @@ export const ImportBackupScreen = observer(function ImportBackupScreen({ route }
|
|||||||
}
|
}
|
||||||
|
|
||||||
// applySnapshot(proofsStore, walletSnapshot.proofsStore)
|
// applySnapshot(proofsStore, walletSnapshot.proofsStore)
|
||||||
for (const proof of walletSnapshot.proofsStore.proofs) {
|
proofsStore.importProofs(walletSnapshot.proofsStore.proofs)
|
||||||
proofsStore.proofs.put(
|
|
||||||
ProofModel.create(proof)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
for(const secret of walletSnapshot.proofsStore.pendingByMintSecrets) {
|
for(const secret of walletSnapshot.proofsStore.pendingByMintSecrets) {
|
||||||
proofsStore.pendingByMintSecrets.push(secret)
|
proofsStore.pendingByMintSecrets.push(secret)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react'
|
import React, { useEffect, useMemo, useState } from 'react'
|
||||||
import { GetInfoResponse as CashuGetInfoResponse, SwapMethod } from '@cashu/cashu-ts'
|
import { GetInfoResponse as CashuGetInfoResponse, SwapMethod } from '@cashu/cashu-ts'
|
||||||
import { isObj } from '@cashu/cashu-ts/src/utils'
|
import { CashuUtils } from '../services/cashu/cashuUtils'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import { observer } from 'mobx-react-lite'
|
import { observer } from 'mobx-react-lite'
|
||||||
import { getSnapshot } from 'mobx-state-tree'
|
import { getSnapshot } from 'mobx-state-tree'
|
||||||
@@ -529,7 +529,7 @@ function MintInfoDetails(props: { info: GetInfoResponse, popupMessage: (msg: str
|
|||||||
text={translate('mintInfo_emptyValueParam', { param: key })}
|
text={translate('mintInfo_emptyValueParam', { param: key })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
let stringValue = isObj(value) ? JSON.stringify(value) : value.toString() ?? ''
|
let stringValue = CashuUtils.isObj(value) ? JSON.stringify(value) : value.toString() ?? ''
|
||||||
let valueComponent = stringValue.trim() !== ''
|
let valueComponent = stringValue.trim() !== ''
|
||||||
? <Text size='xs' text={stringValue} />
|
? <Text size='xs' text={stringValue} />
|
||||||
: missingComponent;
|
: missingComponent;
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import { getSnapshot } from 'mobx-state-tree'
|
|||||||
import { scale } from '@gocodingnow/rn-size-matters'
|
import { scale } from '@gocodingnow/rn-size-matters'
|
||||||
import { WalletUtils } from '../services/wallet/utils'
|
import { WalletUtils } from '../services/wallet/utils'
|
||||||
import { MintUnit, formatCurrency, getCurrency } from '../services/wallet/currency'
|
import { MintUnit, formatCurrency, getCurrency } from '../services/wallet/currency'
|
||||||
import { isObj } from '@cashu/cashu-ts/src/utils'
|
|
||||||
import { translate } from '../i18n'
|
import { translate } from '../i18n'
|
||||||
import { WalletProfileRecord } from '../models/WalletProfileStore'
|
import { WalletProfileRecord } from '../models/WalletProfileStore'
|
||||||
import { MnemonicInput } from './Recovery/MnemonicInput'
|
import { MnemonicInput } from './Recovery/MnemonicInput'
|
||||||
@@ -357,7 +356,7 @@ export const SeedRecoveryScreen = observer(function SeedRecoveryScreen({ route }
|
|||||||
e.params = {mintUrl: selectedMintUrl}
|
e.params = {mintUrl: selectedMintUrl}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.error('[doRecovery]', {name: e.name, message: isObj(e.message) ? JSON.stringify(e.message) : e.message, params: e.params})
|
log.error('[doRecovery]', {name: e.name, message: CashuUtils.isObj(e.message) ? JSON.stringify(e.message) : e.message, params: e.params})
|
||||||
errors.push({name: e.name, message: e.message}) // TODO this could now be single error as we do not loop anymore
|
errors.push({name: e.name, message: e.message}) // TODO this could now be single error as we do not loop anymore
|
||||||
|
|
||||||
if (transaction) {
|
if (transaction) {
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ import { MemoInputCard } from '../components/MemoInputCard'
|
|||||||
import { PaymentRequest as CashuPaymentRequest, PaymentRequestTransport, PaymentRequestTransportType, decodePaymentRequest, getDecodedToken } from '@cashu/cashu-ts'
|
import { PaymentRequest as CashuPaymentRequest, PaymentRequestTransport, PaymentRequestTransportType, decodePaymentRequest, getDecodedToken } from '@cashu/cashu-ts'
|
||||||
import { ProfilePointer } from 'nostr-tools/nip19'
|
import { ProfilePointer } from 'nostr-tools/nip19'
|
||||||
import { MINIBITS_NIP05_DOMAIN } from '@env'
|
import { MINIBITS_NIP05_DOMAIN } from '@env'
|
||||||
import { SEND_TASK } from '../services/wallet/sendTask'
|
|
||||||
import FastImage from 'react-native-fast-image'
|
import FastImage from 'react-native-fast-image'
|
||||||
import { CurrencyAmount } from './Wallet/CurrencyAmount'
|
import { CurrencyAmount } from './Wallet/CurrencyAmount'
|
||||||
import { CashuUtils } from '../services/cashu/cashuUtils'
|
import { CashuUtils } from '../services/cashu/cashuUtils'
|
||||||
@@ -128,7 +127,6 @@ export const SendScreen = observer(function SendScreen({ route }: Props) {
|
|||||||
const [isCashuPrWithDesc, setIsCashuPrWithDesc] = useState(false)
|
const [isCashuPrWithDesc, setIsCashuPrWithDesc] = useState(false)
|
||||||
const [isNostrDMModalVisible, setIsNostrDMModalVisible] = useState(false)
|
const [isNostrDMModalVisible, setIsNostrDMModalVisible] = useState(false)
|
||||||
const [isProofSelectorModalVisible, setIsProofSelectorModalVisible] = useState(false) // offline mode
|
const [isProofSelectorModalVisible, setIsProofSelectorModalVisible] = useState(false) // offline mode
|
||||||
const [isSendTaskSentToQueue, setIsSendTaskSentToQueue] = useState(false)
|
|
||||||
const [isResultModalVisible, setIsResultModalVisible] = useState(false)
|
const [isResultModalVisible, setIsResultModalVisible] = useState(false)
|
||||||
const [isNostrDMSending, setIsNostrDMSending] = useState(false)
|
const [isNostrDMSending, setIsNostrDMSending] = useState(false)
|
||||||
const [isNostrDMSuccess, setIsNostrDMSuccess] = useState(false)
|
const [isNostrDMSuccess, setIsNostrDMSuccess] = useState(false)
|
||||||
@@ -770,8 +768,6 @@ export const SendScreen = observer(function SendScreen({ route }: Props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsSendTaskSentToQueue(true)
|
|
||||||
|
|
||||||
const result = await WalletTask.sendQueueAwaitable(
|
const result = await WalletTask.sendQueueAwaitable(
|
||||||
mintBalanceToSendFrom as MintBalance,
|
mintBalanceToSendFrom as MintBalance,
|
||||||
amountToSendInt,
|
amountToSendInt,
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ export const TransactionListItem = observer(function (props: TransactionListProp
|
|||||||
amountStyle={{color: txReceiveColor}}
|
amountStyle={{color: txReceiveColor}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{[TransactionStatus.ERROR, TransactionStatus.BLOCKED, TransactionStatus.PREPARED_OFFLINE, TransactionStatus.EXPIRED].includes(tx.status) && (
|
{[TransactionStatus.ERROR, TransactionStatus.BLOCKED, TransactionStatus.PREPARED_OFFLINE, TransactionStatus.PENDING, TransactionStatus.EXPIRED].includes(tx.status) && (
|
||||||
<CurrencyAmount
|
<CurrencyAmount
|
||||||
amount={tx.amount}
|
amount={tx.amount}
|
||||||
mintUnit={tx.unit}
|
mintUnit={tx.unit}
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ const onRequestLnurlInvoice = async function () {
|
|||||||
amount: roundUp(lnurlPayParams.minSendable / 1000, 0),
|
amount: roundUp(lnurlPayParams.minSendable / 1000, 0),
|
||||||
currency: CurrencyCode.SAT
|
currency: CurrencyCode.SAT
|
||||||
}))
|
}))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lnurlPayParams.maxSendable && amountSats > lnurlPayParams.maxSendable / 1000) {
|
if (lnurlPayParams.maxSendable && amountSats > lnurlPayParams.maxSendable / 1000) {
|
||||||
@@ -506,7 +506,7 @@ const onRequestLnurlInvoice = async function () {
|
|||||||
amount: roundDown(lnurlPayParams.maxSendable / 1000, 0),
|
amount: roundDown(lnurlPayParams.maxSendable / 1000, 0),
|
||||||
currency: CurrencyCode.SAT
|
currency: CurrencyCode.SAT
|
||||||
}))
|
}))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lnurlPayParams.payerData) {
|
if (lnurlPayParams.payerData) {
|
||||||
|
|||||||
@@ -10,13 +10,27 @@ import AppError, {Err} from '../../utils/AppError'
|
|||||||
import { getDecodedToken } from '@cashu/cashu-ts'
|
import { getDecodedToken } from '@cashu/cashu-ts'
|
||||||
import {Proof} from '../../models/Proof'
|
import {Proof} from '../../models/Proof'
|
||||||
import { log } from '../logService'
|
import { log } from '../logService'
|
||||||
import { decodePaymentRequest, sumProofs } from '@cashu/cashu-ts/src/utils'
|
import { decodePaymentRequest } from '@cashu/cashu-ts'
|
||||||
import { NostrClient } from '../nostrService'
|
import { NostrClient } from '../nostrService'
|
||||||
import { getUnixTime } from 'date-fns/getUnixTime'
|
import { getUnixTime } from 'date-fns/getUnixTime'
|
||||||
import { getSnapshot, isStateTreeNode } from 'mobx-state-tree'
|
import { getSnapshot, isStateTreeNode } from 'mobx-state-tree'
|
||||||
|
|
||||||
export {CashuProof}
|
export {CashuProof}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type guard to check if a value is an object
|
||||||
|
*/
|
||||||
|
const isObj = function(v: unknown): v is object {
|
||||||
|
return typeof v === 'object'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sum the amounts of an array of proofs
|
||||||
|
*/
|
||||||
|
const sumProofs = function(proofs: CashuProof[]): number {
|
||||||
|
return proofs.reduce((acc: number, proof: CashuProof) => acc + proof.amount, 0)
|
||||||
|
}
|
||||||
|
|
||||||
const CASHU_URI_PREFIXES = [
|
const CASHU_URI_PREFIXES = [
|
||||||
'https://wallet.nutstash.app/#',
|
'https://wallet.nutstash.app/#',
|
||||||
'https://wallet.cashu.me/?token=',
|
'https://wallet.cashu.me/?token=',
|
||||||
@@ -407,7 +421,9 @@ export const CashuUtils = {
|
|||||||
getP2PKPubkeySecret,
|
getP2PKPubkeySecret,
|
||||||
getP2PKLocktime,
|
getP2PKLocktime,
|
||||||
isTokenP2PKLocked,
|
isTokenP2PKLocked,
|
||||||
isCollidingKeysetId
|
isCollidingKeysetId,
|
||||||
|
isObj,
|
||||||
|
sumProofs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ const generateWalletKeys = function () {
|
|||||||
const mnemonic = generateMnemonic()
|
const mnemonic = generateMnemonic()
|
||||||
const seedBytesArray = mnemonicToSeedSync(mnemonic)
|
const seedBytesArray = mnemonicToSeedSync(mnemonic)
|
||||||
const seed = Buffer.from(seedBytesArray).toString('base64')
|
const seed = Buffer.from(seedBytesArray).toString('base64')
|
||||||
|
log.trace('[generateWalletKeys] Seed generated from mnemonic (base64)', {seed})
|
||||||
const seedHash = QuickCrypto
|
const seedHash = QuickCrypto
|
||||||
.createHash('sha256')
|
.createHash('sha256')
|
||||||
.update(seedBytesArray)
|
.update(seedBytesArray)
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ import { TransactionTaskResult } from '../walletService'
|
|||||||
import { WalletUtils } from './utils'
|
import { WalletUtils } from './utils'
|
||||||
import { MintUnit, formatCurrency, getCurrency } from './currency'
|
import { MintUnit, formatCurrency, getCurrency } from './currency'
|
||||||
import { PaymentRequestPayload, Token, getDecodedToken } from '@cashu/cashu-ts'
|
import { PaymentRequestPayload, Token, getDecodedToken } from '@cashu/cashu-ts'
|
||||||
import { getEncodedToken, getKeepAmounts } from '@cashu/cashu-ts/src/utils'
|
import { getEncodedToken } from '@cashu/cashu-ts'
|
||||||
import { Proof } from '../../models/Proof'
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mintsStore,
|
mintsStore,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { TransactionTaskResult } from '../walletService'
|
|||||||
import { WalletUtils } from './utils'
|
import { WalletUtils } from './utils'
|
||||||
import { MintUnit } from './currency'
|
import { MintUnit } from './currency'
|
||||||
import { Token } from '@cashu/cashu-ts'
|
import { Token } from '@cashu/cashu-ts'
|
||||||
import { getEncodedToken, getKeepAmounts } from '@cashu/cashu-ts/src/utils'
|
import { getEncodedToken, getKeepAmounts } from '@cashu/cashu-ts'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mintsStore,
|
mintsStore,
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import {rootStoreInstance} from '../../models'
|
|||||||
import {CashuUtils, CashuProof} from '../cashu/cashuUtils'
|
import {CashuUtils, CashuProof} from '../cashu/cashuUtils'
|
||||||
import AppError, {Err} from '../../utils/AppError'
|
import AppError, {Err} from '../../utils/AppError'
|
||||||
import {
|
import {
|
||||||
CashuMint,
|
Mint as CashuMint,
|
||||||
CashuWallet,
|
Wallet as CashuWallet,
|
||||||
CheckStateEnum,
|
CheckStateEnum,
|
||||||
MintKeyset,
|
MintKeyset,
|
||||||
ProofState,
|
ProofState,
|
||||||
@@ -144,7 +144,7 @@ export const sendTask = async function (
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
log.trace('[send] Subscribing to onProofStateUpdates for proof', {secret: proofsToSend[0]})
|
log.trace('[send] Subscribing to onProofStateUpdates for proof', {secret: proofsToSend[0]})
|
||||||
const unsub = await wsWallet.onProofStateUpdates(
|
const unsub = await wsWallet.on.proofStateUpdates(
|
||||||
[proofsToSend[0]],
|
[proofsToSend[0]],
|
||||||
async (proofState: ProofState) => {
|
async (proofState: ProofState) => {
|
||||||
log.trace(`Websocket: proof state updated: ${proofState.state} with secret: ${proofsToSend[0].secret}`)
|
log.trace(`Websocket: proof state updated: ${proofState.state} with secret: ${proofsToSend[0].secret}`)
|
||||||
@@ -338,7 +338,7 @@ export const sendFromMintSync = async function (
|
|||||||
*/
|
*/
|
||||||
if(isSwapNeeded) {
|
if(isSwapNeeded) {
|
||||||
// Calculate feeReserve from mint fee rate
|
// Calculate feeReserve from mint fee rate
|
||||||
const walletInstance = await walletStore.getWallet(mintUrl, unit, {withSeed: true})
|
const walletInstance = await walletStore.getWallet(mintUrl, unit, {withSeed: true}) as CashuWallet
|
||||||
swapFeeReserve = walletInstance.getFeesForProofs(proofsToSendFrom)
|
swapFeeReserve = walletInstance.getFeesForProofs(proofsToSendFrom)
|
||||||
const amountWithFees = amountToSend + swapFeeReserve
|
const amountWithFees = amountToSend + swapFeeReserve
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ import { WalletUtils } from './utils'
|
|||||||
import { MintUnit } from './currency'
|
import { MintUnit } from './currency'
|
||||||
import { NostrEvent } from '../nostrService'
|
import { NostrEvent } from '../nostrService'
|
||||||
import AppError, { Err } from '../../utils/AppError'
|
import AppError, { Err } from '../../utils/AppError'
|
||||||
import { CashuMint, CashuWallet, MintQuoteResponse } from '@cashu/cashu-ts'
|
import {
|
||||||
|
MintQuoteBolt11Response,
|
||||||
|
Mint as CashuMint,
|
||||||
|
Wallet as CashuWallet,
|
||||||
|
} from '@cashu/cashu-ts'
|
||||||
import { addSeconds } from 'date-fns/addSeconds'
|
import { addSeconds } from 'date-fns/addSeconds'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -125,9 +129,9 @@ export const topupTask = async function (
|
|||||||
const wsWallet = new CashuWallet(wsMint)
|
const wsWallet = new CashuWallet(wsMint)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const unsub = await wsWallet.onMintQuotePaid(
|
const unsub = await wsWallet.on.mintQuotePaid(
|
||||||
mintQuote,
|
mintQuote,
|
||||||
async (m: MintQuoteResponse) => {
|
async (m: MintQuoteBolt11Response) => {
|
||||||
log.trace(`Websocket: mint quote PAID: ${m.quote}`)
|
log.trace(`Websocket: mint quote PAID: ${m.quote}`)
|
||||||
WalletTask.handlePendingQueue()
|
WalletTask.handlePendingQueue()
|
||||||
unsub()
|
unsub()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {CashuUtils} from '../cashu/cashuUtils'
|
import {CashuUtils} from '../cashu/cashuUtils'
|
||||||
import AppError, {Err} from '../../utils/AppError'
|
import AppError, {Err} from '../../utils/AppError'
|
||||||
import {MeltProofsResponse, MeltQuoteResponse, MeltQuoteState, getEncodedToken} from '@cashu/cashu-ts'
|
import {MeltProofsResponse, MeltQuoteBolt11Response, MeltQuoteResponse, MeltQuoteState, getEncodedToken} from '@cashu/cashu-ts'
|
||||||
import {rootStoreInstance} from '../../models'
|
import {rootStoreInstance} from '../../models'
|
||||||
import { TransactionTaskResult, WalletTask } from '../walletService'
|
import { TransactionTaskResult, WalletTask } from '../walletService'
|
||||||
import { MintBalance } from '../../models/Mint'
|
import { MintBalance } from '../../models/Mint'
|
||||||
@@ -51,6 +51,7 @@ export const transferTask = async function (
|
|||||||
let proofsToMeltFromAmount: number = 0
|
let proofsToMeltFromAmount: number = 0
|
||||||
let meltFeeReserve: number = 0
|
let meltFeeReserve: number = 0
|
||||||
let meltResponse: MeltProofsResponse
|
let meltResponse: MeltProofsResponse
|
||||||
|
let meltQuoteCheck: MeltQuoteBolt11Response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -249,6 +250,8 @@ export const transferTask = async function (
|
|||||||
lightningFeePaid = totalFeePaid - meltFeeReserve
|
lightningFeePaid = totalFeePaid - meltFeeReserve
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meltQuoteCheck = await walletStore.checkLightningMeltQuote(mintUrl, meltQuote.quote)
|
||||||
|
|
||||||
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance
|
const balanceAfter = proofsStore.getUnitBalance(unit)?.unitBalance
|
||||||
|
|
||||||
// build consolidated update payload
|
// build consolidated update payload
|
||||||
@@ -257,7 +260,7 @@ export const transferTask = async function (
|
|||||||
lightningFeePaid,
|
lightningFeePaid,
|
||||||
meltFeePaid,
|
meltFeePaid,
|
||||||
returnedAmount,
|
returnedAmount,
|
||||||
preimage: meltResponse.quote.payment_preimage,
|
preimage: meltQuoteCheck.payment_preimage,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
}
|
}
|
||||||
transactionData.push(completedDataItem)
|
transactionData.push(completedDataItem)
|
||||||
@@ -273,8 +276,8 @@ export const transferTask = async function (
|
|||||||
updatePayload.outputToken = outputToken
|
updatePayload.outputToken = outputToken
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meltResponse.quote.payment_preimage) {
|
if (meltQuoteCheck.payment_preimage) {
|
||||||
updatePayload.proof = meltResponse.quote.payment_preimage
|
updatePayload.proof = meltQuoteCheck.payment_preimage
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.update(updatePayload)
|
transaction.update(updatePayload)
|
||||||
@@ -287,8 +290,8 @@ export const transferTask = async function (
|
|||||||
lightningFeePaid,
|
lightningFeePaid,
|
||||||
meltFeePaid,
|
meltFeePaid,
|
||||||
totalFeePaid,
|
totalFeePaid,
|
||||||
meltQuote: meltResponse.quote,
|
meltQuote: meltQuoteCheck,
|
||||||
preimage: meltResponse.quote.payment_preimage,
|
preimage: meltQuoteCheck.payment_preimage,
|
||||||
nwcEvent
|
nwcEvent
|
||||||
} as TransactionTaskResult
|
} as TransactionTaskResult
|
||||||
|
|
||||||
@@ -330,31 +333,31 @@ export const transferTask = async function (
|
|||||||
|
|
||||||
if (proofsToMeltFrom.length > 0) {
|
if (proofsToMeltFrom.length > 0) {
|
||||||
|
|
||||||
const refreshedMeltQuote = await walletStore.checkLightningMeltQuote(mintUrl, meltQuote.quote)
|
meltQuoteCheck = await walletStore.checkLightningMeltQuote(mintUrl, meltQuote.quote)
|
||||||
taskResult.meltQuote = refreshedMeltQuote
|
taskResult.meltQuote = meltQuoteCheck
|
||||||
|
|
||||||
if(refreshedMeltQuote.state === MeltQuoteState.PAID) {
|
if(meltQuoteCheck.state === MeltQuoteState.PAID) {
|
||||||
|
|
||||||
message = `Lightning invoice has been successfully paid, however some error occured: ${e.message}`
|
message = `Lightning invoice has been successfully paid, however some error occured: ${e.message}`
|
||||||
|
|
||||||
taskResult.preimage = refreshedMeltQuote.payment_preimage
|
taskResult.preimage = meltQuoteCheck.payment_preimage
|
||||||
taskResult.message = message
|
taskResult.message = message
|
||||||
|
|
||||||
const {recoveredAmount} = await WalletTask.recoverMeltQuoteChange({
|
const {recoveredAmount} = await WalletTask.recoverMeltQuoteChange({
|
||||||
mintUrl,
|
mintUrl,
|
||||||
meltQuote: refreshedMeltQuote,
|
meltQuote: meltQuoteCheck,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
log.error('[transfer]', message, {
|
log.error('[transfer]', message, {
|
||||||
recoveredAmount,
|
recoveredAmount,
|
||||||
error: e.message,
|
error: e.message,
|
||||||
refreshedMeltQuote,
|
meltQuoteCheck,
|
||||||
unit,
|
unit,
|
||||||
transactionId: transaction.id
|
transactionId: transaction.id
|
||||||
})
|
})
|
||||||
|
|
||||||
} else if(refreshedMeltQuote.state === MeltQuoteState.PENDING) {
|
} else if(meltQuoteCheck.state === MeltQuoteState.PENDING) {
|
||||||
|
|
||||||
message = 'Lightning payment did not complete in time. Your ecash will remain pending until the payment completes or fails.'
|
message = 'Lightning payment did not complete in time. Your ecash will remain pending until the payment completes or fails.'
|
||||||
taskResult.message = message
|
taskResult.message = message
|
||||||
@@ -362,7 +365,7 @@ export const transferTask = async function (
|
|||||||
log.error('[transfer]', message, {
|
log.error('[transfer]', message, {
|
||||||
error: `${e.message}: ${e.params.message}`,
|
error: `${e.message}: ${e.params.message}`,
|
||||||
unit,
|
unit,
|
||||||
refreshedMeltQuote,
|
meltQuoteCheck,
|
||||||
transactionId: transaction.id
|
transactionId: transaction.id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import AppError from "../../utils/AppError"
|
import AppError from "../../utils/AppError"
|
||||||
import { isObj } from '@cashu/cashu-ts/src/utils'
|
import { CashuUtils } from '../cashu/cashuUtils'
|
||||||
|
|
||||||
const formatError = function (e: AppError) {
|
const formatError = function (e: AppError) {
|
||||||
return {
|
return {
|
||||||
name: e.name,
|
name: e.name,
|
||||||
message: isObj(e.message) ? JSON.stringify(e.message) : e.message.slice(0, 200),
|
message: CashuUtils.isObj(e.message) ? JSON.stringify(e.message) : e.message.slice(0, 200),
|
||||||
params: e.params || {},
|
params: e.params || {},
|
||||||
} as AppError
|
} as AppError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {CashuProof, CashuUtils} from './cashu/cashuUtils'
|
|||||||
import {LightningUtils} from './lightning/lightningUtils'
|
import {LightningUtils} from './lightning/lightningUtils'
|
||||||
import AppError, {Err} from '../utils/AppError'
|
import AppError, {Err} from '../utils/AppError'
|
||||||
import {MintBalance, MintStatus} from '../models/Mint'
|
import {MintBalance, MintStatus} from '../models/Mint'
|
||||||
import {MeltQuoteResponse, MeltQuoteState, MintQuoteState, PaymentRequestPayload, Token, getDecodedToken, getEncodedToken} from '@cashu/cashu-ts'
|
import {MeltQuoteBolt11Response, MeltQuoteResponse, MeltQuoteState, MintQuoteState, PaymentRequestPayload, Token, getDecodedToken, getEncodedToken} from '@cashu/cashu-ts'
|
||||||
import {Mint} from '../models/Mint'
|
import {Mint} from '../models/Mint'
|
||||||
import {pollerExists, stopPolling} from '../utils/poller'
|
import {pollerExists, stopPolling} from '../utils/poller'
|
||||||
import { NostrClient, NostrEvent, NostrProfile } from './nostrService'
|
import { NostrClient, NostrEvent, NostrProfile } from './nostrService'
|
||||||
@@ -40,7 +40,7 @@ import { MinibitsClient } from './minibitsService'
|
|||||||
import { UnsignedEvent } from 'nostr-tools'
|
import { UnsignedEvent } from 'nostr-tools'
|
||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
import { cashuPaymentRequestTask } from './wallet/cashuPaymentRequestTask'
|
import { cashuPaymentRequestTask } from './wallet/cashuPaymentRequestTask'
|
||||||
import { decodePaymentRequest } from '@cashu/cashu-ts/src/utils'
|
import { decodePaymentRequest } from '@cashu/cashu-ts'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ export interface TransactionTaskResult extends WalletTaskResult {
|
|||||||
swapFeePaid?: number
|
swapFeePaid?: number
|
||||||
lightningFeePaid?: number
|
lightningFeePaid?: number
|
||||||
meltFeePaid?: number
|
meltFeePaid?: number
|
||||||
meltQuote?: MeltQuoteResponse
|
meltQuote?: MeltQuoteBolt11Response
|
||||||
nwcEvent?: NostrEvent
|
nwcEvent?: NostrEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1636,7 +1636,16 @@ const handleInFlightByMintTask = async (mint: Mint): Promise<WalletTaskResult> =
|
|||||||
|
|
||||||
// ─── TRANSFER (melt / lightning out retry) ─────────────
|
// ─── TRANSFER (melt / lightning out retry) ─────────────
|
||||||
case TransactionType.TRANSFER: {
|
case TransactionType.TRANSFER: {
|
||||||
const { quote, change } = await walletStore.payLightningMelt(
|
const meltQuoteCheck = await walletStore.checkLightningMeltQuote(mintUrl, inFlight.request.meltQuote)
|
||||||
|
|
||||||
|
if(meltQuoteCheck.state === MeltQuoteState.PAID || meltQuoteCheck.state === MeltQuoteState.PENDING) {
|
||||||
|
log.debug('[handleInFlightByMintTask] Melt quote already PAID or PENDING', { tId: tx.id })
|
||||||
|
// TODO recover change if any
|
||||||
|
counter.removeInFlightRequest(inFlight.transactionId)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
const { change } = await walletStore.payLightningMelt(
|
||||||
mintUrl,
|
mintUrl,
|
||||||
unit,
|
unit,
|
||||||
inFlight.request.meltQuote,
|
inFlight.request.meltQuote,
|
||||||
@@ -1667,9 +1676,9 @@ const handleInFlightByMintTask = async (mint: Mint): Promise<WalletTaskResult> =
|
|||||||
tx.update({ outputToken })
|
tx.update({ outputToken })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quote.payment_preimage) {
|
/*if (quote.payment_preimage) {
|
||||||
tx.update({ proof: quote.payment_preimage })
|
tx.update({ proof: quote.payment_preimage })
|
||||||
}
|
}*/
|
||||||
|
|
||||||
const inputAmount = CashuUtils.getProofsAmount(inFlight.request.proofsToSend)
|
const inputAmount = CashuUtils.getProofsAmount(inFlight.request.proofsToSend)
|
||||||
const changeAmount = CashuUtils.getProofsAmount(change)
|
const changeAmount = CashuUtils.getProofsAmount(change)
|
||||||
@@ -1680,7 +1689,7 @@ const handleInFlightByMintTask = async (mint: Mint): Promise<WalletTaskResult> =
|
|||||||
txData.push({
|
txData.push({
|
||||||
status: TransactionStatus.COMPLETED,
|
status: TransactionStatus.COMPLETED,
|
||||||
changeAmount,
|
changeAmount,
|
||||||
preimage: quote.payment_preimage,
|
//preimage: quote.payment_preimage,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -2060,7 +2069,7 @@ const recoverMintQuote = async (
|
|||||||
const recoverMeltQuoteChange = async (
|
const recoverMeltQuoteChange = async (
|
||||||
params: {
|
params: {
|
||||||
mintUrl: string
|
mintUrl: string
|
||||||
meltQuote: string | MeltQuoteResponse
|
meltQuote: string | MeltQuoteBolt11Response
|
||||||
}
|
}
|
||||||
): Promise<{ recoveredAmount: number }> => {
|
): Promise<{ recoveredAmount: number }> => {
|
||||||
const { mintUrl, meltQuote } = params
|
const { mintUrl, meltQuote } = params
|
||||||
@@ -2073,7 +2082,7 @@ const recoverMintQuote = async (
|
|||||||
|
|
||||||
log.trace('[recoverMeltQuoteChange] start', { mintUrl, meltQuote })
|
log.trace('[recoverMeltQuoteChange] start', { mintUrl, meltQuote })
|
||||||
|
|
||||||
const meltQuoteResponse: MeltQuoteResponse =
|
const meltQuoteResponse: MeltQuoteBolt11Response =
|
||||||
typeof meltQuote === 'string'
|
typeof meltQuote === 'string'
|
||||||
? await walletStore.checkLightningMeltQuote(mintUrl, meltQuote)
|
? await walletStore.checkLightningMeltQuote(mintUrl, meltQuote)
|
||||||
: meltQuote
|
: meltQuote
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export enum Err {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AppError extends Error {
|
export class AppError extends Error {
|
||||||
public readonly code: Err
|
public readonly code: number | undefined
|
||||||
public readonly params?: Record<string, any>
|
public readonly params?: Record<string, any>
|
||||||
public readonly caller?: string
|
public readonly caller?: string
|
||||||
|
|
||||||
|
|||||||
@@ -2722,28 +2722,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@cashu/cashu-ts@minibits-cash/cashu-ts#e97b1a4ee9a7ddbb1468302c6996a9d6d3efcb6f":
|
"@cashu/cashu-ts@npm:3.2.2":
|
||||||
version: 2.4.0
|
version: 3.2.2
|
||||||
resolution: "@cashu/cashu-ts@https://github.com/minibits-cash/cashu-ts.git#commit=e97b1a4ee9a7ddbb1468302c6996a9d6d3efcb6f"
|
resolution: "@cashu/cashu-ts@npm:3.2.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cashu/crypto": ^0.3.4
|
"@noble/curves": ^2.0.1
|
||||||
"@noble/curves": ^1.3.0
|
"@noble/hashes": ^2.0.1
|
||||||
"@noble/hashes": ^1.3.3
|
"@scure/bip32": ^2.0.1
|
||||||
buffer: ^6.0.3
|
checksum: 49516a22f3afbf249c52d0f36a9e6513948b763af94c703a05375b513b0d3f90bb1feaade201214d315f5a26305e182ee00493634519ad9b69c7bd44615de11c
|
||||||
checksum: 68d46ceb9c60e9cef305aad86534c08b23de434de1efcd217d00c73bdf84704801c3cd700901903256de5a408caf029cea7886e9a303dd423027f08184bc1cb5
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@cashu/crypto@npm:^0.3.4":
|
|
||||||
version: 0.3.4
|
|
||||||
resolution: "@cashu/crypto@npm:0.3.4"
|
|
||||||
dependencies:
|
|
||||||
"@noble/curves": ^1.6.0
|
|
||||||
"@noble/hashes": ^1.5.0
|
|
||||||
"@scure/bip32": ^1.5.0
|
|
||||||
"@scure/bip39": ^1.4.0
|
|
||||||
buffer: ^6.0.3
|
|
||||||
checksum: 634afdd9d8fb262cd3db415794661ba5810f4ba1e64d1af0972c9a9b0a8c45106710a00ee25949014a361458ef544bdfcafe926c548c95b05fff9a41600d34a3
|
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -5299,12 +5285,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@noble/curves@npm:^1.3.0, @noble/curves@npm:^1.6.0, @noble/curves@npm:~1.8.1":
|
"@noble/curves@npm:2.0.1, @noble/curves@npm:^2.0.1":
|
||||||
version: 1.8.1
|
version: 2.0.1
|
||||||
resolution: "@noble/curves@npm:1.8.1"
|
resolution: "@noble/curves@npm:2.0.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@noble/hashes": 1.7.1
|
"@noble/hashes": 2.0.1
|
||||||
checksum: 4143f1248ed57c1ae46dfef5c692a91383e5830420b9c72d3ff1061aa9ebbf8999297da6d2aed8a9716fef8e6b1f5a45737feeab02abf55ca2a4f514bf9339ec
|
checksum: b6844f350d629bb6de55d3a123bc148403901c8b8eed77d2132a389d080d553242bcf1e06913bf51f51e395849ec70b9a8e8902c19e562ea3c6538bb0240d92f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -5317,6 +5303,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@noble/curves@npm:~1.8.1":
|
||||||
|
version: 1.8.1
|
||||||
|
resolution: "@noble/curves@npm:1.8.1"
|
||||||
|
dependencies:
|
||||||
|
"@noble/hashes": 1.7.1
|
||||||
|
checksum: 4143f1248ed57c1ae46dfef5c692a91383e5830420b9c72d3ff1061aa9ebbf8999297da6d2aed8a9716fef8e6b1f5a45737feeab02abf55ca2a4f514bf9339ec
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@noble/hashes@npm:1.3.1":
|
"@noble/hashes@npm:1.3.1":
|
||||||
version: 1.3.1
|
version: 1.3.1
|
||||||
resolution: "@noble/hashes@npm:1.3.1"
|
resolution: "@noble/hashes@npm:1.3.1"
|
||||||
@@ -5331,13 +5326,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@noble/hashes@npm:1.7.1, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:~1.7.1":
|
"@noble/hashes@npm:1.7.1, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:~1.7.1":
|
||||||
version: 1.7.1
|
version: 1.7.1
|
||||||
resolution: "@noble/hashes@npm:1.7.1"
|
resolution: "@noble/hashes@npm:1.7.1"
|
||||||
checksum: 4f1b56428a10323feef17e4f437c9093556cb18db06f94d254043fadb69c3da8475f96eb3f8322d41e8670117d7486475a8875e68265c2839f60fd03edd6a616
|
checksum: 4f1b56428a10323feef17e4f437c9093556cb18db06f94d254043fadb69c3da8475f96eb3f8322d41e8670117d7486475a8875e68265c2839f60fd03edd6a616
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@noble/hashes@npm:2.0.1, @noble/hashes@npm:^2.0.1":
|
||||||
|
version: 2.0.1
|
||||||
|
resolution: "@noble/hashes@npm:2.0.1"
|
||||||
|
checksum: aea67a671ca464027cd512d07666a804bd99abc343ba98c93ee8463a1c870c5594f8de468279ef3c60f3b23b6330db9f1a92bd23723b8a911ec73bddc9420248
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@noble/hashes@npm:^1.1.5, @noble/hashes@npm:~1.8.0":
|
"@noble/hashes@npm:^1.1.5, @noble/hashes@npm:~1.8.0":
|
||||||
version: 1.8.0
|
version: 1.8.0
|
||||||
resolution: "@noble/hashes@npm:1.8.0"
|
resolution: "@noble/hashes@npm:1.8.0"
|
||||||
@@ -6275,6 +6277,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@scure/base@npm:2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "@scure/base@npm:2.0.0"
|
||||||
|
checksum: 15d10f154256f52bb3e02b63cdf93b6df6db3814fa4c61a8bb2d339831aec7859609fb715b93c7fc852755f0fe67fb6411664c06159745711bf38af3b10ab93e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@scure/base@npm:~1.1.0":
|
"@scure/base@npm:~1.1.0":
|
||||||
version: 1.1.9
|
version: 1.1.9
|
||||||
resolution: "@scure/base@npm:1.1.9"
|
resolution: "@scure/base@npm:1.1.9"
|
||||||
@@ -6282,7 +6291,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@scure/base@npm:~1.2.2, @scure/base@npm:~1.2.4":
|
"@scure/base@npm:~1.2.2":
|
||||||
version: 1.2.4
|
version: 1.2.4
|
||||||
resolution: "@scure/base@npm:1.2.4"
|
resolution: "@scure/base@npm:1.2.4"
|
||||||
checksum: db554eb550a1bd17684af9282e1ad751050a13d4add0e83ad61cc496680d7d1c1c1120ca780e72935a293bb59721c20a006a53a5eec6f6b5bdcd702cf27c8cae
|
checksum: db554eb550a1bd17684af9282e1ad751050a13d4add0e83ad61cc496680d7d1c1c1120ca780e72935a293bb59721c20a006a53a5eec6f6b5bdcd702cf27c8cae
|
||||||
@@ -6307,7 +6316,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@scure/bip32@npm:1.6.2, @scure/bip32@npm:^1.5.0":
|
"@scure/bip32@npm:1.6.2":
|
||||||
version: 1.6.2
|
version: 1.6.2
|
||||||
resolution: "@scure/bip32@npm:1.6.2"
|
resolution: "@scure/bip32@npm:1.6.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6318,6 +6327,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@scure/bip32@npm:^2.0.1":
|
||||||
|
version: 2.0.1
|
||||||
|
resolution: "@scure/bip32@npm:2.0.1"
|
||||||
|
dependencies:
|
||||||
|
"@noble/curves": 2.0.1
|
||||||
|
"@noble/hashes": 2.0.1
|
||||||
|
"@scure/base": 2.0.0
|
||||||
|
checksum: 5e6c7b455c4a5599673d5fa1b7edc1b3655fe2f7b8388dc19ebe4a89adb9c80c511215d4af624eb774c63c216fd8b7bb8fecf1eb8c3d5e979e279c7542657a42
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@scure/bip39@npm:1.2.1":
|
"@scure/bip39@npm:1.2.1":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "@scure/bip39@npm:1.2.1"
|
resolution: "@scure/bip39@npm:1.2.1"
|
||||||
@@ -6338,16 +6358,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@scure/bip39@npm:^1.4.0":
|
|
||||||
version: 1.5.4
|
|
||||||
resolution: "@scure/bip39@npm:1.5.4"
|
|
||||||
dependencies:
|
|
||||||
"@noble/hashes": ~1.7.1
|
|
||||||
"@scure/base": ~1.2.4
|
|
||||||
checksum: 744f302559ad05ee6ea4928572ac8f0b5443e8068fd53234c9c2e158814e910a043c54f0688d05546decadd2ff66e0d0c76355d10e103a28cb8f44efe140857a
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"@sentry-internal/browser-utils@npm:10.26.0":
|
"@sentry-internal/browser-utils@npm:10.26.0":
|
||||||
version: 10.26.0
|
version: 10.26.0
|
||||||
resolution: "@sentry-internal/browser-utils@npm:10.26.0"
|
resolution: "@sentry-internal/browser-utils@npm:10.26.0"
|
||||||
@@ -14456,7 +14466,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": "minibits-cash/cashu-ts#e97b1a4ee9a7ddbb1468302c6996a9d6d3efcb6f"
|
"@cashu/cashu-ts": 3.2.2
|
||||||
"@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
|
||||||
|
|||||||
Reference in New Issue
Block a user