summaryrefslogtreecommitdiff
path: root/wallet/src/commonMain/kotlin/net/taler/wallet/kotlin/exchange/Denomination.kt
diff options
context:
space:
mode:
Diffstat (limited to 'wallet/src/commonMain/kotlin/net/taler/wallet/kotlin/exchange/Denomination.kt')
-rw-r--r--wallet/src/commonMain/kotlin/net/taler/wallet/kotlin/exchange/Denomination.kt234
1 files changed, 234 insertions, 0 deletions
diff --git a/wallet/src/commonMain/kotlin/net/taler/wallet/kotlin/exchange/Denomination.kt b/wallet/src/commonMain/kotlin/net/taler/wallet/kotlin/exchange/Denomination.kt
new file mode 100644
index 0000000..88a81fd
--- /dev/null
+++ b/wallet/src/commonMain/kotlin/net/taler/wallet/kotlin/exchange/Denomination.kt
@@ -0,0 +1,234 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.kotlin.exchange
+
+import kotlinx.serialization.Serializable
+import net.taler.wallet.kotlin.Amount
+import net.taler.wallet.kotlin.Base32Crockford
+import net.taler.wallet.kotlin.Duration
+import net.taler.wallet.kotlin.Timestamp
+import net.taler.wallet.kotlin.exchange.DenominationStatus.Unverified
+import net.taler.wallet.kotlin.exchange.DenominationStatus.VerifiedGood
+
+/**
+ * Denomination as found in the /keys response from the exchange.
+ */
+@Serializable
+internal data class Denomination(
+ /**
+ * Value of one coin of the denomination.
+ */
+ val value: Amount,
+
+ /**
+ * Public signing key of the denomination.
+ */
+ val denom_pub: String,
+
+ /**
+ * Fee for withdrawing.
+ */
+ val fee_withdraw: Amount,
+
+ /**
+ * Fee for depositing.
+ */
+ val fee_deposit: Amount,
+
+ /**
+ * Fee for refreshing.
+ */
+ val fee_refresh: Amount,
+
+ /**
+ * Fee for refunding.
+ */
+ val fee_refund: Amount,
+
+ /**
+ * Start date from which withdraw is allowed.
+ */
+ val stamp_start: Timestamp,
+
+ /**
+ * End date for withdrawing.
+ */
+ val stamp_expire_withdraw: Timestamp,
+
+ /**
+ * Expiration date after which the exchange can forget about
+ * the currency.
+ */
+ val stamp_expire_legal: Timestamp,
+
+ /**
+ * Date after which the coins of this denomination can't be
+ * deposited anymore.
+ */
+ val stamp_expire_deposit: Timestamp,
+
+ /**
+ * Signature over the denomination information by the exchange's master
+ * signing key.
+ */
+ val master_sig: String
+) {
+ fun toDenominationRecord(
+ baseUrl: String,
+ denomPubHash: ByteArray,
+ isOffered: Boolean,
+ isRevoked: Boolean,
+ status: DenominationStatus
+ ): DenominationRecord =
+ DenominationRecord(
+ denomPub = denom_pub,
+ denomPubHash = Base32Crockford.encode(denomPubHash),
+ exchangeBaseUrl = baseUrl,
+ feeDeposit = fee_deposit,
+ feeRefresh = fee_refresh,
+ feeRefund = fee_refund,
+ feeWithdraw = fee_withdraw,
+ isOffered = isOffered,
+ isRevoked = isRevoked,
+ masterSig = master_sig,
+ stampExpireDeposit = stamp_expire_deposit,
+ stampExpireLegal = stamp_expire_legal,
+ stampExpireWithdraw = stamp_expire_withdraw,
+ stampStart = stamp_start,
+ status = status,
+ value = value
+ )
+}
+
+enum class DenominationStatus {
+ /**
+ * Verification was delayed.
+ */
+ Unverified,
+
+ /**
+ * Verified as valid.
+ */
+ VerifiedGood,
+
+ /**
+ * Verified as invalid.
+ */
+ VerifiedBad
+}
+
+data class DenominationRecord(
+ /**
+ * Value of one coin of the denomination.
+ */
+ val value: Amount,
+ /**
+ * The denomination public key.
+ */
+ val denomPub: String,
+ /**
+ * Hash of the denomination public key.
+ * Stored in the database for faster lookups.
+ */
+ val denomPubHash: String,
+ /**
+ * Fee for withdrawing.
+ */
+ val feeWithdraw: Amount,
+ /**
+ * Fee for depositing.
+ */
+ val feeDeposit: Amount,
+ /**
+ * Fee for refreshing.
+ */
+ val feeRefresh: Amount,
+ /**
+ * Fee for refunding.
+ */
+ val feeRefund: Amount,
+ /**
+ * Validity start date of the denomination.
+ */
+ val stampStart: Timestamp,
+ /**
+ * Date after which the currency can't be withdrawn anymore.
+ */
+ val stampExpireWithdraw: Timestamp,
+ /**
+ * Date after the denomination officially doesn't exist anymore.
+ */
+ val stampExpireLegal: Timestamp,
+ /**
+ * Data after which coins of this denomination can't be deposited anymore.
+ */
+ val stampExpireDeposit: Timestamp,
+ /**
+ * Signature by the exchange's master key over the denomination
+ * information.
+ */
+ val masterSig: String,
+ /**
+ * Did we verify the signature on the denomination?
+ */
+ val status: DenominationStatus,
+ /**
+ * Was this denomination still offered by the exchange the last time
+ * we checked?
+ * Only false when the exchange redacts a previously published denomination.
+ */
+ val isOffered: Boolean,
+ /**
+ * Did the exchange revoke the denomination?
+ * When this field is set to true in the database, the same transaction
+ * should also mark all affected coins as revoked.
+ */
+ val isRevoked: Boolean,
+ /**
+ * Base URL of the exchange.
+ */
+ val exchangeBaseUrl: String
+) {
+ fun isWithdrawable(now: Timestamp = Timestamp.now()): Boolean {
+ if (isRevoked) return false // can not use revoked denomination
+ if (status != Unverified && status != VerifiedGood) return false // verified to be bad
+ if (now < stampStart) return false // denomination has not yet started
+ val lastPossibleWithdraw = stampExpireWithdraw - Duration(50 * 1000)
+ if ((lastPossibleWithdraw - now).ms == 0L) return false // denomination has expired
+ return true
+ }
+}
+
+data class DenominationSelectionInfo(
+ val totalCoinValue: Amount,
+ val totalWithdrawCost: Amount,
+ val selectedDenominations: List<SelectedDenomination>
+) {
+ fun getEarliestDepositExpiry(): Timestamp {
+ if (selectedDenominations.isEmpty()) return Timestamp(
+ Timestamp.NEVER
+ )
+ var earliest = selectedDenominations[0].denominationRecord.stampExpireDeposit
+ for (i in 1 until selectedDenominations.size) {
+ val stampExpireDeposit = selectedDenominations[i].denominationRecord.stampExpireDeposit
+ if (stampExpireDeposit < earliest) earliest = stampExpireDeposit
+ }
+ return earliest
+ }
+}
+
+data class SelectedDenomination(val count: Int, val denominationRecord: DenominationRecord)