Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-24 16:33:01 +03:00
parent ef8a13cfaa
commit 2f60ccf3fc
14 changed files with 732 additions and 148 deletions

View file

@ -55,13 +55,13 @@ internal class ExpressOnrampConverter : Converter<ExpressOnrampConverter.Input,
payoutHash = entity.payoutHash,
fromFiat = Amount(
currencySymbol = entity.fromCurrencyCode,
value = entity.fromAmount.toBigDecimalOrZero(),
value = entity.fromAmount.toScaledBigDecimal(entity.fromPrecision),
decimals = entity.fromPrecision,
type = AmountType.FiatType(code = entity.fromCurrencyCode),
),
toAsset = ExpressTransactionAsset(
id = ExpressAssetId(networkId = entity.to.network, contractAddress = entity.to.contractAddress),
amount = (entity.to.actualAmount ?: entity.to.amount).toBigDecimalOrZero(),
amount = (entity.to.actualAmount ?: entity.to.amount)?.toScaledBigDecimal(entity.to.decimals),
decimals = entity.to.decimals,
cryptoCurrency = value.toCurrency,
),
@ -90,13 +90,13 @@ private fun convertExchangeTransaction(value: ExpressSwapConverter.Input): Excha
payoutHash = entity.payoutHash,
fromAsset = ExpressTransactionAsset(
id = ExpressAssetId(networkId = entity.from.network, contractAddress = entity.from.contractAddress),
amount = entity.from.amount.toBigDecimalOrZero(),
amount = entity.from.amount.toScaledBigDecimal(entity.from.decimals),
decimals = entity.from.decimals,
cryptoCurrency = value.fromCurrency,
),
toAsset = ExpressTransactionAsset(
id = ExpressAssetId(networkId = entity.to.network, contractAddress = entity.to.contractAddress),
amount = (entity.to.actualAmount ?: entity.to.amount).toBigDecimalOrZero(),
amount = (entity.to.actualAmount ?: entity.to.amount).toScaledBigDecimal(entity.to.decimals),
decimals = entity.to.decimals,
cryptoCurrency = value.toCurrency,
),
@ -105,7 +105,12 @@ private fun convertExchangeTransaction(value: ExpressSwapConverter.Input): Excha
private fun parseIsoMillis(iso: String): Long = DateTime.parse(iso).millis
private fun String?.toBigDecimalOrZero(): BigDecimal = this?.toBigDecimalOrNull() ?: BigDecimal.ZERO
/**
* Parses a raw minimal-unit amount string from the express backend and scales it to the human-readable
* value promised by [ExpressTransactionAsset.amount] (and the onramp fiat [Amount.value]).
*/
private fun String.toScaledBigDecimal(decimals: Int): BigDecimal =
(this.toBigDecimalOrNull() ?: BigDecimal.ZERO).movePointLeft(decimals)
/**
* Active (non-terminal) RAW status values passed to the DAO `observe` queries so in-progress deals

View file

@ -31,8 +31,9 @@ internal class ExpressTxHistoryConverterTest {
assertThat(swap.txInfo).isNull()
assertThat(swap.tx.status).isEqualTo(ExpressExchangeStatus.Waiting)
assertThat(swap.createdAtMillis).isEqualTo(DateTime.parse(CREATED_AT).millis)
assertThat(swap.tx.fromAsset.amount).isEqualTo(BigDecimal("1.5"))
assertThat(swap.tx.toAsset.amount).isEqualTo(BigDecimal("0.001"))
// Raw backend amounts are scaled by decimals into the human-readable value the domain model promises.
assertThat(swap.tx.fromAsset.amount).isEquivalentAccordingToCompareTo(BigDecimal("1.5"))
assertThat(swap.tx.toAsset.amount).isEquivalentAccordingToCompareTo(BigDecimal("0.001"))
}
@Test
@ -50,14 +51,14 @@ internal class ExpressTxHistoryConverterTest {
@Test
fun `GIVEN exchange entity with actual amount WHEN toOutgoingSwap THEN to-asset uses actual amount`() {
// Arrange
val entity = createExchangeEntity(toAmount = "0.001", toActualAmount = "0.00099")
// Arrange (raw minimal-unit amounts, to-asset decimals = 8)
val entity = createExchangeEntity(toAmount = "100000", toActualAmount = "99000")
// Act
val swap = swapConverter.convert(ExpressSwapConverter.Input(entity, provider = null, isOutgoing = true))
// Assert
assertThat(swap.tx.toAsset.amount).isEqualTo(BigDecimal("0.00099"))
assertThat(swap.tx.toAsset.amount).isEquivalentAccordingToCompareTo(BigDecimal("0.00099"))
}
@Test
@ -73,17 +74,18 @@ internal class ExpressTxHistoryConverterTest {
assertThat(onramp.txInfo).isNull()
assertThat(onramp.tx.status).isEqualTo(ExpressOnrampStatus.Finished)
assertThat(onramp.tx.fromFiat.currencySymbol).isEqualTo("USD")
assertThat(onramp.tx.fromFiat.value).isEqualTo(BigDecimal("100.0"))
assertThat(onramp.tx.fromFiat.value).isEquivalentAccordingToCompareTo(BigDecimal("100"))
assertThat(onramp.tx.fromFiat.decimals).isEqualTo(2)
assertThat(onramp.tx.fromFiat.type).isEqualTo(AmountType.FiatType("USD"))
assertThat(onramp.tx.toAsset.amount).isEqualTo(BigDecimal("0.5"))
assertThat(onramp.tx.toAsset.amount).isEquivalentAccordingToCompareTo(BigDecimal("0.5"))
}
private fun createExchangeEntity(
payinHash: String? = "payin",
payoutHash: String? = "payout",
status: String = "waiting",
toAmount: String = "0.001",
// Raw minimal-unit amount (to-asset decimals = 8) → 0.001
toAmount: String = "100000",
toActualAmount: String? = null,
) = ExpressExchangeEntity(
txId = "tx-1",
@ -111,7 +113,8 @@ internal class ExpressTxHistoryConverterTest {
contractAddress = "",
network = "ethereum",
decimals = 18,
amount = "1.5",
// Raw minimal-unit amount (decimals = 18) → 1.5
amount = "1500000000000000000",
actualAmount = null,
),
to = ExpressExchangeEntity.AssetEmbedded(
@ -139,13 +142,15 @@ internal class ExpressTxHistoryConverterTest {
createdAt = CREATED_AT,
updatedAt = CREATED_AT,
fromCurrencyCode = "USD",
fromAmount = "100.0",
// Raw minimal-unit fiat amount (precision = 2) → 100
fromAmount = "10000",
fromPrecision = 2,
to = ExpressOnrampEntity.AssetEmbedded(
contractAddress = "0xtoken",
network = "ethereum",
decimals = 18,
amount = "0.5",
// Raw minimal-unit amount (decimals = 18) → 0.5
amount = "500000000000000000",
actualAmount = null,
),
paymentMethod = "card",