Skip to content

Commit 1699cc3

Browse files
committed
Fix intepreter crashing during formatting
1 parent 4662752 commit 1699cc3

File tree

3 files changed

+78
-24
lines changed

3 files changed

+78
-24
lines changed

.changeset/orange-wolves-watch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@3loop/transaction-interpreter': patch
3+
---
4+
5+
Fix interpreter crash during number formatting

packages/transaction-interpreter/interpreters/std.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface FilterOptions {
1010
excludeZero?: boolean
1111
excludeNull?: boolean
1212
excludeDuplicates?: boolean
13+
sumUpRepeated?: boolean
1314
}
1415

1516
export const filterTransfers = (transfers: Asset[], filters: FilterOptions = {}): Asset[] => {
@@ -29,6 +30,25 @@ export const filterTransfers = (transfers: Asset[], filters: FilterOptions = {})
2930
)
3031
}
3132

33+
if (filters.sumUpRepeated) {
34+
const transferMap = new Map<string, Asset>()
35+
36+
filtered.forEach((transfer) => {
37+
const key = transfer.from.toLowerCase() + '-' + transfer.to.toLowerCase() + '-' + transfer.address.toLowerCase()
38+
39+
if (transferMap.has(key)) {
40+
const existing = transferMap.get(key) || { ...transfer }
41+
const existingAmount = existing.amount ? Number(existing.amount) : 0
42+
const newAmount = transfer.amount ? Number(transfer.amount) : 0
43+
existing.amount = (existingAmount + newAmount).toString()
44+
} else {
45+
transferMap.set(key, { ...transfer })
46+
}
47+
})
48+
49+
filtered = Array.from(transferMap.values())
50+
}
51+
3252
return filtered
3353
}
3454

@@ -176,20 +196,28 @@ export function displayAddress(address: string): string {
176196
}
177197

178198
export const formatNumber = (numberString: string, precision = 3): string => {
179-
const [integerPart, decimalPart] = numberString.split('.')
180-
const bigIntPart = BigInt(integerPart)
199+
// Convert scientific notation to regular number
200+
const num = Number(numberString)
201+
202+
if (isNaN(num)) return numberString
203+
204+
// For very small numbers (less than 0.000001), return in scientific notation
205+
if (num < 0.000001 && num > 0) {
206+
return num.toExponential(precision)
207+
}
208+
209+
const [integerPart, decimalPart] = num.toString().split('.')
181210

182211
if ((integerPart && integerPart.length < 3 && !decimalPart) || (decimalPart && decimalPart.startsWith('000')))
183212
return numberString
184213

185214
// Format the integer part manually
186215
let formattedIntegerPart = ''
187-
const integerStr = bigIntPart.toString()
188-
for (let i = 0; i < integerStr.length; i++) {
189-
if (i > 0 && (integerStr.length - i) % 3 === 0) {
216+
for (let i = 0; i < integerPart.length; i++) {
217+
if (i > 0 && (integerPart.length - i) % 3 === 0) {
190218
formattedIntegerPart += ','
191219
}
192-
formattedIntegerPart += integerStr[i]
220+
formattedIntegerPart += integerPart[i]
193221
}
194222

195223
// Format the decimal part
@@ -235,6 +263,11 @@ export function displayAssets(assets: Payment[]) {
235263
export function isSwap(event: DecodedTransaction): boolean {
236264
if (event.transfers.some((t) => t.type !== 'ERC20' && t.type !== 'native')) return false
237265

266+
const minted = assetsSent(event.transfers, NULL_ADDRESS)
267+
const burned = assetsReceived(event.transfers, NULL_ADDRESS)
268+
269+
if (minted.length > 0 || burned.length > 0) return false
270+
238271
const transfers = filterTransfers(event.transfers, {
239272
excludeZero: true,
240273
excludeNull: true,

packages/transaction-interpreter/interpreters/zeroEx.ts

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,55 @@
1-
import { assetsReceived, categorizedDefaultEvent, displayAsset, getNetTransfers } from './std.js'
1+
import { assetsReceived, categorizedDefaultEvent, displayAsset, getNetTransfers, filterTransfers } from './std.js'
22
import type { InterpretedTransaction } from '@/types.js'
33
import type { DecodedTransaction } from '@3loop/transaction-decoder'
44

55
export function transformEvent(event: DecodedTransaction): InterpretedTransaction {
66
const newEvent = categorizedDefaultEvent(event)
7-
const recipient = event.fromAddress
8-
const contractAddress = event.toAddress
97

10-
if (!contractAddress) return newEvent
8+
if (!event.toAddress) return newEvent
119

12-
const netSent = getNetTransfers({
13-
transfers: event.transfers,
14-
fromAddresses: [event.fromAddress],
15-
type: ['ERC20', 'native'],
10+
const filteredTransfers = filterTransfers(event.transfers, {
11+
excludeZero: true,
12+
excludeNull: true,
13+
sumUpRepeated: true,
1614
})
1715

18-
const netReceived = getNetTransfers({
19-
transfers: event.transfers,
20-
toAddresses: [recipient],
21-
fromAddresses: [contractAddress],
16+
const netSent = getNetTransfers({
17+
transfers: filteredTransfers,
18+
fromAddresses: [event.fromAddress],
2219
type: ['ERC20', 'native'],
2320
})
2421

25-
//filter the same tokne from netReceived (to filter out received fees)
2622
const sentTokens = netSent.map((t) => t.asset.address)
27-
const filteredNetReceived = netReceived.filter((t) => !sentTokens.includes(t.asset.address))
2823

29-
if (netSent.length === 1 && filteredNetReceived.length === 1) {
24+
let netReceived
25+
26+
const buyToken = event.methodCall?.params?.[0]?.components?.find((c) => c.name === 'buyToken') as
27+
| { value: string }
28+
| undefined
29+
30+
if (buyToken) {
31+
netReceived = getNetTransfers({
32+
transfers: filteredTransfers.filter((t) => t.address === buyToken.value),
33+
type: ['ERC20', 'native'],
34+
})
35+
} else {
36+
netReceived = getNetTransfers({
37+
transfers: filteredTransfers,
38+
toAddresses: [event.toAddress],
39+
type: ['ERC20', 'native'],
40+
}).filter((t) => !sentTokens.includes(t.asset.address))
41+
}
42+
43+
const receivedTokens = netReceived.map((t) => t.asset.address)
44+
45+
if (netSent.length === 1 && netReceived.length === 1) {
3046
return {
3147
...newEvent,
3248
type: 'swap',
33-
action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(filteredNetReceived[0]),
49+
action: 'Swapped ' + displayAsset(netSent[0]) + ' for ' + displayAsset(netReceived[0]),
3450
assetsReceived: assetsReceived(
35-
event.transfers.filter((t) => filteredNetReceived.some((r) => r.asset.address === t.address)),
36-
recipient,
51+
filteredTransfers.filter((t) => receivedTokens.includes(t.address)),
52+
event.fromAddress,
3753
),
3854
}
3955
}

0 commit comments

Comments
 (0)