@metamask/assets-controller 8.1.0 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs +80 -56
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts +4 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts +4 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs +80 -56
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -9,8 +9,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _MulticallClient_instances, _MulticallClient_getProvider, _MulticallClient_config, _MulticallClient_multicallBatchBalanceOf, _MulticallClient_fallbackBatchBalanceOf, _MulticallClient_fetchSingleBalance;
|
|
12
|
+
var _MulticallClient_instances, _MulticallClient_getProvider, _MulticallClient_config, _MulticallClient_multicallBatchBalanceOf, _MulticallClient_fallbackBatchBalanceOf, _MulticallClient_fetchSingleBalance, _MulticallClient_createFailedResponses, _MulticallClient_createFailedResponse;
|
|
13
13
|
import { Interface } from "@ethersproject/abi";
|
|
14
|
+
import { createServicePolicy } from "@metamask/controller-utils";
|
|
14
15
|
import { ZERO_ADDRESS } from "../../../utils/constants.mjs";
|
|
15
16
|
import { reduceInBatchesSerially } from "../utils/index.mjs";
|
|
16
17
|
// =============================================================================
|
|
@@ -364,6 +365,8 @@ const MULTICALL3_ADDRESS_BY_CHAIN = {
|
|
|
364
365
|
'0x1079': '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
365
366
|
// Tempo Testnet Moderato
|
|
366
367
|
'0xa5bf': '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
368
|
+
// Arc (5042)
|
|
369
|
+
'0x13b2': '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
367
370
|
};
|
|
368
371
|
// =============================================================================
|
|
369
372
|
// ENCODING/DECODING UTILITIES (using @ethersproject/abi)
|
|
@@ -439,6 +442,11 @@ function decodeUint256(data) {
|
|
|
439
442
|
const decoded = erc20Interface.decodeFunctionResult('balanceOf', data);
|
|
440
443
|
return decoded[0].toString();
|
|
441
444
|
}
|
|
445
|
+
// =============================================================================
|
|
446
|
+
// MULTICALL CLIENT
|
|
447
|
+
// =============================================================================
|
|
448
|
+
/** Retries after the initial multicall attempt before returning failed responses. */
|
|
449
|
+
const MULTICALL_MAX_RETRIES = 2;
|
|
442
450
|
/**
|
|
443
451
|
* Client for batching RPC calls using Multicall3.
|
|
444
452
|
* Falls back to individual calls on chains without Multicall3 support.
|
|
@@ -468,20 +476,22 @@ export class MulticallClient {
|
|
|
468
476
|
*
|
|
469
477
|
* @param chainId - The chain ID.
|
|
470
478
|
* @param requests - Array of balance requests.
|
|
479
|
+
* @param options - Optional batch options (e.g. single-call fallback).
|
|
471
480
|
* @returns Array of balance responses.
|
|
472
481
|
*/
|
|
473
|
-
async batchBalanceOf(chainId, requests) {
|
|
482
|
+
async batchBalanceOf(chainId, requests, options = { fallbackToSingleCalls: false }) {
|
|
474
483
|
if (requests.length === 0) {
|
|
475
484
|
return [];
|
|
476
485
|
}
|
|
477
486
|
const multicallAddress = MULTICALL3_ADDRESS_BY_CHAIN[chainId];
|
|
478
487
|
const provider = __classPrivateFieldGet(this, _MulticallClient_getProvider, "f").call(this, chainId);
|
|
479
|
-
// If Multicall3 is not supported, fall back to individual calls
|
|
480
488
|
if (!multicallAddress) {
|
|
481
|
-
return
|
|
489
|
+
return options.fallbackToSingleCalls
|
|
490
|
+
? __classPrivateFieldGet(this, _MulticallClient_instances, "m", _MulticallClient_fallbackBatchBalanceOf).call(this, provider, requests)
|
|
491
|
+
: __classPrivateFieldGet(this, _MulticallClient_instances, "m", _MulticallClient_createFailedResponses).call(this, requests);
|
|
482
492
|
}
|
|
483
493
|
// Use Multicall3
|
|
484
|
-
return __classPrivateFieldGet(this, _MulticallClient_instances, "m", _MulticallClient_multicallBatchBalanceOf).call(this, provider, multicallAddress, requests);
|
|
494
|
+
return __classPrivateFieldGet(this, _MulticallClient_instances, "m", _MulticallClient_multicallBatchBalanceOf).call(this, provider, multicallAddress, requests, options.fallbackToSingleCalls);
|
|
485
495
|
}
|
|
486
496
|
}
|
|
487
497
|
_MulticallClient_getProvider = new WeakMap(), _MulticallClient_config = new WeakMap(), _MulticallClient_instances = new WeakSet(), _MulticallClient_multicallBatchBalanceOf =
|
|
@@ -491,9 +501,10 @@ _MulticallClient_getProvider = new WeakMap(), _MulticallClient_config = new Weak
|
|
|
491
501
|
* @param provider - The RPC provider.
|
|
492
502
|
* @param multicallAddress - The Multicall3 contract address.
|
|
493
503
|
* @param requests - Array of balance requests.
|
|
504
|
+
* @param fallbackToSingleCalls - Whether to fall back to individual RPC calls on batch failure.
|
|
494
505
|
* @returns Array of balance responses.
|
|
495
506
|
*/
|
|
496
|
-
async function _MulticallClient_multicallBatchBalanceOf(provider, multicallAddress, requests) {
|
|
507
|
+
async function _MulticallClient_multicallBatchBalanceOf(provider, multicallAddress, requests, fallbackToSingleCalls) {
|
|
497
508
|
const batchSize = __classPrivateFieldGet(this, _MulticallClient_config, "f").maxCallsPerBatch;
|
|
498
509
|
const responses = await reduceInBatchesSerially({
|
|
499
510
|
values: requests,
|
|
@@ -501,54 +512,63 @@ async function _MulticallClient_multicallBatchBalanceOf(provider, multicallAddre
|
|
|
501
512
|
initialResult: [],
|
|
502
513
|
eachBatch: async (workingResult, batch) => {
|
|
503
514
|
try {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
:
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
515
|
+
await createServicePolicy({
|
|
516
|
+
maxRetries: MULTICALL_MAX_RETRIES,
|
|
517
|
+
}).execute(async () => {
|
|
518
|
+
// Build aggregate3 calls
|
|
519
|
+
const calls = batch.map((req) => {
|
|
520
|
+
const isNative = req.tokenAddress === ZERO_ADDRESS;
|
|
521
|
+
const target = isNative ? multicallAddress : req.tokenAddress;
|
|
522
|
+
return {
|
|
523
|
+
target,
|
|
524
|
+
allowFailure: true,
|
|
525
|
+
callData: isNative
|
|
526
|
+
? encodeGetEthBalance(req.accountAddress)
|
|
527
|
+
: encodeBalanceOf(req.accountAddress),
|
|
528
|
+
};
|
|
529
|
+
});
|
|
530
|
+
// Encode and send aggregate3 call
|
|
531
|
+
const callData = encodeAggregate3(calls);
|
|
532
|
+
const result = await provider.call({
|
|
533
|
+
to: multicallAddress,
|
|
534
|
+
data: callData,
|
|
535
|
+
});
|
|
536
|
+
// Decode response
|
|
537
|
+
const decoded = decodeAggregate3Response(result, batch.length);
|
|
538
|
+
// Map results back to responses
|
|
539
|
+
for (let i = 0; i < batch.length; i++) {
|
|
540
|
+
const { tokenAddress, accountAddress } = batch[i];
|
|
541
|
+
const { success, returnData } = decoded[i];
|
|
542
|
+
if (success && returnData && returnData.length > 2) {
|
|
543
|
+
workingResult.push({
|
|
544
|
+
tokenAddress,
|
|
545
|
+
accountAddress,
|
|
546
|
+
success: true,
|
|
547
|
+
balance: decodeUint256(returnData),
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
workingResult.push({
|
|
552
|
+
tokenAddress,
|
|
553
|
+
accountAddress,
|
|
554
|
+
success: false,
|
|
555
|
+
});
|
|
556
|
+
}
|
|
542
557
|
}
|
|
543
|
-
}
|
|
558
|
+
});
|
|
544
559
|
}
|
|
545
560
|
catch {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
561
|
+
if (fallbackToSingleCalls) {
|
|
562
|
+
// On aggregate3 error, fall back to individual calls for this batch.
|
|
563
|
+
// #fetchSingleBalance never rejects - it catches all errors internally
|
|
564
|
+
// and returns a failed response, so we use Promise.all here.
|
|
565
|
+
const fallbackResults = await Promise.all(batch.map((req) => __classPrivateFieldGet(this, _MulticallClient_instances, "m", _MulticallClient_fetchSingleBalance).call(this, provider, req)));
|
|
566
|
+
for (const result of fallbackResults) {
|
|
567
|
+
workingResult.push(result);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
workingResult.push(...__classPrivateFieldGet(this, _MulticallClient_instances, "m", _MulticallClient_createFailedResponses).call(this, batch));
|
|
552
572
|
}
|
|
553
573
|
}
|
|
554
574
|
return workingResult;
|
|
@@ -619,11 +639,15 @@ async function _MulticallClient_fetchSingleBalance(provider, request) {
|
|
|
619
639
|
};
|
|
620
640
|
}
|
|
621
641
|
catch {
|
|
622
|
-
return
|
|
623
|
-
tokenAddress: request.tokenAddress,
|
|
624
|
-
accountAddress: request.accountAddress,
|
|
625
|
-
success: false,
|
|
626
|
-
};
|
|
642
|
+
return __classPrivateFieldGet(this, _MulticallClient_instances, "m", _MulticallClient_createFailedResponse).call(this, request);
|
|
627
643
|
}
|
|
644
|
+
}, _MulticallClient_createFailedResponses = function _MulticallClient_createFailedResponses(requests) {
|
|
645
|
+
return requests.map((request) => __classPrivateFieldGet(this, _MulticallClient_instances, "m", _MulticallClient_createFailedResponse).call(this, request));
|
|
646
|
+
}, _MulticallClient_createFailedResponse = function _MulticallClient_createFailedResponse(request) {
|
|
647
|
+
return {
|
|
648
|
+
tokenAddress: request.tokenAddress,
|
|
649
|
+
accountAddress: request.accountAddress,
|
|
650
|
+
success: false,
|
|
651
|
+
};
|
|
628
652
|
};
|
|
629
653
|
//# sourceMappingURL=MulticallClient.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MulticallClient.mjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/clients/MulticallClient.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,2BAA2B;AAG/C,OAAO,EAAE,YAAY,EAAE,qCAAiC;AASxD,OAAO,EAAE,uBAAuB,EAAE,2BAAiB;AAEnD,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,cAAc,GAAG;IACrB;QACE,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,UAAU;QAChB,eAAe,EAAE,SAAS;QAC1B,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,SAAS;gBACf,UAAU,EAAE;oBACV,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;oBACnC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE;oBACtC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE;iBACpC;aACF;SACF;QACD,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,SAAS;gBACf,UAAU,EAAE;oBACV,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE;oBACjC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;iBACtC;aACF;SACF;KACF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,IAAI,EAAE,UAAU;QAChB,eAAe,EAAE,MAAM;QACvB,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC3C,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;KAChD;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,SAAS,GAAG;IAChB;QACE,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,UAAU;QAChB,eAAe,EAAE,MAAM;QACvB,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC9C,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;KAChD;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,mBAAmB,GAAG,IAAI,SAAS,CAAC,cAAc,CAAC,CAAC;AAC1D,MAAM,cAAc,GAAG,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;AAEhD,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF;;;;;GAKG;AACH,MAAM,2BAA2B,GAAqB;IACpD,KAAK,EAAE,4CAA4C;IACnD,MAAM,EAAE,4CAA4C;IACpD,KAAK,EAAE,4CAA4C;IACnD,KAAK,EAAE,4CAA4C;IACnD,KAAK,EAAE,4CAA4C;IACnD,UAAU,EAAE,4CAA4C;IACxD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,SAAS,EAAE,4CAA4C;IACvD,UAAU,EAAE,4CAA4C;IACxD,KAAK,EAAE,4CAA4C;IACnD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,UAAU,EAAE,4CAA4C;IACxD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,WAAW,EAAE,4CAA4C;IACzD,MAAM,EAAE,4CAA4C;IACpD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,aAAa,EAAE,4CAA4C;IAC3D,aAAa,EAAE,4CAA4C;IAC3D,YAAY,EAAE,4CAA4C;IAC1D,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,WAAW,EAAE,4CAA4C;IACzD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,KAAK,EAAE,4CAA4C;IACnD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,YAAY,EAAE,4CAA4C;IAC1D,OAAO,EAAE,4CAA4C;IACrD,UAAU,EAAE,4CAA4C;IACxD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,WAAW,EAAE,4CAA4C;IACzD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,UAAU,EAAE,4CAA4C;IACxD,YAAY,EAAE,4CAA4C;IAC1D,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,YAAY,EAAE,4CAA4C;IAC1D,YAAY,EAAE,4CAA4C;IAC1D,WAAW,EAAE,4CAA4C;IACzD,YAAY,EAAE,4CAA4C;IAC1D,YAAY,EAAE,4CAA4C;IAC1D,YAAY,EAAE,4CAA4C;IAC1D,YAAY,EAAE,4CAA4C;IAC1D,YAAY,EAAE,4CAA4C;IAC1D,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,WAAW,EAAE,4CAA4C;IACzD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,OAAO,EAAE,4CAA4C;IACrD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,aAAa,EAAE,4CAA4C;IAC3D,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,4CAA4C;IACpD,WAAW,EAAE,4CAA4C;IACzD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,SAAS,EAAE,4CAA4C;IACvD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,WAAW,EAAE,4CAA4C;IACzD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,UAAU,EAAE,4CAA4C;IACxD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,UAAU,EAAE,4CAA4C;IACxD,OAAO,EAAE,4CAA4C;IACrD,SAAS,EAAE,4CAA4C;IACvD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,WAAW,EAAE,4CAA4C;IACzD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,OAAO,EAAE,4CAA4C;IACrD,SAAS,EAAE,4CAA4C;IACvD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,WAAW,EAAE,4CAA4C;IACzD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,aAAa,EAAE,4CAA4C;IAC3D,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,WAAW,EAAE,4CAA4C;IACzD,cAAc,EAAE,4CAA4C;IAC5D,UAAU,EAAE,4CAA4C;IACxD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,MAAM,EAAE,4CAA4C;IACpD,UAAU,EAAE,4CAA4C;IACxD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,SAAS,EAAE,4CAA4C;IACvD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,OAAO,EAAE,4CAA4C;IACrD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,MAAM,EAAE,4CAA4C;IACpD,SAAS,EAAE,4CAA4C;IACvD,MAAM,EAAE,4CAA4C;IACpD,MAAM,EAAE,4CAA4C;IACpD,QAAQ,EAAE,4CAA4C;IACtD,QAAQ,EAAE,4CAA4C;IACtD,SAAS,EAAE,4CAA4C;IACvD,cAAc;IACd,QAAQ,EAAE,4CAA4C;IACtD,eAAe;IACf,OAAO,EAAE,4CAA4C;IACrD,gBAAgB;IAChB,QAAQ,EAAE,4CAA4C;IACtD,yBAAyB;IACzB,QAAQ,EAAE,4CAA4C;CACvD,CAAC;AAEF,gFAAgF;AAChF,yDAAyD;AACzD,gFAAgF;AAEhF;;;;;GAKG;AACH,SAAS,eAAe,CAAC,cAAuB;IAC9C,OAAO,cAAc,CAAC,kBAAkB,CAAC,WAAW,EAAE;QACpD,cAAc;KACf,CAAQ,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,cAAuB;IAClD,OAAO,mBAAmB,CAAC,kBAAkB,CAAC,eAAe,EAAE;QAC7D,cAAc;KACf,CAAQ,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAA2E;IAE3E,OAAO,mBAAmB,CAAC,kBAAkB,CAAC,YAAY,EAAE;QAC1D,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;KACJ,CAAQ,CAAC;AACZ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CACtC,IAAS,EACT,SAAiB;IAEjB,MAAM,OAAO,GAAG,mBAAmB,CAAC,oBAAoB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAE7E,0DAA0D;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAGtB,CAAC;IAEJ,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,YAAY,SAAS,iBAAiB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAiB;KACrC,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,IAAS;IAC9B,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACtC,oCAAoC;QACpC,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,oBAAoB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACvE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC/B,CAAC;AAWD;;;GAGG;AACH,MAAM,OAAO,eAAe;IAK1B,YACE,WAAgC,EAChC,MAA8B;;QANvB,+CAAkC;QAElC,0CAAyC;QAMhD,uBAAA,IAAI,gCAAgB,WAAW,MAAA,CAAC;QAChC,uEAAuE;QACvE,gDAAgD;QAChD,MAAM,gBAAgB,GACpB,MAAM,EAAE,gBAAgB,KAAK,SAAS,IAAI,MAAM,CAAC,gBAAgB,GAAG,CAAC;YACnE,CAAC,CAAC,MAAM,CAAC,gBAAgB;YACzB,CAAC,CAAC,GAAG,CAAC;QACV,MAAM,SAAS,GACb,MAAM,EAAE,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC;YACrD,CAAC,CAAC,MAAM,CAAC,SAAS;YAClB,CAAC,CAAC,KAAK,CAAC;QACZ,uBAAA,IAAI,2BAAW;YACb,gBAAgB;YAChB,SAAS;SACV,MAAA,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,cAAc,CAClB,OAAgB,EAChB,QAA4B;QAE5B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,gBAAgB,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,uBAAA,IAAI,oCAAa,MAAjB,IAAI,EAAc,OAAO,CAAC,CAAC;QAE5C,gEAAgE;QAChE,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,OAAO,uBAAA,IAAI,2EAAwB,MAA5B,IAAI,EAAyB,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC1D,CAAC;QAED,iBAAiB;QACjB,OAAO,uBAAA,IAAI,4EAAyB,MAA7B,IAAI,EAA0B,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IAC7E,CAAC;CAiLF;;AA/KC;;;;;;;GAOG;AACH,KAAK,mDACH,QAAkB,EAClB,gBAAqB,EACrB,QAA4B;IAE5B,MAAM,SAAS,GAAG,uBAAA,IAAI,+BAAQ,CAAC,gBAAgB,CAAC;IAEhD,MAAM,SAAS,GAAG,MAAM,uBAAuB,CAG7C;QACA,MAAM,EAAE,QAAQ;QAChB,SAAS;QACT,aAAa,EAAE,EAAE;QACjB,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE;YACxC,IAAI,CAAC;gBACH,yBAAyB;gBACzB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,KAAK,YAAY,CAAC;oBACnD,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;oBAC9D,OAAO;wBACL,MAAM;wBACN,YAAY,EAAE,IAAI;wBAClB,QAAQ,EAAE,QAAQ;4BAChB,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC;4BACzC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,cAAc,CAAC;qBACxC,CAAC;gBACJ,CAAC,CAAC,CAAC;gBAEH,kCAAkC;gBAClC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;gBACzC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;oBACjC,EAAE,EAAE,gBAAgB;oBACpB,IAAI,EAAE,QAAQ;iBACf,CAAC,CAAC;gBAEH,kBAAkB;gBAClB,MAAM,OAAO,GAAG,wBAAwB,CAAC,MAAa,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;gBAEtE,gCAAgC;gBAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACtC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBAClD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;oBAE3C,IAAI,OAAO,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACnD,aAAa,CAAC,IAAI,CAAC;4BACjB,YAAY;4BACZ,cAAc;4BACd,OAAO,EAAE,IAAI;4BACb,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC;yBACnC,CAAC,CAAC;oBACL,CAAC;yBAAM,CAAC;wBACN,aAAa,CAAC,IAAI,CAAC;4BACjB,YAAY;4BACZ,cAAc;4BACd,OAAO,EAAE,KAAK;yBACf,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,qEAAqE;gBACrE,uEAAuE;gBACvE,6DAA6D;gBAC7D,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,GAAG,CACvC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,uBAAA,IAAI,uEAAoB,MAAxB,IAAI,EAAqB,QAAQ,EAAE,GAAG,CAAC,CAAC,CAC5D,CAAC;gBAEF,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;oBACrC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;YAED,OAAO,aAAa,CAAC;QACvB,CAAC;KACF,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,kDACH,QAAkB,EAClB,QAA4B;IAE5B,iFAAiF;IACjF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,uBAAA,IAAI,+BAAQ,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IAE9D,MAAM,SAAS,GAAG,MAAM,uBAAuB,CAG7C;QACA,MAAM,EAAE,QAAQ;QAChB,SAAS;QACT,aAAa,EAAE,EAAE;QACjB,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE;YACxC,uEAAuE;YACvE,6DAA6D;YAC7D,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CACpC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,uBAAA,IAAI,uEAAoB,MAAxB,IAAI,EAAqB,QAAQ,EAAE,GAAG,CAAC,CAAC,CAC5D,CAAC;YAEF,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;gBAClC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;YAED,OAAO,aAAa,CAAC;QACvB,CAAC;KACF,CAAC,CAAC;IAEH,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,8CACH,QAAkB,EAClB,OAAyB;IAEzB,+DAA+D;IAC/D,gEAAgE;IAChE,IAAI,CAAC;QACH,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QAEjD,8BAA8B;QAC9B,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAC1D,OAAO;gBACL,YAAY;gBACZ,cAAc;gBACd,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE;aAC5B,CAAC;QACJ,CAAC;QAED,eAAe;QACf,MAAM,QAAQ,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;YACjC,EAAE,EAAE,YAAY;YAChB,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,aAAa,CAAC,MAAa,CAAC,CAAC;QAC7C,OAAO;YACL,YAAY;YACZ,cAAc;YACd,OAAO,EAAE,IAAI;YACb,OAAO;SACR,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport type { Hex } from '@metamask/utils';\n\nimport { ZERO_ADDRESS } from '../../../utils/constants';\nimport type {\n Address,\n BalanceOfRequest,\n BalanceOfResponse,\n ChainId,\n GetProviderFunction,\n Provider,\n} from '../types';\nimport { reduceInBatchesSerially } from '../utils';\n\n// =============================================================================\n// ABI DEFINITIONS\n// =============================================================================\n\n/**\n * Multicall3 contract ABI (subset for aggregate3 and getEthBalance).\n *\n * @see https://github.com/mds1/multicall\n */\nconst MULTICALL3_ABI = [\n {\n name: 'aggregate3',\n type: 'function',\n stateMutability: 'payable',\n inputs: [\n {\n name: 'calls',\n type: 'tuple[]',\n components: [\n { name: 'target', type: 'address' },\n { name: 'allowFailure', type: 'bool' },\n { name: 'callData', type: 'bytes' },\n ],\n },\n ],\n outputs: [\n {\n name: 'returnData',\n type: 'tuple[]',\n components: [\n { name: 'success', type: 'bool' },\n { name: 'returnData', type: 'bytes' },\n ],\n },\n ],\n },\n {\n name: 'getEthBalance',\n type: 'function',\n stateMutability: 'view',\n inputs: [{ name: 'addr', type: 'address' }],\n outputs: [{ name: 'balance', type: 'uint256' }],\n },\n];\n\n/**\n * ERC-20 ABI (subset for balanceOf).\n */\nconst ERC20_ABI = [\n {\n name: 'balanceOf',\n type: 'function',\n stateMutability: 'view',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: 'balance', type: 'uint256' }],\n },\n];\n\n/**\n * Interface instances for ABI encoding/decoding.\n */\nconst multicall3Interface = new Interface(MULTICALL3_ABI);\nconst erc20Interface = new Interface(ERC20_ABI);\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/**\n * Multicall3 contract addresses by chain ID.\n * Source: https://github.com/mds1/multicall/blob/main/deployments.json\n *\n * TODO: try to find service to use here instead of hardcoding the addresses\n */\nconst MULTICALL3_ADDRESS_BY_CHAIN: Record<Hex, Hex> = {\n '0x1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xaa36a7': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4268': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5e9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1b6e6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x18fc4a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x45': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1a4': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xaa37dc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa4b1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa4ba': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x66eed': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x66eee': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x66eeb': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15f2249': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x89': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13881': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13882': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x44d': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x5a2': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x98a': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x64': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x27d8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa86a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa869': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfa2': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfa': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfaf0': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x38': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x61': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15eb': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xcc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x504': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x505': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x507': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2a15c308d': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x2a15c3083': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x63564c40': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x19': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x152': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5535072': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6c1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x10': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x72': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x120': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4e454152': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x250': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5c2359': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xec0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x42': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x80': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x440': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x257': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe9fe': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xd3a0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x84444': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1e': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2329': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2328': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6c': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x12': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa516': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5afe': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa4ec': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xaef3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x116ea': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x116e9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2019': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3e9': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x7d1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x141': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4d2': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1e14': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1e15': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1251': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7f08': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8ae': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x138b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1389': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1388': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f92': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x14a33': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x14a34': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2105': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x936': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xff': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x46a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x46b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x14f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xd2af': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe9ac0ce': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe705': '0xca11bde05977b3631167028862be2a173976ca11',\n '0xe704': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe708': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2b6f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x39': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x23a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1644': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xdea8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3af': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x171': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3e7': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x76adf1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3b9ac9ff': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2c': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x2e': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x15b3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x82751': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8274f': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x82750': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x96f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3cc5': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4571': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe99': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7d0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1297': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1d5e': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3a14269b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x561bf78b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x235ddd0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3cd156dc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5d456c62': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x79f99296': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x585eb4b1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x507aaa2a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1fc3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x32d': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8a73': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8a72': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8a71': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe9ac0d6': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1069': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7e5': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x53': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x52': '0xca11bde05977b3631167028862be2a173976ca11',\n '0xe298': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1a8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x94': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2c6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2803': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2802': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28c5f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28c60': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4cb2f': '0xdbfa261cd7d17bb40479a0493ad6c0fee435859e',\n '0x7f93': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xb660': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xb02113d3f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xdad': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xdae': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15b38': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15b32': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x45c': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x45b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3d': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x41a6ace': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa729': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f47b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1b59': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1b58': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xc3': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x16fd8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xc7': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x405': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x334': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1ce': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1cf': '0xca11bde05977b3631167028862be2a173976ca11',\n '0xa70e': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x868b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa0c71fd': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13e31': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa1337': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f2b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xf63': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x144': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x118': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x12c': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x18995f': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x2b74': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0xfc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x9da': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x137': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13ed': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x24b1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xba9302': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7c8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x138d5': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6d': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x343b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x34a1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3109': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x91b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa96': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x22c3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2be3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xbf03': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1b254': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa7b14': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2276': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1b9e': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6a63bb8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15af3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15af1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xae3f3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x531': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28c61': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28c58': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1d88': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5b9b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4c7e1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa53b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1a2b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x406': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x2cef': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x18b2': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x182a9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xc4': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfdd': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfde': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x99c0a0f': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x22cf': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x310c5': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x46f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x659': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x139c968f9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xed88': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xd036': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x31bf8c3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1cbc67bfdc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x98967f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4f588': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x16db': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x3a': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x59': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1e0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2eb': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x221': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6f0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa867': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2611': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15f900': '0x6B5eFbC0C82eBb26CA13a4F11836f36Fc6fdBC5D',\n '0x74c': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x407b': '0x90a2377F233E3461BACa6080d4837837d8762927',\n '0xa3c3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xab5': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x138de': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x18c6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8173': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2ba': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x279f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xb67d2': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x18232': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x32': '0x0B1795ccA8E4eC4df02346a082df54D437F8D9aF',\n '0x18c7': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x10e6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x10b3e': '0x99423C88EB5723A590b4C644426069042f137B9e',\n // Ink Mainnet\n '0xdef1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n // Stable (988)\n '0x3dc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n // Tempo Mainnet\n '0x1079': '0xcA11bde05977b3631167028862bE2a173976CA11',\n // Tempo Testnet Moderato\n '0xa5bf': '0xcA11bde05977b3631167028862bE2a173976CA11',\n};\n\n// =============================================================================\n// ENCODING/DECODING UTILITIES (using @ethersproject/abi)\n// =============================================================================\n\n/**\n * Encode a balanceOf call for an ERC-20 token.\n *\n * @param accountAddress - The account address.\n * @returns The encoded call data.\n */\nfunction encodeBalanceOf(accountAddress: Address): Hex {\n return erc20Interface.encodeFunctionData('balanceOf', [\n accountAddress,\n ]) as Hex;\n}\n\n/**\n * Encode a getEthBalance call for native token via Multicall3.\n *\n * @param accountAddress - The account address.\n * @returns The encoded call data.\n */\nfunction encodeGetEthBalance(accountAddress: Address): Hex {\n return multicall3Interface.encodeFunctionData('getEthBalance', [\n accountAddress,\n ]) as Hex;\n}\n\n/**\n * Encode a Multicall3 aggregate3 call.\n *\n * @param calls - Array of calls with target, allowFailure, and callData.\n * @returns The encoded aggregate3 call data.\n */\nexport function encodeAggregate3(\n calls: readonly { target: Address; allowFailure: boolean; callData: Hex }[],\n): Hex {\n return multicall3Interface.encodeFunctionData('aggregate3', [\n calls.map((call) => ({\n target: call.target,\n allowFailure: call.allowFailure,\n callData: call.callData,\n })),\n ]) as Hex;\n}\n\n/**\n * Decode the response from aggregate3.\n * Returns array of (success, returnData) tuples.\n *\n * @param data - The raw response data.\n * @param callCount - Number of calls made (used for validation).\n * @returns Array of success and return data.\n */\nexport function decodeAggregate3Response(\n data: Hex,\n callCount: number,\n): { success: boolean; returnData: Hex }[] {\n const decoded = multicall3Interface.decodeFunctionResult('aggregate3', data);\n\n // decoded[0] is the array of (success, returnData) tuples\n const results = decoded[0] as readonly {\n success: boolean;\n returnData: string;\n }[];\n\n if (results.length !== callCount) {\n throw new Error(`Expected ${callCount} results, got ${results.length}`);\n }\n\n return results.map((result) => ({\n success: result.success,\n returnData: result.returnData as Hex,\n }));\n}\n\n/**\n * Decode a uint256 balance from return data.\n *\n * @param data - The hex return data.\n * @returns The decoded balance as a string.\n */\nfunction decodeUint256(data: Hex): string {\n if (data === '0x' || data.length < 66) {\n // Empty or invalid data; treat as 0\n return '0';\n }\n const decoded = erc20Interface.decodeFunctionResult('balanceOf', data);\n return decoded[0].toString();\n}\n\n// =============================================================================\n// MULTICALL CLIENT\n// =============================================================================\n\nexport type MulticallClientConfig = {\n maxCallsPerBatch?: number;\n timeoutMs?: number;\n};\n\n/**\n * Client for batching RPC calls using Multicall3.\n * Falls back to individual calls on chains without Multicall3 support.\n */\nexport class MulticallClient {\n readonly #getProvider: GetProviderFunction;\n\n readonly #config: Required<MulticallClientConfig>;\n\n constructor(\n getProvider: GetProviderFunction,\n config?: MulticallClientConfig,\n ) {\n this.#getProvider = getProvider;\n // Use default values for invalid (non-positive) batch sizes to prevent\n // infinite loops or errors in divideIntoBatches\n const maxCallsPerBatch =\n config?.maxCallsPerBatch !== undefined && config.maxCallsPerBatch > 0\n ? config.maxCallsPerBatch\n : 300;\n const timeoutMs =\n config?.timeoutMs !== undefined && config.timeoutMs > 0\n ? config.timeoutMs\n : 30000;\n this.#config = {\n maxCallsPerBatch,\n timeoutMs,\n };\n }\n\n /**\n * Fetch ERC-20 and native token balances using Multicall3.\n * Falls back to individual RPC calls on unsupported chains.\n *\n * @param chainId - The chain ID.\n * @param requests - Array of balance requests.\n * @returns Array of balance responses.\n */\n async batchBalanceOf(\n chainId: ChainId,\n requests: BalanceOfRequest[],\n ): Promise<BalanceOfResponse[]> {\n if (requests.length === 0) {\n return [];\n }\n\n const multicallAddress = MULTICALL3_ADDRESS_BY_CHAIN[chainId];\n const provider = this.#getProvider(chainId);\n\n // If Multicall3 is not supported, fall back to individual calls\n if (!multicallAddress) {\n return this.#fallbackBatchBalanceOf(provider, requests);\n }\n\n // Use Multicall3\n return this.#multicallBatchBalanceOf(provider, multicallAddress, requests);\n }\n\n /**\n * Fetch balances using Multicall3 aggregate3.\n *\n * @param provider - The RPC provider.\n * @param multicallAddress - The Multicall3 contract address.\n * @param requests - Array of balance requests.\n * @returns Array of balance responses.\n */\n async #multicallBatchBalanceOf(\n provider: Provider,\n multicallAddress: Hex,\n requests: BalanceOfRequest[],\n ): Promise<BalanceOfResponse[]> {\n const batchSize = this.#config.maxCallsPerBatch;\n\n const responses = await reduceInBatchesSerially<\n BalanceOfRequest,\n BalanceOfResponse[]\n >({\n values: requests,\n batchSize,\n initialResult: [],\n eachBatch: async (workingResult, batch) => {\n try {\n // Build aggregate3 calls\n const calls = batch.map((req) => {\n const isNative = req.tokenAddress === ZERO_ADDRESS;\n const target = isNative ? multicallAddress : req.tokenAddress;\n return {\n target,\n allowFailure: true,\n callData: isNative\n ? encodeGetEthBalance(req.accountAddress)\n : encodeBalanceOf(req.accountAddress),\n };\n });\n\n // Encode and send aggregate3 call\n const callData = encodeAggregate3(calls);\n const result = await provider.call({\n to: multicallAddress,\n data: callData,\n });\n\n // Decode response\n const decoded = decodeAggregate3Response(result as Hex, batch.length);\n\n // Map results back to responses\n for (let i = 0; i < batch.length; i++) {\n const { tokenAddress, accountAddress } = batch[i];\n const { success, returnData } = decoded[i];\n\n if (success && returnData && returnData.length > 2) {\n workingResult.push({\n tokenAddress,\n accountAddress,\n success: true,\n balance: decodeUint256(returnData),\n });\n } else {\n workingResult.push({\n tokenAddress,\n accountAddress,\n success: false,\n });\n }\n }\n } catch {\n // On aggregate3 error, fall back to individual calls for this batch.\n // #fetchSingleBalance never rejects - it catches all errors internally\n // and returns a failed response, so we use Promise.all here.\n const fallbackResults = await Promise.all(\n batch.map((req) => this.#fetchSingleBalance(provider, req)),\n );\n\n for (const result of fallbackResults) {\n workingResult.push(result);\n }\n }\n\n return workingResult;\n },\n });\n\n return responses;\n }\n\n /**\n * Fallback: fetch balances using individual RPC calls.\n *\n * @param provider - The RPC provider.\n * @param requests - Array of balance requests.\n * @returns Array of balance responses.\n */\n async #fallbackBatchBalanceOf(\n provider: Provider,\n requests: BalanceOfRequest[],\n ): Promise<BalanceOfResponse[]> {\n // Use smaller batch size for parallel individual calls to avoid overwhelming RPC\n const batchSize = Math.min(this.#config.maxCallsPerBatch, 50);\n\n const responses = await reduceInBatchesSerially<\n BalanceOfRequest,\n BalanceOfResponse[]\n >({\n values: requests,\n batchSize,\n initialResult: [],\n eachBatch: async (workingResult, batch) => {\n // #fetchSingleBalance never rejects - it catches all errors internally\n // and returns a failed response, so we use Promise.all here.\n const batchResults = await Promise.all(\n batch.map((req) => this.#fetchSingleBalance(provider, req)),\n );\n\n for (const result of batchResults) {\n workingResult.push(result);\n }\n\n return workingResult;\n },\n });\n\n return responses;\n }\n\n /**\n * Fetch a single token balance (fallback method).\n *\n * @param provider - The RPC provider.\n * @param request - The balance request.\n * @returns The balance response.\n */\n async #fetchSingleBalance(\n provider: Provider,\n request: BalanceOfRequest,\n ): Promise<BalanceOfResponse> {\n // Destructure inside try block to ensure any errors are caught\n // and don't cause promise rejections that bypass error handling\n try {\n const { tokenAddress, accountAddress } = request;\n\n // Native token (zero address)\n if (tokenAddress === ZERO_ADDRESS) {\n const balance = await provider.getBalance(accountAddress);\n return {\n tokenAddress,\n accountAddress,\n success: true,\n balance: balance.toString(),\n };\n }\n\n // ERC-20 token\n const callData = encodeBalanceOf(accountAddress);\n const result = await provider.call({\n to: tokenAddress,\n data: callData,\n });\n\n const balance = decodeUint256(result as Hex);\n return {\n tokenAddress,\n accountAddress,\n success: true,\n balance,\n };\n } catch {\n return {\n tokenAddress: request.tokenAddress,\n accountAddress: request.accountAddress,\n success: false,\n };\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MulticallClient.mjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/clients/MulticallClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { createServicePolicy } from '@metamask/controller-utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { ZERO_ADDRESS } from '../../../utils/constants';\nimport type {\n Address,\n BalanceOfRequest,\n BalanceOfResponse,\n ChainId,\n GetProviderFunction,\n Provider,\n} from '../types';\nimport { reduceInBatchesSerially } from '../utils';\n\n// =============================================================================\n// ABI DEFINITIONS\n// =============================================================================\n\n/**\n * Multicall3 contract ABI (subset for aggregate3 and getEthBalance).\n *\n * @see https://github.com/mds1/multicall\n */\nconst MULTICALL3_ABI = [\n {\n name: 'aggregate3',\n type: 'function',\n stateMutability: 'payable',\n inputs: [\n {\n name: 'calls',\n type: 'tuple[]',\n components: [\n { name: 'target', type: 'address' },\n { name: 'allowFailure', type: 'bool' },\n { name: 'callData', type: 'bytes' },\n ],\n },\n ],\n outputs: [\n {\n name: 'returnData',\n type: 'tuple[]',\n components: [\n { name: 'success', type: 'bool' },\n { name: 'returnData', type: 'bytes' },\n ],\n },\n ],\n },\n {\n name: 'getEthBalance',\n type: 'function',\n stateMutability: 'view',\n inputs: [{ name: 'addr', type: 'address' }],\n outputs: [{ name: 'balance', type: 'uint256' }],\n },\n];\n\n/**\n * ERC-20 ABI (subset for balanceOf).\n */\nconst ERC20_ABI = [\n {\n name: 'balanceOf',\n type: 'function',\n stateMutability: 'view',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: 'balance', type: 'uint256' }],\n },\n];\n\n/**\n * Interface instances for ABI encoding/decoding.\n */\nconst multicall3Interface = new Interface(MULTICALL3_ABI);\nconst erc20Interface = new Interface(ERC20_ABI);\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/**\n * Multicall3 contract addresses by chain ID.\n * Source: https://github.com/mds1/multicall/blob/main/deployments.json\n *\n * TODO: try to find service to use here instead of hardcoding the addresses\n */\nconst MULTICALL3_ADDRESS_BY_CHAIN: Record<Hex, Hex> = {\n '0x1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xaa36a7': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4268': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5e9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1b6e6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x18fc4a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x45': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1a4': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xaa37dc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa4b1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa4ba': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x66eed': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x66eee': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x66eeb': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15f2249': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x89': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13881': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13882': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x44d': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x5a2': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x98a': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x64': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x27d8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa86a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa869': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfa2': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfa': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfaf0': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x38': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x61': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15eb': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xcc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x504': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x505': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x507': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2a15c308d': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x2a15c3083': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x63564c40': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x19': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x152': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5535072': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6c1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x10': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x72': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x120': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4e454152': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x250': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5c2359': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xec0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x42': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x80': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x440': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x257': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe9fe': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xd3a0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x84444': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1e': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2329': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2328': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6c': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x12': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa516': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5afe': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa4ec': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xaef3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x116ea': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x116e9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2019': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3e9': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x7d1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x141': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4d2': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1e14': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1e15': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1251': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7f08': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8ae': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x138b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1389': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1388': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f92': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x14a33': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x14a34': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2105': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x936': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xff': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x46a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x46b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x14f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xd2af': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe9ac0ce': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe705': '0xca11bde05977b3631167028862be2a173976ca11',\n '0xe704': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe708': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2b6f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x39': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x23a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1644': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xdea8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3af': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x171': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3e7': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x76adf1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3b9ac9ff': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2c': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x2e': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x15b3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x82751': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8274f': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x82750': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x96f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3cc5': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4571': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe99': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7d0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1297': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1d5e': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3a14269b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x561bf78b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x235ddd0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3cd156dc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5d456c62': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x79f99296': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x585eb4b1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x507aaa2a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1fc3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x32d': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8a73': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8a72': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8a71': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe9ac0d6': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1069': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7e5': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x53': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x52': '0xca11bde05977b3631167028862be2a173976ca11',\n '0xe298': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1a8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x94': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2c6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2803': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2802': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28c5f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28c60': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13a': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4cb2f': '0xdbfa261cd7d17bb40479a0493ad6c0fee435859e',\n '0x7f93': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xb660': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xb02113d3f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xdad': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xdae': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15b38': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15b32': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x45c': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x45b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3d': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x41a6ace': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa729': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f47b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1b59': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1b58': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xc3': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x16fd8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xc7': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x405': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x334': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1ce': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1cf': '0xca11bde05977b3631167028862be2a173976ca11',\n '0xa70e': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x868b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa0c71fd': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13e31': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa1337': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f2b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xf63': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x144': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x118': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x12c': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x18995f': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x2b74': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0xfc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x9da': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x137': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x13ed': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x24b1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xba9302': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x7c8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x138d5': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6d': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x343b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x34a1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x3109': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x91b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa96': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x22c3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2be3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xbf03': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1b254': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa7b14': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2276': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1b9e': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6a63bb8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15af3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15af1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xae3f3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x531': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28c61': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x28c58': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1d88': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x5b9b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4c7e1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa53b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1a2b': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x406': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x2cef': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x18b2': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x182a9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xc4': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfdd': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xfde': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x99c0a0f': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x22cf': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x310c5': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x46f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x659': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x139c968f9': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xed88': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xd036': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1f3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x31bf8c3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x1cbc67bfdc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x98967f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x4f588': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x16db': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x3a': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x59': '0xca11bde05977b3631167028862be2a173976ca11',\n '0x1e0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2eb': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x221': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x6f0': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa867': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2611': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xa6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x15f900': '0x6B5eFbC0C82eBb26CA13a4F11836f36Fc6fdBC5D',\n '0x74c': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x407b': '0x90a2377F233E3461BACa6080d4837837d8762927',\n '0xa3c3': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xab5': '0xF9cda624FBC7e059355ce98a31693d299FACd963',\n '0x138de': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x18c6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8173': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x2ba': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x279f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xb67d2': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0xe8': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x18232': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x8f': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x32': '0x0B1795ccA8E4eC4df02346a082df54D437F8D9aF',\n '0x18c7': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x10e6': '0xcA11bde05977b3631167028862bE2a173976CA11',\n '0x10b3e': '0x99423C88EB5723A590b4C644426069042f137B9e',\n // Ink Mainnet\n '0xdef1': '0xcA11bde05977b3631167028862bE2a173976CA11',\n // Stable (988)\n '0x3dc': '0xcA11bde05977b3631167028862bE2a173976CA11',\n // Tempo Mainnet\n '0x1079': '0xcA11bde05977b3631167028862bE2a173976CA11',\n // Tempo Testnet Moderato\n '0xa5bf': '0xcA11bde05977b3631167028862bE2a173976CA11',\n // Arc (5042)\n '0x13b2': '0xcA11bde05977b3631167028862bE2a173976CA11',\n};\n\n// =============================================================================\n// ENCODING/DECODING UTILITIES (using @ethersproject/abi)\n// =============================================================================\n\n/**\n * Encode a balanceOf call for an ERC-20 token.\n *\n * @param accountAddress - The account address.\n * @returns The encoded call data.\n */\nfunction encodeBalanceOf(accountAddress: Address): Hex {\n return erc20Interface.encodeFunctionData('balanceOf', [\n accountAddress,\n ]) as Hex;\n}\n\n/**\n * Encode a getEthBalance call for native token via Multicall3.\n *\n * @param accountAddress - The account address.\n * @returns The encoded call data.\n */\nfunction encodeGetEthBalance(accountAddress: Address): Hex {\n return multicall3Interface.encodeFunctionData('getEthBalance', [\n accountAddress,\n ]) as Hex;\n}\n\n/**\n * Encode a Multicall3 aggregate3 call.\n *\n * @param calls - Array of calls with target, allowFailure, and callData.\n * @returns The encoded aggregate3 call data.\n */\nexport function encodeAggregate3(\n calls: readonly { target: Address; allowFailure: boolean; callData: Hex }[],\n): Hex {\n return multicall3Interface.encodeFunctionData('aggregate3', [\n calls.map((call) => ({\n target: call.target,\n allowFailure: call.allowFailure,\n callData: call.callData,\n })),\n ]) as Hex;\n}\n\n/**\n * Decode the response from aggregate3.\n * Returns array of (success, returnData) tuples.\n *\n * @param data - The raw response data.\n * @param callCount - Number of calls made (used for validation).\n * @returns Array of success and return data.\n */\nexport function decodeAggregate3Response(\n data: Hex,\n callCount: number,\n): { success: boolean; returnData: Hex }[] {\n const decoded = multicall3Interface.decodeFunctionResult('aggregate3', data);\n\n // decoded[0] is the array of (success, returnData) tuples\n const results = decoded[0] as readonly {\n success: boolean;\n returnData: string;\n }[];\n\n if (results.length !== callCount) {\n throw new Error(`Expected ${callCount} results, got ${results.length}`);\n }\n\n return results.map((result) => ({\n success: result.success,\n returnData: result.returnData as Hex,\n }));\n}\n\n/**\n * Decode a uint256 balance from return data.\n *\n * @param data - The hex return data.\n * @returns The decoded balance as a string.\n */\nfunction decodeUint256(data: Hex): string {\n if (data === '0x' || data.length < 66) {\n // Empty or invalid data; treat as 0\n return '0';\n }\n const decoded = erc20Interface.decodeFunctionResult('balanceOf', data);\n return decoded[0].toString();\n}\n\n// =============================================================================\n// MULTICALL CLIENT\n// =============================================================================\n\n/** Retries after the initial multicall attempt before returning failed responses. */\nconst MULTICALL_MAX_RETRIES = 2;\n\nexport type MulticallClientConfig = {\n maxCallsPerBatch?: number;\n timeoutMs?: number;\n};\n\n/**\n * Client for batching RPC calls using Multicall3.\n * Falls back to individual calls on chains without Multicall3 support.\n */\nexport class MulticallClient {\n readonly #getProvider: GetProviderFunction;\n\n readonly #config: Required<MulticallClientConfig>;\n\n constructor(\n getProvider: GetProviderFunction,\n config?: MulticallClientConfig,\n ) {\n this.#getProvider = getProvider;\n // Use default values for invalid (non-positive) batch sizes to prevent\n // infinite loops or errors in divideIntoBatches\n const maxCallsPerBatch =\n config?.maxCallsPerBatch !== undefined && config.maxCallsPerBatch > 0\n ? config.maxCallsPerBatch\n : 300;\n const timeoutMs =\n config?.timeoutMs !== undefined && config.timeoutMs > 0\n ? config.timeoutMs\n : 30000;\n this.#config = {\n maxCallsPerBatch,\n timeoutMs,\n };\n }\n\n /**\n * Fetch ERC-20 and native token balances using Multicall3.\n * Falls back to individual RPC calls on unsupported chains.\n *\n * @param chainId - The chain ID.\n * @param requests - Array of balance requests.\n * @param options - Optional batch options (e.g. single-call fallback).\n * @returns Array of balance responses.\n */\n async batchBalanceOf(\n chainId: ChainId,\n requests: BalanceOfRequest[],\n options = { fallbackToSingleCalls: false },\n ): Promise<BalanceOfResponse[]> {\n if (requests.length === 0) {\n return [];\n }\n\n const multicallAddress = MULTICALL3_ADDRESS_BY_CHAIN[chainId];\n const provider = this.#getProvider(chainId);\n\n if (!multicallAddress) {\n return options.fallbackToSingleCalls\n ? this.#fallbackBatchBalanceOf(provider, requests)\n : this.#createFailedResponses(requests);\n }\n\n // Use Multicall3\n return this.#multicallBatchBalanceOf(\n provider,\n multicallAddress,\n requests,\n options.fallbackToSingleCalls,\n );\n }\n\n /**\n * Fetch balances using Multicall3 aggregate3.\n *\n * @param provider - The RPC provider.\n * @param multicallAddress - The Multicall3 contract address.\n * @param requests - Array of balance requests.\n * @param fallbackToSingleCalls - Whether to fall back to individual RPC calls on batch failure.\n * @returns Array of balance responses.\n */\n async #multicallBatchBalanceOf(\n provider: Provider,\n multicallAddress: Hex,\n requests: BalanceOfRequest[],\n fallbackToSingleCalls: boolean,\n ): Promise<BalanceOfResponse[]> {\n const batchSize = this.#config.maxCallsPerBatch;\n\n const responses = await reduceInBatchesSerially<\n BalanceOfRequest,\n BalanceOfResponse[]\n >({\n values: requests,\n batchSize,\n initialResult: [],\n eachBatch: async (workingResult, batch) => {\n try {\n await createServicePolicy({\n maxRetries: MULTICALL_MAX_RETRIES,\n }).execute(async () => {\n // Build aggregate3 calls\n const calls = batch.map((req) => {\n const isNative = req.tokenAddress === ZERO_ADDRESS;\n const target = isNative ? multicallAddress : req.tokenAddress;\n return {\n target,\n allowFailure: true,\n callData: isNative\n ? encodeGetEthBalance(req.accountAddress)\n : encodeBalanceOf(req.accountAddress),\n };\n });\n\n // Encode and send aggregate3 call\n const callData = encodeAggregate3(calls);\n const result = await provider.call({\n to: multicallAddress,\n data: callData,\n });\n\n // Decode response\n const decoded = decodeAggregate3Response(\n result as Hex,\n batch.length,\n );\n\n // Map results back to responses\n for (let i = 0; i < batch.length; i++) {\n const { tokenAddress, accountAddress } = batch[i];\n const { success, returnData } = decoded[i];\n\n if (success && returnData && returnData.length > 2) {\n workingResult.push({\n tokenAddress,\n accountAddress,\n success: true,\n balance: decodeUint256(returnData),\n });\n } else {\n workingResult.push({\n tokenAddress,\n accountAddress,\n success: false,\n });\n }\n }\n });\n } catch {\n if (fallbackToSingleCalls) {\n // On aggregate3 error, fall back to individual calls for this batch.\n // #fetchSingleBalance never rejects - it catches all errors internally\n // and returns a failed response, so we use Promise.all here.\n const fallbackResults = await Promise.all(\n batch.map((req) => this.#fetchSingleBalance(provider, req)),\n );\n\n for (const result of fallbackResults) {\n workingResult.push(result);\n }\n } else {\n workingResult.push(...this.#createFailedResponses(batch));\n }\n }\n\n return workingResult;\n },\n });\n\n return responses;\n }\n\n /**\n * Fallback: fetch balances using individual RPC calls.\n *\n * @param provider - The RPC provider.\n * @param requests - Array of balance requests.\n * @returns Array of balance responses.\n */\n async #fallbackBatchBalanceOf(\n provider: Provider,\n requests: BalanceOfRequest[],\n ): Promise<BalanceOfResponse[]> {\n // Use smaller batch size for parallel individual calls to avoid overwhelming RPC\n const batchSize = Math.min(this.#config.maxCallsPerBatch, 50);\n\n const responses = await reduceInBatchesSerially<\n BalanceOfRequest,\n BalanceOfResponse[]\n >({\n values: requests,\n batchSize,\n initialResult: [],\n eachBatch: async (workingResult, batch) => {\n // #fetchSingleBalance never rejects - it catches all errors internally\n // and returns a failed response, so we use Promise.all here.\n const batchResults = await Promise.all(\n batch.map((req) => this.#fetchSingleBalance(provider, req)),\n );\n\n for (const result of batchResults) {\n workingResult.push(result);\n }\n\n return workingResult;\n },\n });\n\n return responses;\n }\n\n /**\n * Fetch a single token balance (fallback method).\n *\n * @param provider - The RPC provider.\n * @param request - The balance request.\n * @returns The balance response.\n */\n async #fetchSingleBalance(\n provider: Provider,\n request: BalanceOfRequest,\n ): Promise<BalanceOfResponse> {\n // Destructure inside try block to ensure any errors are caught\n // and don't cause promise rejections that bypass error handling\n try {\n const { tokenAddress, accountAddress } = request;\n\n // Native token (zero address)\n if (tokenAddress === ZERO_ADDRESS) {\n const balance = await provider.getBalance(accountAddress);\n return {\n tokenAddress,\n accountAddress,\n success: true,\n balance: balance.toString(),\n };\n }\n\n // ERC-20 token\n const callData = encodeBalanceOf(accountAddress);\n const result = await provider.call({\n to: tokenAddress,\n data: callData,\n });\n\n const balance = decodeUint256(result as Hex);\n return {\n tokenAddress,\n accountAddress,\n success: true,\n balance,\n };\n } catch {\n return this.#createFailedResponse(request);\n }\n }\n\n #createFailedResponses(requests: BalanceOfRequest[]): BalanceOfResponse[] {\n return requests.map((request) => this.#createFailedResponse(request));\n }\n\n #createFailedResponse(request: BalanceOfRequest): BalanceOfResponse {\n return {\n tokenAddress: request.tokenAddress,\n accountAddress: request.accountAddress,\n success: false,\n };\n }\n}\n"]}
|
|
@@ -110,7 +110,7 @@ class BalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingContr
|
|
|
110
110
|
failedAddresses: [],
|
|
111
111
|
},
|
|
112
112
|
eachBatch: async (workingResult, batch) => {
|
|
113
|
-
const responses = await __classPrivateFieldGet(this, _BalanceFetcher_multicallClient, "f").batchBalanceOf(chainId, batch);
|
|
113
|
+
const responses = await __classPrivateFieldGet(this, _BalanceFetcher_multicallClient, "f").batchBalanceOf(chainId, batch, { fallbackToSingleCalls: true });
|
|
114
114
|
return __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_processBalanceResponses).call(this, responses, workingResult, chainId, accountId, timestamp, entryByAddress);
|
|
115
115
|
},
|
|
116
116
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BalanceFetcher.cjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\nimport { parseCaipAssetType } from '@metamask/utils';\n\nimport { ZERO_ADDRESS } from '../../../utils/constants';\nimport type { MulticallClient } from '../clients';\nimport type {\n AccountId,\n Address,\n AssetBalance,\n AssetFetchEntry,\n AssetsBalanceState,\n BalanceFetchResult,\n BalanceOfRequest,\n BalanceOfResponse,\n CaipAssetType,\n ChainId,\n} from '../types';\nimport { reduceInBatchesSerially } from '../utils';\n\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\n\n/**\n * Minimal messenger interface for BalanceFetcher.\n */\nexport type BalanceFetcherMessenger = {\n call: (action: 'AssetsController:getState') => AssetsBalanceState;\n};\n\nexport type BalanceFetcherConfig = {\n defaultBatchSize?: number;\n defaultTimeoutMs?: number;\n /** Polling interval in ms (default: 30s) */\n pollingInterval?: number;\n /** Determines whether a CAIP-19 asset ID represents a native asset. */\n isNativeAsset: (assetId: CaipAssetType) => boolean;\n};\n\n/**\n * Polling input for BalanceFetcher - identifies what to poll for.\n */\nexport type BalancePollingInput = {\n /** Chain ID (hex format) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n /**\n * When true, only fetch balances for entries in `state.customAssets`,\n * skipping `state.assetsBalance`. Used by the supplemental RPC\n * subscription on chains that another data source is already covering\n * for regular balance refreshes.\n */\n customAssetsOnly?: boolean;\n};\n\n/**\n * Callback type for balance updates.\n */\nexport type OnBalanceUpdateCallback = (\n result: BalanceFetchResult,\n) => void | Promise<void>;\n\n/**\n * BalanceFetcher - Fetches token balances via multicall.\n * Extends StaticIntervalPollingControllerOnly for built-in polling support.\n *\n * Callers provide CAIP-19 asset IDs; the fetcher extracts on-chain addresses\n * (or uses the zero address for native assets) and maps multicall responses\n * back to the original asset IDs. This ensures the returned balance entries\n * always carry the correct identifier regardless of chain.\n */\nexport class BalanceFetcher extends StaticIntervalPollingControllerOnly<BalancePollingInput>() {\n readonly #multicallClient: MulticallClient;\n\n readonly #messenger: BalanceFetcherMessenger;\n\n readonly #config: Required<\n Omit<BalanceFetcherConfig, 'pollingInterval' | 'isNativeAsset'>\n >;\n\n readonly #isNativeAsset: (assetId: CaipAssetType) => boolean;\n\n #onBalanceUpdate: OnBalanceUpdateCallback | undefined;\n\n constructor(\n multicallClient: MulticallClient,\n messenger: BalanceFetcherMessenger,\n config: BalanceFetcherConfig,\n ) {\n super();\n this.#multicallClient = multicallClient;\n this.#messenger = messenger;\n this.#config = {\n defaultBatchSize: config.defaultBatchSize ?? 300,\n defaultTimeoutMs: config.defaultTimeoutMs ?? 30000,\n };\n this.#isNativeAsset = config.isNativeAsset;\n\n // Set the polling interval\n this.setIntervalLength(config?.pollingInterval ?? DEFAULT_BALANCE_INTERVAL);\n }\n\n /**\n * Set the callback to receive balance updates during polling.\n *\n * @param callback - Function to call with balance results.\n */\n setOnBalanceUpdate(callback: OnBalanceUpdateCallback): void {\n this.#onBalanceUpdate = callback;\n }\n\n /**\n * Execute a poll cycle (required by base class).\n * Fetches balances and calls the update callback.\n *\n * @param input - The polling input.\n */\n async _executePoll(input: BalancePollingInput): Promise<void> {\n const result = await this.#fetchBalances(\n input.chainId,\n input.accountId,\n input.accountAddress,\n input.customAssetsOnly === true,\n );\n\n if (this.#onBalanceUpdate && result.balances.length > 0) {\n await this.#onBalanceUpdate(result);\n }\n }\n\n /**\n * Return asset fetch entries tracked in state for the given account and\n * chain. Both native (`slip44:`) and ERC-20 (`erc20:`) entries are included.\n *\n * @param chainId - Hex chain ID (e.g. \"0x1\").\n * @param accountId - Account UUID.\n * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.\n * @returns Array of asset fetch entries from state for the requested chain.\n */\n #getAssetsToFetch(\n chainId: ChainId,\n accountId: AccountId,\n customAssetsOnly: boolean,\n ): AssetFetchEntry[] {\n const state = this.#messenger.call('AssetsController:getState');\n\n // Convert hex chainId to decimal for CAIP-2 matching\n // This is safe because we are filtring with an accountId that is for evm balances only\n const chainIdDecimal = parseInt(chainId, 16).toString();\n\n const assetsToFetch = new Map<string, AssetFetchEntry>();\n\n const collect = (assetId: CaipAssetType): void => {\n const parsed = parseCaipAssetType(assetId);\n\n if (parsed.chain.reference !== chainIdDecimal) {\n return;\n }\n\n const normalizedAssetId = assetId.toLowerCase();\n\n if (assetsToFetch.has(normalizedAssetId)) {\n return;\n }\n\n const isNative = this.#isNativeAsset(assetId);\n\n assetsToFetch.set(normalizedAssetId, {\n assetId,\n address: isNative\n ? ZERO_ADDRESS\n : (parsed.assetReference.toLowerCase() as Address),\n });\n };\n\n // 1. Assets already tracked with a balance entry — only when not in\n // \"customAssetsOnly\" mode (otherwise another data source is already\n // refreshing them and we'd double-poll).\n if (!customAssetsOnly) {\n const accountBalances = state?.assetsBalance?.[accountId];\n if (accountBalances) {\n for (const assetId of Object.keys(accountBalances) as CaipAssetType[]) {\n collect(assetId);\n }\n }\n }\n\n // 2. User-added custom assets — RPC is the sole balance fetcher for\n // these, so they must be polled even if they have no balance entry\n // yet (e.g. zero balance, first fetch failed, or state was hydrated\n // from disk before any successful fetch).\n const customAssets = state?.customAssets?.[accountId];\n if (customAssets) {\n for (const assetId of customAssets as CaipAssetType[]) {\n collect(assetId);\n }\n }\n\n return Array.from(assetsToFetch.values());\n }\n\n /**\n * Fetch balances for assets already tracked in state for the given\n * account and chain.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.\n * @returns Balance fetch result.\n */\n async #fetchBalances(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n customAssetsOnly: boolean,\n ): Promise<BalanceFetchResult> {\n const assets = this.#getAssetsToFetch(chainId, accountId, customAssetsOnly);\n\n return this.fetchBalancesForAssets(\n chainId,\n accountId,\n accountAddress,\n assets,\n );\n }\n\n /**\n * Fetch balances for the given assets via multicall.\n *\n * Each entry bundles a CAIP-19 asset ID with its on-chain address and\n * optional decimals.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param assets - Asset fetch entries to fetch balances for.\n * @returns Balance fetch result.\n */\n async fetchBalancesForAssets(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n assets: AssetFetchEntry[],\n ): Promise<BalanceFetchResult> {\n const timestamp = Date.now();\n\n // Build a single map keyed by lowercase address that holds all info\n // needed to match multicall responses back to their original entries.\n const balanceRequests: BalanceOfRequest[] = [];\n const entryByAddress = new Map<string, AssetFetchEntry>();\n\n for (const entry of assets) {\n const lowerAddress = entry.address.toLowerCase();\n if (entryByAddress.has(lowerAddress)) {\n continue; // deduplicate\n }\n\n entryByAddress.set(lowerAddress, entry);\n balanceRequests.push({ tokenAddress: entry.address, accountAddress });\n }\n\n if (balanceRequests.length === 0) {\n return {\n chainId,\n accountId,\n accountAddress,\n balances: [],\n failedAddresses: [],\n timestamp,\n };\n }\n\n type FetchAccumulator = {\n balances: AssetBalance[];\n failedAddresses: Address[];\n };\n\n const result = await reduceInBatchesSerially<\n BalanceOfRequest,\n FetchAccumulator\n >({\n values: balanceRequests,\n batchSize: this.#config.defaultBatchSize,\n initialResult: {\n balances: [],\n failedAddresses: [],\n },\n eachBatch: async (workingResult, batch) => {\n const responses = await this.#multicallClient.batchBalanceOf(\n chainId,\n batch,\n );\n\n return this.#processBalanceResponses(\n responses,\n workingResult as FetchAccumulator,\n chainId,\n accountId,\n timestamp,\n entryByAddress,\n );\n },\n });\n\n return {\n chainId,\n accountId,\n accountAddress,\n ...result,\n timestamp,\n };\n }\n\n #processBalanceResponses(\n responses: BalanceOfResponse[],\n accumulator: {\n balances: AssetBalance[];\n failedAddresses: Address[];\n },\n chainId: ChainId,\n accountId: AccountId,\n timestamp: number,\n entryByAddress: Map<string, AssetFetchEntry>,\n ): {\n balances: AssetBalance[];\n failedAddresses: Address[];\n } {\n const { balances, failedAddresses } = accumulator;\n\n for (const response of responses) {\n if (!response.success) {\n failedAddresses.push(response.tokenAddress);\n continue;\n }\n\n const lowerAddress = response.tokenAddress.toLowerCase();\n const entry = entryByAddress.get(lowerAddress);\n if (!entry) {\n continue;\n }\n\n const balance = response.balance ?? '0';\n const isNative = lowerAddress === ZERO_ADDRESS.toLowerCase();\n\n let decimals: number | undefined;\n let formattedBalance: string;\n if (isNative) {\n decimals = 18;\n formattedBalance = this.#formatBalance(balance, decimals);\n } else if (entry.decimals === undefined) {\n formattedBalance = balance;\n } else {\n decimals = entry.decimals;\n formattedBalance = this.#formatBalance(balance, decimals);\n }\n\n const balanceEntry: AssetBalance = {\n assetId: entry.assetId,\n accountId,\n chainId,\n balance,\n formattedBalance,\n timestamp,\n };\n if (typeof decimals === 'number') {\n balanceEntry.decimals = decimals;\n }\n balances.push(balanceEntry);\n }\n\n return { balances, failedAddresses };\n }\n\n #formatBalance(rawBalance: string, decimals: number): string {\n if (rawBalance === '0') {\n return '0';\n }\n\n try {\n const balanceBigInt = BigInt(rawBalance);\n const divisor = BigInt(10 ** decimals);\n\n const integerPart = balanceBigInt / divisor;\n const remainder = balanceBigInt % divisor;\n const fractionalStr = remainder.toString().padStart(decimals, '0');\n const trimmedFractional = fractionalStr.replace(/0+$/u, '');\n\n if (trimmedFractional === '') {\n return integerPart.toString();\n }\n\n return `${integerPart}.${trimmedFractional}`;\n } catch {\n return rawBalance;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"BalanceFetcher.cjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\nimport { parseCaipAssetType } from '@metamask/utils';\n\nimport { ZERO_ADDRESS } from '../../../utils/constants';\nimport type { MulticallClient } from '../clients';\nimport type {\n AccountId,\n Address,\n AssetBalance,\n AssetFetchEntry,\n AssetsBalanceState,\n BalanceFetchResult,\n BalanceOfRequest,\n BalanceOfResponse,\n CaipAssetType,\n ChainId,\n} from '../types';\nimport { reduceInBatchesSerially } from '../utils';\n\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\n\n/**\n * Minimal messenger interface for BalanceFetcher.\n */\nexport type BalanceFetcherMessenger = {\n call: (action: 'AssetsController:getState') => AssetsBalanceState;\n};\n\nexport type BalanceFetcherConfig = {\n defaultBatchSize?: number;\n defaultTimeoutMs?: number;\n /** Polling interval in ms (default: 30s) */\n pollingInterval?: number;\n /** Determines whether a CAIP-19 asset ID represents a native asset. */\n isNativeAsset: (assetId: CaipAssetType) => boolean;\n};\n\n/**\n * Polling input for BalanceFetcher - identifies what to poll for.\n */\nexport type BalancePollingInput = {\n /** Chain ID (hex format) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n /**\n * When true, only fetch balances for entries in `state.customAssets`,\n * skipping `state.assetsBalance`. Used by the supplemental RPC\n * subscription on chains that another data source is already covering\n * for regular balance refreshes.\n */\n customAssetsOnly?: boolean;\n};\n\n/**\n * Callback type for balance updates.\n */\nexport type OnBalanceUpdateCallback = (\n result: BalanceFetchResult,\n) => void | Promise<void>;\n\n/**\n * BalanceFetcher - Fetches token balances via multicall.\n * Extends StaticIntervalPollingControllerOnly for built-in polling support.\n *\n * Callers provide CAIP-19 asset IDs; the fetcher extracts on-chain addresses\n * (or uses the zero address for native assets) and maps multicall responses\n * back to the original asset IDs. This ensures the returned balance entries\n * always carry the correct identifier regardless of chain.\n */\nexport class BalanceFetcher extends StaticIntervalPollingControllerOnly<BalancePollingInput>() {\n readonly #multicallClient: MulticallClient;\n\n readonly #messenger: BalanceFetcherMessenger;\n\n readonly #config: Required<\n Omit<BalanceFetcherConfig, 'pollingInterval' | 'isNativeAsset'>\n >;\n\n readonly #isNativeAsset: (assetId: CaipAssetType) => boolean;\n\n #onBalanceUpdate: OnBalanceUpdateCallback | undefined;\n\n constructor(\n multicallClient: MulticallClient,\n messenger: BalanceFetcherMessenger,\n config: BalanceFetcherConfig,\n ) {\n super();\n this.#multicallClient = multicallClient;\n this.#messenger = messenger;\n this.#config = {\n defaultBatchSize: config.defaultBatchSize ?? 300,\n defaultTimeoutMs: config.defaultTimeoutMs ?? 30000,\n };\n this.#isNativeAsset = config.isNativeAsset;\n\n // Set the polling interval\n this.setIntervalLength(config?.pollingInterval ?? DEFAULT_BALANCE_INTERVAL);\n }\n\n /**\n * Set the callback to receive balance updates during polling.\n *\n * @param callback - Function to call with balance results.\n */\n setOnBalanceUpdate(callback: OnBalanceUpdateCallback): void {\n this.#onBalanceUpdate = callback;\n }\n\n /**\n * Execute a poll cycle (required by base class).\n * Fetches balances and calls the update callback.\n *\n * @param input - The polling input.\n */\n async _executePoll(input: BalancePollingInput): Promise<void> {\n const result = await this.#fetchBalances(\n input.chainId,\n input.accountId,\n input.accountAddress,\n input.customAssetsOnly === true,\n );\n\n if (this.#onBalanceUpdate && result.balances.length > 0) {\n await this.#onBalanceUpdate(result);\n }\n }\n\n /**\n * Return asset fetch entries tracked in state for the given account and\n * chain. Both native (`slip44:`) and ERC-20 (`erc20:`) entries are included.\n *\n * @param chainId - Hex chain ID (e.g. \"0x1\").\n * @param accountId - Account UUID.\n * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.\n * @returns Array of asset fetch entries from state for the requested chain.\n */\n #getAssetsToFetch(\n chainId: ChainId,\n accountId: AccountId,\n customAssetsOnly: boolean,\n ): AssetFetchEntry[] {\n const state = this.#messenger.call('AssetsController:getState');\n\n // Convert hex chainId to decimal for CAIP-2 matching\n // This is safe because we are filtring with an accountId that is for evm balances only\n const chainIdDecimal = parseInt(chainId, 16).toString();\n\n const assetsToFetch = new Map<string, AssetFetchEntry>();\n\n const collect = (assetId: CaipAssetType): void => {\n const parsed = parseCaipAssetType(assetId);\n\n if (parsed.chain.reference !== chainIdDecimal) {\n return;\n }\n\n const normalizedAssetId = assetId.toLowerCase();\n\n if (assetsToFetch.has(normalizedAssetId)) {\n return;\n }\n\n const isNative = this.#isNativeAsset(assetId);\n\n assetsToFetch.set(normalizedAssetId, {\n assetId,\n address: isNative\n ? ZERO_ADDRESS\n : (parsed.assetReference.toLowerCase() as Address),\n });\n };\n\n // 1. Assets already tracked with a balance entry — only when not in\n // \"customAssetsOnly\" mode (otherwise another data source is already\n // refreshing them and we'd double-poll).\n if (!customAssetsOnly) {\n const accountBalances = state?.assetsBalance?.[accountId];\n if (accountBalances) {\n for (const assetId of Object.keys(accountBalances) as CaipAssetType[]) {\n collect(assetId);\n }\n }\n }\n\n // 2. User-added custom assets — RPC is the sole balance fetcher for\n // these, so they must be polled even if they have no balance entry\n // yet (e.g. zero balance, first fetch failed, or state was hydrated\n // from disk before any successful fetch).\n const customAssets = state?.customAssets?.[accountId];\n if (customAssets) {\n for (const assetId of customAssets as CaipAssetType[]) {\n collect(assetId);\n }\n }\n\n return Array.from(assetsToFetch.values());\n }\n\n /**\n * Fetch balances for assets already tracked in state for the given\n * account and chain.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param customAssetsOnly - When true, skip `assetsBalance` and only include `customAssets`.\n * @returns Balance fetch result.\n */\n async #fetchBalances(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n customAssetsOnly: boolean,\n ): Promise<BalanceFetchResult> {\n const assets = this.#getAssetsToFetch(chainId, accountId, customAssetsOnly);\n\n return this.fetchBalancesForAssets(\n chainId,\n accountId,\n accountAddress,\n assets,\n );\n }\n\n /**\n * Fetch balances for the given assets via multicall.\n *\n * Each entry bundles a CAIP-19 asset ID with its on-chain address and\n * optional decimals.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param assets - Asset fetch entries to fetch balances for.\n * @returns Balance fetch result.\n */\n async fetchBalancesForAssets(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n assets: AssetFetchEntry[],\n ): Promise<BalanceFetchResult> {\n const timestamp = Date.now();\n\n // Build a single map keyed by lowercase address that holds all info\n // needed to match multicall responses back to their original entries.\n const balanceRequests: BalanceOfRequest[] = [];\n const entryByAddress = new Map<string, AssetFetchEntry>();\n\n for (const entry of assets) {\n const lowerAddress = entry.address.toLowerCase();\n if (entryByAddress.has(lowerAddress)) {\n continue; // deduplicate\n }\n\n entryByAddress.set(lowerAddress, entry);\n balanceRequests.push({ tokenAddress: entry.address, accountAddress });\n }\n\n if (balanceRequests.length === 0) {\n return {\n chainId,\n accountId,\n accountAddress,\n balances: [],\n failedAddresses: [],\n timestamp,\n };\n }\n\n type FetchAccumulator = {\n balances: AssetBalance[];\n failedAddresses: Address[];\n };\n\n const result = await reduceInBatchesSerially<\n BalanceOfRequest,\n FetchAccumulator\n >({\n values: balanceRequests,\n batchSize: this.#config.defaultBatchSize,\n initialResult: {\n balances: [],\n failedAddresses: [],\n },\n eachBatch: async (workingResult, batch) => {\n const responses = await this.#multicallClient.batchBalanceOf(\n chainId,\n batch,\n { fallbackToSingleCalls: true },\n );\n\n return this.#processBalanceResponses(\n responses,\n workingResult as FetchAccumulator,\n chainId,\n accountId,\n timestamp,\n entryByAddress,\n );\n },\n });\n\n return {\n chainId,\n accountId,\n accountAddress,\n ...result,\n timestamp,\n };\n }\n\n #processBalanceResponses(\n responses: BalanceOfResponse[],\n accumulator: {\n balances: AssetBalance[];\n failedAddresses: Address[];\n },\n chainId: ChainId,\n accountId: AccountId,\n timestamp: number,\n entryByAddress: Map<string, AssetFetchEntry>,\n ): {\n balances: AssetBalance[];\n failedAddresses: Address[];\n } {\n const { balances, failedAddresses } = accumulator;\n\n for (const response of responses) {\n if (!response.success) {\n failedAddresses.push(response.tokenAddress);\n continue;\n }\n\n const lowerAddress = response.tokenAddress.toLowerCase();\n const entry = entryByAddress.get(lowerAddress);\n if (!entry) {\n continue;\n }\n\n const balance = response.balance ?? '0';\n const isNative = lowerAddress === ZERO_ADDRESS.toLowerCase();\n\n let decimals: number | undefined;\n let formattedBalance: string;\n if (isNative) {\n decimals = 18;\n formattedBalance = this.#formatBalance(balance, decimals);\n } else if (entry.decimals === undefined) {\n formattedBalance = balance;\n } else {\n decimals = entry.decimals;\n formattedBalance = this.#formatBalance(balance, decimals);\n }\n\n const balanceEntry: AssetBalance = {\n assetId: entry.assetId,\n accountId,\n chainId,\n balance,\n formattedBalance,\n timestamp,\n };\n if (typeof decimals === 'number') {\n balanceEntry.decimals = decimals;\n }\n balances.push(balanceEntry);\n }\n\n return { balances, failedAddresses };\n }\n\n #formatBalance(rawBalance: string, decimals: number): string {\n if (rawBalance === '0') {\n return '0';\n }\n\n try {\n const balanceBigInt = BigInt(rawBalance);\n const divisor = BigInt(10 ** decimals);\n\n const integerPart = balanceBigInt / divisor;\n const remainder = balanceBigInt % divisor;\n const fractionalStr = remainder.toString().padStart(decimals, '0');\n const trimmedFractional = fractionalStr.replace(/0+$/u, '');\n\n if (trimmedFractional === '') {\n return integerPart.toString();\n }\n\n return `${integerPart}.${trimmedFractional}`;\n } catch {\n return rawBalance;\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BalanceFetcher.d.cts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,6BAAmB;AAClD,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAGlB,aAAa,EACb,OAAO,EACR,2BAAiB;AAKlB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,kBAAkB,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;CACpD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,kBAAkB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;;;AAE1B;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,mBAA0D;;gBAc1F,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,uBAAuB,EAClC,MAAM,EAAE,oBAAoB;IAe9B;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8G7D;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,MAAM,EAAE,eAAe,EAAE,GACxB,OAAO,CAAC,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"BalanceFetcher.d.cts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,6BAAmB;AAClD,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAGlB,aAAa,EACb,OAAO,EACR,2BAAiB;AAKlB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,kBAAkB,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;CACpD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,kBAAkB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;;;AAE1B;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,mBAA0D;;gBAc1F,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,uBAAuB,EAClC,MAAM,EAAE,oBAAoB;IAe9B;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8G7D;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,MAAM,EAAE,eAAe,EAAE,GACxB,OAAO,CAAC,kBAAkB,CAAC;CA0J/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BalanceFetcher.d.mts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,6BAAmB;AAClD,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAGlB,aAAa,EACb,OAAO,EACR,2BAAiB;AAKlB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,kBAAkB,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;CACpD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,kBAAkB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;;;AAE1B;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,mBAA0D;;gBAc1F,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,uBAAuB,EAClC,MAAM,EAAE,oBAAoB;IAe9B;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8G7D;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,MAAM,EAAE,eAAe,EAAE,GACxB,OAAO,CAAC,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"BalanceFetcher.d.mts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,6BAAmB;AAClD,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAGlB,aAAa,EACb,OAAO,EACR,2BAAiB;AAKlB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,kBAAkB,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;CACpD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,kBAAkB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;;;AAE1B;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,mBAA0D;;gBAc1F,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,uBAAuB,EAClC,MAAM,EAAE,oBAAoB;IAe9B;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8G7D;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,MAAM,EAAE,eAAe,EAAE,GACxB,OAAO,CAAC,kBAAkB,CAAC;CA0J/B"}
|
|
@@ -107,7 +107,7 @@ export class BalanceFetcher extends StaticIntervalPollingControllerOnly() {
|
|
|
107
107
|
failedAddresses: [],
|
|
108
108
|
},
|
|
109
109
|
eachBatch: async (workingResult, batch) => {
|
|
110
|
-
const responses = await __classPrivateFieldGet(this, _BalanceFetcher_multicallClient, "f").batchBalanceOf(chainId, batch);
|
|
110
|
+
const responses = await __classPrivateFieldGet(this, _BalanceFetcher_multicallClient, "f").batchBalanceOf(chainId, batch, { fallbackToSingleCalls: true });
|
|
111
111
|
return __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_processBalanceResponses).call(this, responses, workingResult, chainId, accountId, timestamp, entryByAddress);
|
|
112
112
|
},
|
|
113
113
|
});
|