diff options
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.kt | 234 |
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) |