@@ -139,13 +139,69 @@ export const TransactionCard = ({
139
139
const validators = useAtomValue ( allValidatorsAtom ) ;
140
140
const validator = validators ?. data ?. find ( ( v ) => v . address === receiver ) ;
141
141
142
- const getBaseAmount = ( ) : BigNumber | undefined => {
143
- if ( asset && txnInfo ?. amount ) {
144
- if ( isBondingOrUnbondingTransaction )
145
- return toDisplayAmount ( asset , txnInfo . amount ) ;
146
- if ( isNamadaAsset ( asset ) ) return txnInfo . amount ;
147
- return toDisplayAmount ( asset , txnInfo . amount ) ;
148
- } else return undefined ;
142
+ const getDisplayAmount = ( ) : BigNumber => {
143
+ if ( ! txnInfo ?. amount ) {
144
+ return BigNumber ( 0 ) ;
145
+ }
146
+ if ( ! asset ) {
147
+ return txnInfo . amount ;
148
+ }
149
+
150
+ // This is a temporary hack b/c NAM amounts are mixed in nam and unam for indexer before 3.2.0
151
+ // Whenever the migrations are run and all transactions are in micro units we need to remove this
152
+ // before 3.2.0 -> mixed
153
+ // after 3.2.0 -> unam
154
+ const guessIsDisplayAmount = ( ) : boolean => {
155
+ // Only check Namada tokens, not other chain tokens
156
+ if ( ! isNamadaAsset ( asset ) ) {
157
+ return false ;
158
+ }
159
+
160
+ // This is a fixed flag date that most operator have already upgraded to
161
+ // indexer 3.2.0, meaning all transactions after this time are safe
162
+ const timeFlag = new Date ( "2025-06-18T00:00:00" ) . getTime ( ) / 1000 ;
163
+ const txTimestamp = transactionTopLevel . timestamp ;
164
+ if ( txTimestamp && txTimestamp > timeFlag ) {
165
+ return false ;
166
+ }
167
+
168
+ // If the amount contains the float dot, like "1.000000", it's nam
169
+ const hasFloatAmount = ( ) : boolean => {
170
+ try {
171
+ const stringData = transactionTopLevel . tx ?. data ;
172
+ const objData = stringData ? JSON . parse ( stringData ) : { } ;
173
+ return [ ...objData . sources , ...objData . targets ] . find (
174
+ ( { amount } : { amount : string } ) => amount . includes ( "." )
175
+ ) ;
176
+ } catch {
177
+ return false ;
178
+ }
179
+ } ;
180
+ if ( hasFloatAmount ( ) ) {
181
+ return true ;
182
+ }
183
+
184
+ // if it's a huge amount, it should be unam
185
+ if ( txnInfo . amount . gte ( new BigNumber ( 1_000_000 ) ) ) {
186
+ return false ;
187
+ }
188
+
189
+ // if it's a small amount, it should be nam
190
+ if ( txnInfo . amount . lte ( new BigNumber ( 10 ) ) ) {
191
+ return true ;
192
+ }
193
+
194
+ // if has no more hints, just accept the data as it is
195
+ return false ;
196
+ } ;
197
+
198
+ const isAlreadyDisplayAmount = guessIsDisplayAmount ( ) ;
199
+ if ( isAlreadyDisplayAmount ) {
200
+ // Do not transform to display amount in case it was already saved as display amount
201
+ return txnInfo . amount ;
202
+ }
203
+
204
+ return toDisplayAmount ( asset , txnInfo . amount ) ;
149
205
} ;
150
206
151
207
const renderKeplrIcon = ( address : string ) : JSX . Element | null => {
@@ -171,7 +227,7 @@ export const TransactionCard = ({
171
227
return "Transfer" ;
172
228
} ;
173
229
174
- const baseAmount = getBaseAmount ( ) ;
230
+ const displayAmount = getDisplayAmount ( ) ;
175
231
176
232
return (
177
233
< article
@@ -245,7 +301,7 @@ export const TransactionCard = ({
245
301
</ div >
246
302
< TokenCurrency
247
303
className = "font-semibold text-white mt-1 ml-2"
248
- amount = { baseAmount ?? BigNumber ( 0 ) }
304
+ amount = { displayAmount }
249
305
symbol = { asset ?. symbol ?? "" }
250
306
/>
251
307
</ div >
0 commit comments