From 7fbc0fdb8633d398c0ecf9dea30d35e1ac822e28 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 15 Jul 2025 17:31:12 +0200 Subject: [PATCH] nice --- app/release/baselineProfiles/0/app-release.dm | Bin 5445 -> 0 bytes app/release/baselineProfiles/1/app-release.dm | Bin 5403 -> 0 bytes app/release/output-metadata.json | 37 ---- .../android/wallet/service/CashuService.kt | 176 ++++++++++++++++-- .../wallet/viewmodel/WalletViewModel.kt | 31 ++- 5 files changed, 191 insertions(+), 53 deletions(-) delete mode 100644 app/release/baselineProfiles/0/app-release.dm delete mode 100644 app/release/baselineProfiles/1/app-release.dm delete mode 100644 app/release/output-metadata.json diff --git a/app/release/baselineProfiles/0/app-release.dm b/app/release/baselineProfiles/0/app-release.dm deleted file mode 100644 index 604f8becc0e8f6afee390fbc89c1ad3d3ca07a09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5445 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 Bnmzyk diff --git a/app/release/baselineProfiles/1/app-release.dm b/app/release/baselineProfiles/1/app-release.dm deleted file mode 100644 index 57da9f4d6d455fa311f6c6316b5bf0670d5bd6a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5403 zcmZ{oXHXMdw}mNE14N4SDhevS7&_QP2Sr67f`Eb$=|X@IP@@7$i1gkSLApRF(xixV zLkolwYA68$p@kB-zIW!%S7z=yv*+wHXZHTJ)}P1Hgz*d?9V;s<-4Nr3E#1F~<8SZn z>*nF;8>Hy%>*Yd!$j!9zx1m#3QKqAB&8DMU;ijVtq+fr`83nQSZ>p^PG5=Uehty1D zkySG<9)6hnJ+ip{l9Za%-SV@axh2cre*65H+lVbt>WyG(@bp~4L=`H1ke#W#JSO`L z8~f$+*VP@f&KaJ+KgXX#!9D$IRA9xo$^7*x3g-uJf)O)T31e$|WTRmWb_hQ`p~|Pd z4`YGKiqcCr4+PVad7CB=jN@GE)+_KwWB|geniTUpjM%Yf3LxB)Z$*wp>M89F;(^!D z+J5n`vl3X;+iweLjw#JKMv26#62pl_D~4GMSM6jlk1{aX=*|O;C(k<}kNW0CzD~H0 z%EmOpPYh4V!}(L2g}bv2!ZD&ytFNjrd9$DrfuJh`xQFp^prKJvBk*hDUJVm#Ty@%9z#A-jWb-=$@w_Wm=YI@J@b$Q!! zKMSzCis33Jk@(2;4@MDgh~@BlvBl-u^2b9w{C!$YGq3$c)C1|f+BLeJrFNI?uj9)2 zgcRdlrH%*KR%WxRI^Q!SrAjdADbFSex93`O-TvrSyU)rxvZ<{F)}bzMXAx z-=SZwq$smSc=}s$r%_LKPf1|;<1Aj*G>iV-ApNTKKfU0Z0IDJj*MKu%#qNkMgmZs1 zV-pIp#|HYCg*QyZFoIfcYI(*}Y$&&uP^G*z++i5-QYt24Z~v0Lbki$ny{7K(gC$CP zb;r;06NV<~UT){Jz)(pb4GFt-H@E~iQBJI!^qh`7S*JkE0#S2i;-mu96ZoOckNRKh zi>X*ptX#AVm&O%8Q8CAC^!(4g+6L}WzG-8wDOeG8`h#_PdPb{oS2j67dr?c`_{$%E zecy}fe$MiUrlI6={ENt4;{lv!SDCX%O(15DSEG4a4ZT}wV}O6S6XQa4b+;QH4fYy; z9>!b!ZkqAV#LLDB=YpWh$x``t3rd}eU&RYwc+ygN;`Z#PeRx~CpRiAJ9F2Zn3=$cd{G&WtA^woSixK9~b!ELZBaqkpJ954T7^MMe`E z-&za-xmmbxY8oupw7foL0B(I~;($?a$2ZKbNhbZ z3=VC?NFC~28A_H*POC-V)*%Xu&&7fFT~T4bEPsd-v08W?UQ+Wkuu zahHEi@~hZSv})}8z+x-U;X<`#DGi?jp!Y!|FD0^PyxB7^LtVbKco&7S%DkjohznV$ zcKYZNIvC9i3HcG3hg~k%4bxXSx#mXZK*0Nw}wYRsg56YByj~G3YdAb zCmd9o^i>k*y^GX)JH1W9bX>6l_Zjr_*CW0p&A+r=QB|r5LA@AdZJMOW&~Tm69aWv% zJn}!Yd>mDdwBv#tBth*Vt-@S-KKb)aOeChYk5`4Cm5%HiADCi{q^D{J@*fL^CnKXz z3ic0O0qG=N@9SuPaj239yKT#JXfgH@W7hHYaF*IfWj>0oVevw>SU-ltU&uzSef9;m z;I)ZBYdU>wXddF4`EPprdJe&T$#|BN_9j*n%3_*9->(}r9SLmCnNjl;R9>`*&%C#h zCRq^1Wu*7v>pUBNr#2VmzYutqg;iQghiQQi=@{= z)a^^#lW!;NQSO#cvhSE$yK+_uC+$`(r*o~iSNZ6>G49eWtAG-&9Qvy#Ez@Q&F&WM{FCuHEN3KJw%Uc@Iho7K8;&zq_BG?ey} zncHu|d--EJ`Xnv2ElNj7b-O+L!>SL&y<+2r58ch2N1-Kl{ZSO+qmrbDHFY3y9>TX0 zXX`43yv(94?I$JPr=#~x-l})o`FY%0A+os`8;3%NSOLd*pg)M*ViJnl-Uh#jZy5^j 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 X>0xQY#Qe`U!{6io_x{B9&+C5xXHl?z diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json deleted file mode 100644 index 261e92cb..00000000 --- a/app/release/output-metadata.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "version": 3, - "artifactType": { - "type": "APK", - "kind": "Directory" - }, - "applicationId": "com.bitchat.android", - "variantName": "release", - "elements": [ - { - "type": "SINGLE", - "filters": [], - "attributes": [], - "versionCode": 3, - "versionName": "0.7", - "outputFile": "app-release.apk" - } - ], - "elementType": "File", - "baselineProfiles": [ - { - "minApi": 28, - "maxApi": 30, - "baselineProfiles": [ - "baselineProfiles/1/app-release.dm" - ] - }, - { - "minApi": 31, - "maxApi": 2147483647, - "baselineProfiles": [ - "baselineProfiles/0/app-release.dm" - ] - } - ], - "minSdkVersionForDexing": 26 -} \ No newline at end of file diff --git a/app/src/main/java/com/bitchat/android/wallet/service/CashuService.kt b/app/src/main/java/com/bitchat/android/wallet/service/CashuService.kt index c16ccd29..27d0b7b4 100644 --- a/app/src/main/java/com/bitchat/android/wallet/service/CashuService.kt +++ b/app/src/main/java/com/bitchat/android/wallet/service/CashuService.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.Dispatchers import android.util.Log import android.content.Context import com.bitchat.android.wallet.data.* +import com.bitchat.android.wallet.repository.WalletRepository import com.bitchat.android.parsing.CashuTokenParser import uniffi.cdk_ffi.* import java.math.BigDecimal @@ -21,6 +22,7 @@ class CashuService { private var currentUnit: String = "sat" private var isInitialized = false private var isCdkAvailable = false + private var repository: WalletRepository? = null companion object { private const val TAG = "CashuService" @@ -36,6 +38,108 @@ class CashuService { } } + /** + * Initialize the repository instance + */ + private fun initializeRepository() { + if (repository == null) { + val context = getApplicationContext() + repository = WalletRepository.getInstance(context) + } + } + + /** + * Check if a mint exists in the user's mint list + */ + private fun checkMintExists(mintUrl: String, mints: List): Boolean { + return mints.any { it.url == mintUrl } + } + + /** + * Add a mint if authorized (autoAdd = true) + */ + private suspend fun addMintIfAuthorized(mintUrl: String, autoAdd: Boolean): Result { + return withContext(Dispatchers.IO) { + try { + if (!autoAdd) { + Log.d(TAG, "Auto-add not authorized for mint: $mintUrl") + return@withContext Result.success(false) + } + + initializeRepository() + val repo = repository ?: return@withContext Result.failure(Exception("Repository not available")) + + Log.d(TAG, "Adding mint automatically: $mintUrl") + + val mintInfoResult = getMintInfo(mintUrl) + if (mintInfoResult.isFailure) { + val error = mintInfoResult.exceptionOrNull() ?: Exception("Unknown error") + Log.e(TAG, "Failed to get mint info for: $mintUrl", error) + return@withContext Result.failure(error) + } + + val mintInfo = mintInfoResult.getOrThrow() + val mint = Mint( + url = mintUrl, + nickname = mintInfo.name.ifEmpty { "Auto-added Mint" }, + info = mintInfo, + keysets = emptyList(), // Will be populated by CDK + active = true, + dateAdded = Date() + ) + + val saveMintResult = repo.saveMint(mint) + if (saveMintResult.isFailure) { + val error = saveMintResult.exceptionOrNull() ?: Exception("Unknown error") + Log.e(TAG, "Failed to save mint: $mintUrl", error) + return@withContext Result.failure(error) + } + + Log.d(TAG, "Successfully added mint: $mintUrl") + return@withContext Result.success(true) + + } catch (e: Exception) { + Log.e(TAG, "Exception while adding mint: $mintUrl", e) + return@withContext Result.failure(e) + } + } + } + + /** + * Set the active mint and initialize wallet with it + */ + private suspend fun setActiveMintAndInitialize(mintUrl: String): Result { + return withContext(Dispatchers.IO) { + try { + initializeRepository() + val repo = repository ?: return@withContext Result.failure(Exception("Repository not available")) + + // Set active mint in repository + val setActiveMintResult = repo.setActiveMint(mintUrl) + if (setActiveMintResult.isFailure) { + val error = setActiveMintResult.exceptionOrNull() ?: Exception("Unknown error") + Log.e(TAG, "Failed to set active mint: $mintUrl", error) + return@withContext Result.failure(error) + } + + // Initialize wallet with the mint + val initWalletResult = initializeWallet(mintUrl) + if (initWalletResult.isFailure) { + val error = initWalletResult.exceptionOrNull() ?: Exception("Unknown error") + Log.e(TAG, "Failed to initialize wallet with mint: $mintUrl", error) + return@withContext Result.failure(error) + } + + Log.d(TAG, "Set active mint and initialized wallet: $mintUrl") + return@withContext Result.success(Unit) + + } catch (e: Exception) { + Log.e(TAG, "Exception while setting active mint: $mintUrl", e) + return@withContext Result.failure(e) + } + } + } + /** * Check if CDK is available and initialize appropriately */ @@ -263,31 +367,73 @@ class CashuService { } /** - * Receive a Cashu token - * Note: CDK doesn't have explicit "receive" - tokens are auto-received when sent - * This function decodes and validates the token + * Receive a Cashu token with mint management + * @param token The Cashu token to receive + * @param autoAdd Whether to automatically add unknown mints + * @param currentMints The current list of user's mints + * @param decodedToken Optional pre-decoded token to avoid re-decoding */ - suspend fun receiveToken(token: String): Result { + suspend fun receiveToken( + token: String, + autoAdd: Boolean = true, + currentMints: List = emptyList(), + decodedToken: CashuToken? = null + ): Result { return withContext(Dispatchers.IO) { try { - if (!isInitialized) { - initializeWallet(DEFAULT_MINT_URL).getOrThrow() + // Decode token if not provided + val tokenData = decodedToken ?: decodeToken(token).getOrThrow() + val mintUrl = tokenData.mint + val amount = tokenData.amount.toLong() + + Log.d(TAG, "Processing token: amount=$amount from mint=$mintUrl") + + // Check if mint exists + val mintExists = checkMintExists(mintUrl, currentMints) + + if (!mintExists) { + Log.d(TAG, "Mint $mintUrl not found, attempting to add...") + + // Try to add the mint if authorized + addMintIfAuthorized(mintUrl, autoAdd).fold( + onSuccess = { added -> + if (!added) { + return@withContext Result.failure( + Exception("Mint $mintUrl not found and auto-add not authorized") + ) + } + }, + onFailure = { error -> + Log.e(TAG, "Failed to add mint $mintUrl", error) + return@withContext Result.failure( + Exception("Failed to add mint: $mintUrl - ${error.message}") + ) + } + ) } + // Set active mint and initialize wallet with it + setActiveMintAndInitialize(mintUrl).fold( + onSuccess = { + Log.d(TAG, "Successfully set active mint: $mintUrl") + }, + onFailure = { error -> + Log.e(TAG, "Failed to set active mint: $mintUrl", error) + return@withContext Result.failure( + Exception("Failed to set active mint: $mintUrl - ${error.message}") + ) + } + ) + + // Now receive the token with the properly initialized wallet if (!isCdkAvailable || wallet == null) { return@withContext Result.failure(Exception("CDK not available")) } - // Decode the token to get amount - val decodedToken = decodeToken(token).getOrThrow() - val amount = decodedToken.amount.toLong() - - Log.d(TAG, "Token validation successful, amount: $amount") - + Log.d(TAG, "Receiving token with amount: $amount") val ffiAmount = wallet!!.receive(token) - - Log.d(TAG, "FFI amount: ${ffiAmount}") - + + Log.d(TAG, "Successfully received token: ${ffiAmount.value}") Result.success(ffiAmount.value.toLong()) } catch (e: FfiException) { diff --git a/app/src/main/java/com/bitchat/android/wallet/viewmodel/WalletViewModel.kt b/app/src/main/java/com/bitchat/android/wallet/viewmodel/WalletViewModel.kt index 82fc2eec..cd870581 100644 --- a/app/src/main/java/com/bitchat/android/wallet/viewmodel/WalletViewModel.kt +++ b/app/src/main/java/com/bitchat/android/wallet/viewmodel/WalletViewModel.kt @@ -599,7 +599,30 @@ class WalletViewModel(application: Application) : AndroidViewModel(application) viewModelScope.launch { try { _isLoading.value = true - cashuService.receiveToken(token).onSuccess { amount -> + + // Get decoded token and current mints + val decodedToken = _decodedToken.value + if (decodedToken == null) { + val failureData = FailureAnimationData( + errorMessage = "Failed to decode token", + operationType = "Token Receive" + ) + showFailureAnimation(failureData) + clearTokenInput() + delay(500) + hideReceiveDialog() + return@launch + } + + val currentMints = _mints.value ?: emptyList() + + // Use the new CashuService.receiveToken with mint management + cashuService.receiveToken( + token = token, + autoAdd = true, // Enable automatic mint addition + currentMints = currentMints, + decodedToken = decodedToken + ).onSuccess { amount -> // Add transaction val transaction = WalletTransaction( @@ -615,6 +638,10 @@ class WalletViewModel(application: Application) : AndroidViewModel(application) repository.saveTransaction(transaction).onSuccess { loadTransactions() refreshBalance() + // Reload mints in case a new one was added + repository.getMints().onSuccess { mintList -> + _mints.value = mintList + } // Clear token input immediately clearTokenInput() @@ -836,6 +863,8 @@ class WalletViewModel(application: Application) : AndroidViewModel(application) } } + + /** * Set the active mint */