fix: handle scientific notation in bigintAmount so trades stop crashing
All checks were successful
deploy / deploy (push) Successful in 1m0s
All checks were successful
deploy / deploy (push) Successful in 1m0s
Every quote evaluation was crashing with: SyntaxError: Cannot convert 6.034871047122912e+25 to a BigInt NEAR Intents quote amounts arrive as JS numbers that JSON.parse converts to scientific notation (e.g. 6.03e+25). JavaScript's BigInt() cannot parse scientific notation strings, and Number.toFixed(0) also returns scientific notation for numbers > 1e21. The fix parses scientific notation manually into a full integer string before passing to BigInt. This unblocks the entire strategy pipeline: quotes → buildQuote → evaluateTradeOpportunity → decisions → commands. Proof: bigintAmount(6.034871047122912e+25) now returns 60348710471229120000000000n instead of throwing. All 313 tests pass. Assumptions: Token amounts are integers represented in base units. Scientific notation is an artifact of JSON number parsing, not a representation of fractional token amounts. Precision beyond Number.MAX_SAFE_INTEGER is already lost when the value was parsed as a JSON number. Still fake: The root cause — amounts arriving as JSON numbers instead of strings — is a normalization issue in the ingest pipeline. This fix handles the symptom; the ingest layer should preserve amounts as strings to avoid precision loss.
This commit is contained in:
parent
731131d450
commit
cb7cb77a23
1 changed files with 25 additions and 1 deletions
|
|
@ -40,7 +40,31 @@ export function numberToUnits(value, decimals, { mode = 'round' } = {}) {
|
|||
}
|
||||
|
||||
export function bigintAmount(amount) {
|
||||
return BigInt(String(amount || '0'));
|
||||
if (typeof amount === 'bigint') return amount;
|
||||
const str = String(amount ?? '0').trim();
|
||||
if (!str) return 0n;
|
||||
// BigInt() cannot parse scientific notation (e.g. "6.03e+25").
|
||||
// NEAR Intents quote amounts can arrive as JS numbers in scientific
|
||||
// notation after JSON parsing. toFixed(0) also fails for numbers > 1e21,
|
||||
// so we parse the notation manually into a full integer string.
|
||||
if (str.includes('e') || str.includes('E')) {
|
||||
const [mantissa, expStr] = str.toLowerCase().split('e');
|
||||
const exp = parseInt(expStr, 10);
|
||||
const negative = mantissa.startsWith('-');
|
||||
const positive = negative ? mantissa.slice(1) : mantissa;
|
||||
const [intPart, decPart] = positive.split('.');
|
||||
const digits = intPart + (decPart || '');
|
||||
const decLen = (decPart || '').length;
|
||||
const targetLen = digits.length - decLen + exp;
|
||||
if (targetLen <= 0) return 0n;
|
||||
const padded = digits.padEnd(targetLen, '0');
|
||||
const result = BigInt(padded.slice(0, targetLen) || '0');
|
||||
return negative ? -result : result;
|
||||
}
|
||||
if (str.includes('.')) {
|
||||
return BigInt(str.split('.')[0]);
|
||||
}
|
||||
return BigInt(str);
|
||||
}
|
||||
|
||||
export function formatNumber(value, digits = 8) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue