Bug Description
When a swap produces 2+ ERC-20 transfer logs to the same recipient (e.g., partial fills, rebates, or multi-hop output tokens), parseSwap throws:
SyntaxError: Cannot convert 1044719.296572006383948274 to a BigInt
at BigInt (<anonymous>)
at t (dist/index.esm.js:1:7714)
at Array.reduce (<anonymous>)
Root Cause
In the native token output branch, the reduce accumulator stores amount as a formatted decimal string (output of formatUnits), then on the next iteration attempts BigInt(acc.amount) on that decimal string — which throws because BigInt() cannot parse decimal values.
Deminified from index.esm.js:
const outputToken = logs
.filter(u => u.to.toLowerCase() === senderAddress)
.reduce((acc, log) => ({
symbol: log.symbol,
amount: formatUnits(BigInt(acc.amount) + parseUnits(log.amount, log.decimals), log.decimals),
// ^^^^^^^^^^^^^^^^^^^
// BUG: on 2nd+ iteration, acc.amount is a decimal string
// like "1044719.296572006383948274" from the previous
// formatUnits() call — BigInt() can't parse decimals
address: log.address,
}), { symbol: "", amount: "", address: "" });
What happens step by step:
- 1st iteration:
acc.amount is "" → BigInt("") returns 0n (or throws depending on engine). formatUnits(...) produces a decimal string like "1044719.296572006383948274".
- 2nd iteration:
acc.amount is now "1044719.296572006383948274" → BigInt("1044719.296572006383948274") throws SyntaxError.
Suggested Fix
Track the raw bigint value through the accumulator instead of round-tripping through formatUnits:
.reduce((acc, log) => {
const newRaw = acc.amountRaw + parseUnits(log.amount, log.decimals);
return {
symbol: log.symbol,
amountRaw: newRaw,
amount: formatUnits(newRaw, log.decimals),
address: log.address,
};
}, { symbol: "", amount: "", amountRaw: 0n, address: "" });
Reproduction
This triggers when a swap transaction has multiple ERC-20 transfer logs directed to the sender address — for example partial fills or multi-hop swaps with rebates.
Environment
Bug Description
When a swap produces 2+ ERC-20 transfer logs to the same recipient (e.g., partial fills, rebates, or multi-hop output tokens),
parseSwapthrows:Root Cause
In the native token output branch, the
reduceaccumulator storesamountas a formatted decimal string (output offormatUnits), then on the next iteration attemptsBigInt(acc.amount)on that decimal string — which throws becauseBigInt()cannot parse decimal values.Deminified from
index.esm.js:What happens step by step:
acc.amountis""→BigInt("")returns0n(or throws depending on engine).formatUnits(...)produces a decimal string like"1044719.296572006383948274".acc.amountis now"1044719.296572006383948274"→BigInt("1044719.296572006383948274")throwsSyntaxError.Suggested Fix
Track the raw
bigintvalue through the accumulator instead of round-tripping throughformatUnits:Reproduction
This triggers when a swap transaction has multiple ERC-20 transfer logs directed to the sender address — for example partial fills or multi-hop swaps with rebates.
Environment
@0x/0x-parserversion:2.14.0