diff --git a/packages/sdk/src/clients/multicall2/README.md b/packages/sdk/src/clients/multicall2/README.md new file mode 100644 index 0000000000..f29faea42d --- /dev/null +++ b/packages/sdk/src/clients/multicall2/README.md @@ -0,0 +1,17 @@ +# UMA Multicall2 Client + +This client helps you batch multiple calls together in a single transaction. Useful also for +reducing api calls to infura when reading many properties from contracts. + +## Usage + +```js +import { ethers } from "ethers" +import * as uma from "@uma/sdk" + +// assume you have a url injected from env +const provider = new ethers.providers.WebSocketProvider(env.CUSTOM_NODE_URL) + +// get the contract instance +const client = uma.clients.multicall2.connect(address, provider) +``` diff --git a/packages/sdk/src/clients/multicall2/client.e2e.ts b/packages/sdk/src/clients/multicall2/client.e2e.ts new file mode 100644 index 0000000000..9f13efbfff --- /dev/null +++ b/packages/sdk/src/clients/multicall2/client.e2e.ts @@ -0,0 +1,70 @@ +require("dotenv").config(); +import assert from "assert"; +import * as Client from "./client"; +import { ethers } from "ethers"; +import { emp } from ".."; + +// multicall contract deployed to mainnet +const address = "0x5ba1e12693dc8f9c48aad8770482f4739beed696"; +const empAddress = "0x4E3168Ea1082f3dda1694646B5EACdeb572009F1"; +// these require integration testing, skip for ci +describe("multicall2", function () { + let client: Client.Instance; + let empClient: emp.Instance; + + test("inits", function () { + const provider = ethers.providers.getDefaultProvider(process.env.CUSTOM_NODE_URL); + client = Client.connect(address, provider); + empClient = emp.connect(empAddress, provider); + assert.ok(client); + assert.ok(empClient); + }); + + test("multicall2 on emp", async function () { + const calls = ["priceIdentifier", "tokenCurrency", "collateralCurrency"]; + const multicalls = calls.map((call: any) => { + return { + target: empAddress, + callData: empClient.interface.encodeFunctionData(call), + }; + }); + const response = await client.callStatic.aggregate(multicalls); + const decoded = calls.map((call: any, i: number) => { + const result = response.returnData[i]; + return empClient.interface.decodeFunctionResult(call, result); + }); + assert.equal(decoded.length, calls.length); + }); + + test("multicall2 on emp with no errors", async function () { + const calls = ["priceIdentifier", "tokenCurrency", "collateralCurrency"]; + const multicalls = calls.map((call: any) => { + return { + target: empAddress, + callData: empClient.interface.encodeFunctionData(call), + }; + }); + const response = await client.callStatic.tryBlockAndAggregate(false, multicalls); + const decoded = calls.map((call: any, i: number) => { + const result = response.returnData[i].returnData; + return empClient.interface.decodeFunctionResult(call, result); + }); + assert.equal(decoded.length, calls.length); + }); + + test("multicall2 on emp with errors", async function () { + const calls = ["priceIdentifier", "tokenCurrency", "disputeBondPercentage"]; + const multicalls = calls.map((call) => { + return { + target: empAddress, + callData: empClient.interface.encodeFunctionData(call as any), + }; + }); + const response = await client.callStatic.tryBlockAndAggregate(false, multicalls); + const decoded = calls.map((call: any, i: number) => { + const result = response.returnData[i].returnData; + return response.returnData[i].success ? empClient.interface.decodeFunctionResult(call, result) : {}; + }); + assert.equal(decoded.length, calls.length); + }); +}); diff --git a/packages/sdk/src/clients/multicall2/client.ts b/packages/sdk/src/clients/multicall2/client.ts new file mode 100644 index 0000000000..bd015a0367 --- /dev/null +++ b/packages/sdk/src/clients/multicall2/client.ts @@ -0,0 +1,9 @@ +import { EthersContracts } from "@uma/core"; +import type { SignerOrProvider } from "../.."; + +export type Instance = EthersContracts.Multicall2; +const Factory = EthersContracts.Multicall2__factory; + +export function connect(address: string, provider: SignerOrProvider): Instance { + return Factory.connect(address, provider); +} diff --git a/packages/sdk/src/clients/multicall2/index.ts b/packages/sdk/src/clients/multicall2/index.ts new file mode 100644 index 0000000000..5ec76921e1 --- /dev/null +++ b/packages/sdk/src/clients/multicall2/index.ts @@ -0,0 +1 @@ +export * from "./client";