@@ -6,6 +6,7 @@ import { UiHelperUtil } from './UiHelperUtil.js'
66
77// -- Helpers --------------------------------------------- //
88const FLOAT_FIXED_VALUE = 3
9+ const GAS_FEE_THRESHOLD = 0.1
910const plusTypes : TransactionType [ ] = [ 'receive' , 'deposit' , 'borrow' , 'claim' ]
1011const minusTypes : TransactionType [ ] = [ 'withdraw' , 'repay' , 'burn' ]
1112
@@ -20,16 +21,10 @@ export const TransactionUtil = {
2021 } ,
2122
2223 getTransactionImages ( transfers : TransactionTransfer [ ] ) : TransactionImage [ ] {
23- const [ transfer , secondTransfer ] = transfers
24- const isAllNFT = Boolean ( transfer ) && transfers ?. every ( item => Boolean ( item . nft_info ) )
25- const haveMultipleTransfers = transfers ?. length > 1
26- const haveTwoTransfers = transfers ?. length === 2
24+ const [ transfer ] = transfers
25+ const hasMultipleTransfers = transfers ?. length > 1
2726
28- if ( haveTwoTransfers && ! isAllNFT ) {
29- return [ this . getTransactionImage ( secondTransfer ) , this . getTransactionImage ( transfer ) ]
30- }
31-
32- if ( haveMultipleTransfers ) {
27+ if ( hasMultipleTransfers ) {
3328 return transfers . map ( item => this . getTransactionImage ( item ) )
3429 }
3530
@@ -67,20 +62,19 @@ export const TransactionUtil = {
6762 return undefined
6863 } ,
6964
70- getTransactionDescriptions ( transaction : Transaction ) {
65+ getTransactionDescriptions ( transaction : Transaction , mergedTransfers ?: TransactionTransfer [ ] ) {
7166 const type = transaction ?. metadata ?. operationType as TransactionType
7267
73- const transfers = transaction ?. transfers
74- const haveTransfer = transaction ?. transfers ?. length > 0
75- const haveMultipleTransfers = transaction ?. transfers ?. length > 1
76- const isFungible =
77- haveTransfer && transfers ?. every ( transfer => Boolean ( transfer ?. fungible_info ) )
68+ const transfers = mergedTransfers || transaction ?. transfers
69+ const hasTransfer = transfers ?. length > 0
70+ const hasMultipleTransfers = transfers ?. length > 1
71+ const isFungible = hasTransfer && transfers ?. every ( transfer => Boolean ( transfer ?. fungible_info ) )
7872 const [ firstTransfer , secondTransfer ] = transfers
7973
8074 let firstDescription = this . getTransferDescription ( firstTransfer )
8175 let secondDescription = this . getTransferDescription ( secondTransfer )
8276
83- if ( ! haveTransfer ) {
77+ if ( ! hasTransfer ) {
8478 const isSendOrReceive = type === 'send' || type === 'receive'
8579
8680 if ( isSendOrReceive && isFungible ) {
@@ -103,8 +97,8 @@ export const TransactionUtil = {
10397 return [ transaction . metadata . status ]
10498 }
10599
106- if ( haveMultipleTransfers ) {
107- return transfers . map ( item => this . getTransferDescription ( item ) ) . reverse ( )
100+ if ( hasMultipleTransfers ) {
101+ return transfers . map ( item => this . getTransferDescription ( item ) )
108102 }
109103
110104 let prefix = ''
@@ -146,26 +140,165 @@ export const TransactionUtil = {
146140 return description
147141 } ,
148142 mergeTransfers ( transfers : TransactionTransfer [ ] ) {
149- let mergedTransfers = transfers
150- // If we have more than two transfers, we need to merge transfers with same direction and same token
151- if ( transfers ?. length > 1 ) {
152- mergedTransfers = transfers . reduce < TransactionTransfer [ ] > ( ( acc , t ) => {
153- const name = t ?. fungible_info ?. name
154- const existingTransfer = acc . find (
155- ( { fungible_info } ) => name && name === fungible_info ?. name
156- )
157- if ( existingTransfer ) {
158- const quantity = Number ( existingTransfer . quantity . numeric ) + Number ( t . quantity . numeric )
159- existingTransfer . quantity . numeric = quantity . toString ( )
143+ if ( transfers ?. length <= 1 ) {
144+ return transfers
145+ }
146+
147+ const filteredTransfers = this . filterGasFeeTransfers ( transfers )
148+
149+ // Merge transfers with same token and same direction
150+ const mergedTransfers = filteredTransfers . reduce < TransactionTransfer [ ] > ( ( acc , t ) => {
151+ const name = t ?. fungible_info ?. name
152+ const existingTransfer = acc . find (
153+ ( { fungible_info, direction } ) =>
154+ name && name === fungible_info ?. name && direction === t . direction
155+ )
156+ if ( existingTransfer ) {
157+ const quantity = Number ( existingTransfer . quantity . numeric ) + Number ( t . quantity . numeric )
158+ existingTransfer . quantity . numeric = quantity . toString ( )
159+
160+ existingTransfer . value = ( existingTransfer . value || 0 ) + ( t . value || 0 )
161+ } else {
162+ acc . push ( t )
163+ }
164+
165+ return acc
166+ } , [ ] )
167+
168+ let finalTransfers = mergedTransfers
169+ if ( mergedTransfers . length > 2 ) {
170+ finalTransfers = mergedTransfers . sort ( ( a , b ) => ( b . value || 0 ) - ( a . value || 0 ) ) . slice ( 0 , 2 )
171+ }
172+
173+ // Correctly order transfers for display
174+ finalTransfers = finalTransfers . sort ( ( a , b ) => {
175+ if ( a . direction === 'out' && b . direction === 'in' ) {
176+ return - 1
177+ }
178+ if ( a . direction === 'in' && b . direction === 'out' ) {
179+ return 1
180+ }
181+
182+ return 0
183+ } )
184+
185+ return finalTransfers
186+ } ,
187+
188+ filterGasFeeTransfers ( transfers : TransactionTransfer [ ] ) : TransactionTransfer [ ] {
189+ // Group transfers by token name
190+ const tokenGroups = transfers . reduce < Record < string , TransactionTransfer [ ] > > (
191+ ( groups , transfer ) => {
192+ const tokenName = transfer ?. fungible_info ?. name
193+ if ( tokenName ) {
194+ if ( ! groups [ tokenName ] ) {
195+ groups [ tokenName ] = [ ]
196+ }
197+ groups [ tokenName ] . push ( transfer )
198+ }
199+
200+ return groups
201+ } ,
202+ { }
203+ )
204+
205+ const filteredTransfers : TransactionTransfer [ ] = [ ]
206+
207+ Object . values ( tokenGroups ) . forEach ( tokenTransfers => {
208+ if ( tokenTransfers . length === 1 ) {
209+ const firstTransfer = tokenTransfers [ 0 ]
210+ if ( firstTransfer ) {
211+ filteredTransfers . push ( firstTransfer )
212+ }
213+ } else {
214+ // Multiple transfers for same token, check for gas fee pattern
215+ const inTransfers = tokenTransfers . filter ( t => t . direction === 'in' )
216+ const outTransfers = tokenTransfers . filter ( t => t . direction === 'out' )
217+
218+ if ( inTransfers . length === 1 && outTransfers . length === 1 ) {
219+ const inTransfer = inTransfers [ 0 ]
220+ const outTransfer = outTransfers [ 0 ]
221+
222+ let didApplyGasFeeFilter = false
223+ if ( inTransfer && outTransfer ) {
224+ const inAmount = Number ( inTransfer . quantity . numeric )
225+ const outAmount = Number ( outTransfer . quantity . numeric )
226+
227+ // If one amount is less than 10% of the other, consider it gas and filter out the gas transfer
228+ if ( outAmount < inAmount * GAS_FEE_THRESHOLD ) {
229+ filteredTransfers . push ( inTransfer )
230+ didApplyGasFeeFilter = true
231+ } else if ( inAmount < outAmount * GAS_FEE_THRESHOLD ) {
232+ filteredTransfers . push ( outTransfer )
233+ didApplyGasFeeFilter = true
234+ }
235+ }
236+
237+ if ( ! didApplyGasFeeFilter ) {
238+ filteredTransfers . push ( ...tokenTransfers )
239+ }
160240 } else {
161- acc . push ( t )
241+ const significantTransfers = this . filterGasFeesFromTokenGroup ( tokenTransfers )
242+ filteredTransfers . push ( ...significantTransfers )
162243 }
244+ }
245+ } )
246+
247+ transfers . forEach ( transfer => {
248+ if ( ! transfer ?. fungible_info ?. name ) {
249+ filteredTransfers . push ( transfer )
250+ }
251+ } )
252+
253+ return filteredTransfers
254+ } ,
255+
256+ filterGasFeesFromTokenGroup ( tokenTransfers : TransactionTransfer [ ] ) : TransactionTransfer [ ] {
257+ if ( tokenTransfers . length <= 1 ) {
258+ return tokenTransfers
259+ }
260+
261+ const amounts = tokenTransfers . map ( t => Number ( t . quantity . numeric ) )
262+ const maxAmount = Math . max ( ...amounts )
263+ const minAmount = Math . min ( ...amounts )
264+
265+ // If minimum amount is extremely small compared to maximum (less than 1% of max), it's likely gas
266+ const extremeGasThreshold = 0.01
267+
268+ if ( minAmount < maxAmount * extremeGasThreshold ) {
269+ // Filter out extremely small amounts that are likely gas fees
163270
164- return acc
165- } , [ ] )
271+ const filtered = tokenTransfers . filter ( t => {
272+ const amount = Number ( t . quantity . numeric )
273+
274+ return amount >= maxAmount * extremeGasThreshold
275+ } )
276+
277+ return filtered
278+ }
279+
280+ // If no extremely small amounts, apply standard gas fee logic
281+ const inTransfers = tokenTransfers . filter ( t => t . direction === 'in' )
282+ const outTransfers = tokenTransfers . filter ( t => t . direction === 'out' )
283+
284+ if ( inTransfers . length === 1 && outTransfers . length === 1 ) {
285+ const inTransfer = inTransfers [ 0 ]
286+ const outTransfer = outTransfers [ 0 ]
287+
288+ if ( inTransfer && outTransfer ) {
289+ const inAmount = Number ( inTransfer . quantity . numeric )
290+ const outAmount = Number ( outTransfer . quantity . numeric )
291+
292+ if ( outAmount < inAmount * GAS_FEE_THRESHOLD ) {
293+ return [ inTransfer ]
294+ } else if ( inAmount < outAmount * GAS_FEE_THRESHOLD ) {
295+ return [ outTransfer ]
296+ }
297+ }
166298 }
167299
168- return mergedTransfers
300+ // Default: keep all transfers if no gas fee pattern detected
301+ return tokenTransfers
169302 } ,
170303
171304 getQuantityFixedValue ( value : string | undefined ) {
0 commit comments