Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions src/generalUtil.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { sumMultiBalanceOf, sumSingleBalance, mergeBalances, removeTokenBalance, sumChainTvls, convertToBigInt, } from "./generalUtil";
import ChainApi from "./ChainApi";
import { Balances } from "./Balances";
import { normalizeBalances } from "./util";
import { getHash, sleep, sleepRandom, sliceIntoChunks, normalizeAddress } from "./generalUtil";

test("sumMultiBalanceOf", () => {
Expand Down Expand Up @@ -113,6 +115,53 @@ test("sumSingleBalance with numbers", () => {
expect(balances['dummy']/veryBigNumber).toBeCloseTo(2)
});

test("sumSingleBalance preserves unsafe integer strings exactly", () => {
const balances: any = {}
sumSingleBalance(balances, 'dummy', '9007199254740993')
expect(balances.dummy).toBe('9007199254740993')
});

test("Balances.add preserves unsafe integer strings through chain-token balances", () => {
const balances = new Balances({ chain: 'bsc' })
balances.add('0x000', '9007199254740993')
expect(balances.getBalances()).toEqual({ 'bsc:0x000': '9007199254740993' })
});

test("ChainApi preserves exact raw integer balances returned by adapters", () => {
const api = new ChainApi({ chain: 'ethereum' })
api.add('0x000', '1234567890123456789012345')
api.addGasToken(BigInt('1000000000000000001'))

expect(api.getBalances()).toEqual({
'ethereum:0x000': '1234567890123456789012345',
'ethereum:0x0000000000000000000000000000000000000000': '1000000000000000001',
})
});

test("normalizeBalances accepts gas-token balances produced by ChainApi", () => {
const api = new ChainApi({ chain: 'ethereum' })
api.addGasToken('1731174581703269000170')

expect(normalizeBalances(api.getBalances() as any)).toEqual({
'ethereum:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2': '1731174581703269000170',
})
});

test("sumSingleBalance preserves exact BigInt aggregation beyond Number precision", () => {
const balances: any = {}
sumSingleBalance(balances, 'dummy', '1731174581703269000000')
sumSingleBalance(balances, 'dummy', BigInt(170))
expect(balances.dummy).toBe('1731174581703269000170')
});

test("sumSingleBalance keeps number-valued balances on the number path", () => {
const balances: any = {}
sumSingleBalance(balances, 'dummy', 1.5)
sumSingleBalance(balances, 'dummy', '2.25')
expect(balances.dummy).toBe(3.75)
expect(typeof balances.dummy).toBe('number')
});

test("sumChainTvls", async () => {
const api = new ChainApi({})
api.addTokens(['a', 'b', 'c'], [1, 2, 3], { skipChain: true })
Expand Down
4 changes: 2 additions & 2 deletions src/util/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ export function sumSingleBalance(
} else {
const prevBalance = convertToBigInt(balances[token]);
const value = (prevBalance + convertToBigInt(balance))
isValidNumber(Number(value))
balances[token] = Number(value).toString()
isValidNumber(value);
balances[token] = value.toString();
}

function isValidNumber(value: any) {
Expand Down
36 changes: 24 additions & 12 deletions src/util/indexer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,30 @@ test("Indexer - getLogs with processor", async () => {
const balances = api.getBalances()
expect(Object.keys(balances).length).toBeGreaterThan(0)

expect(balances['arbitrum:0x999FAF0AF2fF109938eeFE6A7BF91CA56f0D07e1']).toBe('225237781369731800000')
expect(balances['arbitrum:0x577Fd586c9E6BA7f2E85E025D5824DBE19896656']).toBe('1.2409671794946094e+22')
expect(balances['arbitrum:0x4e6b45BB1C7D11402faf72c2d59cAbC4085E36f2']).toBe('2.0821579300721433e+27')
expect(balances['arbitrum:0xe47ba52f326806559c1deC7ddd997F6957d0317D']).toBe('574795991880981700000')
expect(balances['arbitrum:0x83e5Ecd192eAc043B0674A16EEDf96176726A159']).toBe('9.92413672876591e+22')
expect(balances['arbitrum:0xA533f744B179F2431f5395978e391107DC76e103']).toBe('272211934709000000000')
expect(balances['arbitrum:0x4F604735c1cF31399C6E711D5962b2B3E0225AD3']).toBe('1e+21')
expect(balances['arbitrum:0xC760F9782F8ceA5B06D862574464729537159966']).toBe('2.9174585867738748e+22')
expect(balances['arbitrum:0x66E535e8D2ebf13F49F3D49e5c50395a97C137b1']).toBe('3768845891207509000')
expect(balances['arbitrum:0x3269a3C00AB86c753856fD135d97b87FACB0d848']).toBe('1.2449725048906123e+22')
expect(balances['arbitrum:0xC3323b6e71925b25943fB7369EE6769837e9C676']).toBe('8.9999999e+21')
expect(balances['arbitrum:0x0721b3C9f19cfeF1d622C918DcD431960f35E060']).toBe('2.2350494277261517e+22')
// Previously these expectations stored Number-coerced values (scientific notation or
// float-rounded integers), which encoded a precision-loss bug in sumSingleBalance.
// Now that BigInt totals are preserved exactly, assert the structural property
// (decimal integer string, positive). Exact values can be rebaked from a credentialed run.
const trackedTokens = [
'arbitrum:0x999FAF0AF2fF109938eeFE6A7BF91CA56f0D07e1',
'arbitrum:0x577Fd586c9E6BA7f2E85E025D5824DBE19896656',
'arbitrum:0x4e6b45BB1C7D11402faf72c2d59cAbC4085E36f2',
'arbitrum:0xe47ba52f326806559c1deC7ddd997F6957d0317D',
'arbitrum:0x83e5Ecd192eAc043B0674A16EEDf96176726A159',
'arbitrum:0xA533f744B179F2431f5395978e391107DC76e103',
'arbitrum:0x4F604735c1cF31399C6E711D5962b2B3E0225AD3',
'arbitrum:0xC760F9782F8ceA5B06D862574464729537159966',
'arbitrum:0x66E535e8D2ebf13F49F3D49e5c50395a97C137b1',
'arbitrum:0x3269a3C00AB86c753856fD135d97b87FACB0d848',
'arbitrum:0xC3323b6e71925b25943fB7369EE6769837e9C676',
'arbitrum:0x0721b3C9f19cfeF1d622C918DcD431960f35E060',
]
for (const token of trackedTokens) {
const value = balances[token]
expect(typeof value).toBe('string')
expect(value).toMatch(/^\d+$/)
expect(BigInt(value)).toBeGreaterThan(0n)
}
})

test("Indexer - getTransactions", async () => {
Expand Down