Skip to content

Commit 0dc720a

Browse files
committed
fix(crypto): add MintAsStringSerializer so Mint deserializes correctly
PublicKeyAsStringSerializer.deserialize() always returned PublicKey, causing ClassCastException when deserializing classes with Mint fields (e.g. LocalFiat). Introduce MintAsStringSerializer that returns Mint and apply it to the Mint class.
1 parent eba7b82 commit 0dc720a

4 files changed

Lines changed: 46 additions & 24 deletions

File tree

apps/flipcash/shared/workers/src/test/kotlin/com/flipcash/app/workers/internal/GiftCardFundingWorkerTest.kt

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,12 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
2323
import kotlinx.coroutines.test.runTest
2424
import kotlinx.serialization.encodeToString
2525
import kotlinx.serialization.json.Json
26-
import kotlinx.serialization.json.jsonObject
27-
import kotlinx.serialization.json.jsonPrimitive
2826
import org.junit.After
2927
import org.junit.Before
3028
import org.junit.Test
3129
import org.junit.runner.RunWith
3230
import org.robolectric.RobolectricTestRunner
3331
import kotlin.test.assertEquals
34-
import kotlin.test.assertTrue
3532

3633
@OptIn(ExperimentalCoroutinesApi::class)
3734
@RunWith(RobolectricTestRunner::class)
@@ -148,33 +145,25 @@ class GiftCardFundingWorkerTest {
148145
// ---- buildInputData serialization roundtrip ----
149146

150147
@Test
151-
fun `buildInputData serializes amount to valid JSON`() {
148+
fun `buildInputData serializes and deserializes amount roundtrip`() {
152149
val amount = testLocalFiat()
153150
val serialized = Json.encodeToString(LocalFiat.serializer(), amount)
154-
155-
// Verify the JSON is valid and contains expected fields
156-
val jsonElement = Json.parseToJsonElement(serialized)
157-
val jsonObject = jsonElement.jsonObject
158-
159-
// Verify structure: underlyingTokenAmount, nativeAmount, rate, mint
160-
assertTrue(jsonObject.containsKey("underlyingTokenAmount"), "Missing underlyingTokenAmount")
161-
assertTrue(jsonObject.containsKey("nativeAmount"), "Missing nativeAmount")
162-
assertTrue(jsonObject.containsKey("rate"), "Missing rate")
163-
assertTrue(jsonObject.containsKey("mint"), "Missing mint")
164-
165-
// Verify mint serializes as base58 string
166-
val mintValue = jsonObject["mint"]?.jsonPrimitive?.content
167-
assertEquals("5AMAA9JV9H97YYVxx8F6FsCMmTwXSuTTQneiup4RYAUQ", mintValue)
151+
val deserialized = Json.decodeFromString(LocalFiat.serializer(), serialized)
152+
153+
assertEquals(amount.underlyingTokenAmount.quarks, deserialized.underlyingTokenAmount.quarks)
154+
assertEquals(amount.underlyingTokenAmount.currencyCode, deserialized.underlyingTokenAmount.currencyCode)
155+
assertEquals(amount.nativeAmount.quarks, deserialized.nativeAmount.quarks)
156+
assertEquals(amount.nativeAmount.currencyCode, deserialized.nativeAmount.currencyCode)
157+
assertEquals(amount.rate.fx, deserialized.rate.fx)
158+
assertEquals(amount.rate.currency, deserialized.rate.currency)
159+
assertEquals(amount.mint.bytes, deserialized.mint.bytes)
168160
}
169161

170162
@Test
171163
fun `buildInputData serializes and deserializes token roundtrip`() {
172-
// Mint uses PublicKeyAsStringSerializer which deserializes to PublicKey (parent class).
173-
// We verify the base58 string roundtrips correctly — this is what the worker uses.
174164
val mint = Mint.usdf
175165
val serialized = Json.encodeToString(mint)
176-
// Deserialize as PublicKey since the serializer returns PublicKey, then verify bytes match
177-
val deserialized = Json.decodeFromString<com.getcode.solana.keys.PublicKey>(serialized)
166+
val deserialized = Json.decodeFromString<Mint>(serialized)
178167

179168
assertEquals(mint.bytes, deserialized.bytes)
180169
}

libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/Mint.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package com.getcode.solana.keys
22

3-
import com.getcode.utils.serializer.PublicKeyAsStringSerializer
3+
import com.getcode.utils.serializer.MintAsStringSerializer
44
import com.getcode.vendor.Base58
55
import kotlinx.serialization.Serializable
66

7-
@Serializable(with = PublicKeyAsStringSerializer::class)
7+
@Serializable(with = MintAsStringSerializer::class)
88
class Mint(bytes: List<Byte>): PublicKey(bytes) {
99
constructor(base58: String) : this(Base58.decode(base58).toList())
1010

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.getcode.utils.serializer
2+
3+
import com.getcode.solana.keys.Mint
4+
import com.getcode.solana.keys.base58
5+
import kotlinx.serialization.KSerializer
6+
import kotlinx.serialization.descriptors.PrimitiveKind
7+
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
8+
import kotlinx.serialization.descriptors.SerialDescriptor
9+
import kotlinx.serialization.encoding.Decoder
10+
import kotlinx.serialization.encoding.Encoder
11+
12+
object MintAsStringSerializer : KSerializer<Mint> {
13+
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Mint", PrimitiveKind.STRING)
14+
15+
override fun serialize(encoder: Encoder, value: Mint) {
16+
encoder.encodeString(value.base58())
17+
}
18+
19+
override fun deserialize(decoder: Decoder): Mint {
20+
val base58 = decoder.decodeString()
21+
return Mint(base58)
22+
}
23+
}

libs/encryption/keys/src/test/kotlin/com/getcode/utils/serializer/SerializerTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.getcode.utils.serializer
22

3+
import com.getcode.solana.keys.Mint
34
import com.getcode.solana.keys.PublicKey
45
import kotlinx.serialization.Serializable
56
import kotlinx.serialization.json.Json
@@ -73,6 +74,15 @@ class SerializerTest {
7374
assertEquals(original.key, decoded.key)
7475
}
7576

77+
@Test
78+
fun mintSerializerRoundtrip() {
79+
val mint = Mint.usdf
80+
val json = Json.encodeToString(mint)
81+
val decoded = Json.decodeFromString<Mint>(json)
82+
assertEquals(mint.bytes, decoded.bytes)
83+
assertTrue(decoded is Mint, "Deserialized value should be Mint, not just PublicKey")
84+
}
85+
7686
@Test
7787
fun publicKeySerializerProducesBase58String() {
7888
val bytes = ByteArray(32) { 1 }

0 commit comments

Comments
 (0)