From 9b4420d8f280dbbeb425b35c6365bd44f11a8a81 Mon Sep 17 00:00:00 2001 From: Luiz Date: Wed, 3 Jun 2026 01:01:53 -0300 Subject: [PATCH] =?UTF-8?q?fix(runtime):=20read=20getBalance=20BigInt-safe?= =?UTF-8?q?ly=20=E2=80=94=20TronWeb's=20JSON.parse=20quantizes=20balances?= =?UTF-8?q?=20>=202^53?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/runtime/ethers-bridge.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/runtime/ethers-bridge.js b/src/runtime/ethers-bridge.js index e6cf418..04b6816 100644 --- a/src/runtime/ethers-bridge.js +++ b/src/runtime/ethers-bridge.js @@ -153,8 +153,23 @@ const stubProvider = { if (!tw) return 0n; const remapped = lookupTvmActualBase58(address); const addr = remapped || signersMod.toBase58(address); - const sun = await tw.trx.getBalance(addr).catch(() => 0); - return BigInt(sun); + // Read the balance BigInt-safely. TronWeb's `trx.getBalance` parses the + // account JSON with lossy `JSON.parse`, quantizing any balance above 2^53 to + // the nearest IEEE-754 double (~1024-sun ULP at a ~5e18 balance) — so a small + // balance delta (e.g. a 10-sun refund landing on a pre-funded signer) reads as + // 0 even though the transfer happened. Pull `balance` out of the raw + // /wallet/getaccount text so no precision is lost. (Same >2^53 hazard the + // wait.js receipt parser already avoids.) + const base = tw.fullNode.host.replace(/\/$/, ''); + const text = await fetch(base + '/wallet/getaccount', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ address: TronWeb.address.toHex(addr), visible: false }), + }) + .then((r) => r.text()) + .catch(() => ''); + const m = text && text.match(/"balance"\s*:\s*(\d+)/); + return m ? BigInt(m[1]) : 0n; }, async getBlockNumber() { const tw = this._tw();