Skip to content

Commit

Permalink
feat(max-calldata-length): enable setting maxMulticallDataLength
Browse files Browse the repository at this point in the history
  • Loading branch information
Rubilmax committed Mar 12, 2023
1 parent f408786 commit dbdd046
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 6 deletions.
22 changes: 16 additions & 6 deletions src/multicall-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,19 @@ export interface ContractCall {
export interface MulticallProviderOverload {
_multicallDelay: number;
multicallDelay: number;
_performMulticall: DebouncedFunc<() => Promise<void>>;
maxMulticallDataLength: number;
_performMulticall: () => Promise<void>;
_debouncedPerformMulticall: DebouncedFunc<() => Promise<void>>;
}

export class MulticallProvider {
/**
* Wraps a given ethers provider to enable automatic call batching.
* @param provider The underlying provider to use to batch calls.
* @param delay The delay (in milliseconds) to wait before performing the ongoing batch of calls. Defaults to 16ms.
* @param maxMulticallDataLength The maximum total calldata length allowed in a multicall batch, to avoid having the RPC backend to revert because of too large (or too long) request. Set to 0 to disable this behavior. Defaults to 200k.
* @returns The multicall provider, which is a proxy to the given provider, automatically batching any call performed with it.
*/
public static wrap<T extends BaseProvider>(
provider: T,
delay = 16,
Expand Down Expand Up @@ -62,7 +71,7 @@ export class MulticallProvider {

let queuedCalls: ContractCall[] = [];

const _performMulticall = async () => {
multicallProvider._performMulticall = async function () {
const _queuedCalls = [...queuedCalls];

if (queuedCalls.length === 0) return;
Expand Down Expand Up @@ -93,7 +102,7 @@ export class MulticallProvider {
callStructs.forEach((callStruct) => {
const newLength = currentLength + callStruct.callData.length;

if (newLength > maxMulticallDataLength) {
if (this.maxMulticallDataLength > 0 && newLength > this.maxMulticallDataLength) {
currentLength = callStruct.callData.length;
calls.push([]);
} else currentLength = newLength;
Expand Down Expand Up @@ -135,15 +144,16 @@ export class MulticallProvider {
return this._multicallDelay;
},
set: function (delay: number) {
this._performMulticall?.flush();
this._debouncedPerformMulticall?.flush();

this._multicallDelay = delay;

this._performMulticall = _debounce(_performMulticall, delay);
this._debouncedPerformMulticall = _debounce(this._performMulticall, delay);
},
enumerable: true,
});
multicallProvider.multicallDelay = delay;
multicallProvider.maxMulticallDataLength = maxMulticallDataLength;

// Overload `BaseProvider.perform`

Expand All @@ -166,7 +176,7 @@ export class MulticallProvider {
if (!to || !data || multicallVersion == null || multicallAddresses.has(to.toLowerCase()))
return _perform(method, params);

this._performMulticall();
this._debouncedPerformMulticall();

return new Promise<string>((resolve, reject) => {
queuedCalls.push({
Expand Down
10 changes: 10 additions & 0 deletions test/multicall-provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ describe("ethers-multicall-provider", () => {
expect(multicallProvider.multicallDelay === newDelay);
});

it("should set maxMulticallDataLength", () => {
const multicallProvider = MulticallProvider.wrap(provider);

const newMaxMulticallDataLength = multicallProvider.maxMulticallDataLength + 1;

multicallProvider.maxMulticallDataLength = newMaxMulticallDataLength;

expect(multicallProvider.maxMulticallDataLength === newMaxMulticallDataLength);
});

it("should have properties shallow cloned", () => {
const multicallProvider = MulticallProvider.wrap(provider);

Expand Down

0 comments on commit dbdd046

Please sign in to comment.