diff --git a/package.json b/package.json index addd56e95..c46404e6e 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,10 @@ }, "scripts": { "start": "nodemon -e ts,tsx,json,js,jsx --watch ./src --ignore ./dist --exec 'yarn build'", - "build": "yarn run clean && yarn run build:cjs & yarn run build:esm & yarn run build:types; wait", - "build:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}' && yarn copy-abi:cjs", - "build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir ./dist/esm && echo > ./dist/esm/package.json '{\"type\":\"module\",\"sideEffects\":false}' && yarn copy-abi:esm", + "build": "yarn run clean && yarn typechain && yarn run build:cjs & yarn run build:esm & yarn run build:types; wait", + "build:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", + "build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir ./dist/esm && echo > ./dist/esm/package.json '{\"type\":\"module\",\"sideEffects\":false}'", "build:types": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", - "copy-abi:cjs": "DIR=cjs yarn copy-abi", - "copy-abi:esm": "DIR=esm yarn copy-abi", - "copy-abi": "abi=utils/abi/contracts; dstdir=\"./dist/${DIR}/${abi}\"; mkdir -p \"${dstdir}\"; cp ./src/${abi}/*.json \"${dstdir}\"", "test": "hardhat test", "test:watch": "hardhat watch test", "test:run:arweave": "npx -y arlocal", @@ -31,7 +28,8 @@ "clean": "rm -rf ./dist", "bump-version:major": "yarn version --major --no-git-tag-version --no-commit-hooks && git commit -m 'chore: bump version' ./package.json --no-verify", "bump-version:minor": "yarn version --minor --no-git-tag-version --no-commit-hooks && git commit -m 'chore: bump version' ./package.json --no-verify", - "bump-version:patch": "yarn version --patch --no-git-tag-version --no-commit-hooks && git commit -m 'chore: bump version' ./package.json --no-verify" + "bump-version:patch": "yarn version --patch --no-git-tag-version --no-commit-hooks && git commit -m 'chore: bump version' ./package.json --no-verify", + "typechain": "typechain --target ethers-v5 --out-dir src/utils/abi/typechain 'src/utils/abi/contracts/*.json' && eslint --fix src/utils/abi/typechain && yarn prettier --write \"src/utils/abi/typechain/**/*.ts\"" }, "lint-staged": { "*.ts": "yarn lint" diff --git a/src/utils/Multicall.ts b/src/utils/Multicall.ts index 788a46349..5ca86f9bd 100644 --- a/src/utils/Multicall.ts +++ b/src/utils/Multicall.ts @@ -1,5 +1,6 @@ import { BigNumber, Contract, providers, Signer, utils as ethersUtils } from "ethers"; -import { getABI } from "./abi"; +import { CHAIN_IDs } from "@across-protocol/constants"; +import { Multicall3, Multicall3__factory } from "./abi/typechain"; type Provider = providers.Provider; type BlockTag = providers.BlockTag; @@ -12,41 +13,48 @@ export type Call3 = { args?: any[]; }; -// Multicall3 Constants: -export const multicall3Addresses: Record = { - 1: "0xcA11bde05977b3631167028862bE2a173976CA11", - 10: "0xcA11bde05977b3631167028862bE2a173976CA11", - 137: "0xcA11bde05977b3631167028862bE2a173976CA11", - 324: "0xF9cda624FBC7e059355ce98a31693d299FACd963", - 8453: "0xcA11bde05977b3631167028862bE2a173976CA11", - 34443: "0xcA11bde05977b3631167028862bE2a173976CA11", - 42161: "0xcA11bde05977b3631167028862bE2a173976CA11", - 59144: "0xcA11bde05977b3631167028862bE2a173976CA11", - 534352: "0xcA11bde05977b3631167028862bE2a173976CA11", - // Testnets - 5: "0xcA11bde05977b3631167028862bE2a173976CA11", - 300: "0xF9cda624FBC7e059355ce98a31693d299FACd963", - 59140: "0xcA11bde05977b3631167028862bE2a173976CA11", - 59141: "0xcA11bde05977b3631167028862bE2a173976CA11", - 80002: "0xcA11bde05977b3631167028862bE2a173976CA11", - 84531: "0xcA11bde05977b3631167028862bE2a173976CA11", - 84532: "0xcA11bde05977b3631167028862bE2a173976CA11", - 421613: "0xcA11bde05977b3631167028862bE2a173976CA11", - 534351: "0xcA11bde05977b3631167028862bE2a173976CA11", - 11155111: "0xcA11bde05977b3631167028862bE2a173976CA11", - 11155420: "0xcA11bde05977b3631167028862bE2a173976CA11", +const DETERMINISTIC_MULTICALL_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11"; + +const NON_DETERMINISTIC_MULTICALL_ADDRESSES = { + [CHAIN_IDs.ZK_SYNC]: "0xF9cda624FBC7e059355ce98a31693d299FACd963", }; -export async function getMulticall3( - chainId: number, - signerOrProvider?: Signer | Provider -): Promise { - const address = multicall3Addresses[chainId]; +const DETERMINISTIC_MULTICALL_CHAINS = [ + CHAIN_IDs.ARBITRUM, + CHAIN_IDs.BASE, + CHAIN_IDs.BLAST, + CHAIN_IDs.BOBA, + CHAIN_IDs.LINEA, + CHAIN_IDs.LISK, + CHAIN_IDs.MAINNET, + CHAIN_IDs.MODE, + CHAIN_IDs.OPTIMISM, + CHAIN_IDs.POLYGON, + CHAIN_IDs.REDSTONE, + CHAIN_IDs.SCROLL, + CHAIN_IDs.ZORA, + // Testnet: + CHAIN_IDs.BASE_SEPOLIA, + CHAIN_IDs.BLAST_SEPOLIA, + CHAIN_IDs.POLYGON_AMOY, + CHAIN_IDs.SCROLL_SEPOLIA, + CHAIN_IDs.SEPOLIA, +]; + +export function getMulticallAddress(chainId: number): string | undefined { + if (DETERMINISTIC_MULTICALL_CHAINS.includes(chainId)) { + return DETERMINISTIC_MULTICALL_ADDRESS; + } + return NON_DETERMINISTIC_MULTICALL_ADDRESSES[chainId]; +} + +export function getMulticall3(chainId: number, signerOrProvider: Signer | Provider): Multicall3 | undefined { + const address = getMulticallAddress(chainId); if (!address) { return undefined; } - return new Contract(address, await getABI("Multicall3"), signerOrProvider); + return Multicall3__factory.connect(address, signerOrProvider); } export async function aggregate(multicall3: Contract, calls: Call3[], blockTag?: BlockTag): Promise { diff --git a/src/utils/abi/contracts/index.ts b/src/utils/abi/contracts/index.ts new file mode 100644 index 000000000..afba96e64 --- /dev/null +++ b/src/utils/abi/contracts/index.ts @@ -0,0 +1 @@ +export { default as Multicall3Abi } from "./Multicall3.json"; diff --git a/src/utils/abi/typechain/Multicall3.ts b/src/utils/abi/typechain/Multicall3.ts new file mode 100644 index 000000000..eb70f31bc --- /dev/null +++ b/src/utils/abi/typechain/Multicall3.ts @@ -0,0 +1,433 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { + BaseContract, + BigNumber, + BigNumberish, + BytesLike, + CallOverrides, + ContractTransaction, + PayableOverrides, + PopulatedTransaction, + Signer, + utils, +} from "ethers"; +import type { FunctionFragment, Result } from "@ethersproject/abi"; +import type { Listener, Provider } from "@ethersproject/providers"; +import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from "./common"; + +export declare namespace Multicall3 { + export type CallStruct = { target: string; callData: BytesLike }; + + export type CallStructOutput = [string, string] & { + target: string; + callData: string; + }; + + export type Call3Struct = { + target: string; + allowFailure: boolean; + callData: BytesLike; + }; + + export type Call3StructOutput = [string, boolean, string] & { + target: string; + allowFailure: boolean; + callData: string; + }; + + export type ResultStruct = { success: boolean; returnData: BytesLike }; + + export type ResultStructOutput = [boolean, string] & { + success: boolean; + returnData: string; + }; + + export type Call3ValueStruct = { + target: string; + allowFailure: boolean; + value: BigNumberish; + callData: BytesLike; + }; + + export type Call3ValueStructOutput = [string, boolean, BigNumber, string] & { + target: string; + allowFailure: boolean; + value: BigNumber; + callData: string; + }; +} + +export interface Multicall3Interface extends utils.Interface { + functions: { + "aggregate((address,bytes)[])": FunctionFragment; + "aggregate3((address,bool,bytes)[])": FunctionFragment; + "aggregate3Value((address,bool,uint256,bytes)[])": FunctionFragment; + "blockAndAggregate((address,bytes)[])": FunctionFragment; + "getBasefee()": FunctionFragment; + "getBlockHash(uint256)": FunctionFragment; + "getBlockNumber()": FunctionFragment; + "getChainId()": FunctionFragment; + "getCurrentBlockCoinbase()": FunctionFragment; + "getCurrentBlockDifficulty()": FunctionFragment; + "getCurrentBlockGasLimit()": FunctionFragment; + "getCurrentBlockTimestamp()": FunctionFragment; + "getEthBalance(address)": FunctionFragment; + "getLastBlockHash()": FunctionFragment; + "tryAggregate(bool,(address,bytes)[])": FunctionFragment; + "tryBlockAndAggregate(bool,(address,bytes)[])": FunctionFragment; + }; + + getFunction( + nameOrSignatureOrTopic: + | "aggregate" + | "aggregate3" + | "aggregate3Value" + | "blockAndAggregate" + | "getBasefee" + | "getBlockHash" + | "getBlockNumber" + | "getChainId" + | "getCurrentBlockCoinbase" + | "getCurrentBlockDifficulty" + | "getCurrentBlockGasLimit" + | "getCurrentBlockTimestamp" + | "getEthBalance" + | "getLastBlockHash" + | "tryAggregate" + | "tryBlockAndAggregate" + ): FunctionFragment; + + encodeFunctionData(functionFragment: "aggregate", values: [Multicall3.CallStruct[]]): string; + encodeFunctionData(functionFragment: "aggregate3", values: [Multicall3.Call3Struct[]]): string; + encodeFunctionData(functionFragment: "aggregate3Value", values: [Multicall3.Call3ValueStruct[]]): string; + encodeFunctionData(functionFragment: "blockAndAggregate", values: [Multicall3.CallStruct[]]): string; + encodeFunctionData(functionFragment: "getBasefee", values?: undefined): string; + encodeFunctionData(functionFragment: "getBlockHash", values: [BigNumberish]): string; + encodeFunctionData(functionFragment: "getBlockNumber", values?: undefined): string; + encodeFunctionData(functionFragment: "getChainId", values?: undefined): string; + encodeFunctionData(functionFragment: "getCurrentBlockCoinbase", values?: undefined): string; + encodeFunctionData(functionFragment: "getCurrentBlockDifficulty", values?: undefined): string; + encodeFunctionData(functionFragment: "getCurrentBlockGasLimit", values?: undefined): string; + encodeFunctionData(functionFragment: "getCurrentBlockTimestamp", values?: undefined): string; + encodeFunctionData(functionFragment: "getEthBalance", values: [string]): string; + encodeFunctionData(functionFragment: "getLastBlockHash", values?: undefined): string; + encodeFunctionData(functionFragment: "tryAggregate", values: [boolean, Multicall3.CallStruct[]]): string; + encodeFunctionData(functionFragment: "tryBlockAndAggregate", values: [boolean, Multicall3.CallStruct[]]): string; + + decodeFunctionResult(functionFragment: "aggregate", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "aggregate3", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "aggregate3Value", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "blockAndAggregate", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getBasefee", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getBlockHash", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getBlockNumber", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getChainId", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getCurrentBlockCoinbase", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getCurrentBlockDifficulty", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getCurrentBlockGasLimit", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getCurrentBlockTimestamp", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getEthBalance", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "getLastBlockHash", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "tryAggregate", data: BytesLike): Result; + decodeFunctionResult(functionFragment: "tryBlockAndAggregate", data: BytesLike): Result; + + events: {}; +} + +export interface Multicall3 extends BaseContract { + connect(signerOrProvider: Signer | Provider | string): this; + attach(addressOrName: string): this; + deployed(): Promise; + + interface: Multicall3Interface; + + queryFilter( + event: TypedEventFilter, + fromBlockOrBlockhash?: string | number | undefined, + toBlock?: string | number | undefined + ): Promise>; + + listeners(eventFilter?: TypedEventFilter): Array>; + listeners(eventName?: string): Array; + removeAllListeners(eventFilter: TypedEventFilter): this; + removeAllListeners(eventName?: string): this; + off: OnEvent; + on: OnEvent; + once: OnEvent; + removeListener: OnEvent; + + functions: { + aggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + aggregate3( + calls: Multicall3.Call3Struct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + getBasefee(overrides?: CallOverrides): Promise<[BigNumber] & { basefee: BigNumber }>; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise<[string] & { blockHash: string }>; + + getBlockNumber(overrides?: CallOverrides): Promise<[BigNumber] & { blockNumber: BigNumber }>; + + getChainId(overrides?: CallOverrides): Promise<[BigNumber] & { chainid: BigNumber }>; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise<[string] & { coinbase: string }>; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise<[BigNumber] & { difficulty: BigNumber }>; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise<[BigNumber] & { gaslimit: BigNumber }>; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise<[BigNumber] & { timestamp: BigNumber }>; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise<[BigNumber] & { balance: BigNumber }>; + + getLastBlockHash(overrides?: CallOverrides): Promise<[string] & { blockHash: string }>; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + }; + + aggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + aggregate3( + calls: Multicall3.Call3Struct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + getBasefee(overrides?: CallOverrides): Promise; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise; + + getBlockNumber(overrides?: CallOverrides): Promise; + + getChainId(overrides?: CallOverrides): Promise; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise; + + getLastBlockHash(overrides?: CallOverrides): Promise; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + callStatic: { + aggregate( + calls: Multicall3.CallStruct[], + overrides?: CallOverrides + ): Promise<[BigNumber, string[]] & { blockNumber: BigNumber; returnData: string[] }>; + + aggregate3(calls: Multicall3.Call3Struct[], overrides?: CallOverrides): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: CallOverrides + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: CallOverrides + ): Promise< + [BigNumber, string, Multicall3.ResultStructOutput[]] & { + blockNumber: BigNumber; + blockHash: string; + returnData: Multicall3.ResultStructOutput[]; + } + >; + + getBasefee(overrides?: CallOverrides): Promise; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise; + + getBlockNumber(overrides?: CallOverrides): Promise; + + getChainId(overrides?: CallOverrides): Promise; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise; + + getLastBlockHash(overrides?: CallOverrides): Promise; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: CallOverrides + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: CallOverrides + ): Promise< + [BigNumber, string, Multicall3.ResultStructOutput[]] & { + blockNumber: BigNumber; + blockHash: string; + returnData: Multicall3.ResultStructOutput[]; + } + >; + }; + + filters: {}; + + estimateGas: { + aggregate(calls: Multicall3.CallStruct[], overrides?: PayableOverrides & { from?: string }): Promise; + + aggregate3(calls: Multicall3.Call3Struct[], overrides?: PayableOverrides & { from?: string }): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + getBasefee(overrides?: CallOverrides): Promise; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise; + + getBlockNumber(overrides?: CallOverrides): Promise; + + getChainId(overrides?: CallOverrides): Promise; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise; + + getLastBlockHash(overrides?: CallOverrides): Promise; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + }; + + populateTransaction: { + aggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + aggregate3( + calls: Multicall3.Call3Struct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + getBasefee(overrides?: CallOverrides): Promise; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise; + + getBlockNumber(overrides?: CallOverrides): Promise; + + getChainId(overrides?: CallOverrides): Promise; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise; + + getLastBlockHash(overrides?: CallOverrides): Promise; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string } + ): Promise; + }; +} diff --git a/src/utils/abi/typechain/common.ts b/src/utils/abi/typechain/common.ts new file mode 100644 index 000000000..e070c605c --- /dev/null +++ b/src/utils/abi/typechain/common.ts @@ -0,0 +1,30 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +import type { Listener } from "@ethersproject/providers"; +import type { Event, EventFilter } from "ethers"; + +export interface TypedEvent = any, TArgsObject = any> extends Event { + args: TArgsArray & TArgsObject; +} + +export interface TypedEventFilter<_TEvent extends TypedEvent> extends EventFilter {} + +export interface TypedListener { + (...listenerArg: [...__TypechainArgsArray, TEvent]): void; +} + +type __TypechainArgsArray = T extends TypedEvent ? U : never; + +export interface OnEvent { + (eventFilter: TypedEventFilter, listener: TypedListener): TRes; + (eventName: string, listener: Listener): TRes; +} + +export type MinEthersFactory = { + deploy(...a: ARGS[]): Promise; +}; + +export type GetContractTypeFromFactory = F extends MinEthersFactory ? C : never; + +export type GetARGsTypeFromFactory = F extends MinEthersFactory ? Parameters : never; diff --git a/src/utils/abi/typechain/factories/Multicall3__factory.ts b/src/utils/abi/typechain/factories/Multicall3__factory.ts new file mode 100644 index 000000000..f45ae5c43 --- /dev/null +++ b/src/utils/abi/typechain/factories/Multicall3__factory.ts @@ -0,0 +1,458 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ + +import { Contract, Signer, utils } from "ethers"; +import type { Provider } from "@ethersproject/providers"; +import type { Multicall3, Multicall3Interface } from "../Multicall3"; + +const _abi = [ + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bytes", + name: "callData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Call[]", + name: "calls", + type: "tuple[]", + }, + ], + name: "aggregate", + outputs: [ + { + internalType: "uint256", + name: "blockNumber", + type: "uint256", + }, + { + internalType: "bytes[]", + name: "returnData", + type: "bytes[]", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bool", + name: "allowFailure", + type: "bool", + }, + { + internalType: "bytes", + name: "callData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Call3[]", + name: "calls", + type: "tuple[]", + }, + ], + name: "aggregate3", + outputs: [ + { + components: [ + { + internalType: "bool", + name: "success", + type: "bool", + }, + { + internalType: "bytes", + name: "returnData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Result[]", + name: "returnData", + type: "tuple[]", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bool", + name: "allowFailure", + type: "bool", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + internalType: "bytes", + name: "callData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Call3Value[]", + name: "calls", + type: "tuple[]", + }, + ], + name: "aggregate3Value", + outputs: [ + { + components: [ + { + internalType: "bool", + name: "success", + type: "bool", + }, + { + internalType: "bytes", + name: "returnData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Result[]", + name: "returnData", + type: "tuple[]", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bytes", + name: "callData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Call[]", + name: "calls", + type: "tuple[]", + }, + ], + name: "blockAndAggregate", + outputs: [ + { + internalType: "uint256", + name: "blockNumber", + type: "uint256", + }, + { + internalType: "bytes32", + name: "blockHash", + type: "bytes32", + }, + { + components: [ + { + internalType: "bool", + name: "success", + type: "bool", + }, + { + internalType: "bytes", + name: "returnData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Result[]", + name: "returnData", + type: "tuple[]", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "getBasefee", + outputs: [ + { + internalType: "uint256", + name: "basefee", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "blockNumber", + type: "uint256", + }, + ], + name: "getBlockHash", + outputs: [ + { + internalType: "bytes32", + name: "blockHash", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getBlockNumber", + outputs: [ + { + internalType: "uint256", + name: "blockNumber", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getChainId", + outputs: [ + { + internalType: "uint256", + name: "chainid", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getCurrentBlockCoinbase", + outputs: [ + { + internalType: "address", + name: "coinbase", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getCurrentBlockDifficulty", + outputs: [ + { + internalType: "uint256", + name: "difficulty", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getCurrentBlockGasLimit", + outputs: [ + { + internalType: "uint256", + name: "gaslimit", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getCurrentBlockTimestamp", + outputs: [ + { + internalType: "uint256", + name: "timestamp", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "addr", + type: "address", + }, + ], + name: "getEthBalance", + outputs: [ + { + internalType: "uint256", + name: "balance", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getLastBlockHash", + outputs: [ + { + internalType: "bytes32", + name: "blockHash", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bool", + name: "requireSuccess", + type: "bool", + }, + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bytes", + name: "callData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Call[]", + name: "calls", + type: "tuple[]", + }, + ], + name: "tryAggregate", + outputs: [ + { + components: [ + { + internalType: "bool", + name: "success", + type: "bool", + }, + { + internalType: "bytes", + name: "returnData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Result[]", + name: "returnData", + type: "tuple[]", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "bool", + name: "requireSuccess", + type: "bool", + }, + { + components: [ + { + internalType: "address", + name: "target", + type: "address", + }, + { + internalType: "bytes", + name: "callData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Call[]", + name: "calls", + type: "tuple[]", + }, + ], + name: "tryBlockAndAggregate", + outputs: [ + { + internalType: "uint256", + name: "blockNumber", + type: "uint256", + }, + { + internalType: "bytes32", + name: "blockHash", + type: "bytes32", + }, + { + components: [ + { + internalType: "bool", + name: "success", + type: "bool", + }, + { + internalType: "bytes", + name: "returnData", + type: "bytes", + }, + ], + internalType: "struct Multicall3.Result[]", + name: "returnData", + type: "tuple[]", + }, + ], + stateMutability: "payable", + type: "function", + }, +] as const; + +export class Multicall3__factory { + static readonly abi = _abi; + static createInterface(): Multicall3Interface { + return new utils.Interface(_abi) as Multicall3Interface; + } + static connect(address: string, signerOrProvider: Signer | Provider): Multicall3 { + return new Contract(address, _abi, signerOrProvider) as Multicall3; + } +} diff --git a/src/utils/abi/typechain/factories/index.ts b/src/utils/abi/typechain/factories/index.ts new file mode 100644 index 000000000..0a9422c46 --- /dev/null +++ b/src/utils/abi/typechain/factories/index.ts @@ -0,0 +1,4 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export { Multicall3__factory } from "./Multicall3__factory"; diff --git a/src/utils/abi/typechain/index.ts b/src/utils/abi/typechain/index.ts new file mode 100644 index 000000000..e467ad439 --- /dev/null +++ b/src/utils/abi/typechain/index.ts @@ -0,0 +1,6 @@ +/* Autogenerated file. Do not edit manually. */ +/* tslint:disable */ +/* eslint-disable */ +export type { Multicall3 } from "./Multicall3"; +export * as factories from "./factories"; +export { Multicall3__factory } from "./factories/Multicall3__factory"; diff --git a/test/abi.ts b/test/abi.ts index 5b632bbf2..7c36d955d 100644 --- a/test/abi.ts +++ b/test/abi.ts @@ -11,6 +11,8 @@ describe("ABI Utils", () => { // trailing '.json', since readdir() returns the full filename, but callers should only supply the ABI name. abiFiles = abiFiles .filter((fileName) => !fileName.startsWith(".")) + // filter out barrel file + .filter((fileName) => !(fileName === "index.ts")) .map((fileName) => fileName.slice(0, fileName.lastIndexOf(".json"))); for (const abiFile of abiFiles) { diff --git a/test/multicall.test.ts b/test/multicall.test.ts new file mode 100644 index 000000000..4f392e8ef --- /dev/null +++ b/test/multicall.test.ts @@ -0,0 +1,46 @@ +import { CHAIN_IDs } from "@across-protocol/constants"; +import { getMulticall3, getMulticallAddress } from "../src/utils/Multicall"; +import { expect, waffle } from "./utils"; + +describe("getMulticallAddress", () => { + it("should return the deterministic multicall address for a chain in DETERMINISTIC_MULTICALL_CHAINS", () => { + const chainId = CHAIN_IDs.ARBITRUM; + const address = getMulticallAddress(chainId); + + expect(address).to.be.eq("0xcA11bde05977b3631167028862bE2a173976CA11"); + }); + + it("should return the non-deterministic multicall address for ZK_SYNC", () => { + const chainId = CHAIN_IDs.ZK_SYNC; + const address = getMulticallAddress(chainId); + + expect(address).to.be.eq("0xF9cda624FBC7e059355ce98a31693d299FACd963"); + }); + + it("should return undefined for an unknown chainId", () => { + const chainId = 9999; // random chain + const address = getMulticallAddress(chainId); + + expect(address).to.be.undefined; + }); +}); + +describe("getMulticall3", () => { + it("should return undefined for an unsupported chainId", () => { + const chainId = 100; // Unsupported chain (Mumbai) + const provider = waffle.provider; + const multicall = getMulticall3(chainId, provider); + + expect(multicall).to.be.undefined; + }); + + it("should return a Multicall3 instance for a supported chainId", () => { + const chainId = CHAIN_IDs.ARBITRUM; + const provider = waffle.provider; + const multicall = getMulticall3(chainId, provider); + + expect(multicall).to.not.be.undefined; + + expect(multicall?.aggregate).to.be.a("function"); + }); +}); diff --git a/test/utils/index.ts b/test/utils/index.ts index 863f1e571..91f17f9c0 100644 --- a/test/utils/index.ts +++ b/test/utils/index.ts @@ -1,5 +1,5 @@ export * as contractsV2Utils from "@across-protocol/contracts/dist/test-utils"; -export { ethers } from "hardhat"; +export { ethers, waffle } from "hardhat"; export { smock } from "@defi-wonderland/smock"; export * from "./utils"; diff --git a/tsconfig.json b/tsconfig.json index 2614cc937..1ba5139d7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,8 @@ "module": "CommonJS", "target": "ES5", "lib": ["dom", "esnext"], + // allow bundling of json files + "resolveJsonModule": true, "importHelpers": true, // output .d.ts declaration files for consumers "declaration": true,