From 7be7582c1b3deb302b222f4765488c090fa6abca Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 22 May 2026 16:29:54 -0700 Subject: [PATCH 01/13] feat: support CTX Redeem URL and save data in DB --- .../wallet/common/data/entity/GiftCard.kt | 3 ++- .../dashspend/ctx/model/GiftCardResponse.kt | 2 ++ .../data/dashspend/model/GiftCardInfo.kt | 1 + .../repository/CTXSpendRepository.kt | 1 + .../ui/dashspend/DashSpendViewModel.kt | 7 +++++- .../dialogs/GiftCardDetailsDialog.kt | 16 ++++++++++++ .../dialogs/GiftCardDetailsViewModel.kt | 25 ++++++------------- .../main/res/values/strings-explore-dash.xml | 1 + .../schildbach/wallet/database/AppDatabase.kt | 2 +- .../wallet/database/AppDatabaseMigrations.kt | 10 ++++++++ .../de/schildbach/wallet/di/DatabaseModule.kt | 3 ++- 11 files changed, 50 insertions(+), 21 deletions(-) diff --git a/common/src/main/java/org/dash/wallet/common/data/entity/GiftCard.kt b/common/src/main/java/org/dash/wallet/common/data/entity/GiftCard.kt index 5fe60bf1d5..149e441e49 100644 --- a/common/src/main/java/org/dash/wallet/common/data/entity/GiftCard.kt +++ b/common/src/main/java/org/dash/wallet/common/data/entity/GiftCard.kt @@ -33,5 +33,6 @@ data class GiftCard( var barcodeFormat: BarcodeFormat? = null, var merchantUrl: String? = null, // holds claimLink or redeemUrl var note: String? = null, // holds order number - var index: Int = 0 + var index: Int = 0, + var redeemUrlChallenge: String? = null ) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/ctx/model/GiftCardResponse.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/ctx/model/GiftCardResponse.kt index d522c7093a..63afde081c 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/ctx/model/GiftCardResponse.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/ctx/model/GiftCardResponse.kt @@ -33,7 +33,9 @@ data class GiftCardResponse( val paymentId: String? = "", val percentDiscount: String? = "", val rate: String? = "", + val redeemType: String? = "", val redeemUrl: String? = "", + val redeemUrlChallenge: String? = "", @SerializedName("paymentFiatAmount") val fiatAmount: String? = "", @SerializedName("paymentFiatCurrency") val fiatCurrency: String? = "", @SerializedName("paymentUrls") val paymentUrls: Map? = buildMap { } diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/model/GiftCardInfo.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/model/GiftCardInfo.kt index b087bcfc51..36f04eca2b 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/model/GiftCardInfo.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/model/GiftCardInfo.kt @@ -23,6 +23,7 @@ data class GiftCardInfo( val percentDiscount: String? = "", val rate: String? = "", val redeemUrl: String? = "", + val redeemUrlChallenge: String? = "", val fiatAmount: String? = "", val fiatCurrency: String? = "", val paymentUrls: Map? = buildMap { } diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt index ad9fd9bf6f..f2025b9165 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt @@ -212,6 +212,7 @@ class CTXSpendRepository @Inject constructor( percentDiscount = response.percentDiscount, rate = response.rate, redeemUrl = response.redeemUrl, + redeemUrlChallenge = response.redeemUrlChallenge, fiatAmount = response.fiatAmount, fiatCurrency = response.fiatCurrency, paymentUrls = response.paymentUrls diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/DashSpendViewModel.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/DashSpendViewModel.kt index 4d58791818..88135b0568 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/DashSpendViewModel.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/DashSpendViewModel.kt @@ -395,7 +395,11 @@ class DashSpendViewModel @Inject constructor( try { response?.apply { return merchant.deepCopy( - savingsPercentage = this.first.maxOf { it.savingsPercentage }, + savingsPercentage = if (this.first.isNotEmpty()) { + this.first.maxOf { it.savingsPercentage } + } else { + 0 + }, giftCardProviders = this.second ) } @@ -554,6 +558,7 @@ class DashSpendViewModel @Inject constructor( merchantName = _giftCardMerchant.value?.name ?: "", price = it.fiatAmount?.toDouble() ?: 0.0, merchantUrl = it.redeemUrl, + redeemUrlChallenge = it.redeemUrlChallenge, note = it.id, index = index++ ) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsDialog.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsDialog.kt index 4e61e4a56b..a3bf97de9d 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsDialog.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsDialog.kt @@ -421,6 +421,7 @@ private fun GiftCardItemCard( val hasNumber = !giftCard?.number.isNullOrEmpty() val hasPin = !giftCard?.pin.isNullOrEmpty() val hasMerchantUrl = !giftCard?.merchantUrl.isNullOrEmpty() + val hasRedeemUrlChallenge = !giftCard?.redeemUrlChallenge.isNullOrEmpty() val isLoading = giftCard != null && !hasNumber && !hasMerchantUrl && @@ -449,6 +450,21 @@ private fun GiftCardItemCard( trailingActionText = stringResource(R.string.purchase_check_current_balance), onTrailingActionClick = { onBalanceCheck() } ) + if (hasRedeemUrlChallenge) { + ListItem( + label = stringResource(R.string.purchase_redeem_url_challange), + trailingText = giftCard.redeemUrlChallenge, + trailingTrailingIcon = { + Icon( + painter = painterResource(R.drawable.ic_copy), + contentDescription = null, + modifier = Modifier + .size(14.dp) + .clickable { onCopyNumber(giftCard.redeemUrlChallenge!!) } + ) + } + ) + } } // Error text diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt index fccf031f24..774f9abb31 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt @@ -263,24 +263,14 @@ class GiftCardDetailsViewModel @Inject constructor( state } else if (giftCard.redeemUrl?.isNotEmpty() == true) { log.error("CTXSpend returned a redeem url card: not supported") - val state = uiState.value.copy( + updateGiftCardWithURL(index = 0, giftCard.redeemUrl, giftCard.redeemUrlChallenge) + val newState = uiState.value.copy( status = giftCard.status, queries = uiState.value.queries + 1, - error = CTXSpendException( - ResourceString( - R.string.gift_card_redeem_url_not_supported, - listOf( - GiftCardProviderType.CTX.name, - giftCard.id, - giftCard.paymentId ?: "", - txid - ) - ), - giftCard - ) + error = null ) cancelTicker() - state + newState } else { uiState.value.copy( status = giftCard.status, @@ -465,7 +455,7 @@ class GiftCardDetailsViewModel @Inject constructor( } } } else if (giftCard.redeemUrl?.isNotEmpty() == true) { - updateGiftCard(index, giftCard.redeemUrl) + updateGiftCard(index, giftCard.redeemUrl, giftCard.redeemUrlChallenge) } } cancelTicker() @@ -560,13 +550,14 @@ class GiftCardDetailsViewModel @Inject constructor( logOnPurchaseEvents(giftCard) } - private suspend fun updateGiftCard(index: Int, merchantUrl: String) { + private suspend fun updateGiftCardWithURL(index: Int, redeemUrl: String, redeemUrlChallenge: String?) { val giftCard = uiState.value.giftCards.find { it.index == index } ?: return applicationScope.launch { metadataProvider.updateGiftCardMetadata( giftCard.copy( - merchantUrl = merchantUrl + merchantUrl = redeemUrl, + redeemUrlChallenge = redeemUrlChallenge ) ) }.join() diff --git a/features/exploredash/src/main/res/values/strings-explore-dash.xml b/features/exploredash/src/main/res/values/strings-explore-dash.xml index 51ea57368b..1ff5e3e79c 100644 --- a/features/exploredash/src/main/res/values/strings-explore-dash.xml +++ b/features/exploredash/src/main/res/values/strings-explore-dash.xml @@ -203,6 +203,7 @@ Gift card details Original purchase See card details + Challenge Card Number Card PIN View Transaction Details diff --git a/wallet/src/de/schildbach/wallet/database/AppDatabase.kt b/wallet/src/de/schildbach/wallet/database/AppDatabase.kt index fc32c1e862..d0df3cd049 100644 --- a/wallet/src/de/schildbach/wallet/database/AppDatabase.kt +++ b/wallet/src/de/schildbach/wallet/database/AppDatabase.kt @@ -64,7 +64,7 @@ import org.dash.wallet.features.exploredash.utils.RoomConverters TxDisplayCacheEntry::class, TxGroupCacheEntry::class ], - version = 18, // if increasing version, we need migrations to preserve tx/addr metadata, + version = 19, // if increasing version, we need migrations to preserve tx/addr metadata, exportSchema = true ) @TypeConverters(RoomConverters::class, BlockchainStateRoomConverters::class) diff --git a/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt b/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt index 38efb03760..0532af889c 100644 --- a/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt +++ b/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt @@ -189,6 +189,16 @@ class AppDatabaseMigrations { } } + val migration18to19 = object : Migration(18, 19) { + override fun migrate(database: SupportSQLiteDatabase) { + // gift_cards gained a nullable `redeemUrlChallenge` column to persist + // the CTX redeem-URL challenge alongside each gift card. + database.execSQL( + "ALTER TABLE `gift_cards` ADD COLUMN `redeemUrlChallenge` TEXT" + ) + } + } + val migration15to16 = object : Migration(15, 16) { override fun migrate(database: SupportSQLiteDatabase) { // previous versions have no data in invitations table, so do this diff --git a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt index 607bda9912..0978b3c688 100644 --- a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt +++ b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt @@ -45,7 +45,8 @@ object DatabaseModule { AppDatabaseMigrations.migration14to15, AppDatabaseMigrations.migration15to16, AppDatabaseMigrations.migration16to17, - AppDatabaseMigrations.migration17to18 + AppDatabaseMigrations.migration17to18, + AppDatabaseMigrations.migration18to19 ) // destructive migrations are used from versions 1 to 11 .fallbackToDestructiveMigration() From 327f4d12258246f5c86c5e5905cc76c621756a05 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 22 May 2026 16:31:08 -0700 Subject: [PATCH 02/13] fix: display 0% instead of nothing on the purchase giftcard confirmation dialog --- .../dash/wallet/features/exploredash/utils/SavingsFormatting.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/utils/SavingsFormatting.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/utils/SavingsFormatting.kt index e3bc1f7d4d..16b77179c4 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/utils/SavingsFormatting.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/utils/SavingsFormatting.kt @@ -38,7 +38,6 @@ object SavingsFormatting { decimals: Int = 2, discountPrefix: String = "" ): String { - if (percent == 0.0) return "" val numberFormat = DecimalFormat().apply { maximumFractionDigits = decimals minimumFractionDigits = 0 From f01792458f62fe50888335244f3680c17c86d10e Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Wed, 27 May 2026 14:12:04 -0400 Subject: [PATCH 03/13] fix: add support for CTX redeem url gift cards --- .../parsers/DashPaymentIntentParser.kt | 3 + .../exploredash/di/ExploreDashModule.kt | 4 +- .../network/service/ctxspend/CTXSpendApi.kt | 5 +- .../repository/CTXSpendRepository.kt | 66 +- .../repository/DashSpendRepository.kt | 1 + .../repository/PiggyCardsRepository.kt | 4 + .../dialogs/GiftCardDetailsViewModel.kt | 7 +- .../19.json | 1188 +++++++++++++++++ .../wallet/payments/SendCoinsTaskRunner.kt | 2 +- 9 files changed, 1269 insertions(+), 11 deletions(-) create mode 100644 wallet/schemas/de.schildbach.wallet.database.AppDatabase/19.json diff --git a/common/src/main/java/org/dash/wallet/common/payments/parsers/DashPaymentIntentParser.kt b/common/src/main/java/org/dash/wallet/common/payments/parsers/DashPaymentIntentParser.kt index a4580e1d89..42c832f2f3 100644 --- a/common/src/main/java/org/dash/wallet/common/payments/parsers/DashPaymentIntentParser.kt +++ b/common/src/main/java/org/dash/wallet/common/payments/parsers/DashPaymentIntentParser.kt @@ -54,6 +54,9 @@ class DashPaymentIntentParser(params: NetworkParameters) : PaymentIntentParser(" private val log = LoggerFactory.getLogger(DashPaymentIntentParser::class.java) private val addressParser = AddressParser.getDashAddressParser(params) + init { + log.info("network parameters = {}", params.id) + } override suspend fun parse(input: String): PaymentIntent { return parse(input, true) } diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/di/ExploreDashModule.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/di/ExploreDashModule.kt index 45850b1f73..c226c3dfce 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/di/ExploreDashModule.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/di/ExploreDashModule.kt @@ -97,6 +97,6 @@ abstract class ExploreDashModule { @Binds abstract fun bindDataSyncService(exploreDatabase: ExploreDataSyncStatus): DataSyncStatusService - @Binds - abstract fun provideCTXSpendRepository(ctxSpendRepository: CTXSpendRepository): CTXSpendRepositoryInt + //@Binds + //abstract fun provideCTXSpendRepository(ctxSpendRepository: CTXSpendRepository): CTXSpendRepositoryInt } diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/service/ctxspend/CTXSpendApi.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/service/ctxspend/CTXSpendApi.kt index 9812c688e4..a9ccce7ba0 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/service/ctxspend/CTXSpendApi.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/network/service/ctxspend/CTXSpendApi.kt @@ -40,7 +40,10 @@ interface CTXSpendApi { suspend fun purchaseGiftCard(@Body purchaseGiftCardRequest: PurchaseGiftCardRequest): GiftCardResponse @GET("gift-cards") - suspend fun getGiftCard(@Query("txid") txid: String): GiftCardResponse? + suspend fun getGiftCardByTxId(@Query("txid") txid: String): GiftCardResponse? + + @GET("gift-cards/{id}") + suspend fun getGiftCardByOrderId(@Path("id") id: String): GiftCardResponse? @GET("merchants/{id}") suspend fun getMerchant(@Path("id") id: String): GetMerchantResponse? diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt index f2025b9165..c99be86340 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/CTXSpendRepository.kt @@ -102,7 +102,7 @@ class CTXSpendRepository @Inject constructor( private val api: CTXSpendApi, private val config: CTXSpendConfig, private val tokenAuthenticator: TokenAuthenticator -) : CTXSpendRepositoryInt, DashSpendRepository { +) : DashSpendRepository { companion object { private val REFRESH_TOKEN_EXPIRATION = TimeUnit.DAYS.toMillis(90) } @@ -144,7 +144,7 @@ class CTXSpendRepository @Inject constructor( config.set(CTXSpendConfig.PREFS_KEY_REFRESH_TOKEN_TIME, 0L) } - override suspend fun purchaseGiftCard( + suspend fun purchaseGiftCard( cryptoCurrency: String, fiatCurrency: String, fiatAmount: String, @@ -153,7 +153,7 @@ class CTXSpendRepository @Inject constructor( return api.purchaseGiftCard( purchaseGiftCardRequest = PurchaseGiftCardRequest( cryptoCurrency = "DASH", - fiatCurrency = "USD", + fiatCurrency = fiatCurrency, fiatAmount = fiatAmount, merchantId = merchantId ) @@ -194,7 +194,57 @@ class CTXSpendRepository @Inject constructor( } override suspend fun getGiftCard(giftCardId: String): List { - val response = getGiftCardByTxid(giftCardId) + val response = getGiftCardByOrderId2(giftCardId) + + return response?.let { card -> + listOf( + GiftCardInfo( + card.id, + merchantName = card.merchantName, + status = GiftCardStatus.valueOf(card.status.uppercase()), + barcodeUrl = card.barcodeUrl, + cardNumber = card.cardNumber, + cardPin = card.cardPin, + cryptoAmount = card.cryptoAmount, + cryptoCurrency = card.cryptoCurrency, + paymentCryptoNetwork = card.paymentCryptoNetwork, + paymentId = card.paymentId, + percentDiscount = card.percentDiscount, + rate = card.rate, + redeemUrl = card.redeemUrl, + redeemUrlChallenge = card.redeemUrlChallenge, + fiatAmount = card.fiatAmount, + fiatCurrency = card.fiatCurrency, + paymentUrls = card.paymentUrls + ) + ) + } ?: listOf() + +// return response?.result?.map { card -> +// GiftCardInfo( +// card.id, +// merchantName = card.merchantName, +// status = GiftCardStatus.valueOf(card.status.uppercase()), +// barcodeUrl = card.barcodeUrl, +// cardNumber = card.cardNumber, +// cardPin = card.cardPin, +// cryptoAmount = card.cryptoAmount, +// cryptoCurrency = card.cryptoCurrency, +// paymentCryptoNetwork = card.paymentCryptoNetwork, +// paymentId = card.paymentId, +// percentDiscount = card.percentDiscount, +// rate = card.rate, +// redeemUrl = card.redeemUrl, +// redeemUrlChallenge = card.redeemUrlChallenge, +// fiatAmount = card.fiatAmount, +// fiatCurrency = card.fiatCurrency, +// paymentUrls = card.paymentUrls +// ) +// } ?: listOf() + } + + override suspend fun getGiftCardByTxId(giftCardId: String): List { + val response = _getGiftCardByTxId(giftCardId) return response?.let { listOf( @@ -248,8 +298,12 @@ class CTXSpendRepository @Inject constructor( // override suspend fun getMerchant(merchantId: String): GetMerchantResponse? = // api.getMerchant(merchantId) - override suspend fun getGiftCardByTxid(txid: String): GiftCardResponse? { - return api.getGiftCard(txid) + private suspend fun _getGiftCardByTxId(txid: String): GiftCardResponse? { + return api.getGiftCardByTxId(txid) + } + + private suspend fun getGiftCardByOrderId2(orderId: String): GiftCardResponse? { + return api.getGiftCardByOrderId(orderId) } override suspend fun refreshToken(): Boolean { diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/DashSpendRepository.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/DashSpendRepository.kt index 26ba818456..a6b3ea28db 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/DashSpendRepository.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/DashSpendRepository.kt @@ -41,5 +41,6 @@ interface DashSpendRepository { merchantId: String ): List suspend fun getGiftCard(giftCardId: String): List + suspend fun getGiftCardByTxId(txId: String): List fun getGiftCardDiscount(merchantId: String, denomination: Double): Double } diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/PiggyCardsRepository.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/PiggyCardsRepository.kt index b4c7076c1d..68dfa278ff 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/PiggyCardsRepository.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/repository/PiggyCardsRepository.kt @@ -530,6 +530,10 @@ class PiggyCardsRepository @Inject constructor( } } + override suspend fun getGiftCardByTxId(txId: String): List { + TODO("PiggyCards requires an orderId, not a txId") + } + suspend fun getAccountEmail(): String? { return config.getSecuredData(PiggyCardsConfig.PREFS_KEY_EMAIL) } diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt index 774f9abb31..289b141f20 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt @@ -197,7 +197,12 @@ class GiftCardDetailsViewModel @Inject constructor( } try { - val giftCards = ctxSpendRepository.getGiftCard(txid.toStringBase58()) + val orderId = giftCardDao.getCardForTransaction(txid).firstOrNull()?.note + val giftCards = if (orderId != null) { + ctxSpendRepository.getGiftCard(orderId) + } else { + ctxSpendRepository.getGiftCardByTxId(txid.toStringBase58()) + } val giftCard = giftCards.firstOrNull() // Single state update with all changes val newState = if (giftCard != null) { diff --git a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/19.json b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/19.json new file mode 100644 index 0000000000..6cf3365543 --- /dev/null +++ b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/19.json @@ -0,0 +1,1188 @@ +{ + "formatVersion": 1, + "database": { + "version": 19, + "identityHash": "37d0d678c5a25041983b612b1d9eba0f", + "entities": [ + { + "tableName": "exchange_rates", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`currencyCode` TEXT NOT NULL, `rate` TEXT, PRIMARY KEY(`currencyCode`))", + "fields": [ + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "currencyCode" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "blockchain_state", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bestChainDate` INTEGER, `bestChainHeight` INTEGER NOT NULL, `replaying` INTEGER NOT NULL, `impediments` TEXT NOT NULL, `chainlockHeight` INTEGER NOT NULL, `mnlistHeight` INTEGER NOT NULL, `percentageSync` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "bestChainDate", + "columnName": "bestChainDate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bestChainHeight", + "columnName": "bestChainHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "replaying", + "columnName": "replaying", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "impediments", + "columnName": "impediments", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chainlockHeight", + "columnName": "chainlockHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mnlistHeight", + "columnName": "mnlistHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "percentageSync", + "columnName": "percentageSync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `timestamp` INTEGER NOT NULL, `value` INTEGER NOT NULL, `type` TEXT NOT NULL, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT NOT NULL, `service` TEXT, `customIconId` BLOB, PRIMARY KEY(`txId`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconId", + "columnName": "customIconId", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "address_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address` TEXT NOT NULL, `isInput` INTEGER NOT NULL, `taxCategory` TEXT NOT NULL, `service` TEXT NOT NULL, PRIMARY KEY(`address`, `isInput`))", + "fields": [ + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isInput", + "columnName": "isInput", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "address", + "isInput" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "icon_bitmaps", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` BLOB NOT NULL, `imageData` BLOB NOT NULL, `originalUrl` TEXT NOT NULL, `height` INTEGER NOT NULL, `width` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "imageData", + "columnName": "imageData", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "originalUrl", + "columnName": "originalUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "gift_cards", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `merchantName` TEXT NOT NULL, `price` REAL NOT NULL, `number` TEXT, `pin` TEXT, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `note` TEXT, `index` INTEGER NOT NULL, `redeemUrlChallenge` TEXT, PRIMARY KEY(`txId`, `index`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pin", + "columnName": "pin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redeemUrlChallenge", + "columnName": "redeemUrlChallenge", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId", + "index" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "dashpay_profile", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `publicMessage` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `avatarHash` BLOB, `avatarFingerprint` BLOB, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`userId`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "publicMessage", + "columnName": "publicMessage", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarHash", + "columnName": "avatarHash", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "avatarFingerprint", + "columnName": "avatarFingerprint", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "userId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "dashpay_contact_request", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `toUserId` TEXT NOT NULL, `accountReference` INTEGER NOT NULL, `encryptedPublicKey` BLOB NOT NULL, `senderKeyIndex` INTEGER NOT NULL, `recipientKeyIndex` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `encryptedAccountLabel` BLOB, `autoAcceptProof` BLOB, PRIMARY KEY(`userId`, `toUserId`, `accountReference`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "toUserId", + "columnName": "toUserId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountReference", + "columnName": "accountReference", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "encryptedPublicKey", + "columnName": "encryptedPublicKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "senderKeyIndex", + "columnName": "senderKeyIndex", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipientKeyIndex", + "columnName": "recipientKeyIndex", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "encryptedAccountLabel", + "columnName": "encryptedAccountLabel", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "autoAcceptProof", + "columnName": "autoAcceptProof", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "userId", + "toUserId", + "accountReference" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "user_alerts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`stringResId` INTEGER NOT NULL, `iconResId` INTEGER NOT NULL, `dismissed` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL, PRIMARY KEY(`stringResId`))", + "fields": [ + { + "fieldPath": "stringResId", + "columnName": "stringResId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconResId", + "columnName": "iconResId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dismissed", + "columnName": "dismissed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "stringResId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "invitation_table", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`fundingAddress` TEXT NOT NULL, `userId` TEXT NOT NULL, `txid` BLOB, `createdAt` INTEGER NOT NULL, `memo` TEXT NOT NULL, `sentAt` INTEGER NOT NULL, `acceptedAt` INTEGER NOT NULL, `shortDynamicLink` TEXT, `dynamicLink` TEXT, PRIMARY KEY(`fundingAddress`))", + "fields": [ + { + "fieldPath": "fundingAddress", + "columnName": "fundingAddress", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "txid", + "columnName": "txid", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sentAt", + "columnName": "sentAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "acceptedAt", + "columnName": "acceptedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortDynamicLink", + "columnName": "shortDynamicLink", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dynamicLink", + "columnName": "dynamicLink", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "fundingAddress" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cacheTimestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "cacheTimestamp", + "columnName": "cacheTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "sentTimestamp", + "columnName": "sentTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconUrl", + "columnName": "customIconUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardNumber", + "columnName": "giftCardNumber", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardPin", + "columnName": "giftCardPin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "originalPrice", + "columnName": "originalPrice", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata_platform", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` REAL, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, PRIMARY KEY(`id`, `txId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "sentTimestamp", + "columnName": "sentTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconUrl", + "columnName": "customIconUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardNumber", + "columnName": "giftCardNumber", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardPin", + "columnName": "giftCardPin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "originalPrice", + "columnName": "originalPrice", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "username_requests", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`requestId` TEXT NOT NULL, `username` TEXT NOT NULL, `normalizedLabel` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `identity` TEXT NOT NULL, `link` TEXT, `votes` INTEGER NOT NULL, `lockVotes` INTEGER NOT NULL, `isApproved` INTEGER NOT NULL, PRIMARY KEY(`requestId`))", + "fields": [ + { + "fieldPath": "requestId", + "columnName": "requestId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "normalizedLabel", + "columnName": "normalizedLabel", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "identity", + "columnName": "identity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "link", + "columnName": "link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "votes", + "columnName": "votes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lockVotes", + "columnName": "lockVotes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isApproved", + "columnName": "isApproved", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "requestId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "username_votes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `username` TEXT NOT NULL, `identity` TEXT NOT NULL, `type` TEXT NOT NULL, `timestamp` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "identity", + "columnName": "identity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "imported_masternode_keys", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`proTxHash` BLOB NOT NULL, `address` TEXT NOT NULL, `votingPrivateKey` BLOB NOT NULL, `votingPublicKey` BLOB NOT NULL, `votingPubKeyHash` BLOB NOT NULL, PRIMARY KEY(`proTxHash`))", + "fields": [ + { + "fieldPath": "proTxHash", + "columnName": "proTxHash", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "votingPrivateKey", + "columnName": "votingPrivateKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "votingPublicKey", + "columnName": "votingPublicKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "votingPubKeyHash", + "columnName": "votingPubKeyHash", + "affinity": "BLOB", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "proTxHash" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "topup_table", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `toUserId` TEXT NOT NULL, `workId` TEXT NOT NULL, `creditedAt` INTEGER NOT NULL, PRIMARY KEY(`txId`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "toUserId", + "columnName": "toUserId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "workId", + "columnName": "workId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "creditedAt", + "columnName": "creditedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "tx_display_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` TEXT NOT NULL, `title` TEXT NOT NULL, `valueSatoshis` INTEGER NOT NULL, `iconType` INTEGER NOT NULL, `iconBgType` INTEGER NOT NULL, `statusText` TEXT NOT NULL, `comment` TEXT NOT NULL, `transactionAmount` INTEGER NOT NULL, `time` INTEGER NOT NULL, `hasErrors` INTEGER NOT NULL, `service` TEXT, `exchangeRateFiatCode` TEXT, `exchangeRateFiatValue` INTEGER, `contactUsername` TEXT, `contactDisplayName` TEXT, `contactAvatarUrl` TEXT, `contactUserId` TEXT, `filterFlags` INTEGER NOT NULL, PRIMARY KEY(`rowId`))", + "fields": [ + { + "fieldPath": "rowId", + "columnName": "rowId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "valueSatoshis", + "columnName": "valueSatoshis", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconType", + "columnName": "iconType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconBgType", + "columnName": "iconBgType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "statusText", + "columnName": "statusText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "transactionAmount", + "columnName": "transactionAmount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasErrors", + "columnName": "hasErrors", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "exchangeRateFiatCode", + "columnName": "exchangeRateFiatCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "exchangeRateFiatValue", + "columnName": "exchangeRateFiatValue", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contactUsername", + "columnName": "contactUsername", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactDisplayName", + "columnName": "contactDisplayName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactAvatarUrl", + "columnName": "contactAvatarUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactUserId", + "columnName": "contactUserId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "filterFlags", + "columnName": "filterFlags", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "rowId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "tx_group_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` TEXT NOT NULL, `txId` TEXT NOT NULL, `wrapperType` TEXT NOT NULL, `groupDate` TEXT NOT NULL, `sortOrder` INTEGER NOT NULL, PRIMARY KEY(`groupId`, `txId`))", + "fields": [ + { + "fieldPath": "groupId", + "columnName": "groupId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "wrapperType", + "columnName": "wrapperType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "groupDate", + "columnName": "groupDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sortOrder", + "columnName": "sortOrder", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "groupId", + "txId" + ] + }, + "indices": [ + { + "name": "index_tx_group_cache_txId", + "unique": false, + "columnNames": [ + "txId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tx_group_cache_txId` ON `${TABLE_NAME}` (`txId`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '37d0d678c5a25041983b612b1d9eba0f')" + ] + } +} \ No newline at end of file diff --git a/wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt b/wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt index 386d7d49bb..9bd978000b 100644 --- a/wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt +++ b/wallet/src/de/schildbach/wallet/payments/SendCoinsTaskRunner.kt @@ -119,7 +119,7 @@ class SendCoinsTaskRunner @Inject constructor( coinJoinSend = coinJoinMode != CoinJoinMode.NONE && coinJoinMixingState != MixingStatus.FINISHING } - private val paymentIntentParser = DashPaymentIntentParser(Constants.NETWORK_PARAMETERS) + private val paymentIntentParser = DashPaymentIntentParser(NETWORK_PARAMETERS) @Throws(LeftoverBalanceException::class) override suspend fun sendCoins( From 66c93459aa3bf81f0c5d98b75e70484f5ec21893 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Mon, 8 Jun 2026 20:29:46 -0700 Subject: [PATCH 04/13] fix: address some QA feedback for -0% and clipping a buttons in a bottom sheet dialog --- .../dialogs/PurchaseGiftCardConfirmDialog.kt | 13 +++++-------- .../features/exploredash/utils/SavingsFormatting.kt | 5 +++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt index 5e6b01494d..077173965f 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt @@ -611,15 +611,12 @@ internal fun PurchaseGiftCardConfirmView( Column( modifier = Modifier - .let { if (uiState.useExpandedLayout) it.weight(1f) else it } + // Always allow the body to scroll so the pinned buttons below stay + // visible on short screens. fill = false keeps the sheet wrapping its + // content when it fits, and only caps/scrolls the body when it doesn't. + .weight(1f, fill = uiState.useExpandedLayout) .fillMaxWidth() - .let { - if (uiState.useExpandedLayout) { - it.verticalScroll(rememberScrollState()) - } else { - it - } - } + .verticalScroll(rememberScrollState()) .padding(horizontal = 20.dp) .padding(bottom = 20.dp), verticalArrangement = Arrangement.spacedBy(20.dp) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/utils/SavingsFormatting.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/utils/SavingsFormatting.kt index 16b77179c4..8a930990cf 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/utils/SavingsFormatting.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/utils/SavingsFormatting.kt @@ -44,6 +44,11 @@ object SavingsFormatting { roundingMode = RoundingMode.HALF_UP } val absValue = numberFormat.format(abs(percent)) + // If the value rounds to zero at the requested precision, there is no + // discount or fee to show (avoids rendering "-0%"). + if (absValue == numberFormat.format(0.0)) { + return "${numberFormat.format(0.0)}%" + } return if (percent < 0.0) { context.getString(R.string.explore_fee, absValue) } else { From cc55e727d485cd5904384e6f87bbe9f3427550d4 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Mon, 15 Jun 2026 10:03:54 -0700 Subject: [PATCH 05/13] fix: save more giftcard metadata --- docs/proposals/persist-gift-card-order-id.md | 240 ++++++++++++++++++ .../schildbach/wallet/database/AppDatabase.kt | 2 +- .../wallet/database/AppDatabaseMigrations.kt | 22 ++ .../dao/TransactionMetadataChangeCacheDao.kt | 6 +- .../entity/TransactionMetadataCacheItem.kt | 17 +- .../entity/TransactionMetadataDocument.kt | 4 +- .../de/schildbach/wallet/di/DatabaseModule.kt | 3 +- .../WalletTransactionMetadataProvider.kt | 8 +- .../service/platform/PlatformSyncService.kt | 37 ++- 9 files changed, 327 insertions(+), 12 deletions(-) create mode 100644 docs/proposals/persist-gift-card-order-id.md diff --git a/docs/proposals/persist-gift-card-order-id.md b/docs/proposals/persist-gift-card-order-id.md new file mode 100644 index 0000000000..75b387817e --- /dev/null +++ b/docs/proposals/persist-gift-card-order-id.md @@ -0,0 +1,240 @@ +# Proposal: Persist Gift Card Order ID in Transaction Metadata Backup + +## Problem + +Multi-quantity PiggyCards orders produce one Dash transaction with **N** gift cards +attached. Locally these are stored as N rows in the `gift_cards` table, keyed by +`(txId, index)`. The merchant API (PiggyCards) is the authoritative source for each +card's number, PIN, and barcode — the app re-fetches them using the **order ID**, +which is stored in `GiftCard.note` for `index = 0`. + +After a wallet restore from the Dash Platform metadata backup, all N cards are gone +except for whatever can be reconstructed from `TransactionMetadataDocument`. Today +that reconstruction: + +1. Restores **only Card #0** — `WalletTransactionMetadataProvider.updateGiftCardMetadata` + gates the cache write on `giftCard.index == 0`. +2. **Drops the order ID entirely** — neither `TransactionMetadataCacheItem` nor + `TransactionMetadataDocument` (nor the wire-format `TxMetadataItem` in DPP) has a + `note` field. The order ID is never serialized. + +The combined effect: after restore, the local DB has one card with no order ID, the +PiggyCards branch of `GiftCardDetailsViewModel.fetchGiftCardInfo` bails immediately +with `"piggycards order # is missing"`, and there is no way to recover cards #1..N. + +A short-term mitigation already shipped (`maybeRecoverMissingPiggyCards` in +`GiftCardDetailsViewModel.kt`) triggers a one-shot merchant fetch when a single +PiggyCards card is present and still has its order ID — but the order ID is exactly +the field that gets wiped on restore, so the mitigation does not help the restore +case. It only helps forced-refresh and pre-restore scenarios. + +## Goal + +After a wallet restore, opening the details screen for a multi-quantity PiggyCards +purchase should automatically recover all N cards (number, PIN, barcode) by: + +1. Reading the order ID from the restored metadata. +2. Calling the PiggyCards merchant API. +3. Letting the existing fetch path (`fetchGiftCardInfo` lines 437-470) add + placeholders for missing siblings and populate them. + +We do **not** need to back up cards #1..N individually — the merchant API is the +source of truth. Persisting the order ID is sufficient. + +## Proposed Solution + +Add a `note` field to the transaction metadata document type so the PiggyCards order +ID survives the round trip through Dash Platform. + +The field travels through four representations and each needs to be updated: + +| Layer | Type | Repo | +|---|---|---| +| DPP data contract | `txMetadata` document schema | **dashpay-platform (DPP)** — separate repo | +| SDK wrapper | `org.dashj.platform.wallet.TxMetadataItem` | **dashj-platform** — separate repo (re-published with new DPP) | +| Outgoing local cache | `TransactionMetadataCacheItem` | this repo | +| Incoming local mirror | `TransactionMetadataDocument` | this repo | + +### Phase 1 — DPP / SDK changes (out-of-repo) + +1. **DPP `txMetadata` document type** — add `note` (string, optional, max length + matching existing free-text fields such as `memo`). Bump contract version per DPP + conventions and confirm the platform contract owner ships the update. + +2. **dashj-platform SDK** — regenerate / hand-edit `TxMetadataItem` so the new + `note` field is included in the constructor, serialization, and deserialization + paths. Ship a new SDK version. The wallet's `wallet/build.gradle` `dppVersion` + then bumps to the new SDK. + +These two steps must land first because the wallet's serialization path goes through +the SDK. Until they ship, the local Room columns can exist but the value cannot +leave the device. + +### Phase 2 — Local entity + DAO changes (this repo) + +1. **`TransactionMetadataCacheItem`** + ```kotlin + @Entity(tableName = "transaction_metadata_cache") + data class TransactionMetadataCacheItem( + // existing fields … + var note: String? = null + ) + ``` + Update the constructor that takes a `GiftCard`: + ```kotlin + constructor(transactionMetadata: TransactionMetadata, giftCard: GiftCard? = null, …) : this( + … + giftCard?.note // <-- new + ) + ``` + Include `note` in `isNotEmpty`, `compare`, and the `minus` operator. + +2. **`TransactionMetadataDocument`** — add the same `var note: String? = null`. + +3. **Room migration** — add two `ALTER TABLE` statements bumping the database + version (current version + 1): + ```sql + ALTER TABLE transaction_metadata_cache ADD COLUMN note TEXT; + ALTER TABLE transaction_metadata_platform ADD COLUMN note TEXT; + ``` + Register a new `Migration(from, to)` in `AppDatabaseMigrations.kt` and add it to + the migration chain in `AppDatabase`. + +4. **`TransactionMetadataChangeCacheDao`** — extend `insertGiftCardData`: + ```kotlin + @Query( + """INSERT INTO transaction_metadata_cache + (txId, cacheTimestamp, giftCardNumber, giftCardPin, merchantName, + originalPrice, merchantUrl, note) + VALUES (:txId, :cacheTimestamp, :giftCardNumber, :giftCardPin, + :merchantName, :originalPrice, :merchantUrl, :note)""" + ) + suspend fun insertGiftCardData( + txId: Sha256Hash, + giftCardNumber: String?, + giftCardPin: String?, + merchantName: String?, + originalPrice: Double?, + merchantUrl: String?, + note: String?, + cacheTimestamp: Long = System.currentTimeMillis() + ) + ``` + +### Phase 3 — Provider + sync changes (this repo) + +1. **`WalletTransactionMetadataProvider.updateGiftCardMetadata`** — pass `note` into + the cache write. The `index == 0` gate stays (one cache row per txid is the + correct shape; the order ID is the same across all cards in the order): + ```kotlin + if (giftCard.index == 0) { + transactionMetadataChangeCacheDao.insertGiftCardData( + giftCard.txId, + giftCard.number, + giftCard.pin, + giftCard.merchantName, + giftCard.price, + giftCard.merchantUrl, + giftCard.note // <-- new + ) + } + ``` + +2. **`WalletTransactionMetadataProvider.insertOrUpdateGiftCard`** — preserve `note` + on updates and accept it on inserts: + ```kotlin + val updatedGiftCard = existingGiftCard.copy( + // existing fields … + note = giftCard.note ?: existingGiftCard.note + ) + ``` + +3. **`PlatformSyncService.publishTransactionMetadata`** — extend the + `TxMetadataItem` builder once the SDK exposes the new field: + ```kotlin + TxMetadataItem( + it.txId.reversedBytes, + it.sentTimestamp, + it.memo, + it.rate?.toDouble(), + it.currencyCode, + it.taxCategory?.name?.lowercase(), + it.service, + it.customIconUrl, + it.giftCardNumber, + it.giftCardPin, + it.merchantName, + it.originalPrice, + it.barcodeValue, + it.barcodeFormat, + it.merchantUrl, + it.note // <-- new + ) + ``` + +4. **`PlatformSyncService` fetch path** (around line 1080, the `merchantUrl` block + is the closest analogue) — on inbound metadata documents, copy `note` onto both + the `metadataDocumentRecord` and the live `giftCard`: + ```kotlin + metadata.note?.let { orderId -> + metadataDocumentRecord.note = orderId + log.info("processing TxMetadata: note change") + if (cachedItems.find { + it.txId == txIdAsHash && it.cacheTimestamp > doc.updatedAt!! && + it.note != null && it.note != orderId + } == null + ) { + giftCard.note = orderId + } + } + ``` + +5. **`mergeTransactionMetadataDocuments`** — include `note` in the last-write-wins + reduction: + ```kotlin + note = docs.lastOrNull { it.note != null }?.note + ``` + +6. **Change-detection plumbing** — wherever cache items are diffed to detect new + uploads (`compare`, `minus`, `isNotEmpty`), include `note`. + +### Phase 4 — Restore-time recovery (already in place) + +`GiftCardDetailsViewModel.maybeRecoverMissingPiggyCards` already triggers a one-shot +merchant fetch when a single PiggyCards card has a non-empty `note`. Once Phases +1-3 are in place this path becomes effective on restore: the restored Card #0 will +have its `note` populated, the probe fires, `fetchGiftCardInfo` adds placeholders +for siblings, and the PiggyCards API fills them in. + +No further change to `GiftCardDetailsViewModel` is required. + +## Backwards Compatibility + +- **Local DB:** new `note` column is nullable; existing rows migrate to `note = + NULL` and the app behaves as today for those rows. +- **DPP documents:** old SDK versions reading new documents will silently ignore + the unknown `note` field (standard protobuf behavior). New SDK reading old + documents reads `note = null`. +- **Old orders made before this lands:** `note` is `NULL` in their backup. After + restore they continue to lose cards #1..N — no way to retrofit. Document this in + the release notes. + +## Sequencing + +1. Land DPP contract update + new dashj-platform SDK release. +2. Bump `dppVersion` in `wallet/build.gradle` to the new SDK. +3. Land Phases 2-3 in this repo, including the Room migration, in a single PR. +4. Verify end-to-end on testnet: purchase 2-card PiggyCards order, force a metadata + publish, wipe the local app data, restore from seed, open the order, confirm + both cards reappear. + +## Out of Scope + +- **Backing up cards #1..N individually.** Not needed; the merchant API is the + source of truth and the existing fetch path handles recovery once the order ID + is available. +- **Restructuring the cache schema to support multiple gift cards per txid.** Same + reason — would be required only if we wanted the metadata document itself to be + self-sufficient without API access. +- **CTX (DashSpend / CTXSpend) flow.** CTX fetches by `txid`, not by `note`, so it + is unaffected by this gap and unaffected by this change. \ No newline at end of file diff --git a/wallet/src/de/schildbach/wallet/database/AppDatabase.kt b/wallet/src/de/schildbach/wallet/database/AppDatabase.kt index d0df3cd049..a71d991666 100644 --- a/wallet/src/de/schildbach/wallet/database/AppDatabase.kt +++ b/wallet/src/de/schildbach/wallet/database/AppDatabase.kt @@ -64,7 +64,7 @@ import org.dash.wallet.features.exploredash.utils.RoomConverters TxDisplayCacheEntry::class, TxGroupCacheEntry::class ], - version = 19, // if increasing version, we need migrations to preserve tx/addr metadata, + version = 20, // if increasing version, we need migrations to preserve tx/addr metadata, exportSchema = true ) @TypeConverters(RoomConverters::class, BlockchainStateRoomConverters::class) diff --git a/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt b/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt index 0532af889c..c90926904d 100644 --- a/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt +++ b/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt @@ -199,6 +199,28 @@ class AppDatabaseMigrations { } } + val migration19to20 = object : Migration(19, 20) { + override fun migrate(database: SupportSQLiteDatabase) { + // Persist the PiggyCards order ID (`order`) and the CTX redeem-URL + // challenge (`giftCardChallenge`) in the transaction metadata backup so + // they survive a wallet restore from the Dash Platform metadata backup. + // Both tables gain the same two nullable columns. `order` is a SQL + // keyword, so it must be quoted. + database.execSQL( + "ALTER TABLE `transaction_metadata_cache` ADD COLUMN `order` TEXT" + ) + database.execSQL( + "ALTER TABLE `transaction_metadata_cache` ADD COLUMN `giftCardChallenge` TEXT" + ) + database.execSQL( + "ALTER TABLE `transaction_metadata_platform` ADD COLUMN `order` TEXT" + ) + database.execSQL( + "ALTER TABLE `transaction_metadata_platform` ADD COLUMN `giftCardChallenge` TEXT" + ) + } + } + val migration15to16 = object : Migration(15, 16) { override fun migrate(database: SupportSQLiteDatabase) { // previous versions have no data in invitations table, so do this diff --git a/wallet/src/de/schildbach/wallet/database/dao/TransactionMetadataChangeCacheDao.kt b/wallet/src/de/schildbach/wallet/database/dao/TransactionMetadataChangeCacheDao.kt index 6efd3e0f31..35681cc0e9 100644 --- a/wallet/src/de/schildbach/wallet/database/dao/TransactionMetadataChangeCacheDao.kt +++ b/wallet/src/de/schildbach/wallet/database/dao/TransactionMetadataChangeCacheDao.kt @@ -111,8 +111,8 @@ interface TransactionMetadataChangeCacheDao { ) @Query( - """INSERT INTO transaction_metadata_cache (txId, cacheTimestamp, giftCardNumber, giftCardPin, merchantName, originalPrice, merchantUrl) - VALUES (:txId, :cacheTimestamp, :giftCardNumber, :giftCardPin, :merchantName, :originalPrice, :merchantUrl)""" + """INSERT INTO transaction_metadata_cache (txId, cacheTimestamp, giftCardNumber, giftCardPin, merchantName, originalPrice, merchantUrl, `order`, giftCardChallenge) + VALUES (:txId, :cacheTimestamp, :giftCardNumber, :giftCardPin, :merchantName, :originalPrice, :merchantUrl, :order, :giftCardChallenge)""" ) suspend fun insertGiftCardData( txId: Sha256Hash, @@ -121,6 +121,8 @@ interface TransactionMetadataChangeCacheDao { merchantName: String?, originalPrice: Double?, merchantUrl: String?, + order: String?, + giftCardChallenge: String?, cacheTimestamp: Long = System.currentTimeMillis() ) diff --git a/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataCacheItem.kt b/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataCacheItem.kt index 711ed88bec..876bad8d32 100644 --- a/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataCacheItem.kt +++ b/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataCacheItem.kt @@ -41,7 +41,9 @@ data class TransactionMetadataCacheItem( var originalPrice: Double? = null, var barcodeValue: String? = null, var barcodeFormat: String? = null, - var merchantUrl: String? = null + var merchantUrl: String? = null, + var order: String? = null, + var giftCardChallenge: String? = null ) { @PrimaryKey(autoGenerate = true) var id: Long = 0 @@ -66,14 +68,17 @@ data class TransactionMetadataCacheItem( giftCard?.price, giftCard?.barcodeValue, giftCard?.barcodeFormat?.toString(), - giftCard?.merchantUrl + giftCard?.merchantUrl, + giftCard?.note, + giftCard?.redeemUrlChallenge ) fun isNotEmpty(): Boolean { return taxCategory != null || !memo.isNullOrEmpty() || currencyCode != null || rate != null || service != null || customIconUrl != null || giftCardNumber != null || giftCardPin != null || merchantName != null || originalPrice != null || - barcodeValue != null || barcodeFormat != null || merchantUrl != null + barcodeValue != null || barcodeFormat != null || merchantUrl != null || + order != null || giftCardChallenge != null } fun isEmpty(): Boolean = !isNotEmpty() @@ -100,6 +105,8 @@ data class TransactionMetadataCacheItem( barcodeValue = if (barcodeValue == other.barcodeValue) null else barcodeValue, barcodeFormat = if (barcodeFormat == other.barcodeFormat) null else barcodeFormat, merchantUrl = if (merchantUrl == other.merchantUrl) null else merchantUrl, + order = if (order == other.order) null else order, + giftCardChallenge = if (giftCardChallenge == other.giftCardChallenge) null else giftCardChallenge ) } @@ -117,7 +124,9 @@ data class TransactionMetadataCacheItem( this.barcodeFormat == giftCard.barcodeFormat.toString() && this.merchantName == giftCard.merchantName && this.merchantUrl == giftCard.merchantUrl && - this.originalPrice == giftCard.price + this.originalPrice == giftCard.price && + this.order == giftCard.note && + this.giftCardChallenge == giftCard.redeemUrlChallenge } return txData && (giftCard == null || giftCardEquals == true) } diff --git a/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataDocument.kt b/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataDocument.kt index b57538f10b..d8226a4d91 100644 --- a/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataDocument.kt +++ b/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataDocument.kt @@ -38,5 +38,7 @@ data class TransactionMetadataDocument( var originalPrice: Double? = null, var barcodeValue: String? = null, var barcodeFormat: String? = null, - var merchantUrl: String? = null + var merchantUrl: String? = null, + var order: String? = null, + var giftCardChallenge: String? = null ) diff --git a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt index 0978b3c688..df127efd95 100644 --- a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt +++ b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt @@ -46,7 +46,8 @@ object DatabaseModule { AppDatabaseMigrations.migration15to16, AppDatabaseMigrations.migration16to17, AppDatabaseMigrations.migration17to18, - AppDatabaseMigrations.migration18to19 + AppDatabaseMigrations.migration18to19, + AppDatabaseMigrations.migration19to20 ) // destructive migrations are used from versions 1 to 11 .fallbackToDestructiveMigration() diff --git a/wallet/src/de/schildbach/wallet/service/WalletTransactionMetadataProvider.kt b/wallet/src/de/schildbach/wallet/service/WalletTransactionMetadataProvider.kt index 2dd874bf20..62ac1afa7c 100644 --- a/wallet/src/de/schildbach/wallet/service/WalletTransactionMetadataProvider.kt +++ b/wallet/src/de/schildbach/wallet/service/WalletTransactionMetadataProvider.kt @@ -355,7 +355,9 @@ class WalletTransactionMetadataProvider @Inject constructor( giftCard.pin, giftCard.merchantName, giftCard.price, - giftCard.merchantUrl + giftCard.merchantUrl, + giftCard.note, + giftCard.redeemUrlChallenge ) } } @@ -688,7 +690,9 @@ class WalletTransactionMetadataProvider @Inject constructor( pin = giftCard.pin ?: existingGiftCard.pin, barcodeValue = giftCard.barcodeValue ?: existingGiftCard.barcodeValue, barcodeFormat = giftCard.barcodeFormat ?: existingGiftCard.barcodeFormat, - merchantUrl = giftCard.merchantUrl ?: existingGiftCard.merchantUrl + merchantUrl = giftCard.merchantUrl ?: existingGiftCard.merchantUrl, + note = giftCard.note ?: existingGiftCard.note, + redeemUrlChallenge = giftCard.redeemUrlChallenge ?: existingGiftCard.redeemUrlChallenge ) giftCardDao.updateGiftCard(updatedGiftCard) } diff --git a/wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt b/wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt index 2a2b4d9cf7..e067e027d9 100644 --- a/wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt +++ b/wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt @@ -1089,6 +1089,30 @@ class PlatformSynchronizationService @Inject constructor( giftCard.merchantUrl = url } } + metadata.order?.let { order -> + metadataDocumentRecord.order = order + log.info("processing TxMetadata: order change") + if (cachedItems.find { + it.txId == txIdAsHash && it.cacheTimestamp > doc.updatedAt!! && + it.order != null && it.order != order + } == null + ) { + log.info("processing TxMetadata: order change: changing order") + giftCard.note = order + } + } + metadata.giftCardChallenge?.let { challenge -> + metadataDocumentRecord.giftCardChallenge = challenge + log.info("processing TxMetadata: gift card challenge change") + if (cachedItems.find { + it.txId == txIdAsHash && it.cacheTimestamp > doc.updatedAt!! && + it.giftCardChallenge != null && it.giftCardChallenge != challenge + } == null + ) { + log.info("processing TxMetadata: gift card challenge change: changing challenge") + giftCard.redeemUrlChallenge = challenge + } + } log.info("syncing metadata with platform updates: $updatedMetadata") transactionMetadataProvider.syncPlatformMetadata(txIdAsHash, updatedMetadata, giftCard, iconUrl) @@ -1134,7 +1158,10 @@ class PlatformSynchronizationService @Inject constructor( it.originalPrice, it.barcodeValue, it.barcodeFormat, - it.merchantUrl + it.merchantUrl, + null, + it.order, + it.giftCardChallenge ) } progressListener?.invoke(10) @@ -1171,6 +1198,8 @@ class PlatformSynchronizationService @Inject constructor( barcodeValue = docs.lastOrNull { it.barcodeValue != null }?.barcodeValue, barcodeFormat = docs.lastOrNull { it.barcodeFormat != null }?.barcodeFormat, merchantUrl = docs.lastOrNull { it.merchantUrl != null }?.merchantUrl, + order = docs.lastOrNull { it.order != null }?.order, + giftCardChallenge = docs.lastOrNull { it.giftCardChallenge != null}?.giftCardChallenge ) } @@ -1332,6 +1361,12 @@ class PlatformSynchronizationService @Inject constructor( changedItem.merchantUrl?.let { merchantUrl -> item.merchantUrl = merchantUrl } + changedItem.order?.let { order -> + item.order = order + } + changedItem.giftCardChallenge?.let { giftCardChallenge -> + item.giftCardChallenge = giftCardChallenge + } } } else { itemsToPublish[changedItem.txId] = changedItem From 07f6ea2ec373c62455964c734fa2f7a89541361f Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Tue, 16 Jun 2026 18:46:02 -0700 Subject: [PATCH 06/13] fix: improve debugging of GiftCardInfo --- .../features/exploredash/data/dashspend/model/GiftCardInfo.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/model/GiftCardInfo.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/model/GiftCardInfo.kt index 36f04eca2b..41b06bb4ea 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/model/GiftCardInfo.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/data/dashspend/model/GiftCardInfo.kt @@ -37,6 +37,7 @@ data class GiftCardInfo( "paymentUrls=$paymentUrls, barcodeUrl=${if (barcodeUrl != null) "[REDACTED]" else null}, " + "cardNumber=${if (cardNumber != null) "[REDACTED]" else null}, " + "cardPin=${if (cardPin != null) "[REDACTED]" else null}, " + - "redeemUrl=${if (redeemUrl != null) "[REDACTED]" else null})" + "redeemUrl=${if (redeemUrl != null) "[REDACTED]" else null}, " + + "redeemUrlChallenge=${if (redeemUrlChallenge != null) "[REDACTED]" else null})" } } From 80612eeea869df897dcc0a05b36ba8f6a6451aa6 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Tue, 16 Jun 2026 18:46:26 -0700 Subject: [PATCH 07/13] fix: expand PurchaseGiftCardConfirmDialog on small screens with higher font scales --- .../dialogs/PurchaseGiftCardConfirmDialog.kt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt index 077173965f..296f0c57ce 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt @@ -115,6 +115,13 @@ class PurchaseGiftCardConfirmDialog : ComposeBottomSheet() { companion object { private val log = LoggerFactory.getLogger(PurchaseGiftCardConfirmDialog::class.java) + // Baseline screen height (in dp, at the default font scale) needed to fit the amount, + // detail card and action buttons in the wrap-content sheet. The actual threshold is + // this value multiplied by the current fontScale: bigger fonts inflate the content, so + // they require a taller screen before the compact layout is safe. Below the threshold we + // force the sheet to expand (full height + scrollable body with pinned buttons). + // Tune this value if clipping is still observed. + private const val SMALL_SCREEN_HEIGHT_DP = 720 private val USD_CURRENCY = Currency.getInstance(Constants.USD_CURRENCY) private val noCentsFormat = NumberFormat.getCurrencyInstance().apply { currency = USD_CURRENCY @@ -205,7 +212,14 @@ class PurchaseGiftCardConfirmDialog : ComposeBottomSheet() { ) val breakdownLines = breakdown?.lineSequence()?.count() ?: 0 - needsExpand = breakdownLines >= 2 + // Expand when there are multiple breakdown lines, or when the available height is too + // small to show everything without clipping the bottom action buttons. The effective + // content height grows with the user's font scale (and narrow screens wrap text taller), + // so the threshold is scaled by fontScale rather than compared to a fixed dp value. + val config = resources.configuration + val requiredHeightDp = SMALL_SCREEN_HEIGHT_DP * config.fontScale + val isShortScreen = config.screenHeightDp < requiredHeightDp + needsExpand = breakdownLines >= 2 || isShortScreen if (needsExpand) { view.updateLayoutParams { height = ViewGroup.LayoutParams.MATCH_PARENT } } From 7466c2bce6eee19727e72ebded82d6abaa69d787 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Tue, 16 Jun 2026 18:47:03 -0700 Subject: [PATCH 08/13] fix: add index to the tx metadata that is saved --- .../wallet/database/DatabaseMigrationTest.kt | 7 +- .../20.json | 1212 ++++++++++++++++ .../21.json | 1224 +++++++++++++++++ .../schildbach/wallet/database/AppDatabase.kt | 2 +- .../wallet/database/AppDatabaseMigrations.kt | 15 + .../dao/TransactionMetadataChangeCacheDao.kt | 15 +- .../entity/TransactionMetadataCacheItem.kt | 14 +- .../entity/TransactionMetadataDocument.kt | 3 +- .../de/schildbach/wallet/di/DatabaseModule.kt | 3 +- .../WalletTransactionMetadataProvider.kt | 8 +- .../service/platform/PlatformSyncService.kt | 18 +- 11 files changed, 2501 insertions(+), 20 deletions(-) create mode 100644 wallet/schemas/de.schildbach.wallet.database.AppDatabase/20.json create mode 100644 wallet/schemas/de.schildbach.wallet.database.AppDatabase/21.json diff --git a/wallet/androidTest/de/schildbach/wallet/database/DatabaseMigrationTest.kt b/wallet/androidTest/de/schildbach/wallet/database/DatabaseMigrationTest.kt index cdb809278b..e80422b8e3 100644 --- a/wallet/androidTest/de/schildbach/wallet/database/DatabaseMigrationTest.kt +++ b/wallet/androidTest/de/schildbach/wallet/database/DatabaseMigrationTest.kt @@ -63,7 +63,12 @@ open class DatabaseMigrationTest { AppDatabaseMigrations.migration12To13, AppDatabaseMigrations.migration13to14, AppDatabaseMigrations.migration14to15, - AppDatabaseMigrations.migration15to16 + AppDatabaseMigrations.migration15to16, + AppDatabaseMigrations.migration16to17, + AppDatabaseMigrations.migration17to18, + AppDatabaseMigrations.migration18to19, + AppDatabaseMigrations.migration19to20, + AppDatabaseMigrations.migration20to21 ) @Rule diff --git a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/20.json b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/20.json new file mode 100644 index 0000000000..9f75cb5a29 --- /dev/null +++ b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/20.json @@ -0,0 +1,1212 @@ +{ + "formatVersion": 1, + "database": { + "version": 20, + "identityHash": "38d8513cefeb1edf9e2c05633490c234", + "entities": [ + { + "tableName": "exchange_rates", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`currencyCode` TEXT NOT NULL, `rate` TEXT, PRIMARY KEY(`currencyCode`))", + "fields": [ + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "currencyCode" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "blockchain_state", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bestChainDate` INTEGER, `bestChainHeight` INTEGER NOT NULL, `replaying` INTEGER NOT NULL, `impediments` TEXT NOT NULL, `chainlockHeight` INTEGER NOT NULL, `mnlistHeight` INTEGER NOT NULL, `percentageSync` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "bestChainDate", + "columnName": "bestChainDate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bestChainHeight", + "columnName": "bestChainHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "replaying", + "columnName": "replaying", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "impediments", + "columnName": "impediments", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chainlockHeight", + "columnName": "chainlockHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mnlistHeight", + "columnName": "mnlistHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "percentageSync", + "columnName": "percentageSync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `timestamp` INTEGER NOT NULL, `value` INTEGER NOT NULL, `type` TEXT NOT NULL, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT NOT NULL, `service` TEXT, `customIconId` BLOB, PRIMARY KEY(`txId`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconId", + "columnName": "customIconId", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "address_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address` TEXT NOT NULL, `isInput` INTEGER NOT NULL, `taxCategory` TEXT NOT NULL, `service` TEXT NOT NULL, PRIMARY KEY(`address`, `isInput`))", + "fields": [ + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isInput", + "columnName": "isInput", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "address", + "isInput" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "icon_bitmaps", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` BLOB NOT NULL, `imageData` BLOB NOT NULL, `originalUrl` TEXT NOT NULL, `height` INTEGER NOT NULL, `width` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "imageData", + "columnName": "imageData", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "originalUrl", + "columnName": "originalUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "gift_cards", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `merchantName` TEXT NOT NULL, `price` REAL NOT NULL, `number` TEXT, `pin` TEXT, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `note` TEXT, `index` INTEGER NOT NULL, `redeemUrlChallenge` TEXT, PRIMARY KEY(`txId`, `index`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pin", + "columnName": "pin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redeemUrlChallenge", + "columnName": "redeemUrlChallenge", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId", + "index" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "dashpay_profile", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `publicMessage` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `avatarHash` BLOB, `avatarFingerprint` BLOB, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`userId`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "publicMessage", + "columnName": "publicMessage", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarHash", + "columnName": "avatarHash", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "avatarFingerprint", + "columnName": "avatarFingerprint", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "userId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "dashpay_contact_request", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `toUserId` TEXT NOT NULL, `accountReference` INTEGER NOT NULL, `encryptedPublicKey` BLOB NOT NULL, `senderKeyIndex` INTEGER NOT NULL, `recipientKeyIndex` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `encryptedAccountLabel` BLOB, `autoAcceptProof` BLOB, PRIMARY KEY(`userId`, `toUserId`, `accountReference`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "toUserId", + "columnName": "toUserId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountReference", + "columnName": "accountReference", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "encryptedPublicKey", + "columnName": "encryptedPublicKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "senderKeyIndex", + "columnName": "senderKeyIndex", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipientKeyIndex", + "columnName": "recipientKeyIndex", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "encryptedAccountLabel", + "columnName": "encryptedAccountLabel", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "autoAcceptProof", + "columnName": "autoAcceptProof", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "userId", + "toUserId", + "accountReference" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "user_alerts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`stringResId` INTEGER NOT NULL, `iconResId` INTEGER NOT NULL, `dismissed` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL, PRIMARY KEY(`stringResId`))", + "fields": [ + { + "fieldPath": "stringResId", + "columnName": "stringResId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconResId", + "columnName": "iconResId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dismissed", + "columnName": "dismissed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "stringResId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "invitation_table", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`fundingAddress` TEXT NOT NULL, `userId` TEXT NOT NULL, `txid` BLOB, `createdAt` INTEGER NOT NULL, `memo` TEXT NOT NULL, `sentAt` INTEGER NOT NULL, `acceptedAt` INTEGER NOT NULL, `shortDynamicLink` TEXT, `dynamicLink` TEXT, PRIMARY KEY(`fundingAddress`))", + "fields": [ + { + "fieldPath": "fundingAddress", + "columnName": "fundingAddress", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "txid", + "columnName": "txid", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sentAt", + "columnName": "sentAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "acceptedAt", + "columnName": "acceptedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortDynamicLink", + "columnName": "shortDynamicLink", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dynamicLink", + "columnName": "dynamicLink", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "fundingAddress" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cacheTimestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "cacheTimestamp", + "columnName": "cacheTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "sentTimestamp", + "columnName": "sentTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconUrl", + "columnName": "customIconUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardNumber", + "columnName": "giftCardNumber", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardPin", + "columnName": "giftCardPin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "originalPrice", + "columnName": "originalPrice", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardChallenge", + "columnName": "giftCardChallenge", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata_platform", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` REAL, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, PRIMARY KEY(`id`, `txId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "sentTimestamp", + "columnName": "sentTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconUrl", + "columnName": "customIconUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardNumber", + "columnName": "giftCardNumber", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardPin", + "columnName": "giftCardPin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "originalPrice", + "columnName": "originalPrice", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardChallenge", + "columnName": "giftCardChallenge", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "username_requests", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`requestId` TEXT NOT NULL, `username` TEXT NOT NULL, `normalizedLabel` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `identity` TEXT NOT NULL, `link` TEXT, `votes` INTEGER NOT NULL, `lockVotes` INTEGER NOT NULL, `isApproved` INTEGER NOT NULL, PRIMARY KEY(`requestId`))", + "fields": [ + { + "fieldPath": "requestId", + "columnName": "requestId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "normalizedLabel", + "columnName": "normalizedLabel", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "identity", + "columnName": "identity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "link", + "columnName": "link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "votes", + "columnName": "votes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lockVotes", + "columnName": "lockVotes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isApproved", + "columnName": "isApproved", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "requestId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "username_votes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `username` TEXT NOT NULL, `identity` TEXT NOT NULL, `type` TEXT NOT NULL, `timestamp` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "identity", + "columnName": "identity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "imported_masternode_keys", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`proTxHash` BLOB NOT NULL, `address` TEXT NOT NULL, `votingPrivateKey` BLOB NOT NULL, `votingPublicKey` BLOB NOT NULL, `votingPubKeyHash` BLOB NOT NULL, PRIMARY KEY(`proTxHash`))", + "fields": [ + { + "fieldPath": "proTxHash", + "columnName": "proTxHash", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "votingPrivateKey", + "columnName": "votingPrivateKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "votingPublicKey", + "columnName": "votingPublicKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "votingPubKeyHash", + "columnName": "votingPubKeyHash", + "affinity": "BLOB", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "proTxHash" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "topup_table", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `toUserId` TEXT NOT NULL, `workId` TEXT NOT NULL, `creditedAt` INTEGER NOT NULL, PRIMARY KEY(`txId`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "toUserId", + "columnName": "toUserId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "workId", + "columnName": "workId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "creditedAt", + "columnName": "creditedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "tx_display_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` TEXT NOT NULL, `title` TEXT NOT NULL, `valueSatoshis` INTEGER NOT NULL, `iconType` INTEGER NOT NULL, `iconBgType` INTEGER NOT NULL, `statusText` TEXT NOT NULL, `comment` TEXT NOT NULL, `transactionAmount` INTEGER NOT NULL, `time` INTEGER NOT NULL, `hasErrors` INTEGER NOT NULL, `service` TEXT, `exchangeRateFiatCode` TEXT, `exchangeRateFiatValue` INTEGER, `contactUsername` TEXT, `contactDisplayName` TEXT, `contactAvatarUrl` TEXT, `contactUserId` TEXT, `filterFlags` INTEGER NOT NULL, PRIMARY KEY(`rowId`))", + "fields": [ + { + "fieldPath": "rowId", + "columnName": "rowId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "valueSatoshis", + "columnName": "valueSatoshis", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconType", + "columnName": "iconType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconBgType", + "columnName": "iconBgType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "statusText", + "columnName": "statusText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "transactionAmount", + "columnName": "transactionAmount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasErrors", + "columnName": "hasErrors", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "exchangeRateFiatCode", + "columnName": "exchangeRateFiatCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "exchangeRateFiatValue", + "columnName": "exchangeRateFiatValue", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contactUsername", + "columnName": "contactUsername", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactDisplayName", + "columnName": "contactDisplayName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactAvatarUrl", + "columnName": "contactAvatarUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactUserId", + "columnName": "contactUserId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "filterFlags", + "columnName": "filterFlags", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "rowId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "tx_group_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` TEXT NOT NULL, `txId` TEXT NOT NULL, `wrapperType` TEXT NOT NULL, `groupDate` TEXT NOT NULL, `sortOrder` INTEGER NOT NULL, PRIMARY KEY(`groupId`, `txId`))", + "fields": [ + { + "fieldPath": "groupId", + "columnName": "groupId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "wrapperType", + "columnName": "wrapperType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "groupDate", + "columnName": "groupDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sortOrder", + "columnName": "sortOrder", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "groupId", + "txId" + ] + }, + "indices": [ + { + "name": "index_tx_group_cache_txId", + "unique": false, + "columnNames": [ + "txId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tx_group_cache_txId` ON `${TABLE_NAME}` (`txId`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '38d8513cefeb1edf9e2c05633490c234')" + ] + } +} \ No newline at end of file diff --git a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/21.json b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/21.json new file mode 100644 index 0000000000..cedfb132a5 --- /dev/null +++ b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/21.json @@ -0,0 +1,1224 @@ +{ + "formatVersion": 1, + "database": { + "version": 21, + "identityHash": "384655556eee4a9efd557d8f84d88495", + "entities": [ + { + "tableName": "exchange_rates", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`currencyCode` TEXT NOT NULL, `rate` TEXT, PRIMARY KEY(`currencyCode`))", + "fields": [ + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "currencyCode" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "blockchain_state", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bestChainDate` INTEGER, `bestChainHeight` INTEGER NOT NULL, `replaying` INTEGER NOT NULL, `impediments` TEXT NOT NULL, `chainlockHeight` INTEGER NOT NULL, `mnlistHeight` INTEGER NOT NULL, `percentageSync` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "bestChainDate", + "columnName": "bestChainDate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bestChainHeight", + "columnName": "bestChainHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "replaying", + "columnName": "replaying", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "impediments", + "columnName": "impediments", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "chainlockHeight", + "columnName": "chainlockHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mnlistHeight", + "columnName": "mnlistHeight", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "percentageSync", + "columnName": "percentageSync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `timestamp` INTEGER NOT NULL, `value` INTEGER NOT NULL, `type` TEXT NOT NULL, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT NOT NULL, `service` TEXT, `customIconId` BLOB, PRIMARY KEY(`txId`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconId", + "columnName": "customIconId", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "address_metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address` TEXT NOT NULL, `isInput` INTEGER NOT NULL, `taxCategory` TEXT NOT NULL, `service` TEXT NOT NULL, PRIMARY KEY(`address`, `isInput`))", + "fields": [ + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isInput", + "columnName": "isInput", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "address", + "isInput" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "icon_bitmaps", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` BLOB NOT NULL, `imageData` BLOB NOT NULL, `originalUrl` TEXT NOT NULL, `height` INTEGER NOT NULL, `width` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "imageData", + "columnName": "imageData", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "originalUrl", + "columnName": "originalUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "height", + "columnName": "height", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "width", + "columnName": "width", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "gift_cards", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `merchantName` TEXT NOT NULL, `price` REAL NOT NULL, `number` TEXT, `pin` TEXT, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `note` TEXT, `index` INTEGER NOT NULL, `redeemUrlChallenge` TEXT, PRIMARY KEY(`txId`, `index`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "price", + "columnName": "price", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pin", + "columnName": "pin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "note", + "columnName": "note", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "redeemUrlChallenge", + "columnName": "redeemUrlChallenge", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId", + "index" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "dashpay_profile", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `publicMessage` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `avatarHash` BLOB, `avatarFingerprint` BLOB, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`userId`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "displayName", + "columnName": "displayName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "publicMessage", + "columnName": "publicMessage", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarUrl", + "columnName": "avatarUrl", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "avatarHash", + "columnName": "avatarHash", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "avatarFingerprint", + "columnName": "avatarFingerprint", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "updatedAt", + "columnName": "updatedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "userId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "dashpay_contact_request", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `toUserId` TEXT NOT NULL, `accountReference` INTEGER NOT NULL, `encryptedPublicKey` BLOB NOT NULL, `senderKeyIndex` INTEGER NOT NULL, `recipientKeyIndex` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `encryptedAccountLabel` BLOB, `autoAcceptProof` BLOB, PRIMARY KEY(`userId`, `toUserId`, `accountReference`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "toUserId", + "columnName": "toUserId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountReference", + "columnName": "accountReference", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "encryptedPublicKey", + "columnName": "encryptedPublicKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "senderKeyIndex", + "columnName": "senderKeyIndex", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipientKeyIndex", + "columnName": "recipientKeyIndex", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "encryptedAccountLabel", + "columnName": "encryptedAccountLabel", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "autoAcceptProof", + "columnName": "autoAcceptProof", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "userId", + "toUserId", + "accountReference" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "user_alerts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`stringResId` INTEGER NOT NULL, `iconResId` INTEGER NOT NULL, `dismissed` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL, PRIMARY KEY(`stringResId`))", + "fields": [ + { + "fieldPath": "stringResId", + "columnName": "stringResId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconResId", + "columnName": "iconResId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dismissed", + "columnName": "dismissed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "stringResId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "invitation_table", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`fundingAddress` TEXT NOT NULL, `userId` TEXT NOT NULL, `txid` BLOB, `createdAt` INTEGER NOT NULL, `memo` TEXT NOT NULL, `sentAt` INTEGER NOT NULL, `acceptedAt` INTEGER NOT NULL, `shortDynamicLink` TEXT, `dynamicLink` TEXT, PRIMARY KEY(`fundingAddress`))", + "fields": [ + { + "fieldPath": "fundingAddress", + "columnName": "fundingAddress", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "txid", + "columnName": "txid", + "affinity": "BLOB", + "notNull": false + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sentAt", + "columnName": "sentAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "acceptedAt", + "columnName": "acceptedAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortDynamicLink", + "columnName": "shortDynamicLink", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dynamicLink", + "columnName": "dynamicLink", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "fundingAddress" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cacheTimestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, `index` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "cacheTimestamp", + "columnName": "cacheTimestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "sentTimestamp", + "columnName": "sentTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconUrl", + "columnName": "customIconUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardNumber", + "columnName": "giftCardNumber", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardPin", + "columnName": "giftCardPin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "originalPrice", + "columnName": "originalPrice", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardChallenge", + "columnName": "giftCardChallenge", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "transaction_metadata_platform", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` REAL, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, `index` INTEGER, PRIMARY KEY(`id`, `txId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "sentTimestamp", + "columnName": "sentTimestamp", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "taxCategory", + "columnName": "taxCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "currencyCode", + "columnName": "currencyCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rate", + "columnName": "rate", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "memo", + "columnName": "memo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "customIconUrl", + "columnName": "customIconUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardNumber", + "columnName": "giftCardNumber", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardPin", + "columnName": "giftCardPin", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantName", + "columnName": "merchantName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "originalPrice", + "columnName": "originalPrice", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "barcodeValue", + "columnName": "barcodeValue", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "barcodeFormat", + "columnName": "barcodeFormat", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "merchantUrl", + "columnName": "merchantUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardChallenge", + "columnName": "giftCardChallenge", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id", + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "username_requests", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`requestId` TEXT NOT NULL, `username` TEXT NOT NULL, `normalizedLabel` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `identity` TEXT NOT NULL, `link` TEXT, `votes` INTEGER NOT NULL, `lockVotes` INTEGER NOT NULL, `isApproved` INTEGER NOT NULL, PRIMARY KEY(`requestId`))", + "fields": [ + { + "fieldPath": "requestId", + "columnName": "requestId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "normalizedLabel", + "columnName": "normalizedLabel", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "identity", + "columnName": "identity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "link", + "columnName": "link", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "votes", + "columnName": "votes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lockVotes", + "columnName": "lockVotes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isApproved", + "columnName": "isApproved", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "requestId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "username_votes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `username` TEXT NOT NULL, `identity` TEXT NOT NULL, `type` TEXT NOT NULL, `timestamp` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "identity", + "columnName": "identity", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "imported_masternode_keys", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`proTxHash` BLOB NOT NULL, `address` TEXT NOT NULL, `votingPrivateKey` BLOB NOT NULL, `votingPublicKey` BLOB NOT NULL, `votingPubKeyHash` BLOB NOT NULL, PRIMARY KEY(`proTxHash`))", + "fields": [ + { + "fieldPath": "proTxHash", + "columnName": "proTxHash", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "votingPrivateKey", + "columnName": "votingPrivateKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "votingPublicKey", + "columnName": "votingPublicKey", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "votingPubKeyHash", + "columnName": "votingPubKeyHash", + "affinity": "BLOB", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "proTxHash" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "topup_table", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `toUserId` TEXT NOT NULL, `workId` TEXT NOT NULL, `creditedAt` INTEGER NOT NULL, PRIMARY KEY(`txId`))", + "fields": [ + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "toUserId", + "columnName": "toUserId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "workId", + "columnName": "workId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "creditedAt", + "columnName": "creditedAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "txId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "tx_display_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` TEXT NOT NULL, `title` TEXT NOT NULL, `valueSatoshis` INTEGER NOT NULL, `iconType` INTEGER NOT NULL, `iconBgType` INTEGER NOT NULL, `statusText` TEXT NOT NULL, `comment` TEXT NOT NULL, `transactionAmount` INTEGER NOT NULL, `time` INTEGER NOT NULL, `hasErrors` INTEGER NOT NULL, `service` TEXT, `exchangeRateFiatCode` TEXT, `exchangeRateFiatValue` INTEGER, `contactUsername` TEXT, `contactDisplayName` TEXT, `contactAvatarUrl` TEXT, `contactUserId` TEXT, `filterFlags` INTEGER NOT NULL, PRIMARY KEY(`rowId`))", + "fields": [ + { + "fieldPath": "rowId", + "columnName": "rowId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "valueSatoshis", + "columnName": "valueSatoshis", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconType", + "columnName": "iconType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "iconBgType", + "columnName": "iconBgType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "statusText", + "columnName": "statusText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "transactionAmount", + "columnName": "transactionAmount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasErrors", + "columnName": "hasErrors", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "service", + "columnName": "service", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "exchangeRateFiatCode", + "columnName": "exchangeRateFiatCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "exchangeRateFiatValue", + "columnName": "exchangeRateFiatValue", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contactUsername", + "columnName": "contactUsername", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactDisplayName", + "columnName": "contactDisplayName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactAvatarUrl", + "columnName": "contactAvatarUrl", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "contactUserId", + "columnName": "contactUserId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "filterFlags", + "columnName": "filterFlags", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "rowId" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "tx_group_cache", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` TEXT NOT NULL, `txId` TEXT NOT NULL, `wrapperType` TEXT NOT NULL, `groupDate` TEXT NOT NULL, `sortOrder` INTEGER NOT NULL, PRIMARY KEY(`groupId`, `txId`))", + "fields": [ + { + "fieldPath": "groupId", + "columnName": "groupId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "txId", + "columnName": "txId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "wrapperType", + "columnName": "wrapperType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "groupDate", + "columnName": "groupDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sortOrder", + "columnName": "sortOrder", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "groupId", + "txId" + ] + }, + "indices": [ + { + "name": "index_tx_group_cache_txId", + "unique": false, + "columnNames": [ + "txId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_tx_group_cache_txId` ON `${TABLE_NAME}` (`txId`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '384655556eee4a9efd557d8f84d88495')" + ] + } +} \ No newline at end of file diff --git a/wallet/src/de/schildbach/wallet/database/AppDatabase.kt b/wallet/src/de/schildbach/wallet/database/AppDatabase.kt index a71d991666..c6e2a28bba 100644 --- a/wallet/src/de/schildbach/wallet/database/AppDatabase.kt +++ b/wallet/src/de/schildbach/wallet/database/AppDatabase.kt @@ -64,7 +64,7 @@ import org.dash.wallet.features.exploredash.utils.RoomConverters TxDisplayCacheEntry::class, TxGroupCacheEntry::class ], - version = 20, // if increasing version, we need migrations to preserve tx/addr metadata, + version = 21, // if increasing version, we need migrations to preserve tx/addr metadata, exportSchema = true ) @TypeConverters(RoomConverters::class, BlockchainStateRoomConverters::class) diff --git a/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt b/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt index c90926904d..73c8a2e24f 100644 --- a/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt +++ b/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt @@ -221,6 +221,21 @@ class AppDatabaseMigrations { } } + val migration20to21 = object : Migration(20, 21) { + override fun migrate(database: SupportSQLiteDatabase) { + // Persist the TxMetadataItem `index` (which gift card the metadata refers + // to when a single transaction has multiple gift cards) in the transaction + // metadata backup so it survives a wallet restore from the Dash Platform + // metadata backup. Both tables gain the same nullable column. + database.execSQL( + "ALTER TABLE `transaction_metadata_cache` ADD COLUMN `index` INTEGER" + ) + database.execSQL( + "ALTER TABLE `transaction_metadata_platform` ADD COLUMN `index` INTEGER" + ) + } + } + val migration15to16 = object : Migration(15, 16) { override fun migrate(database: SupportSQLiteDatabase) { // previous versions have no data in invitations table, so do this diff --git a/wallet/src/de/schildbach/wallet/database/dao/TransactionMetadataChangeCacheDao.kt b/wallet/src/de/schildbach/wallet/database/dao/TransactionMetadataChangeCacheDao.kt index 35681cc0e9..aaf6706916 100644 --- a/wallet/src/de/schildbach/wallet/database/dao/TransactionMetadataChangeCacheDao.kt +++ b/wallet/src/de/schildbach/wallet/database/dao/TransactionMetadataChangeCacheDao.kt @@ -99,20 +99,21 @@ interface TransactionMetadataChangeCacheDao { ) @Query( - """INSERT INTO transaction_metadata_cache (txId, cacheTimestamp, service, taxCategory, customIconUrl) - VALUES (:txId, :cacheTimestamp, :service, :taxCategory, :customIconUrl)""" + """INSERT INTO transaction_metadata_cache (txId, cacheTimestamp, service, taxCategory, customIconUrl, `index`) + VALUES (:txId, :cacheTimestamp, :service, :taxCategory, :customIconUrl, :index)""" ) suspend fun markGiftCardTx( txId: Sha256Hash, service: String, taxCategory: TaxCategory, customIconUrl: String?, + index: Int, cacheTimestamp: Long = System.currentTimeMillis() ) @Query( - """INSERT INTO transaction_metadata_cache (txId, cacheTimestamp, giftCardNumber, giftCardPin, merchantName, originalPrice, merchantUrl, `order`, giftCardChallenge) - VALUES (:txId, :cacheTimestamp, :giftCardNumber, :giftCardPin, :merchantName, :originalPrice, :merchantUrl, :order, :giftCardChallenge)""" + """INSERT INTO transaction_metadata_cache (txId, cacheTimestamp, giftCardNumber, giftCardPin, merchantName, originalPrice, merchantUrl, `order`, giftCardChallenge, `index`) + VALUES (:txId, :cacheTimestamp, :giftCardNumber, :giftCardPin, :merchantName, :originalPrice, :merchantUrl, :order, :giftCardChallenge, :index)""" ) suspend fun insertGiftCardData( txId: Sha256Hash, @@ -123,17 +124,19 @@ interface TransactionMetadataChangeCacheDao { merchantUrl: String?, order: String?, giftCardChallenge: String?, + index: Int, cacheTimestamp: Long = System.currentTimeMillis() ) @Query( - """INSERT INTO transaction_metadata_cache (txId, cacheTimestamp, barcodeValue, barcodeFormat) - VALUES (:txId, :cacheTimestamp, :barcodeValue, :barcodeFormat)""" + """INSERT INTO transaction_metadata_cache (txId, cacheTimestamp, barcodeValue, barcodeFormat, `index`) + VALUES (:txId, :cacheTimestamp, :barcodeValue, :barcodeFormat, :index)""" ) suspend fun insertBarcode( txId: Sha256Hash, barcodeValue: String?, barcodeFormat: String?, + index: Int, cacheTimestamp: Long = System.currentTimeMillis() ) diff --git a/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataCacheItem.kt b/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataCacheItem.kt index 876bad8d32..8d96990f30 100644 --- a/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataCacheItem.kt +++ b/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataCacheItem.kt @@ -43,7 +43,8 @@ data class TransactionMetadataCacheItem( var barcodeFormat: String? = null, var merchantUrl: String? = null, var order: String? = null, - var giftCardChallenge: String? = null + var giftCardChallenge: String? = null, + var index: Int? = null ) { @PrimaryKey(autoGenerate = true) var id: Long = 0 @@ -70,7 +71,8 @@ data class TransactionMetadataCacheItem( giftCard?.barcodeFormat?.toString(), giftCard?.merchantUrl, giftCard?.note, - giftCard?.redeemUrlChallenge + giftCard?.redeemUrlChallenge, + giftCard?.index ) fun isNotEmpty(): Boolean { @@ -78,7 +80,7 @@ data class TransactionMetadataCacheItem( currencyCode != null || rate != null || service != null || customIconUrl != null || giftCardNumber != null || giftCardPin != null || merchantName != null || originalPrice != null || barcodeValue != null || barcodeFormat != null || merchantUrl != null || - order != null || giftCardChallenge != null + order != null || giftCardChallenge != null || index != null } fun isEmpty(): Boolean = !isNotEmpty() @@ -106,7 +108,8 @@ data class TransactionMetadataCacheItem( barcodeFormat = if (barcodeFormat == other.barcodeFormat) null else barcodeFormat, merchantUrl = if (merchantUrl == other.merchantUrl) null else merchantUrl, order = if (order == other.order) null else order, - giftCardChallenge = if (giftCardChallenge == other.giftCardChallenge) null else giftCardChallenge + giftCardChallenge = if (giftCardChallenge == other.giftCardChallenge) null else giftCardChallenge, + index = if (index == other.index) null else index ) } @@ -126,7 +129,8 @@ data class TransactionMetadataCacheItem( this.merchantUrl == giftCard.merchantUrl && this.originalPrice == giftCard.price && this.order == giftCard.note && - this.giftCardChallenge == giftCard.redeemUrlChallenge + this.giftCardChallenge == giftCard.redeemUrlChallenge && + this.index == giftCard.index } return txData && (giftCard == null || giftCardEquals == true) } diff --git a/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataDocument.kt b/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataDocument.kt index d8226a4d91..e9709dde0b 100644 --- a/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataDocument.kt +++ b/wallet/src/de/schildbach/wallet/database/entity/TransactionMetadataDocument.kt @@ -40,5 +40,6 @@ data class TransactionMetadataDocument( var barcodeFormat: String? = null, var merchantUrl: String? = null, var order: String? = null, - var giftCardChallenge: String? = null + var giftCardChallenge: String? = null, + var index: Int? = null ) diff --git a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt index df127efd95..2fbefc2f0c 100644 --- a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt +++ b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt @@ -47,7 +47,8 @@ object DatabaseModule { AppDatabaseMigrations.migration16to17, AppDatabaseMigrations.migration17to18, AppDatabaseMigrations.migration18to19, - AppDatabaseMigrations.migration19to20 + AppDatabaseMigrations.migration19to20, + AppDatabaseMigrations.migration20to21 ) // destructive migrations are used from versions 1 to 11 .fallbackToDestructiveMigration() diff --git a/wallet/src/de/schildbach/wallet/service/WalletTransactionMetadataProvider.kt b/wallet/src/de/schildbach/wallet/service/WalletTransactionMetadataProvider.kt index 62ac1afa7c..9ee3d7a15b 100644 --- a/wallet/src/de/schildbach/wallet/service/WalletTransactionMetadataProvider.kt +++ b/wallet/src/de/schildbach/wallet/service/WalletTransactionMetadataProvider.kt @@ -330,7 +330,8 @@ class WalletTransactionMetadataProvider @Inject constructor( txId, service, TaxCategory.Expense, - iconUrl + iconUrl, + 0 ) } @@ -357,7 +358,8 @@ class WalletTransactionMetadataProvider @Inject constructor( giftCard.price, giftCard.merchantUrl, giftCard.note, - giftCard.redeemUrlChallenge + giftCard.redeemUrlChallenge, + giftCard.index ) } } @@ -365,7 +367,7 @@ class WalletTransactionMetadataProvider @Inject constructor( override suspend fun updateGiftCardBarcode(txId: Sha256Hash, index: Int, barcodeValue: String, barcodeFormat: BarcodeFormat) { giftCardDao.updateBarcode(txId, index, barcodeValue, barcodeFormat) if (index == 0) { - transactionMetadataChangeCacheDao.insertBarcode(txId, barcodeValue, barcodeFormat.toString()) + transactionMetadataChangeCacheDao.insertBarcode(txId, barcodeValue, barcodeFormat.toString(), index) } } diff --git a/wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt b/wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt index e067e027d9..486ce3b03c 100644 --- a/wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt +++ b/wallet/src/de/schildbach/wallet/service/platform/PlatformSyncService.kt @@ -1113,6 +1113,18 @@ class PlatformSynchronizationService @Inject constructor( giftCard.redeemUrlChallenge = challenge } } + metadata.index?.let { index -> + metadataDocumentRecord.index = index + log.info("processing TxMetadata: gift card index change") + if (cachedItems.find { + it.txId == txIdAsHash && it.cacheTimestamp > doc.updatedAt!! && + it.index != null && it.index != index + } == null + ) { + log.info("processing TxMetadata: gift card index change: changing index") + giftCard.index = index + } + } log.info("syncing metadata with platform updates: $updatedMetadata") transactionMetadataProvider.syncPlatformMetadata(txIdAsHash, updatedMetadata, giftCard, iconUrl) @@ -1161,7 +1173,8 @@ class PlatformSynchronizationService @Inject constructor( it.merchantUrl, null, it.order, - it.giftCardChallenge + it.giftCardChallenge, + it.index ) } progressListener?.invoke(10) @@ -1199,7 +1212,8 @@ class PlatformSynchronizationService @Inject constructor( barcodeFormat = docs.lastOrNull { it.barcodeFormat != null }?.barcodeFormat, merchantUrl = docs.lastOrNull { it.merchantUrl != null }?.merchantUrl, order = docs.lastOrNull { it.order != null }?.order, - giftCardChallenge = docs.lastOrNull { it.giftCardChallenge != null}?.giftCardChallenge + giftCardChallenge = docs.lastOrNull { it.giftCardChallenge != null}?.giftCardChallenge, + index = docs.lastOrNull { it.index != null }?.index ) } From d9f24a6d7bd0ad56ec88972c6a9efea6740691c1 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Wed, 17 Jun 2026 09:04:43 -0700 Subject: [PATCH 09/13] fix: collapse 19, 20, 21 db versions --- .../wallet/database/DatabaseMigrationTest.kt | 4 +- .../19.json | 44 +- .../20.json | 1212 ---------------- .../21.json | 1224 ----------------- .../schildbach/wallet/database/AppDatabase.kt | 2 +- .../wallet/database/AppDatabaseMigrations.kt | 36 +- .../de/schildbach/wallet/di/DatabaseModule.kt | 4 +- 7 files changed, 55 insertions(+), 2471 deletions(-) delete mode 100644 wallet/schemas/de.schildbach.wallet.database.AppDatabase/20.json delete mode 100644 wallet/schemas/de.schildbach.wallet.database.AppDatabase/21.json diff --git a/wallet/androidTest/de/schildbach/wallet/database/DatabaseMigrationTest.kt b/wallet/androidTest/de/schildbach/wallet/database/DatabaseMigrationTest.kt index e80422b8e3..5d73764b63 100644 --- a/wallet/androidTest/de/schildbach/wallet/database/DatabaseMigrationTest.kt +++ b/wallet/androidTest/de/schildbach/wallet/database/DatabaseMigrationTest.kt @@ -66,9 +66,7 @@ open class DatabaseMigrationTest { AppDatabaseMigrations.migration15to16, AppDatabaseMigrations.migration16to17, AppDatabaseMigrations.migration17to18, - AppDatabaseMigrations.migration18to19, - AppDatabaseMigrations.migration19to20, - AppDatabaseMigrations.migration20to21 + AppDatabaseMigrations.migration18to19 ) @Rule diff --git a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/19.json b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/19.json index 6cf3365543..cc38f9fae4 100644 --- a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/19.json +++ b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/19.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 19, - "identityHash": "37d0d678c5a25041983b612b1d9eba0f", + "identityHash": "384655556eee4a9efd557d8f84d88495", "entities": [ { "tableName": "exchange_rates", @@ -576,7 +576,7 @@ }, { "tableName": "transaction_metadata_cache", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cacheTimestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cacheTimestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, `index` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", "fields": [ { "fieldPath": "cacheTimestamp", @@ -674,6 +674,24 @@ "affinity": "TEXT", "notNull": false }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardChallenge", + "columnName": "giftCardChallenge", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": false + }, { "fieldPath": "id", "columnName": "id", @@ -692,7 +710,7 @@ }, { "tableName": "transaction_metadata_platform", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` REAL, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, PRIMARY KEY(`id`, `txId`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` REAL, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, `index` INTEGER, PRIMARY KEY(`id`, `txId`))", "fields": [ { "fieldPath": "id", @@ -795,6 +813,24 @@ "columnName": "merchantUrl", "affinity": "TEXT", "notNull": false + }, + { + "fieldPath": "order", + "columnName": "order", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "giftCardChallenge", + "columnName": "giftCardChallenge", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": false } ], "primaryKey": { @@ -1182,7 +1218,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '37d0d678c5a25041983b612b1d9eba0f')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '384655556eee4a9efd557d8f84d88495')" ] } } \ No newline at end of file diff --git a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/20.json b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/20.json deleted file mode 100644 index 9f75cb5a29..0000000000 --- a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/20.json +++ /dev/null @@ -1,1212 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 20, - "identityHash": "38d8513cefeb1edf9e2c05633490c234", - "entities": [ - { - "tableName": "exchange_rates", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`currencyCode` TEXT NOT NULL, `rate` TEXT, PRIMARY KEY(`currencyCode`))", - "fields": [ - { - "fieldPath": "currencyCode", - "columnName": "currencyCode", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "rate", - "columnName": "rate", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "currencyCode" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "blockchain_state", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bestChainDate` INTEGER, `bestChainHeight` INTEGER NOT NULL, `replaying` INTEGER NOT NULL, `impediments` TEXT NOT NULL, `chainlockHeight` INTEGER NOT NULL, `mnlistHeight` INTEGER NOT NULL, `percentageSync` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "bestChainDate", - "columnName": "bestChainDate", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "bestChainHeight", - "columnName": "bestChainHeight", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "replaying", - "columnName": "replaying", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "impediments", - "columnName": "impediments", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "chainlockHeight", - "columnName": "chainlockHeight", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "mnlistHeight", - "columnName": "mnlistHeight", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "percentageSync", - "columnName": "percentageSync", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "transaction_metadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `timestamp` INTEGER NOT NULL, `value` INTEGER NOT NULL, `type` TEXT NOT NULL, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT NOT NULL, `service` TEXT, `customIconId` BLOB, PRIMARY KEY(`txId`))", - "fields": [ - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "value", - "columnName": "value", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "taxCategory", - "columnName": "taxCategory", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "currencyCode", - "columnName": "currencyCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "rate", - "columnName": "rate", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "memo", - "columnName": "memo", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "customIconId", - "columnName": "customIconId", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "txId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "address_metadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address` TEXT NOT NULL, `isInput` INTEGER NOT NULL, `taxCategory` TEXT NOT NULL, `service` TEXT NOT NULL, PRIMARY KEY(`address`, `isInput`))", - "fields": [ - { - "fieldPath": "address", - "columnName": "address", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "isInput", - "columnName": "isInput", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "taxCategory", - "columnName": "taxCategory", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "address", - "isInput" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "icon_bitmaps", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` BLOB NOT NULL, `imageData` BLOB NOT NULL, `originalUrl` TEXT NOT NULL, `height` INTEGER NOT NULL, `width` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "imageData", - "columnName": "imageData", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "originalUrl", - "columnName": "originalUrl", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "height", - "columnName": "height", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "width", - "columnName": "width", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "gift_cards", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `merchantName` TEXT NOT NULL, `price` REAL NOT NULL, `number` TEXT, `pin` TEXT, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `note` TEXT, `index` INTEGER NOT NULL, `redeemUrlChallenge` TEXT, PRIMARY KEY(`txId`, `index`))", - "fields": [ - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "merchantName", - "columnName": "merchantName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "price", - "columnName": "price", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "pin", - "columnName": "pin", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "barcodeValue", - "columnName": "barcodeValue", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "barcodeFormat", - "columnName": "barcodeFormat", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantUrl", - "columnName": "merchantUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "note", - "columnName": "note", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "index", - "columnName": "index", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "redeemUrlChallenge", - "columnName": "redeemUrlChallenge", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "txId", - "index" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "dashpay_profile", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `publicMessage` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `avatarHash` BLOB, `avatarFingerprint` BLOB, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`userId`))", - "fields": [ - { - "fieldPath": "userId", - "columnName": "userId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "username", - "columnName": "username", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "publicMessage", - "columnName": "publicMessage", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "avatarUrl", - "columnName": "avatarUrl", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "avatarHash", - "columnName": "avatarHash", - "affinity": "BLOB", - "notNull": false - }, - { - "fieldPath": "avatarFingerprint", - "columnName": "avatarFingerprint", - "affinity": "BLOB", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "userId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "dashpay_contact_request", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `toUserId` TEXT NOT NULL, `accountReference` INTEGER NOT NULL, `encryptedPublicKey` BLOB NOT NULL, `senderKeyIndex` INTEGER NOT NULL, `recipientKeyIndex` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `encryptedAccountLabel` BLOB, `autoAcceptProof` BLOB, PRIMARY KEY(`userId`, `toUserId`, `accountReference`))", - "fields": [ - { - "fieldPath": "userId", - "columnName": "userId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "toUserId", - "columnName": "toUserId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "accountReference", - "columnName": "accountReference", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "encryptedPublicKey", - "columnName": "encryptedPublicKey", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "senderKeyIndex", - "columnName": "senderKeyIndex", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "recipientKeyIndex", - "columnName": "recipientKeyIndex", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "encryptedAccountLabel", - "columnName": "encryptedAccountLabel", - "affinity": "BLOB", - "notNull": false - }, - { - "fieldPath": "autoAcceptProof", - "columnName": "autoAcceptProof", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "userId", - "toUserId", - "accountReference" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_alerts", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`stringResId` INTEGER NOT NULL, `iconResId` INTEGER NOT NULL, `dismissed` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL, PRIMARY KEY(`stringResId`))", - "fields": [ - { - "fieldPath": "stringResId", - "columnName": "stringResId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "iconResId", - "columnName": "iconResId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dismissed", - "columnName": "dismissed", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "stringResId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "invitation_table", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`fundingAddress` TEXT NOT NULL, `userId` TEXT NOT NULL, `txid` BLOB, `createdAt` INTEGER NOT NULL, `memo` TEXT NOT NULL, `sentAt` INTEGER NOT NULL, `acceptedAt` INTEGER NOT NULL, `shortDynamicLink` TEXT, `dynamicLink` TEXT, PRIMARY KEY(`fundingAddress`))", - "fields": [ - { - "fieldPath": "fundingAddress", - "columnName": "fundingAddress", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "userId", - "columnName": "userId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "txid", - "columnName": "txid", - "affinity": "BLOB", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "memo", - "columnName": "memo", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "sentAt", - "columnName": "sentAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "acceptedAt", - "columnName": "acceptedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "shortDynamicLink", - "columnName": "shortDynamicLink", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "dynamicLink", - "columnName": "dynamicLink", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "fundingAddress" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "transaction_metadata_cache", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cacheTimestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", - "fields": [ - { - "fieldPath": "cacheTimestamp", - "columnName": "cacheTimestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "sentTimestamp", - "columnName": "sentTimestamp", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "taxCategory", - "columnName": "taxCategory", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "currencyCode", - "columnName": "currencyCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "rate", - "columnName": "rate", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "memo", - "columnName": "memo", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "customIconUrl", - "columnName": "customIconUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardNumber", - "columnName": "giftCardNumber", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardPin", - "columnName": "giftCardPin", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantName", - "columnName": "merchantName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "originalPrice", - "columnName": "originalPrice", - "affinity": "REAL", - "notNull": false - }, - { - "fieldPath": "barcodeValue", - "columnName": "barcodeValue", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "barcodeFormat", - "columnName": "barcodeFormat", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantUrl", - "columnName": "merchantUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardChallenge", - "columnName": "giftCardChallenge", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "transaction_metadata_platform", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` REAL, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, PRIMARY KEY(`id`, `txId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "sentTimestamp", - "columnName": "sentTimestamp", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "taxCategory", - "columnName": "taxCategory", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "currencyCode", - "columnName": "currencyCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "rate", - "columnName": "rate", - "affinity": "REAL", - "notNull": false - }, - { - "fieldPath": "memo", - "columnName": "memo", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "customIconUrl", - "columnName": "customIconUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardNumber", - "columnName": "giftCardNumber", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardPin", - "columnName": "giftCardPin", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantName", - "columnName": "merchantName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "originalPrice", - "columnName": "originalPrice", - "affinity": "REAL", - "notNull": false - }, - { - "fieldPath": "barcodeValue", - "columnName": "barcodeValue", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "barcodeFormat", - "columnName": "barcodeFormat", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantUrl", - "columnName": "merchantUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardChallenge", - "columnName": "giftCardChallenge", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "txId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "username_requests", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`requestId` TEXT NOT NULL, `username` TEXT NOT NULL, `normalizedLabel` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `identity` TEXT NOT NULL, `link` TEXT, `votes` INTEGER NOT NULL, `lockVotes` INTEGER NOT NULL, `isApproved` INTEGER NOT NULL, PRIMARY KEY(`requestId`))", - "fields": [ - { - "fieldPath": "requestId", - "columnName": "requestId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "username", - "columnName": "username", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "normalizedLabel", - "columnName": "normalizedLabel", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "link", - "columnName": "link", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "votes", - "columnName": "votes", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lockVotes", - "columnName": "lockVotes", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isApproved", - "columnName": "isApproved", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "requestId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "username_votes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `username` TEXT NOT NULL, `identity` TEXT NOT NULL, `type` TEXT NOT NULL, `timestamp` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "username", - "columnName": "username", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "imported_masternode_keys", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`proTxHash` BLOB NOT NULL, `address` TEXT NOT NULL, `votingPrivateKey` BLOB NOT NULL, `votingPublicKey` BLOB NOT NULL, `votingPubKeyHash` BLOB NOT NULL, PRIMARY KEY(`proTxHash`))", - "fields": [ - { - "fieldPath": "proTxHash", - "columnName": "proTxHash", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "address", - "columnName": "address", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "votingPrivateKey", - "columnName": "votingPrivateKey", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "votingPublicKey", - "columnName": "votingPublicKey", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "votingPubKeyHash", - "columnName": "votingPubKeyHash", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "proTxHash" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "topup_table", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `toUserId` TEXT NOT NULL, `workId` TEXT NOT NULL, `creditedAt` INTEGER NOT NULL, PRIMARY KEY(`txId`))", - "fields": [ - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "toUserId", - "columnName": "toUserId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "workId", - "columnName": "workId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "creditedAt", - "columnName": "creditedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "txId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tx_display_cache", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` TEXT NOT NULL, `title` TEXT NOT NULL, `valueSatoshis` INTEGER NOT NULL, `iconType` INTEGER NOT NULL, `iconBgType` INTEGER NOT NULL, `statusText` TEXT NOT NULL, `comment` TEXT NOT NULL, `transactionAmount` INTEGER NOT NULL, `time` INTEGER NOT NULL, `hasErrors` INTEGER NOT NULL, `service` TEXT, `exchangeRateFiatCode` TEXT, `exchangeRateFiatValue` INTEGER, `contactUsername` TEXT, `contactDisplayName` TEXT, `contactAvatarUrl` TEXT, `contactUserId` TEXT, `filterFlags` INTEGER NOT NULL, PRIMARY KEY(`rowId`))", - "fields": [ - { - "fieldPath": "rowId", - "columnName": "rowId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "title", - "columnName": "title", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "valueSatoshis", - "columnName": "valueSatoshis", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "iconType", - "columnName": "iconType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "iconBgType", - "columnName": "iconBgType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "statusText", - "columnName": "statusText", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "comment", - "columnName": "comment", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "transactionAmount", - "columnName": "transactionAmount", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "hasErrors", - "columnName": "hasErrors", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "exchangeRateFiatCode", - "columnName": "exchangeRateFiatCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "exchangeRateFiatValue", - "columnName": "exchangeRateFiatValue", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "contactUsername", - "columnName": "contactUsername", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "contactDisplayName", - "columnName": "contactDisplayName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "contactAvatarUrl", - "columnName": "contactAvatarUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "contactUserId", - "columnName": "contactUserId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filterFlags", - "columnName": "filterFlags", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "rowId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tx_group_cache", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` TEXT NOT NULL, `txId` TEXT NOT NULL, `wrapperType` TEXT NOT NULL, `groupDate` TEXT NOT NULL, `sortOrder` INTEGER NOT NULL, PRIMARY KEY(`groupId`, `txId`))", - "fields": [ - { - "fieldPath": "groupId", - "columnName": "groupId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wrapperType", - "columnName": "wrapperType", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "groupDate", - "columnName": "groupDate", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "sortOrder", - "columnName": "sortOrder", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "groupId", - "txId" - ] - }, - "indices": [ - { - "name": "index_tx_group_cache_txId", - "unique": false, - "columnNames": [ - "txId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_tx_group_cache_txId` ON `${TABLE_NAME}` (`txId`)" - } - ], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '38d8513cefeb1edf9e2c05633490c234')" - ] - } -} \ No newline at end of file diff --git a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/21.json b/wallet/schemas/de.schildbach.wallet.database.AppDatabase/21.json deleted file mode 100644 index cedfb132a5..0000000000 --- a/wallet/schemas/de.schildbach.wallet.database.AppDatabase/21.json +++ /dev/null @@ -1,1224 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 21, - "identityHash": "384655556eee4a9efd557d8f84d88495", - "entities": [ - { - "tableName": "exchange_rates", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`currencyCode` TEXT NOT NULL, `rate` TEXT, PRIMARY KEY(`currencyCode`))", - "fields": [ - { - "fieldPath": "currencyCode", - "columnName": "currencyCode", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "rate", - "columnName": "rate", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "currencyCode" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "blockchain_state", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`bestChainDate` INTEGER, `bestChainHeight` INTEGER NOT NULL, `replaying` INTEGER NOT NULL, `impediments` TEXT NOT NULL, `chainlockHeight` INTEGER NOT NULL, `mnlistHeight` INTEGER NOT NULL, `percentageSync` INTEGER NOT NULL, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "bestChainDate", - "columnName": "bestChainDate", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "bestChainHeight", - "columnName": "bestChainHeight", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "replaying", - "columnName": "replaying", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "impediments", - "columnName": "impediments", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "chainlockHeight", - "columnName": "chainlockHeight", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "mnlistHeight", - "columnName": "mnlistHeight", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "percentageSync", - "columnName": "percentageSync", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "transaction_metadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `timestamp` INTEGER NOT NULL, `value` INTEGER NOT NULL, `type` TEXT NOT NULL, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT NOT NULL, `service` TEXT, `customIconId` BLOB, PRIMARY KEY(`txId`))", - "fields": [ - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "value", - "columnName": "value", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "taxCategory", - "columnName": "taxCategory", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "currencyCode", - "columnName": "currencyCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "rate", - "columnName": "rate", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "memo", - "columnName": "memo", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "customIconId", - "columnName": "customIconId", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "txId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "address_metadata", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`address` TEXT NOT NULL, `isInput` INTEGER NOT NULL, `taxCategory` TEXT NOT NULL, `service` TEXT NOT NULL, PRIMARY KEY(`address`, `isInput`))", - "fields": [ - { - "fieldPath": "address", - "columnName": "address", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "isInput", - "columnName": "isInput", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "taxCategory", - "columnName": "taxCategory", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "address", - "isInput" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "icon_bitmaps", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` BLOB NOT NULL, `imageData` BLOB NOT NULL, `originalUrl` TEXT NOT NULL, `height` INTEGER NOT NULL, `width` INTEGER NOT NULL, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "imageData", - "columnName": "imageData", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "originalUrl", - "columnName": "originalUrl", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "height", - "columnName": "height", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "width", - "columnName": "width", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "gift_cards", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `merchantName` TEXT NOT NULL, `price` REAL NOT NULL, `number` TEXT, `pin` TEXT, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `note` TEXT, `index` INTEGER NOT NULL, `redeemUrlChallenge` TEXT, PRIMARY KEY(`txId`, `index`))", - "fields": [ - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "merchantName", - "columnName": "merchantName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "price", - "columnName": "price", - "affinity": "REAL", - "notNull": true - }, - { - "fieldPath": "number", - "columnName": "number", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "pin", - "columnName": "pin", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "barcodeValue", - "columnName": "barcodeValue", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "barcodeFormat", - "columnName": "barcodeFormat", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantUrl", - "columnName": "merchantUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "note", - "columnName": "note", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "index", - "columnName": "index", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "redeemUrlChallenge", - "columnName": "redeemUrlChallenge", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "txId", - "index" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "dashpay_profile", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `publicMessage` TEXT NOT NULL, `avatarUrl` TEXT NOT NULL, `avatarHash` BLOB, `avatarFingerprint` BLOB, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, PRIMARY KEY(`userId`))", - "fields": [ - { - "fieldPath": "userId", - "columnName": "userId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "username", - "columnName": "username", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "displayName", - "columnName": "displayName", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "publicMessage", - "columnName": "publicMessage", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "avatarUrl", - "columnName": "avatarUrl", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "avatarHash", - "columnName": "avatarHash", - "affinity": "BLOB", - "notNull": false - }, - { - "fieldPath": "avatarFingerprint", - "columnName": "avatarFingerprint", - "affinity": "BLOB", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "updatedAt", - "columnName": "updatedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "userId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "dashpay_contact_request", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `toUserId` TEXT NOT NULL, `accountReference` INTEGER NOT NULL, `encryptedPublicKey` BLOB NOT NULL, `senderKeyIndex` INTEGER NOT NULL, `recipientKeyIndex` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `encryptedAccountLabel` BLOB, `autoAcceptProof` BLOB, PRIMARY KEY(`userId`, `toUserId`, `accountReference`))", - "fields": [ - { - "fieldPath": "userId", - "columnName": "userId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "toUserId", - "columnName": "toUserId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "accountReference", - "columnName": "accountReference", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "encryptedPublicKey", - "columnName": "encryptedPublicKey", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "senderKeyIndex", - "columnName": "senderKeyIndex", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "recipientKeyIndex", - "columnName": "recipientKeyIndex", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "encryptedAccountLabel", - "columnName": "encryptedAccountLabel", - "affinity": "BLOB", - "notNull": false - }, - { - "fieldPath": "autoAcceptProof", - "columnName": "autoAcceptProof", - "affinity": "BLOB", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "userId", - "toUserId", - "accountReference" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "user_alerts", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`stringResId` INTEGER NOT NULL, `iconResId` INTEGER NOT NULL, `dismissed` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL, PRIMARY KEY(`stringResId`))", - "fields": [ - { - "fieldPath": "stringResId", - "columnName": "stringResId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "iconResId", - "columnName": "iconResId", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "dismissed", - "columnName": "dismissed", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "stringResId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "invitation_table", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`fundingAddress` TEXT NOT NULL, `userId` TEXT NOT NULL, `txid` BLOB, `createdAt` INTEGER NOT NULL, `memo` TEXT NOT NULL, `sentAt` INTEGER NOT NULL, `acceptedAt` INTEGER NOT NULL, `shortDynamicLink` TEXT, `dynamicLink` TEXT, PRIMARY KEY(`fundingAddress`))", - "fields": [ - { - "fieldPath": "fundingAddress", - "columnName": "fundingAddress", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "userId", - "columnName": "userId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "txid", - "columnName": "txid", - "affinity": "BLOB", - "notNull": false - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "memo", - "columnName": "memo", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "sentAt", - "columnName": "sentAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "acceptedAt", - "columnName": "acceptedAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "shortDynamicLink", - "columnName": "shortDynamicLink", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "dynamicLink", - "columnName": "dynamicLink", - "affinity": "TEXT", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "fundingAddress" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "transaction_metadata_cache", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`cacheTimestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` TEXT, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, `index` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", - "fields": [ - { - "fieldPath": "cacheTimestamp", - "columnName": "cacheTimestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "sentTimestamp", - "columnName": "sentTimestamp", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "taxCategory", - "columnName": "taxCategory", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "currencyCode", - "columnName": "currencyCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "rate", - "columnName": "rate", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "memo", - "columnName": "memo", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "customIconUrl", - "columnName": "customIconUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardNumber", - "columnName": "giftCardNumber", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardPin", - "columnName": "giftCardPin", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantName", - "columnName": "merchantName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "originalPrice", - "columnName": "originalPrice", - "affinity": "REAL", - "notNull": false - }, - { - "fieldPath": "barcodeValue", - "columnName": "barcodeValue", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "barcodeFormat", - "columnName": "barcodeFormat", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantUrl", - "columnName": "merchantUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardChallenge", - "columnName": "giftCardChallenge", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "index", - "columnName": "index", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "transaction_metadata_platform", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txId` BLOB NOT NULL, `sentTimestamp` INTEGER, `taxCategory` TEXT, `currencyCode` TEXT, `rate` REAL, `memo` TEXT, `service` TEXT, `customIconUrl` TEXT, `giftCardNumber` TEXT, `giftCardPin` TEXT, `merchantName` TEXT, `originalPrice` REAL, `barcodeValue` TEXT, `barcodeFormat` TEXT, `merchantUrl` TEXT, `order` TEXT, `giftCardChallenge` TEXT, `index` INTEGER, PRIMARY KEY(`id`, `txId`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "sentTimestamp", - "columnName": "sentTimestamp", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "taxCategory", - "columnName": "taxCategory", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "currencyCode", - "columnName": "currencyCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "rate", - "columnName": "rate", - "affinity": "REAL", - "notNull": false - }, - { - "fieldPath": "memo", - "columnName": "memo", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "customIconUrl", - "columnName": "customIconUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardNumber", - "columnName": "giftCardNumber", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardPin", - "columnName": "giftCardPin", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantName", - "columnName": "merchantName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "originalPrice", - "columnName": "originalPrice", - "affinity": "REAL", - "notNull": false - }, - { - "fieldPath": "barcodeValue", - "columnName": "barcodeValue", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "barcodeFormat", - "columnName": "barcodeFormat", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "merchantUrl", - "columnName": "merchantUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "order", - "columnName": "order", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "giftCardChallenge", - "columnName": "giftCardChallenge", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "index", - "columnName": "index", - "affinity": "INTEGER", - "notNull": false - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "id", - "txId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "username_requests", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`requestId` TEXT NOT NULL, `username` TEXT NOT NULL, `normalizedLabel` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `identity` TEXT NOT NULL, `link` TEXT, `votes` INTEGER NOT NULL, `lockVotes` INTEGER NOT NULL, `isApproved` INTEGER NOT NULL, PRIMARY KEY(`requestId`))", - "fields": [ - { - "fieldPath": "requestId", - "columnName": "requestId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "username", - "columnName": "username", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "normalizedLabel", - "columnName": "normalizedLabel", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "createdAt", - "columnName": "createdAt", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "link", - "columnName": "link", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "votes", - "columnName": "votes", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "lockVotes", - "columnName": "lockVotes", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "isApproved", - "columnName": "isApproved", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "requestId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "username_votes", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `username` TEXT NOT NULL, `identity` TEXT NOT NULL, `type` TEXT NOT NULL, `timestamp` INTEGER NOT NULL)", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "username", - "columnName": "username", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "identity", - "columnName": "identity", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "type", - "columnName": "type", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "timestamp", - "columnName": "timestamp", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": true, - "columnNames": [ - "id" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "imported_masternode_keys", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`proTxHash` BLOB NOT NULL, `address` TEXT NOT NULL, `votingPrivateKey` BLOB NOT NULL, `votingPublicKey` BLOB NOT NULL, `votingPubKeyHash` BLOB NOT NULL, PRIMARY KEY(`proTxHash`))", - "fields": [ - { - "fieldPath": "proTxHash", - "columnName": "proTxHash", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "address", - "columnName": "address", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "votingPrivateKey", - "columnName": "votingPrivateKey", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "votingPublicKey", - "columnName": "votingPublicKey", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "votingPubKeyHash", - "columnName": "votingPubKeyHash", - "affinity": "BLOB", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "proTxHash" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "topup_table", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`txId` BLOB NOT NULL, `toUserId` TEXT NOT NULL, `workId` TEXT NOT NULL, `creditedAt` INTEGER NOT NULL, PRIMARY KEY(`txId`))", - "fields": [ - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "BLOB", - "notNull": true - }, - { - "fieldPath": "toUserId", - "columnName": "toUserId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "workId", - "columnName": "workId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "creditedAt", - "columnName": "creditedAt", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "txId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tx_display_cache", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` TEXT NOT NULL, `title` TEXT NOT NULL, `valueSatoshis` INTEGER NOT NULL, `iconType` INTEGER NOT NULL, `iconBgType` INTEGER NOT NULL, `statusText` TEXT NOT NULL, `comment` TEXT NOT NULL, `transactionAmount` INTEGER NOT NULL, `time` INTEGER NOT NULL, `hasErrors` INTEGER NOT NULL, `service` TEXT, `exchangeRateFiatCode` TEXT, `exchangeRateFiatValue` INTEGER, `contactUsername` TEXT, `contactDisplayName` TEXT, `contactAvatarUrl` TEXT, `contactUserId` TEXT, `filterFlags` INTEGER NOT NULL, PRIMARY KEY(`rowId`))", - "fields": [ - { - "fieldPath": "rowId", - "columnName": "rowId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "title", - "columnName": "title", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "valueSatoshis", - "columnName": "valueSatoshis", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "iconType", - "columnName": "iconType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "iconBgType", - "columnName": "iconBgType", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "statusText", - "columnName": "statusText", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "comment", - "columnName": "comment", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "transactionAmount", - "columnName": "transactionAmount", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "time", - "columnName": "time", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "hasErrors", - "columnName": "hasErrors", - "affinity": "INTEGER", - "notNull": true - }, - { - "fieldPath": "service", - "columnName": "service", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "exchangeRateFiatCode", - "columnName": "exchangeRateFiatCode", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "exchangeRateFiatValue", - "columnName": "exchangeRateFiatValue", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "contactUsername", - "columnName": "contactUsername", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "contactDisplayName", - "columnName": "contactDisplayName", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "contactAvatarUrl", - "columnName": "contactAvatarUrl", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "contactUserId", - "columnName": "contactUserId", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "filterFlags", - "columnName": "filterFlags", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "rowId" - ] - }, - "indices": [], - "foreignKeys": [] - }, - { - "tableName": "tx_group_cache", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`groupId` TEXT NOT NULL, `txId` TEXT NOT NULL, `wrapperType` TEXT NOT NULL, `groupDate` TEXT NOT NULL, `sortOrder` INTEGER NOT NULL, PRIMARY KEY(`groupId`, `txId`))", - "fields": [ - { - "fieldPath": "groupId", - "columnName": "groupId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "txId", - "columnName": "txId", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "wrapperType", - "columnName": "wrapperType", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "groupDate", - "columnName": "groupDate", - "affinity": "TEXT", - "notNull": true - }, - { - "fieldPath": "sortOrder", - "columnName": "sortOrder", - "affinity": "INTEGER", - "notNull": true - } - ], - "primaryKey": { - "autoGenerate": false, - "columnNames": [ - "groupId", - "txId" - ] - }, - "indices": [ - { - "name": "index_tx_group_cache_txId", - "unique": false, - "columnNames": [ - "txId" - ], - "orders": [], - "createSql": "CREATE INDEX IF NOT EXISTS `index_tx_group_cache_txId` ON `${TABLE_NAME}` (`txId`)" - } - ], - "foreignKeys": [] - } - ], - "views": [], - "setupQueries": [ - "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '384655556eee4a9efd557d8f84d88495')" - ] - } -} \ No newline at end of file diff --git a/wallet/src/de/schildbach/wallet/database/AppDatabase.kt b/wallet/src/de/schildbach/wallet/database/AppDatabase.kt index c6e2a28bba..d0df3cd049 100644 --- a/wallet/src/de/schildbach/wallet/database/AppDatabase.kt +++ b/wallet/src/de/schildbach/wallet/database/AppDatabase.kt @@ -64,7 +64,7 @@ import org.dash.wallet.features.exploredash.utils.RoomConverters TxDisplayCacheEntry::class, TxGroupCacheEntry::class ], - version = 21, // if increasing version, we need migrations to preserve tx/addr metadata, + version = 19, // if increasing version, we need migrations to preserve tx/addr metadata, exportSchema = true ) @TypeConverters(RoomConverters::class, BlockchainStateRoomConverters::class) diff --git a/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt b/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt index 73c8a2e24f..cb6568c29d 100644 --- a/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt +++ b/wallet/src/de/schildbach/wallet/database/AppDatabaseMigrations.kt @@ -191,21 +191,18 @@ class AppDatabaseMigrations { val migration18to19 = object : Migration(18, 19) { override fun migrate(database: SupportSQLiteDatabase) { - // gift_cards gained a nullable `redeemUrlChallenge` column to persist - // the CTX redeem-URL challenge alongside each gift card. + // Collapsed CTX redeem-URL / gift card backup migration. None of the + // intermediate versions (19, 20, 21) ever shipped past master (v18), so + // the column additions are merged into a single 18 -> 19 step: + // - gift_cards gains `redeemUrlChallenge` (CTX redeem-URL challenge). + // - the transaction metadata backup tables gain `order` (PiggyCards + // order ID), `giftCardChallenge` (CTX redeem-URL challenge), and + // `index` (which gift card the metadata refers to when a single + // transaction has multiple gift cards). + // `order` and `index` are SQL keywords, so they must be quoted. database.execSQL( "ALTER TABLE `gift_cards` ADD COLUMN `redeemUrlChallenge` TEXT" ) - } - } - - val migration19to20 = object : Migration(19, 20) { - override fun migrate(database: SupportSQLiteDatabase) { - // Persist the PiggyCards order ID (`order`) and the CTX redeem-URL - // challenge (`giftCardChallenge`) in the transaction metadata backup so - // they survive a wallet restore from the Dash Platform metadata backup. - // Both tables gain the same two nullable columns. `order` is a SQL - // keyword, so it must be quoted. database.execSQL( "ALTER TABLE `transaction_metadata_cache` ADD COLUMN `order` TEXT" ) @@ -213,22 +210,13 @@ class AppDatabaseMigrations { "ALTER TABLE `transaction_metadata_cache` ADD COLUMN `giftCardChallenge` TEXT" ) database.execSQL( - "ALTER TABLE `transaction_metadata_platform` ADD COLUMN `order` TEXT" + "ALTER TABLE `transaction_metadata_cache` ADD COLUMN `index` INTEGER" ) database.execSQL( - "ALTER TABLE `transaction_metadata_platform` ADD COLUMN `giftCardChallenge` TEXT" + "ALTER TABLE `transaction_metadata_platform` ADD COLUMN `order` TEXT" ) - } - } - - val migration20to21 = object : Migration(20, 21) { - override fun migrate(database: SupportSQLiteDatabase) { - // Persist the TxMetadataItem `index` (which gift card the metadata refers - // to when a single transaction has multiple gift cards) in the transaction - // metadata backup so it survives a wallet restore from the Dash Platform - // metadata backup. Both tables gain the same nullable column. database.execSQL( - "ALTER TABLE `transaction_metadata_cache` ADD COLUMN `index` INTEGER" + "ALTER TABLE `transaction_metadata_platform` ADD COLUMN `giftCardChallenge` TEXT" ) database.execSQL( "ALTER TABLE `transaction_metadata_platform` ADD COLUMN `index` INTEGER" diff --git a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt index 2fbefc2f0c..0978b3c688 100644 --- a/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt +++ b/wallet/src/de/schildbach/wallet/di/DatabaseModule.kt @@ -46,9 +46,7 @@ object DatabaseModule { AppDatabaseMigrations.migration15to16, AppDatabaseMigrations.migration16to17, AppDatabaseMigrations.migration17to18, - AppDatabaseMigrations.migration18to19, - AppDatabaseMigrations.migration19to20, - AppDatabaseMigrations.migration20to21 + AppDatabaseMigrations.migration18to19 ) // destructive migrations are used from versions 1 to 11 .fallbackToDestructiveMigration() From f33d73112629c7c04dea921f7ba5a0feeb31aebb Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Wed, 17 Jun 2026 09:11:55 -0700 Subject: [PATCH 10/13] style: ktlint --- .../dash/wallet/features/exploredash/di/ExploreDashModule.kt | 4 ++-- .../ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/di/ExploreDashModule.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/di/ExploreDashModule.kt index c226c3dfce..aab2a1f0a1 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/di/ExploreDashModule.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/di/ExploreDashModule.kt @@ -97,6 +97,6 @@ abstract class ExploreDashModule { @Binds abstract fun bindDataSyncService(exploreDatabase: ExploreDataSyncStatus): DataSyncStatusService - //@Binds - //abstract fun provideCTXSpendRepository(ctxSpendRepository: CTXSpendRepository): CTXSpendRepositoryInt + // @Binds + // abstract fun provideCTXSpendRepository(ctxSpendRepository: CTXSpendRepository): CTXSpendRepositoryInt } diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt index 296f0c57ce..a57095d6e0 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/PurchaseGiftCardConfirmDialog.kt @@ -115,6 +115,7 @@ class PurchaseGiftCardConfirmDialog : ComposeBottomSheet() { companion object { private val log = LoggerFactory.getLogger(PurchaseGiftCardConfirmDialog::class.java) + // Baseline screen height (in dp, at the default font scale) needed to fit the amount, // detail card and action buttons in the wrap-content sheet. The actual threshold is // this value multiplied by the current fontScale: bigger fonts inflate the content, so From d245ab9e001008de15d9c533bd2a75bfc95f86b5 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 19 Jun 2026 00:55:46 -0700 Subject: [PATCH 11/13] chore: use dpp 2.0.6-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 50fb65ad98..99c24d249e 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { coroutinesVersion = '1.6.4' ok_http_version = '4.12.0' dashjVersion = '22.0.3' - dppVersion = "2.0.5" + dppVersion = "2.0.6-SNAPSHOT" hiltVersion = '2.53' hiltCompilerVersion = '1.2.0' hiltWorkVersion = '1.2.0' From 0b6ee673101804f77a358f1112a26614d6e67329 Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Fri, 19 Jun 2026 08:22:58 -0700 Subject: [PATCH 12/13] fix: use correct update function for piggycards and URL's --- .../ui/dashspend/dialogs/GiftCardDetailsViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt index f00cc29b63..70da6771fb 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt @@ -480,7 +480,7 @@ class GiftCardDetailsViewModel @Inject constructor( } } } else if (giftCard.redeemUrl?.isNotEmpty() == true) { - updateGiftCard(cardIndex, giftCard.redeemUrl, giftCard.redeemUrlChallenge) + updateGiftCardWithURL(cardIndex, giftCard.redeemUrl, giftCard.redeemUrlChallenge) } } cancelTicker() From 1b2a0b291900370b6c75d1c93384f54167d6ed8f Mon Sep 17 00:00:00 2001 From: HashEngineering Date: Tue, 23 Jun 2026 08:04:29 -0700 Subject: [PATCH 13/13] style(dashspend): ktlint --- .../ui/dashspend/dialogs/GiftCardDetailsViewModel.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt index 70da6771fb..483412882c 100644 --- a/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt +++ b/features/exploredash/src/main/java/org/dash/wallet/features/exploredash/ui/dashspend/dialogs/GiftCardDetailsViewModel.kt @@ -480,7 +480,11 @@ class GiftCardDetailsViewModel @Inject constructor( } } } else if (giftCard.redeemUrl?.isNotEmpty() == true) { - updateGiftCardWithURL(cardIndex, giftCard.redeemUrl, giftCard.redeemUrlChallenge) + updateGiftCardWithURL( + cardIndex, + giftCard.redeemUrl, + giftCard.redeemUrlChallenge + ) } } cancelTicker()