Skip to content

Commit

Permalink
feat(batch): make batching great again
Browse files Browse the repository at this point in the history
  • Loading branch information
Rubilmax committed Apr 5, 2024
1 parent e20fb83 commit f100869
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 13 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ With multicall, batch these queries into a single, on-chain query, without addit

### Using ethers-v6

> [!WARNING]
> Ethers made changes to their `Provider` & `Signer` classes throughout v6, that are breaking types. For versions `v6.7` to `v6.10`, use `[email protected]`. For later versions, use `[email protected]`.
```bash
npm install ethers-multicall-provider
```
Expand Down
42 changes: 29 additions & 13 deletions test/multicall-provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,29 +110,31 @@ describe("ethers-multicall-provider", () => {
const result = await Promise.all([uni.name(), uni.symbol(), uni.decimals()]);

expect(result).toEqual(["Uniswap", "UNI", 18n]);
expect(provider.send).toHaveBeenCalledTimes(1);
expect(provider.send).toHaveBeenCalledTimes(2);
expect(provider.send).toHaveBeenNthCalledWith(1, "eth_call", [
{
data: "0xbce38bd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001600000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000406fdde03000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000495d89b41000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004313ce56700000000000000000000000000000000000000000000000000000000",
to: "0xca11bde05977b3631167028862be2a173976ca11",
},
"latest",
]);
expect(provider.send).toHaveBeenNthCalledWith(2, "eth_chainId", []);
});

it("should batch UNI calls without Promise.all", async () => {
expect(uni.name()).resolves.toEqual("Uniswap");
expect(uni.symbol()).resolves.toEqual("UNI");
expect(await uni.decimals()).toEqual(18n);

expect(provider.send).toHaveBeenCalledTimes(1);
expect(provider.send).toHaveBeenCalledTimes(2);
expect(provider.send).toHaveBeenNthCalledWith(1, "eth_call", [
{
data: "0xbce38bd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001600000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000406fdde03000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000495d89b41000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004313ce56700000000000000000000000000000000000000000000000000000000",
to: multicall3Address.toLowerCase(),
},
"latest",
]);
expect(provider.send).toHaveBeenNthCalledWith(2, "eth_chainId", []);
});

it("should batch calls using Multicall2 at block 14_000_000", async () => {
Expand All @@ -145,14 +147,15 @@ describe("ethers-multicall-provider", () => {
]);

expect(result).toEqual(["Uniswap", "UNI", 18n]);
expect(provider.send).toHaveBeenCalledTimes(1);
expect(provider.send).toHaveBeenCalledTimes(2);
expect(provider.send).toHaveBeenNthCalledWith(1, "eth_call", [
{
data: "0xbce38bd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001600000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000406fdde03000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000495d89b41000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004313ce56700000000000000000000000000000000000000000000000000000000",
to: multicall2Address.toLowerCase(),
},
"0xd59f80",
]);
expect(provider.send).toHaveBeenNthCalledWith(2, "eth_chainId", []);
});

it("should not batch calls at block 12_000_000", async () => {
Expand All @@ -165,7 +168,8 @@ describe("ethers-multicall-provider", () => {
]);

expect(result).toEqual(["Uniswap", "UNI", 18n]);
expect(provider.send).toHaveBeenCalledTimes(3);
expect(provider.send).toHaveBeenCalledTimes(4);
expect(provider.send).toHaveBeenCalledWith("eth_chainId", []);
});

it("should not batch calls at earliest block", async () => {
Expand All @@ -178,13 +182,14 @@ describe("ethers-multicall-provider", () => {
]);

expect(result).toEqual(["Uniswap", "UNI", 18]);
expect(provider.send).toHaveBeenCalledTimes(3);
expect(provider.send).toHaveBeenCalledTimes(4);
expect(provider.send).toHaveBeenCalledWith("eth_chainId", []);
});

it("should throw a descriptive Error when querying unknown contract", async () => {
await expect(unknownUni.symbol()).rejects.toEqual(
new Error(
`could not decode result data (value="0x", info={ "method": "symbol", "signature": "symbol()" }, code=BAD_DATA, version=6.7.1)`
`could not decode result data (value="0x", info={ "method": "symbol", "signature": "symbol()" }, code=BAD_DATA, version=6.11.1)`
)
);
});
Expand All @@ -200,7 +205,7 @@ describe("ethers-multicall-provider", () => {
expect(unknownUni.symbol().catch(() => "UNI")).resolves.toEqual("UNI");
await expect(unknownUni.symbol()).rejects.toEqual(
new Error(
`could not decode result data (value="0x", info={ "method": "symbol", "signature": "symbol()" }, code=BAD_DATA, version=6.7.1)`
`could not decode result data (value="0x", info={ "method": "symbol", "signature": "symbol()" }, code=BAD_DATA, version=6.11.1)`
)
);
});
Expand All @@ -212,7 +217,7 @@ describe("ethers-multicall-provider", () => {
expect(uni.symbol(overrides).catch(() => "UNI")).resolves.toEqual("UNI");
await expect(unknownUni.symbol(overrides)).rejects.toEqual(
new Error(
`could not decode result data (value="0x", info={ "method": "symbol", "signature": "symbol()" }, code=BAD_DATA, version=6.7.1)`
`could not decode result data (value="0x", info={ "method": "symbol", "signature": "symbol()" }, code=BAD_DATA, version=6.11.1)`
)
);
});
Expand All @@ -221,7 +226,16 @@ describe("ethers-multicall-provider", () => {
const range = _range(1_000);
const result: bigint[] = await Promise.all(range.map(() => uni.balanceOf(ZeroAddress)));

expect(provider.send).toHaveBeenCalledTimes(1);
expect(provider.send).toHaveBeenCalledTimes(2);
expect(provider.send).toHaveBeenNthCalledWith(1, "eth_call", [
{
data: "0xbce38bd700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a08231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
to: multicall3Address.toLowerCase(),
},
"latest",
]);
expect(provider.send).toHaveBeenNthCalledWith(2, "eth_chainId", []);

expect(result).toEqual(range.map(() => 0n));
});

Expand All @@ -232,18 +246,19 @@ describe("ethers-multicall-provider", () => {
_range(1, 25).map((i) => uni.balanceOf("0x" + i.toString(16).padStart(40, "0")))
);

expect(provider.send).toHaveBeenCalledTimes(2);
expect(provider.send).toHaveBeenCalledTimes(3);
expect(provider.send).toHaveBeenNthCalledWith(1, "eth_call", [
{
data: "0xbce38bd700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000074000000000000000000000000000000000000000000000000000000000000007e0000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009200000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a08231000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a08231000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a08231000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a08231000000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000",
to: "0xca11bde05977b3631167028862be2a173976ca11",
to: multicall3Address.toLowerCase(),
},
"latest",
]);
expect(provider.send).toHaveBeenNthCalledWith(2, "eth_call", [
expect(provider.send).toHaveBeenNthCalledWith(2, "eth_chainId", []);
expect(provider.send).toHaveBeenNthCalledWith(3, "eth_call", [
{
data: "0xbce38bd700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000005c00000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000007a00000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a08231000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a08231000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a082310000000000000000000000000000000000000000000000000000000000000017000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002470a08231000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000",
to: "0xca11bde05977b3631167028862be2a173976ca11",
to: multicall3Address.toLowerCase(),
},
"latest",
]);
Expand All @@ -257,6 +272,7 @@ describe("ethers-multicall-provider", () => {
);

expect(provider.send).toHaveBeenCalledTimes(4);
expect(provider.send).toHaveBeenCalledWith("eth_chainId", []);
});

it("should not cache latest request", async () => {
Expand Down

0 comments on commit f100869

Please sign in to comment.