@pancakeswap/multicall 2.0.0 → 3.0.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/dist/index.js CHANGED
@@ -1,332 +1,314 @@
1
1
  'use strict';
2
2
 
3
- var abi = require('@ethersproject/abi');
4
- var contracts = require('@ethersproject/contracts');
5
3
  var sdk = require('@pancakeswap/sdk');
4
+ var viem = require('viem');
6
5
 
7
- // index.ts
6
+ // ../utils/toBigInt.ts
7
+ function toBigInt(num) {
8
+ return BigInt(num.toString());
9
+ }
10
+ var MULTICALL_ADDRESS = {
11
+ [sdk.ChainId.ZKSYNC]: "0x95071cBD09184083E7F732a710c2e30c9882Fd5f",
12
+ [sdk.ChainId.BSC]: "0x39eecaE833c944ebb94942Fa44CaE46e87a8Da17",
13
+ [sdk.ChainId.ETHEREUM]: "0xC0916D7E360c31D5F6D0c497E6a36B7B0E80e3cf",
14
+ [sdk.ChainId.ARBITRUM_ONE]: "0xbFfE39cDD04f0183e0493c1Deb6E275c5cf84AdF",
15
+ [sdk.ChainId.POLYGON_ZKEVM]: "0xe05b539447B17630Cb087473F6b50E5c5f73FDeb",
16
+ [sdk.ChainId.LINEA]: "0x6E6B30d65D605DAa4CaC65eB270100Ecca36b140",
17
+ [sdk.ChainId.BASE]: "0x3EFaAb8D7A631cfF5ccF5f149d1Bbb3B5bfda2C0",
18
+ // Testnets
19
+ [sdk.ChainId.BSC_TESTNET]: "0xeeF6ff30cF5D5b8aBA0DE16A01d17A0697a275b5",
20
+ [sdk.ChainId.GOERLI]: "0xD55CAFAB2Ffa1139Be46bc5C0b8259c620050dFC",
21
+ [sdk.ChainId.ARBITRUM_GOERLI]: "0xe12a5c707Fb528acbE6117b20AF1f7c20b0A8077",
22
+ [sdk.ChainId.POLYGON_ZKEVM_TESTNET]: "0x236e713bFF45adb30e25D1c29A887aBCb0Ea7E21",
23
+ [sdk.ChainId.ZKSYNC_TESTNET]: "0x8A23CB45E5F4d5a1b2DB673663Ea2aAedc48acff",
24
+ [sdk.ChainId.LINEA_TESTNET]: "0x990010b6DBA3e7faa025790bC0433A9f690c65F3",
25
+ [sdk.ChainId.BASE_TESTNET]: "0x6F7f93D929d6FBaF16c245e42846EF21aee23437",
26
+ [sdk.ChainId.OPBNB_TESTNET]: "0x6A70ED893D85cf6D4059e1CF3e63a48e4D204D32",
27
+ [sdk.ChainId.SCROLL_SEPOLIA]: "0x052a99849Ef2e13a5CB28275862991671D4b6fF5"
28
+ };
29
+ var DEFAULT_BLOCK_CONFLICT_TOLERANCE = 0;
30
+ var BLOCK_CONFLICT_TOLERANCE = {
31
+ [sdk.ChainId.BSC]: 3,
32
+ [sdk.ChainId.ETHEREUM]: 1,
33
+ [sdk.ChainId.ARBITRUM_ONE]: 5,
34
+ [sdk.ChainId.POLYGON_ZKEVM]: 1,
35
+ [sdk.ChainId.ZKSYNC]: 3,
36
+ [sdk.ChainId.LINEA]: 3,
37
+ [sdk.ChainId.BASE]: 3,
38
+ // Testnets
39
+ [sdk.ChainId.BSC_TESTNET]: 3,
40
+ [sdk.ChainId.GOERLI]: 1,
41
+ [sdk.ChainId.ARBITRUM_GOERLI]: 5,
42
+ [sdk.ChainId.POLYGON_ZKEVM_TESTNET]: 1,
43
+ [sdk.ChainId.ZKSYNC_TESTNET]: 3,
44
+ [sdk.ChainId.LINEA_TESTNET]: 3,
45
+ [sdk.ChainId.OPBNB_TESTNET]: 3,
46
+ [sdk.ChainId.BASE_TESTNET]: 3,
47
+ [sdk.ChainId.SCROLL_SEPOLIA]: 3
48
+ };
49
+ var DEFAULT_GAS_LIMIT = 150000000n;
50
+ var DEFAULT_GAS_LIMIT_BY_CHAIN = {
51
+ [sdk.ChainId.BSC]: 100000000n,
52
+ [sdk.ChainId.ZKSYNC]: 500000000n,
53
+ [sdk.ChainId.POLYGON_ZKEVM]: 1500000n
54
+ };
55
+ var DEFAULT_GAS_BUFFER = 3000000n;
56
+ var DEFAULT_GAS_BUFFER_BY_CHAIN = {
57
+ [sdk.ChainId.BSC]: DEFAULT_GAS_BUFFER,
58
+ [sdk.ChainId.POLYGON_ZKEVM]: 0n
59
+ };
8
60
 
9
- // Multicall.json
10
- var Multicall_default = [
11
- {
12
- inputs: [
13
- {
14
- components: [
15
- { internalType: "address", name: "target", type: "address" },
16
- { internalType: "bytes", name: "callData", type: "bytes" }
17
- ],
18
- internalType: "struct Multicall3.Call[]",
19
- name: "calls",
20
- type: "tuple[]"
21
- }
22
- ],
23
- name: "aggregate",
24
- outputs: [
25
- { internalType: "uint256", name: "blockNumber", type: "uint256" },
26
- { internalType: "bytes[]", name: "returnData", type: "bytes[]" }
27
- ],
28
- stateMutability: "payable",
29
- type: "function"
30
- },
31
- {
32
- inputs: [
33
- {
34
- components: [
35
- { internalType: "address", name: "target", type: "address" },
36
- { internalType: "bool", name: "allowFailure", type: "bool" },
37
- { internalType: "bytes", name: "callData", type: "bytes" }
38
- ],
39
- internalType: "struct Multicall3.Call3[]",
40
- name: "calls",
41
- type: "tuple[]"
42
- }
43
- ],
44
- name: "aggregate3",
45
- outputs: [
46
- {
47
- components: [
48
- { internalType: "bool", name: "success", type: "bool" },
49
- { internalType: "bytes", name: "returnData", type: "bytes" }
50
- ],
51
- internalType: "struct Multicall3.Result[]",
52
- name: "returnData",
53
- type: "tuple[]"
54
- }
55
- ],
56
- stateMutability: "payable",
57
- type: "function"
58
- },
59
- {
60
- inputs: [
61
- {
62
- components: [
63
- { internalType: "address", name: "target", type: "address" },
64
- { internalType: "bool", name: "allowFailure", type: "bool" },
65
- { internalType: "uint256", name: "value", type: "uint256" },
66
- { internalType: "bytes", name: "callData", type: "bytes" }
67
- ],
68
- internalType: "struct Multicall3.Call3Value[]",
69
- name: "calls",
70
- type: "tuple[]"
71
- }
72
- ],
73
- name: "aggregate3Value",
74
- outputs: [
75
- {
76
- components: [
77
- { internalType: "bool", name: "success", type: "bool" },
78
- { internalType: "bytes", name: "returnData", type: "bytes" }
79
- ],
80
- internalType: "struct Multicall3.Result[]",
81
- name: "returnData",
82
- type: "tuple[]"
83
- }
84
- ],
85
- stateMutability: "payable",
86
- type: "function"
87
- },
88
- {
89
- inputs: [
90
- {
91
- components: [
92
- { internalType: "address", name: "target", type: "address" },
93
- { internalType: "bytes", name: "callData", type: "bytes" }
94
- ],
95
- internalType: "struct Multicall3.Call[]",
96
- name: "calls",
97
- type: "tuple[]"
98
- }
99
- ],
100
- name: "blockAndAggregate",
101
- outputs: [
102
- { internalType: "uint256", name: "blockNumber", type: "uint256" },
103
- { internalType: "bytes32", name: "blockHash", type: "bytes32" },
104
- {
105
- components: [
106
- { internalType: "bool", name: "success", type: "bool" },
107
- { internalType: "bytes", name: "returnData", type: "bytes" }
108
- ],
109
- internalType: "struct Multicall3.Result[]",
110
- name: "returnData",
111
- type: "tuple[]"
112
- }
113
- ],
114
- stateMutability: "payable",
115
- type: "function"
116
- },
117
- {
118
- inputs: [],
119
- name: "getBasefee",
120
- outputs: [{ internalType: "uint256", name: "basefee", type: "uint256" }],
121
- stateMutability: "view",
122
- type: "function"
123
- },
124
- {
125
- inputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }],
126
- name: "getBlockHash",
127
- outputs: [{ internalType: "bytes32", name: "blockHash", type: "bytes32" }],
128
- stateMutability: "view",
129
- type: "function"
130
- },
131
- {
132
- inputs: [],
133
- name: "getBlockNumber",
134
- outputs: [{ internalType: "uint256", name: "blockNumber", type: "uint256" }],
135
- stateMutability: "view",
136
- type: "function"
137
- },
138
- {
139
- inputs: [],
140
- name: "getChainId",
141
- outputs: [{ internalType: "uint256", name: "chainid", type: "uint256" }],
142
- stateMutability: "view",
143
- type: "function"
144
- },
145
- {
146
- inputs: [],
147
- name: "getCurrentBlockCoinbase",
148
- outputs: [{ internalType: "address", name: "coinbase", type: "address" }],
149
- stateMutability: "view",
150
- type: "function"
151
- },
152
- {
153
- inputs: [],
154
- name: "getCurrentBlockDifficulty",
155
- outputs: [{ internalType: "uint256", name: "difficulty", type: "uint256" }],
156
- stateMutability: "view",
157
- type: "function"
158
- },
159
- {
160
- inputs: [],
161
- name: "getCurrentBlockGasLimit",
162
- outputs: [{ internalType: "uint256", name: "gaslimit", type: "uint256" }],
163
- stateMutability: "view",
164
- type: "function"
165
- },
61
+ // src/abis/IMulticall.ts
62
+ var iMulticallABI = [
166
63
  {
167
64
  inputs: [],
168
- name: "getCurrentBlockTimestamp",
169
- outputs: [{ internalType: "uint256", name: "timestamp", type: "uint256" }],
170
- stateMutability: "view",
171
- type: "function"
172
- },
173
- {
174
- inputs: [{ internalType: "address", name: "addr", type: "address" }],
175
- name: "getEthBalance",
176
- outputs: [{ internalType: "uint256", name: "balance", type: "uint256" }],
65
+ name: "gasLeft",
66
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
177
67
  stateMutability: "view",
178
68
  type: "function"
179
69
  },
180
70
  {
181
71
  inputs: [],
182
- name: "getLastBlockHash",
183
- outputs: [{ internalType: "bytes32", name: "blockHash", type: "bytes32" }],
72
+ name: "gaslimit",
73
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
184
74
  stateMutability: "view",
185
75
  type: "function"
186
76
  },
187
77
  {
188
78
  inputs: [
189
- { internalType: "bool", name: "requireSuccess", type: "bool" },
190
79
  {
191
80
  components: [
192
81
  { internalType: "address", name: "target", type: "address" },
82
+ { internalType: "uint256", name: "gasLimit", type: "uint256" },
193
83
  { internalType: "bytes", name: "callData", type: "bytes" }
194
84
  ],
195
- internalType: "struct Multicall3.Call[]",
85
+ internalType: "struct MultiCallV2.Call[]",
196
86
  name: "calls",
197
87
  type: "tuple[]"
198
88
  }
199
89
  ],
200
- name: "tryAggregate",
90
+ name: "multicall",
201
91
  outputs: [
92
+ { internalType: "uint256", name: "blockNumber", type: "uint256" },
202
93
  {
203
94
  components: [
204
95
  { internalType: "bool", name: "success", type: "bool" },
96
+ { internalType: "uint256", name: "gasUsed", type: "uint256" },
205
97
  { internalType: "bytes", name: "returnData", type: "bytes" }
206
98
  ],
207
- internalType: "struct Multicall3.Result[]",
99
+ internalType: "struct MultiCallV2.Result[]",
208
100
  name: "returnData",
209
101
  type: "tuple[]"
210
102
  }
211
103
  ],
212
- stateMutability: "payable",
104
+ stateMutability: "nonpayable",
213
105
  type: "function"
214
106
  },
215
107
  {
216
108
  inputs: [
217
- { internalType: "bool", name: "requireSuccess", type: "bool" },
218
109
  {
219
110
  components: [
220
111
  { internalType: "address", name: "target", type: "address" },
112
+ { internalType: "uint256", name: "gasLimit", type: "uint256" },
221
113
  { internalType: "bytes", name: "callData", type: "bytes" }
222
114
  ],
223
- internalType: "struct Multicall3.Call[]",
115
+ internalType: "struct MultiCallV2.Call[]",
224
116
  name: "calls",
225
117
  type: "tuple[]"
226
- }
118
+ },
119
+ { internalType: "uint256", name: "gasBuffer", type: "uint256" }
227
120
  ],
228
- name: "tryBlockAndAggregate",
121
+ name: "multicallWithGasLimitation",
229
122
  outputs: [
230
123
  { internalType: "uint256", name: "blockNumber", type: "uint256" },
231
- { internalType: "bytes32", name: "blockHash", type: "bytes32" },
232
124
  {
233
125
  components: [
234
126
  { internalType: "bool", name: "success", type: "bool" },
127
+ { internalType: "uint256", name: "gasUsed", type: "uint256" },
235
128
  { internalType: "bytes", name: "returnData", type: "bytes" }
236
129
  ],
237
- internalType: "struct Multicall3.Result[]",
130
+ internalType: "struct MultiCallV2.Result[]",
238
131
  name: "returnData",
239
132
  type: "tuple[]"
240
- }
133
+ },
134
+ { internalType: "uint256", name: "lastSuccessIndex", type: "uint256" }
241
135
  ],
242
- stateMutability: "payable",
136
+ stateMutability: "nonpayable",
243
137
  type: "function"
244
138
  }
245
139
  ];
246
140
 
247
- // index.ts
248
- var multicallAddresses = {
249
- 1: "0xcA11bde05977b3631167028862bE2a173976CA11",
250
- 4: "0xcA11bde05977b3631167028862bE2a173976CA11",
251
- 5: "0xcA11bde05977b3631167028862bE2a173976CA11",
252
- 56: "0xcA11bde05977b3631167028862bE2a173976CA11",
253
- 97: "0xcA11bde05977b3631167028862bE2a173976CA11"
254
- };
255
- var getMulticallContract = (chainId, provider) => {
256
- if (multicallAddresses[chainId]) {
257
- return new contracts.Contract(multicallAddresses[chainId], Multicall_default, provider);
141
+ // src/getMulticallContract.ts
142
+ function getMulticallContract({
143
+ chainId,
144
+ client
145
+ }) {
146
+ const address = MULTICALL_ADDRESS[chainId];
147
+ if (!address) {
148
+ throw new Error(`PancakeMulticall not supported on chain ${chainId}`);
258
149
  }
259
- return null;
260
- };
261
- function createMulticall(provider) {
262
- const multicall = async (abi$1, calls, chainId = sdk.ChainId.BSC) => {
263
- const multi = getMulticallContract(chainId, provider({ chainId }));
264
- if (!multi)
265
- throw new Error(`Multicall Provider missing for ${chainId}`);
266
- const itf = new abi.Interface(abi$1);
267
- const calldata = calls.map((call) => ({
268
- target: call.address.toLowerCase(),
269
- callData: itf.encodeFunctionData(call.name, call.params)
270
- }));
271
- const { returnData } = await multi.callStatic.aggregate(calldata);
272
- const res = returnData.map((call, i) => itf.decodeFunctionResult(calls[i].name, call));
273
- return res;
274
- };
275
- const multicallv2 = async ({ abi: abi$1, calls, chainId = sdk.ChainId.BSC, options, provider: _provider }) => {
276
- const { requireSuccess = true, ...overrides } = options || {};
277
- const multi = getMulticallContract(chainId, _provider || provider({ chainId }));
278
- if (!multi)
279
- throw new Error(`Multicall Provider missing for ${chainId}`);
280
- const itf = new abi.Interface(abi$1);
281
- const calldata = calls.map((call) => ({
282
- target: call.address.toLowerCase(),
283
- callData: itf.encodeFunctionData(call.name, call.params)
284
- }));
285
- const returnData = await multi.callStatic.tryAggregate(requireSuccess, calldata, overrides);
286
- const res = returnData.map((call, i) => {
287
- const [result, data] = call;
288
- return result && data !== "0x" ? itf.decodeFunctionResult(calls[i].name, data) : null;
289
- });
290
- return res;
150
+ return viem.getContract({ abi: iMulticallABI, address, publicClient: client });
151
+ }
152
+
153
+ // src/getGasLimit.ts
154
+ function getDefaultGasLimit(chainId) {
155
+ const gasLimitOnChain = chainId && DEFAULT_GAS_LIMIT_BY_CHAIN[chainId];
156
+ return gasLimitOnChain !== void 0 ? gasLimitOnChain : DEFAULT_GAS_LIMIT;
157
+ }
158
+ function getDefaultGasBuffer(chainId) {
159
+ const gasBufferOnChain = chainId && DEFAULT_GAS_BUFFER_BY_CHAIN[chainId];
160
+ return gasBufferOnChain !== void 0 ? gasBufferOnChain : DEFAULT_GAS_BUFFER;
161
+ }
162
+ async function getGasLimitOnChain({ chainId, client }) {
163
+ const multicall = getMulticallContract({ chainId, client });
164
+ const gasLeft = await multicall.read.gasLeft();
165
+ return gasLeft;
166
+ }
167
+ async function getGasLimit({
168
+ chainId,
169
+ gasLimit: gasLimitInput,
170
+ maxGasLimit: maxGasLimitInput = getDefaultGasLimit(chainId),
171
+ gasBuffer: gasBufferInput = getDefaultGasBuffer(chainId),
172
+ client
173
+ }) {
174
+ const gasLimitOverride = gasLimitInput && toBigInt(gasLimitInput);
175
+ const maxGasLimit = toBigInt(maxGasLimitInput);
176
+ const gasBuffer = toBigInt(gasBufferInput);
177
+ const gasLimit = gasLimitOverride || await getGasLimitOnChain({ chainId, client }) || maxGasLimit;
178
+ const minGasLimit = gasLimit < maxGasLimit ? gasLimit : maxGasLimit;
179
+ return minGasLimit - gasBuffer;
180
+ }
181
+
182
+ // src/getBlockConflictTolerance.ts
183
+ function getBlockConflictTolerance(chainId) {
184
+ return BLOCK_CONFLICT_TOLERANCE[chainId] || DEFAULT_BLOCK_CONFLICT_TOLERANCE;
185
+ }
186
+
187
+ // src/multicall.ts
188
+ async function multicallByGasLimit(calls, { chainId, gasBuffer = getDefaultGasBuffer(chainId), client, ...rest }) {
189
+ const gasLimit = await getGasLimit({
190
+ chainId,
191
+ gasBuffer,
192
+ client,
193
+ ...rest
194
+ });
195
+ const callChunks = splitCallsIntoChunks(calls, gasLimit);
196
+ return callByChunks(callChunks, { gasBuffer, client, chainId });
197
+ }
198
+ function formatCallReturn([blockNumber, results, successIndex]) {
199
+ const lastSuccessIndex = Number(successIndex);
200
+ return {
201
+ lastSuccessIndex,
202
+ blockNumber,
203
+ results: results.slice(0, lastSuccessIndex + 1).map(({ gasUsed, success, returnData }) => ({
204
+ gasUsed,
205
+ success,
206
+ result: returnData
207
+ }))
291
208
  };
292
- const multicallv3 = async ({ calls, chainId = sdk.ChainId.BSC, allowFailure, overrides }) => {
293
- const multi = getMulticallContract(chainId, provider({ chainId }));
294
- if (!multi)
295
- throw new Error(`Multicall Provider missing for ${chainId}`);
296
- const interfaceCache = /* @__PURE__ */ new WeakMap();
297
- const _calls = calls.map(({ abi: abi$1, address, name, params, allowFailure: _allowFailure }) => {
298
- let itf = interfaceCache.get(abi$1);
299
- if (!itf) {
300
- itf = new abi.Interface(abi$1);
301
- interfaceCache.set(abi$1, itf);
302
- }
303
- if (!itf.fragments.some((fragment) => fragment.name === name))
304
- console.error(`${name} missing on ${address}`);
305
- const callData = itf.encodeFunctionData(name, params ?? []);
306
- return {
307
- target: address.toLowerCase(),
308
- allowFailure: allowFailure || _allowFailure,
309
- callData
310
- };
311
- });
312
- const result = await multi.callStatic.aggregate3(_calls, ...overrides ? [overrides] : []);
313
- return result.map((call, i) => {
314
- const { returnData, success } = call;
315
- if (!success || returnData === "0x")
316
- return null;
317
- const { abi, name } = calls[i];
318
- const itf = interfaceCache.get(abi);
319
- const decoded = itf == null ? void 0 : itf.decodeFunctionResult(name, returnData);
320
- return decoded;
321
- });
209
+ }
210
+ async function call(calls, params) {
211
+ const {
212
+ chainId,
213
+ client,
214
+ gasBuffer = getDefaultGasBuffer(chainId),
215
+ blockConflictTolerance = getBlockConflictTolerance(chainId)
216
+ } = params;
217
+ if (!calls.length) {
218
+ return {
219
+ results: [],
220
+ blockNumber: 0n
221
+ };
222
+ }
223
+ const contract = getMulticallContract({ chainId, client });
224
+ const { result } = await contract.simulate.multicallWithGasLimitation([calls, gasBuffer]);
225
+ const { results, lastSuccessIndex, blockNumber } = formatCallReturn(result);
226
+ if (lastSuccessIndex === calls.length - 1) {
227
+ return {
228
+ results,
229
+ blockNumber
230
+ };
231
+ }
232
+ console.warn(
233
+ `Gas limit reached. Total num of ${calls.length} calls. First ${lastSuccessIndex + 1} calls executed. The remaining ${calls.length - lastSuccessIndex - 1} calls are not executed. Pls try adjust the gas limit per call.`
234
+ );
235
+ const { results: remainingResults, blockNumber: nextBlockNumber } = await call(
236
+ calls.slice(lastSuccessIndex + 1),
237
+ params
238
+ );
239
+ if (Number(nextBlockNumber - blockNumber) > blockConflictTolerance) {
240
+ throw new Error(
241
+ `Multicall failed because of block conflict. Latest calls are made at block ${nextBlockNumber} while last calls made at block ${blockNumber}. Block conflict tolerance is ${blockConflictTolerance}`
242
+ );
243
+ }
244
+ return {
245
+ results: [...results, ...remainingResults],
246
+ // Use the latest block number
247
+ blockNumber: nextBlockNumber
322
248
  };
249
+ }
250
+ async function callByChunks(chunks, params) {
251
+ const { blockConflictTolerance = getBlockConflictTolerance(params.chainId) } = params;
252
+ const callReturns = await Promise.all(chunks.map((chunk) => call(chunk, params)));
253
+ let minBlock = 0n;
254
+ let maxBlock = 0n;
255
+ let results = [];
256
+ for (const { results: callResults, blockNumber } of callReturns) {
257
+ if (minBlock === 0n || blockNumber < minBlock) {
258
+ minBlock = blockNumber;
259
+ }
260
+ if (blockNumber > maxBlock) {
261
+ maxBlock = blockNumber;
262
+ }
263
+ if (Number(maxBlock - minBlock) > blockConflictTolerance) {
264
+ throw new Error(
265
+ `Multicall failed because of block conflict. Min block is ${minBlock} while max block is ${maxBlock}. Block conflict tolerance is ${blockConflictTolerance}`
266
+ );
267
+ }
268
+ results = [...results, ...callResults];
269
+ }
323
270
  return {
324
- multicall,
325
- multicallv2,
326
- multicallv3
271
+ results,
272
+ blockNumber: maxBlock
327
273
  };
328
274
  }
275
+ function splitCallsIntoChunks(calls, gasLimit) {
276
+ const chunks = [[]];
277
+ let gasLeft = gasLimit;
278
+ for (const callRequest of calls) {
279
+ const { target, callData, gasLimit: gasCostLimit } = callRequest;
280
+ const singleGasLimit = toBigInt(gasCostLimit);
281
+ const currentChunk = chunks[chunks.length - 1];
282
+ if (singleGasLimit > gasLeft) {
283
+ chunks.push([callRequest]);
284
+ gasLeft = gasLimit - singleGasLimit;
285
+ if (gasLeft < 0n) {
286
+ console.warn(
287
+ `Multicall request may fail as the gas cost of a single call exceeds the gas limit ${gasLimit}. Gas cost: ${singleGasLimit}. To: ${target}. Data: ${callData}`
288
+ );
289
+ }
290
+ continue;
291
+ }
292
+ currentChunk.push(callRequest);
293
+ gasLeft -= singleGasLimit;
294
+ }
295
+ return chunks;
296
+ }
329
297
 
330
- exports.createMulticall = createMulticall;
298
+ exports.BLOCK_CONFLICT_TOLERANCE = BLOCK_CONFLICT_TOLERANCE;
299
+ exports.DEFAULT_BLOCK_CONFLICT_TOLERANCE = DEFAULT_BLOCK_CONFLICT_TOLERANCE;
300
+ exports.DEFAULT_GAS_BUFFER = DEFAULT_GAS_BUFFER;
301
+ exports.DEFAULT_GAS_BUFFER_BY_CHAIN = DEFAULT_GAS_BUFFER_BY_CHAIN;
302
+ exports.DEFAULT_GAS_LIMIT = DEFAULT_GAS_LIMIT;
303
+ exports.DEFAULT_GAS_LIMIT_BY_CHAIN = DEFAULT_GAS_LIMIT_BY_CHAIN;
304
+ exports.MULTICALL_ADDRESS = MULTICALL_ADDRESS;
305
+ exports.getBlockConflictTolerance = getBlockConflictTolerance;
306
+ exports.getDefaultGasBuffer = getDefaultGasBuffer;
307
+ exports.getDefaultGasLimit = getDefaultGasLimit;
308
+ exports.getGasLimit = getGasLimit;
309
+ exports.getGasLimitOnChain = getGasLimitOnChain;
331
310
  exports.getMulticallContract = getMulticallContract;
332
- exports.multicallAddresses = multicallAddresses;
311
+ exports.iMulticallABI = iMulticallABI;
312
+ exports.multicallByGasLimit = multicallByGasLimit;
313
+ //# sourceMappingURL=out.js.map
314
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../utils/toBigInt.ts","../src/constants/contracts.ts","../src/constants/blockConflictTolerance.ts","../src/constants/gasLimit.ts","../src/getMulticallContract.ts","../src/abis/IMulticall.ts","../src/getGasLimit.ts","../src/getBlockConflictTolerance.ts","../src/multicall.ts"],"names":["ChainId"],"mappings":"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","sourcesContent":["import { BigintIsh } from '@pancakeswap/sdk'\n\nexport function toBigInt(num: BigintIsh): bigint {\n return BigInt(num.toString())\n}\n","import { ChainId } from '@pancakeswap/sdk'\nimport { Address } from 'viem'\n\nexport const MULTICALL_ADDRESS: { [key in ChainId]?: Address } = {\n [ChainId.ZKSYNC]: '0x95071cBD09184083E7F732a710c2e30c9882Fd5f',\n [ChainId.BSC]: '0x39eecaE833c944ebb94942Fa44CaE46e87a8Da17',\n [ChainId.ETHEREUM]: '0xC0916D7E360c31D5F6D0c497E6a36B7B0E80e3cf',\n [ChainId.ARBITRUM_ONE]: '0xbFfE39cDD04f0183e0493c1Deb6E275c5cf84AdF',\n [ChainId.POLYGON_ZKEVM]: '0xe05b539447B17630Cb087473F6b50E5c5f73FDeb',\n [ChainId.LINEA]: '0x6E6B30d65D605DAa4CaC65eB270100Ecca36b140',\n [ChainId.BASE]: '0x3EFaAb8D7A631cfF5ccF5f149d1Bbb3B5bfda2C0',\n\n // Testnets\n [ChainId.BSC_TESTNET]: '0xeeF6ff30cF5D5b8aBA0DE16A01d17A0697a275b5',\n [ChainId.GOERLI]: '0xD55CAFAB2Ffa1139Be46bc5C0b8259c620050dFC',\n [ChainId.ARBITRUM_GOERLI]: '0xe12a5c707Fb528acbE6117b20AF1f7c20b0A8077',\n [ChainId.POLYGON_ZKEVM_TESTNET]: '0x236e713bFF45adb30e25D1c29A887aBCb0Ea7E21',\n [ChainId.ZKSYNC_TESTNET]: '0x8A23CB45E5F4d5a1b2DB673663Ea2aAedc48acff',\n [ChainId.LINEA_TESTNET]: '0x990010b6DBA3e7faa025790bC0433A9f690c65F3',\n [ChainId.BASE_TESTNET]: '0x6F7f93D929d6FBaF16c245e42846EF21aee23437',\n [ChainId.OPBNB_TESTNET]: '0x6A70ED893D85cf6D4059e1CF3e63a48e4D204D32',\n [ChainId.SCROLL_SEPOLIA]: '0x052a99849Ef2e13a5CB28275862991671D4b6fF5',\n}\n","import { ChainId } from '@pancakeswap/sdk'\n\nexport const DEFAULT_BLOCK_CONFLICT_TOLERANCE = 0\n\nexport const BLOCK_CONFLICT_TOLERANCE: { [key in ChainId]?: number } = {\n [ChainId.BSC]: 3,\n [ChainId.ETHEREUM]: 1,\n [ChainId.ARBITRUM_ONE]: 5,\n [ChainId.POLYGON_ZKEVM]: 1,\n [ChainId.ZKSYNC]: 3,\n [ChainId.LINEA]: 3,\n [ChainId.BASE]: 3,\n\n // Testnets\n [ChainId.BSC_TESTNET]: 3,\n [ChainId.GOERLI]: 1,\n [ChainId.ARBITRUM_GOERLI]: 5,\n [ChainId.POLYGON_ZKEVM_TESTNET]: 1,\n [ChainId.ZKSYNC_TESTNET]: 3,\n [ChainId.LINEA_TESTNET]: 3,\n [ChainId.OPBNB_TESTNET]: 3,\n [ChainId.BASE_TESTNET]: 3,\n [ChainId.SCROLL_SEPOLIA]: 3,\n}\n","import { ChainId } from '@pancakeswap/sdk'\n\nexport const DEFAULT_GAS_LIMIT = 150000000n\n\nexport const DEFAULT_GAS_LIMIT_BY_CHAIN: { [key in ChainId]?: bigint } = {\n [ChainId.BSC]: 100000000n,\n [ChainId.ZKSYNC]: 500000000n,\n [ChainId.POLYGON_ZKEVM]: 1500000n,\n}\n\nexport const DEFAULT_GAS_BUFFER = 3000000n\n\nexport const DEFAULT_GAS_BUFFER_BY_CHAIN: { [key in ChainId]?: bigint } = {\n [ChainId.BSC]: DEFAULT_GAS_BUFFER,\n [ChainId.POLYGON_ZKEVM]: 0n,\n}\n","import { ChainId } from '@pancakeswap/sdk'\nimport { GetContractReturnType, PublicClient, getContract } from 'viem'\n\nimport { MULTICALL_ADDRESS } from './constants/contracts'\nimport { iMulticallABI } from './abis/IMulticall'\n\ntype Params = {\n chainId: ChainId\n client?: PublicClient\n}\n\nexport function getMulticallContract({\n chainId,\n client,\n}: Params): GetContractReturnType<typeof iMulticallABI, PublicClient> {\n const address = MULTICALL_ADDRESS[chainId]\n if (!address) {\n throw new Error(`PancakeMulticall not supported on chain ${chainId}`)\n }\n\n return getContract({ abi: iMulticallABI, address, publicClient: client })\n}\n","export const iMulticallABI = [\n {\n inputs: [],\n name: 'gasLeft',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [],\n name: 'gaslimit',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [\n {\n components: [\n { internalType: 'address', name: 'target', type: 'address' },\n { internalType: 'uint256', name: 'gasLimit', type: 'uint256' },\n { internalType: 'bytes', name: 'callData', type: 'bytes' },\n ],\n internalType: 'struct MultiCallV2.Call[]',\n name: 'calls',\n type: 'tuple[]',\n },\n ],\n name: 'multicall',\n outputs: [\n { internalType: 'uint256', name: 'blockNumber', type: 'uint256' },\n {\n components: [\n { internalType: 'bool', name: 'success', type: 'bool' },\n { internalType: 'uint256', name: 'gasUsed', type: 'uint256' },\n { internalType: 'bytes', name: 'returnData', type: 'bytes' },\n ],\n internalType: 'struct MultiCallV2.Result[]',\n name: 'returnData',\n type: 'tuple[]',\n },\n ],\n stateMutability: 'nonpayable',\n type: 'function',\n },\n {\n inputs: [\n {\n components: [\n { internalType: 'address', name: 'target', type: 'address' },\n { internalType: 'uint256', name: 'gasLimit', type: 'uint256' },\n { internalType: 'bytes', name: 'callData', type: 'bytes' },\n ],\n internalType: 'struct MultiCallV2.Call[]',\n name: 'calls',\n type: 'tuple[]',\n },\n { internalType: 'uint256', name: 'gasBuffer', type: 'uint256' },\n ],\n name: 'multicallWithGasLimitation',\n outputs: [\n { internalType: 'uint256', name: 'blockNumber', type: 'uint256' },\n {\n components: [\n { internalType: 'bool', name: 'success', type: 'bool' },\n { internalType: 'uint256', name: 'gasUsed', type: 'uint256' },\n { internalType: 'bytes', name: 'returnData', type: 'bytes' },\n ],\n internalType: 'struct MultiCallV2.Result[]',\n name: 'returnData',\n type: 'tuple[]',\n },\n { internalType: 'uint256', name: 'lastSuccessIndex', type: 'uint256' },\n ],\n stateMutability: 'nonpayable',\n type: 'function',\n },\n]\n","import { BigintIsh, ChainId } from '@pancakeswap/sdk'\nimport { toBigInt } from '@pancakeswap/utils/toBigInt'\nimport { PublicClient } from 'viem'\n\nimport {\n DEFAULT_GAS_BUFFER,\n DEFAULT_GAS_BUFFER_BY_CHAIN,\n DEFAULT_GAS_LIMIT,\n DEFAULT_GAS_LIMIT_BY_CHAIN,\n} from './constants'\nimport { getMulticallContract } from './getMulticallContract'\n\nexport type GetGasLimitParams = {\n chainId: ChainId\n client?: PublicClient\n\n // If provided then would override the gas limit got from on chain\n gasLimit?: BigintIsh\n\n // The gas limit should be whichever is smaller between gasLimit and maxGasLimit\n maxGasLimit?: BigintIsh\n\n gasBuffer?: BigintIsh\n}\n\nexport function getDefaultGasLimit(chainId?: ChainId) {\n const gasLimitOnChain = chainId && DEFAULT_GAS_LIMIT_BY_CHAIN[chainId]\n return gasLimitOnChain !== undefined ? gasLimitOnChain : DEFAULT_GAS_LIMIT\n}\n\nexport function getDefaultGasBuffer(chainId?: ChainId) {\n const gasBufferOnChain = chainId && DEFAULT_GAS_BUFFER_BY_CHAIN[chainId]\n return gasBufferOnChain !== undefined ? gasBufferOnChain : DEFAULT_GAS_BUFFER\n}\n\nexport type GetGasLimitOnChainParams = Pick<GetGasLimitParams, 'chainId' | 'client'>\n\nexport async function getGasLimitOnChain({ chainId, client }: GetGasLimitOnChainParams) {\n const multicall = getMulticallContract({ chainId, client })\n const gasLeft = (await multicall.read.gasLeft()) as bigint\n return gasLeft\n}\n\nexport async function getGasLimit({\n chainId,\n gasLimit: gasLimitInput,\n maxGasLimit: maxGasLimitInput = getDefaultGasLimit(chainId),\n gasBuffer: gasBufferInput = getDefaultGasBuffer(chainId),\n client,\n}: GetGasLimitParams) {\n const gasLimitOverride = gasLimitInput && toBigInt(gasLimitInput)\n const maxGasLimit = toBigInt(maxGasLimitInput)\n const gasBuffer = toBigInt(gasBufferInput)\n\n const gasLimit = gasLimitOverride || (await getGasLimitOnChain({ chainId, client })) || maxGasLimit\n const minGasLimit = gasLimit < maxGasLimit ? gasLimit : maxGasLimit\n return minGasLimit - gasBuffer\n}\n","import { ChainId } from '@pancakeswap/sdk'\n\nimport { BLOCK_CONFLICT_TOLERANCE, DEFAULT_BLOCK_CONFLICT_TOLERANCE } from './constants'\n\nexport function getBlockConflictTolerance(chainId: ChainId) {\n return BLOCK_CONFLICT_TOLERANCE[chainId] || DEFAULT_BLOCK_CONFLICT_TOLERANCE\n}\n","import { toBigInt } from '@pancakeswap/utils/toBigInt'\n\nimport { GetGasLimitParams, getDefaultGasBuffer, getGasLimit } from './getGasLimit'\nimport { MulticallRequestWithGas } from './types'\nimport { getMulticallContract } from './getMulticallContract'\nimport { getBlockConflictTolerance } from './getBlockConflictTolerance'\n\nexport type CallByGasLimitParams = GetGasLimitParams & {\n // Normally we expect to get quotes from within the same block\n // But for some chains like BSC the block time is quite short so need some extra tolerance\n // 0 means no block conflict and all the multicall results should be queried within the same block\n blockConflictTolerance?: number\n}\n\nexport async function multicallByGasLimit(\n calls: MulticallRequestWithGas[],\n { chainId, gasBuffer = getDefaultGasBuffer(chainId), client, ...rest }: CallByGasLimitParams,\n) {\n const gasLimit = await getGasLimit({\n chainId,\n gasBuffer,\n client,\n ...rest,\n })\n const callChunks = splitCallsIntoChunks(calls, gasLimit)\n return callByChunks(callChunks, { gasBuffer, client, chainId })\n}\n\ntype CallParams = Pick<CallByGasLimitParams, 'chainId' | 'client' | 'gasBuffer' | 'blockConflictTolerance'>\n\nexport type SingleCallResult = {\n result: string\n gasUsed: bigint\n success: boolean\n}\n\nexport type CallResult = {\n results: SingleCallResult[]\n // Will be the greatest block number if block conflict tolerance is not 0\n blockNumber: bigint\n}\n\nexport type MulticallReturn = CallResult & {\n lastSuccessIndex: number\n}\n\ntype CallReturnFromContract = [bigint, { success: boolean; gasUsed: bigint; returnData: string }[], bigint]\n\nfunction formatCallReturn([blockNumber, results, successIndex]: CallReturnFromContract): MulticallReturn {\n const lastSuccessIndex = Number(successIndex)\n return {\n lastSuccessIndex,\n blockNumber,\n results: results.slice(0, lastSuccessIndex + 1).map(({ gasUsed, success, returnData }) => ({\n gasUsed,\n success,\n result: returnData,\n })),\n }\n}\n\nasync function call(calls: MulticallRequestWithGas[], params: CallParams): Promise<CallResult> {\n const {\n chainId,\n client,\n gasBuffer = getDefaultGasBuffer(chainId),\n blockConflictTolerance = getBlockConflictTolerance(chainId),\n } = params\n if (!calls.length) {\n return {\n results: [],\n blockNumber: 0n,\n }\n }\n\n const contract = getMulticallContract({ chainId, client })\n const { result } = await contract.simulate.multicallWithGasLimitation([calls, gasBuffer])\n const { results, lastSuccessIndex, blockNumber } = formatCallReturn(result as CallReturnFromContract)\n if (lastSuccessIndex === calls.length - 1) {\n return {\n results,\n blockNumber,\n }\n }\n console.warn(\n `Gas limit reached. Total num of ${calls.length} calls. First ${\n lastSuccessIndex + 1\n } calls executed. The remaining ${\n calls.length - lastSuccessIndex - 1\n } calls are not executed. Pls try adjust the gas limit per call.`,\n )\n const { results: remainingResults, blockNumber: nextBlockNumber } = await call(\n calls.slice(lastSuccessIndex + 1),\n params,\n )\n if (Number(nextBlockNumber - blockNumber) > blockConflictTolerance) {\n throw new Error(\n `Multicall failed because of block conflict. Latest calls are made at block ${nextBlockNumber} while last calls made at block ${blockNumber}. Block conflict tolerance is ${blockConflictTolerance}`,\n )\n }\n return {\n results: [...results, ...remainingResults],\n // Use the latest block number\n blockNumber: nextBlockNumber,\n }\n}\n\nasync function callByChunks(chunks: MulticallRequestWithGas[][], params: CallParams): Promise<CallResult> {\n const { blockConflictTolerance = getBlockConflictTolerance(params.chainId) } = params\n const callReturns = await Promise.all(chunks.map((chunk) => call(chunk, params)))\n\n let minBlock = 0n\n let maxBlock = 0n\n let results: SingleCallResult[] = []\n for (const { results: callResults, blockNumber } of callReturns) {\n if (minBlock === 0n || blockNumber < minBlock) {\n minBlock = blockNumber\n }\n if (blockNumber > maxBlock) {\n maxBlock = blockNumber\n }\n if (Number(maxBlock - minBlock) > blockConflictTolerance) {\n throw new Error(\n `Multicall failed because of block conflict. Min block is ${minBlock} while max block is ${maxBlock}. Block conflict tolerance is ${blockConflictTolerance}`,\n )\n }\n results = [...results, ...callResults]\n }\n return {\n results,\n blockNumber: maxBlock,\n }\n}\n\nfunction splitCallsIntoChunks(calls: MulticallRequestWithGas[], gasLimit: bigint): MulticallRequestWithGas[][] {\n const chunks: MulticallRequestWithGas[][] = [[]]\n\n let gasLeft = gasLimit\n for (const callRequest of calls) {\n const { target, callData, gasLimit: gasCostLimit } = callRequest\n const singleGasLimit = toBigInt(gasCostLimit)\n const currentChunk = chunks[chunks.length - 1]\n if (singleGasLimit > gasLeft) {\n chunks.push([callRequest])\n gasLeft = gasLimit - singleGasLimit\n\n // Single call exceeds the gas limit\n if (gasLeft < 0n) {\n console.warn(\n `Multicall request may fail as the gas cost of a single call exceeds the gas limit ${gasLimit}. Gas cost: ${singleGasLimit}. To: ${target}. Data: ${callData}`,\n )\n }\n continue\n }\n\n currentChunk.push(callRequest)\n gasLeft -= singleGasLimit\n }\n\n return chunks\n}\n"]}