@@ -10,6 +10,7 @@ use std::fmt;
1010#[ derive( Serialize , Deserialize , Decode , Encode , Debug , Clone , PartialEq , Eq ) ]
1111#[ serde( rename_all = "camelCase" ) ]
1212pub struct TokenPreProgrammedDistributionV0 {
13+ #[ serde( deserialize_with = "deserialize_ts_to_id_amount_map" ) ]
1314 pub distributions : BTreeMap < TimestampMillis , BTreeMap < Identifier , TokenAmount > > ,
1415}
1516
@@ -26,3 +27,46 @@ impl fmt::Display for TokenPreProgrammedDistributionV0 {
2627 write ! ( f, "}}" )
2728 }
2829}
30+
31+ use serde:: de:: Deserializer ;
32+
33+ // Custom deserializer for `distributions` that tolerates two JSON shapes:
34+ // - a map keyed by timestamp millis as numbers (u64)
35+ // - a map keyed by timestamp millis as strings (e.g. "1735689600000")
36+ // It normalizes both into `BTreeMap<u64, V>` where V is the inner value map
37+ // (`BTreeMap<Identifier, TokenAmount>` here). If a string key cannot be parsed
38+ // as `u64`, deserialization fails with a serde error. Using `BTreeMap` keeps
39+ // keys ordered by timestamp.
40+ fn deserialize_ts_to_id_amount_map < ' de , D > (
41+ deserializer : D ,
42+ ) -> Result < BTreeMap < TimestampMillis , BTreeMap < Identifier , TokenAmount > > , D :: Error >
43+ where
44+ D : Deserializer < ' de > ,
45+ {
46+ // Untagged enum attempts the variants in order: first try a map with u64
47+ // keys; if that doesn't match, try a map with string keys.
48+ #[ derive( Deserialize ) ]
49+ #[ serde( untagged) ]
50+ enum U64OrStrTs < V > {
51+ // JSON: { 1735689600000: { <id>: <amount>, ... }, ... }
52+ U64 ( BTreeMap < TimestampMillis , V > ) ,
53+ // JSON: { "1735689600000": { <id>: <amount>, ... }, ... }
54+ Str ( BTreeMap < String , V > ) ,
55+ }
56+
57+ let helper: U64OrStrTs < BTreeMap < Identifier , TokenAmount > > =
58+ U64OrStrTs :: deserialize ( deserializer) ?;
59+ match helper {
60+ // Already has numeric timestamp keys; return as-is
61+ U64OrStrTs :: U64 ( m) => Ok ( m) ,
62+ // Convert string timestamp keys into u64, preserving values unchanged
63+ U64OrStrTs :: Str ( sm) => sm
64+ . into_iter ( )
65+ . map ( |( k, v) | {
66+ k. parse :: < u64 > ( )
67+ . map_err ( serde:: de:: Error :: custom)
68+ . map ( |ts| ( ts, v) )
69+ } )
70+ . collect ( ) ,
71+ }
72+ }
0 commit comments