├── .env ├── .env.example ├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── push.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .husky ├── .gitignore ├── pre-commit └── prepare-commit-msg ├── .prettierrc ├── LICENSE ├── README.md ├── contracts └── Multicall3.sol ├── foundry.toml ├── package.json ├── src ├── abis │ └── Multicall3.json ├── contracts │ ├── Multicall3.ts │ ├── common.ts │ ├── factories │ │ ├── Multicall3__factory.ts │ │ └── index.ts │ └── index.ts ├── ethers.ts └── index.ts ├── test ├── abis │ ├── Morpho.json │ └── Uni.json └── index.spec.ts ├── tsconfig.build.json ├── tsconfig.json └── yarn.lock /.env: -------------------------------------------------------------------------------- 1 | # Local env vars for debugging 2 | TS_NODE_IGNORE="false" 3 | TS_NODE_FILES="true" -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | HTTP_RPC_URL= 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/types/global.d.ts -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": ["./tsconfig.json"] 5 | }, 6 | "plugins": ["@typescript-eslint", "node"], 7 | "extends": ["plugin:node/recommended", "plugin:@typescript-eslint/eslint-recommended"], 8 | "rules": { 9 | "node/no-missing-import": "off", 10 | "node/no-unsupported-features/es-syntax": "off", 11 | "node/shebang": "off" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the repository to show as TypeScript rather than JS in GitHub 2 | *.js linguist-detectable=false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "🐛 Bug Report" 3 | about: Report a reproducible bug or regression. 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Current Behavior 11 | 12 | 13 | 14 | ## Expected Behavior 15 | 16 | 17 | 18 | ## Steps to Reproduce the Problem 19 | 20 | 1. 21 | 1. 22 | 1. 23 | 24 | ## Environment 25 | 26 | - Version: 27 | - Platform: 28 | - Node.js Version: 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🌈 Feature request 3 | about: Suggest an amazing new idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Feature Request 11 | 12 | **Is your feature request related to a problem? Please describe.** 13 | 14 | 15 | **Describe the solution you'd like** 16 | 17 | 18 | **Describe alternatives you've considered** 19 | 20 | 21 | ## Are you willing to resolve this issue by submitting a Pull Request? 22 | 23 | 26 | 27 | - [ ] Yes, I have the time, and I know how to start. 28 | - [ ] Yes, I have the time, but I don't know how to start. I would need guidance. 29 | - [ ] No, I don't have the time, although I believe I could do it if I had the time... 30 | - [ ] No, I don't have the time and I wouldn't even know how to start. 31 | 32 | 35 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ### Description of change 9 | 10 | 23 | 24 | ### Pull-Request Checklist 25 | 26 | 31 | 32 | - [ ] Code is up-to-date with the `main` branch 33 | - [ ] `npm run lint` passes with this change 34 | - [ ] `npm run test` passes with this change 35 | - [ ] This pull request links relevant issues as `Fixes #0000` 36 | - [ ] There are new or updated unit tests validating the change 37 | - [ ] Documentation has been updated to reflect this change 38 | - [ ] The new commits follow conventions outlined in the [conventional commit spec](https://www.conventionalcommits.org/en/v1.0.0/) 39 | 40 | 43 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: Push 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - next 8 | 9 | jobs: 10 | test: 11 | uses: morpho-labs/ethers-multicall/.github/workflows/test.yml@main 12 | 13 | release: 14 | needs: test 15 | 16 | uses: morpho-labs/ethers-multicall/.github/workflows/release.yml@main 17 | secrets: inherit 18 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | node-version: 7 | type: string 8 | default: lts/* 9 | secrets: 10 | NPM_TOKEN: 11 | required: true 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | semantic-release: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v3 24 | 25 | - name: Setup Node.js ${{ inputs.node-version }} 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: ${{ inputs.node-version }} 29 | cache: yarn 30 | 31 | - name: Install dependencies 32 | run: yarn --frozen-lockfile 33 | 34 | - name: Build package 35 | run: yarn build 36 | 37 | - name: Publish package 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 41 | run: npx semantic-release 42 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Jest Test Suite 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - src/** 7 | - test/** 8 | - package.json 9 | - yarn.lock 10 | workflow_call: 11 | 12 | jobs: 13 | jest: 14 | runs-on: ubuntu-latest 15 | if: github.head_ref != 'next' # already triggered by push 16 | 17 | strategy: 18 | matrix: 19 | node-version: [14.x, 16.x, 18.x] 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v3 24 | 25 | - name: Setup Node.js ${{ matrix.node-version }} 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | cache: yarn 30 | 31 | - name: Install dependencies 32 | run: yarn --frozen-lockfile 33 | 34 | - name: Run Jest test suite 35 | run: yarn test 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env.test 73 | .env.local 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | 118 | # Compiled code 119 | lib/ 120 | cache/ 121 | .vscode 122 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.husky/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | exec ⚡🚀 Call multiple view functions, from multiple Smart Contracts, in a single RPC query! 13 | 14 | Querying an RPC endpoint can be very costly (**100+ queries**) when loading data from multiple smart contracts. 15 | With multicall, batch these queries into a single, on-chain query, without additional over-head! 16 | 17 | This is the standalone package of the library formerly created & used by [Zapper](https://github.com/Zapper-fi/studio/tree/main/src/multicall). 18 | 19 | ## Install 20 | 21 | ```bash 22 | npm install @morpho-labs/ethers-multicall 23 | ``` 24 | 25 | ```bash 26 | yarn add @morpho-labs/ethers-multicall 27 | ``` 28 | 29 | ## Usage 30 | 31 | ```typescript 32 | import { ethers } from "ethers"; 33 | 34 | import { EthersMulticall } from "@morpho-labs/ethers-multicall"; 35 | 36 | const provider = new ethers.providers.JsonRpcBatchProvider("..."); 37 | const multicall = new EthersMulticall(provider); 38 | 39 | const uni = multicall.wrap( 40 | new ethers.Contract("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", UniswapAbi) 41 | ); // make sure to always wrap contracts to benefit from multicalls 42 | 43 | Promise.all([ 44 | uni.name(), 45 | uni.symbol(), 46 | uni.decimals(), 47 | uni.inexistantFunction().catch(() => "default value"), 48 | ]).then(console.log); 49 | ``` 50 | 51 | [build-img]: https://github.com/morpho-labs/ethers-multicall/actions/workflows/release.yml/badge.svg 52 | [build-url]: https://github.com/morpho-labs/ethers-multicall/actions/workflows/release.yml 53 | [downloads-img]: https://img.shields.io/npm/dt/@morpho-labs/ethers-multicall 54 | [downloads-url]: https://www.npmtrends.com/@morpho-labs/ethers-multicall 55 | [npm-img]: https://img.shields.io/npm/v/@morpho-labs/ethers-multicall 56 | [npm-url]: https://www.npmjs.com/package/@morpho-labs/ethers-multicall 57 | [issues-img]: https://img.shields.io/github/issues/morpho-labs/ethers-multicall 58 | [issues-url]: https://github.com/morpho-labs/ethers-multicall/issues 59 | [codecov-img]: https://codecov.io/gh/morpho-labs/ethers-multicall/branch/main/graph/badge.svg 60 | [codecov-url]: https://codecov.io/gh/morpho-labs/ethers-multicall 61 | [semantic-release-img]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg 62 | [semantic-release-url]: https://github.com/semantic-release/semantic-release 63 | [commitizen-img]: https://img.shields.io/badge/commitizen-friendly-brightgreen.svg 64 | [commitizen-url]: http://commitizen.github.io/cz-cli/ 65 | -------------------------------------------------------------------------------- /contracts/Multicall3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.12; 3 | 4 | /// @title Multicall3 5 | /// @notice Aggregate results from multiple function calls 6 | /// @dev Multicall & Multicall2 backwards-compatible 7 | /// @dev Aggregate methods are marked `payable` to save 24 gas per call 8 | /// @author Michael Elliot 9 | /// @author Joshua Levine 10 | /// @author Nick Johnson 11 | /// @author Andreas Bigger 12 | /// @author Matt Solomon 13 | contract Multicall3 { 14 | struct Call { 15 | address target; 16 | bytes callData; 17 | } 18 | 19 | struct Call3 { 20 | address target; 21 | bool allowFailure; 22 | bytes callData; 23 | } 24 | 25 | struct Call3Value { 26 | address target; 27 | bool allowFailure; 28 | uint256 value; 29 | bytes callData; 30 | } 31 | 32 | struct Result { 33 | bool success; 34 | bytes returnData; 35 | } 36 | 37 | /// @notice Backwards-compatible call aggregation with Multicall 38 | /// @param calls An array of Call structs 39 | /// @return blockNumber The block number where the calls were executed 40 | /// @return returnData An array of bytes containing the responses 41 | function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData) { 42 | blockNumber = block.number; 43 | uint256 length = calls.length; 44 | returnData = new bytes[](length); 45 | Call calldata call; 46 | for (uint256 i = 0; i < length;) { 47 | bool success; 48 | call = calls[i]; 49 | (success, returnData[i]) = call.target.call(call.callData); 50 | require(success, "Multicall3: call failed"); 51 | unchecked { ++i; } 52 | } 53 | } 54 | 55 | /// @notice Backwards-compatible with Multicall2 56 | /// @notice Aggregate calls without requiring success 57 | /// @param requireSuccess If true, require all calls to succeed 58 | /// @param calls An array of Call structs 59 | /// @return returnData An array of Result structs 60 | function tryAggregate(bool requireSuccess, Call[] calldata calls) public payable returns (Result[] memory returnData) { 61 | uint256 length = calls.length; 62 | returnData = new Result[](length); 63 | Call calldata call; 64 | for (uint256 i = 0; i < length;) { 65 | Result memory result = returnData[i]; 66 | call = calls[i]; 67 | (result.success, result.returnData) = call.target.call(call.callData); 68 | if (requireSuccess) require(result.success, "Multicall3: call failed"); 69 | unchecked { ++i; } 70 | } 71 | } 72 | 73 | /// @notice Backwards-compatible with Multicall2 74 | /// @notice Aggregate calls and allow failures using tryAggregate 75 | /// @param calls An array of Call structs 76 | /// @return blockNumber The block number where the calls were executed 77 | /// @return blockHash The hash of the block where the calls were executed 78 | /// @return returnData An array of Result structs 79 | function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { 80 | blockNumber = block.number; 81 | blockHash = blockhash(block.number); 82 | returnData = tryAggregate(requireSuccess, calls); 83 | } 84 | 85 | /// @notice Backwards-compatible with Multicall2 86 | /// @notice Aggregate calls and allow failures using tryAggregate 87 | /// @param calls An array of Call structs 88 | /// @return blockNumber The block number where the calls were executed 89 | /// @return blockHash The hash of the block where the calls were executed 90 | /// @return returnData An array of Result structs 91 | function blockAndAggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) { 92 | (blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls); 93 | } 94 | 95 | /// @notice Aggregate calls, ensuring each returns success if required 96 | /// @param calls An array of Call3 structs 97 | /// @return returnData An array of Result structs 98 | function aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData) { 99 | uint256 length = calls.length; 100 | returnData = new Result[](length); 101 | Call3 calldata calli; 102 | for (uint256 i = 0; i < length;) { 103 | Result memory result = returnData[i]; 104 | calli = calls[i]; 105 | (result.success, result.returnData) = calli.target.call(calli.callData); 106 | assembly { 107 | // Revert if the call fails and failure is not allowed 108 | // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` 109 | if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { 110 | // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) 111 | mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) 112 | // set data offset 113 | mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) 114 | // set length of revert string 115 | mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) 116 | // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) 117 | mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) 118 | revert(0x00, 0x64) 119 | } 120 | } 121 | unchecked { ++i; } 122 | } 123 | } 124 | 125 | /// @notice Aggregate calls with a msg value 126 | /// @notice Reverts if msg.value is less than the sum of the call values 127 | /// @param calls An array of Call3Value structs 128 | /// @return returnData An array of Result structs 129 | function aggregate3Value(Call3Value[] calldata calls) public payable returns (Result[] memory returnData) { 130 | uint256 valAccumulator; 131 | uint256 length = calls.length; 132 | returnData = new Result[](length); 133 | Call3Value calldata calli; 134 | for (uint256 i = 0; i < length;) { 135 | Result memory result = returnData[i]; 136 | calli = calls[i]; 137 | uint256 val = calli.value; 138 | // Humanity will be a Type V Kardashev Civilization before this overflows - andreas 139 | // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256 140 | unchecked { valAccumulator += val; } 141 | (result.success, result.returnData) = calli.target.call{value: val}(calli.callData); 142 | assembly { 143 | // Revert if the call fails and failure is not allowed 144 | // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` 145 | if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { 146 | // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) 147 | mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) 148 | // set data offset 149 | mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) 150 | // set length of revert string 151 | mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) 152 | // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) 153 | mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) 154 | revert(0x00, 0x84) 155 | } 156 | } 157 | unchecked { ++i; } 158 | } 159 | // Finally, make sure the msg.value = SUM(call[0...i].value) 160 | require(msg.value == valAccumulator, "Multicall3: value mismatch"); 161 | } 162 | 163 | /// @notice Returns the block hash for the given block number 164 | /// @param blockNumber The block number 165 | function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) { 166 | blockHash = blockhash(blockNumber); 167 | } 168 | 169 | /// @notice Returns the block number 170 | function getBlockNumber() public view returns (uint256 blockNumber) { 171 | blockNumber = block.number; 172 | } 173 | 174 | /// @notice Returns the block coinbase 175 | function getCurrentBlockCoinbase() public view returns (address coinbase) { 176 | coinbase = block.coinbase; 177 | } 178 | 179 | /// @notice Returns the block difficulty 180 | function getCurrentBlockDifficulty() public view returns (uint256 difficulty) { 181 | difficulty = block.difficulty; 182 | } 183 | 184 | /// @notice Returns the block gas limit 185 | function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) { 186 | gaslimit = block.gaslimit; 187 | } 188 | 189 | /// @notice Returns the block timestamp 190 | function getCurrentBlockTimestamp() public view returns (uint256 timestamp) { 191 | timestamp = block.timestamp; 192 | } 193 | 194 | /// @notice Returns the (ETH) balance of a given address 195 | function getEthBalance(address addr) public view returns (uint256 balance) { 196 | balance = addr.balance; 197 | } 198 | 199 | /// @notice Returns the block hash of the last block 200 | function getLastBlockHash() public view returns (bytes32 blockHash) { 201 | unchecked { 202 | blockHash = blockhash(block.number - 1); 203 | } 204 | } 205 | 206 | /// @notice Gets the base fee of the given block 207 | /// @notice Can revert if the BASEFEE opcode is not implemented by the given chain 208 | function getBasefee() public view returns (uint256 basefee) { 209 | basefee = block.basefee; 210 | } 211 | 212 | /// @notice Returns the chain id 213 | function getChainId() public view returns (uint256 chainid) { 214 | chainid = block.chainid; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = "contracts" 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@morpho-labs/ethers-multicall", 3 | "version": "1.3.4", 4 | "description": "⚡🚀 Call multiple view functions, from multiple Smart Contracts, in a single RPC query!", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "lib/**/*" 8 | ], 9 | "scripts": { 10 | "build": "tsc --build ./tsconfig.build.json", 11 | "clean": "rm -rf ./lib/", 12 | "cm": "cz", 13 | "lint": "eslint ./src --fix", 14 | "prepare": "husky install", 15 | "test:watch": "jest --watch", 16 | "test": "jest --coverage", 17 | "typecheck": "tsc --noEmit", 18 | "type:multicall": "typechain --target ethers-v5 --out-dir src/contracts 'src/abis/*.json'" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/morpho-labs/ethers-multicall.git" 23 | }, 24 | "license": "MIT", 25 | "author": { 26 | "name": "Romain (Rubilmax) Milon", 27 | "email": "rmilon@gmail.com", 28 | "url": "https://github.com/rubilmax" 29 | }, 30 | "engines": { 31 | "node": ">=12.0" 32 | }, 33 | "keywords": [ 34 | "ethers", 35 | "multicall", 36 | "rpc", 37 | "call", 38 | "evm", 39 | "smart contract" 40 | ], 41 | "bugs": { 42 | "url": "https://github.com/morpho-labs/ethers-multicall/issues" 43 | }, 44 | "homepage": "https://github.com/morpho-labs/ethers-multicall#readme", 45 | "dependencies": { 46 | "dataloader": "^2.2.2", 47 | "ethers": "^5.0.0" 48 | }, 49 | "devDependencies": { 50 | "@ethersproject/abi": "^5.0.0", 51 | "@ethersproject/providers": "^5.0.0", 52 | "@trivago/prettier-plugin-sort-imports": "^4.0.0", 53 | "@typechain/ethers-v5": "^10.2.0", 54 | "@types/jest": "^29.4.0", 55 | "@types/lodash": "^4.14.191", 56 | "@typescript-eslint/eslint-plugin": "^5.53.0", 57 | "@typescript-eslint/parser": "^5.53.0", 58 | "commitizen": "^4.3.0", 59 | "conventional-changelog-conventionalcommits": "^5.0.0", 60 | "cz-conventional-changelog": "^3.3.0", 61 | "dotenv": "^16.0.3", 62 | "eslint": "^8.34.0", 63 | "eslint-config-prettier": "^8.6.0", 64 | "eslint-plugin-node": "^11.1.0", 65 | "eslint-plugin-prettier": "^4.2.1", 66 | "husky": "^8.0.3", 67 | "jest": "^29.4.3", 68 | "lint-staged": "^13.1.2", 69 | "lodash": "^4.17.21", 70 | "prettier": "^2.8.4", 71 | "ts-jest": "^29.0.5", 72 | "typechain": "^8.1.1", 73 | "typescript": "^5.0.2" 74 | }, 75 | "peerDependencies": { 76 | "@ethersproject/abi": "^5.0.0", 77 | "@ethersproject/providers": "^5.0.0", 78 | "ethers": "^5.0.0" 79 | }, 80 | "config": { 81 | "commitizen": { 82 | "path": "./node_modules/cz-conventional-changelog" 83 | } 84 | }, 85 | "publishConfig": { 86 | "access": "public" 87 | }, 88 | "lint-staged": { 89 | "*.ts": "eslint --cache --cache-location .eslintcache --fix" 90 | }, 91 | "release": { 92 | "branches": [ 93 | "main", 94 | "next" 95 | ], 96 | "plugins": [ 97 | [ 98 | "@semantic-release/commit-analyzer", 99 | { 100 | "preset": "conventionalcommits", 101 | "releaseRules": [ 102 | { 103 | "type": "build", 104 | "scope": "deps", 105 | "release": "patch" 106 | } 107 | ] 108 | } 109 | ], 110 | [ 111 | "@semantic-release/release-notes-generator", 112 | { 113 | "preset": "conventionalcommits", 114 | "presetConfig": { 115 | "types": [ 116 | { 117 | "type": "feat", 118 | "section": "Features" 119 | }, 120 | { 121 | "type": "fix", 122 | "section": "Bug Fixes" 123 | }, 124 | { 125 | "type": "build", 126 | "section": "Dependencies and Other Build Updates", 127 | "hidden": false 128 | } 129 | ] 130 | } 131 | } 132 | ], 133 | "@semantic-release/npm", 134 | "@semantic-release/github" 135 | ] 136 | }, 137 | "jest": { 138 | "preset": "ts-jest", 139 | "testEnvironment": "node", 140 | "testMatch": [ 141 | "**/test/**/*.spec.ts" 142 | ], 143 | "collectCoverageFrom": [ 144 | "/src/**/*.ts", 145 | "!/src/types/**/*.ts" 146 | ], 147 | "globals": { 148 | "ts-jest": { 149 | "diagnostics": false, 150 | "isolatedModules": true 151 | } 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/abis/Multicall3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "components": [ 6 | { 7 | "internalType": "address", 8 | "name": "target", 9 | "type": "address" 10 | }, 11 | { 12 | "internalType": "bytes", 13 | "name": "callData", 14 | "type": "bytes" 15 | } 16 | ], 17 | "internalType": "struct Multicall3.Call[]", 18 | "name": "calls", 19 | "type": "tuple[]" 20 | } 21 | ], 22 | "name": "aggregate", 23 | "outputs": [ 24 | { 25 | "internalType": "uint256", 26 | "name": "blockNumber", 27 | "type": "uint256" 28 | }, 29 | { 30 | "internalType": "bytes[]", 31 | "name": "returnData", 32 | "type": "bytes[]" 33 | } 34 | ], 35 | "stateMutability": "payable", 36 | "type": "function" 37 | }, 38 | { 39 | "inputs": [ 40 | { 41 | "components": [ 42 | { 43 | "internalType": "address", 44 | "name": "target", 45 | "type": "address" 46 | }, 47 | { 48 | "internalType": "bool", 49 | "name": "allowFailure", 50 | "type": "bool" 51 | }, 52 | { 53 | "internalType": "bytes", 54 | "name": "callData", 55 | "type": "bytes" 56 | } 57 | ], 58 | "internalType": "struct Multicall3.Call3[]", 59 | "name": "calls", 60 | "type": "tuple[]" 61 | } 62 | ], 63 | "name": "aggregate3", 64 | "outputs": [ 65 | { 66 | "components": [ 67 | { 68 | "internalType": "bool", 69 | "name": "success", 70 | "type": "bool" 71 | }, 72 | { 73 | "internalType": "bytes", 74 | "name": "returnData", 75 | "type": "bytes" 76 | } 77 | ], 78 | "internalType": "struct Multicall3.Result[]", 79 | "name": "returnData", 80 | "type": "tuple[]" 81 | } 82 | ], 83 | "stateMutability": "payable", 84 | "type": "function" 85 | }, 86 | { 87 | "inputs": [ 88 | { 89 | "components": [ 90 | { 91 | "internalType": "address", 92 | "name": "target", 93 | "type": "address" 94 | }, 95 | { 96 | "internalType": "bool", 97 | "name": "allowFailure", 98 | "type": "bool" 99 | }, 100 | { 101 | "internalType": "uint256", 102 | "name": "value", 103 | "type": "uint256" 104 | }, 105 | { 106 | "internalType": "bytes", 107 | "name": "callData", 108 | "type": "bytes" 109 | } 110 | ], 111 | "internalType": "struct Multicall3.Call3Value[]", 112 | "name": "calls", 113 | "type": "tuple[]" 114 | } 115 | ], 116 | "name": "aggregate3Value", 117 | "outputs": [ 118 | { 119 | "components": [ 120 | { 121 | "internalType": "bool", 122 | "name": "success", 123 | "type": "bool" 124 | }, 125 | { 126 | "internalType": "bytes", 127 | "name": "returnData", 128 | "type": "bytes" 129 | } 130 | ], 131 | "internalType": "struct Multicall3.Result[]", 132 | "name": "returnData", 133 | "type": "tuple[]" 134 | } 135 | ], 136 | "stateMutability": "payable", 137 | "type": "function" 138 | }, 139 | { 140 | "inputs": [ 141 | { 142 | "components": [ 143 | { 144 | "internalType": "address", 145 | "name": "target", 146 | "type": "address" 147 | }, 148 | { 149 | "internalType": "bytes", 150 | "name": "callData", 151 | "type": "bytes" 152 | } 153 | ], 154 | "internalType": "struct Multicall3.Call[]", 155 | "name": "calls", 156 | "type": "tuple[]" 157 | } 158 | ], 159 | "name": "blockAndAggregate", 160 | "outputs": [ 161 | { 162 | "internalType": "uint256", 163 | "name": "blockNumber", 164 | "type": "uint256" 165 | }, 166 | { 167 | "internalType": "bytes32", 168 | "name": "blockHash", 169 | "type": "bytes32" 170 | }, 171 | { 172 | "components": [ 173 | { 174 | "internalType": "bool", 175 | "name": "success", 176 | "type": "bool" 177 | }, 178 | { 179 | "internalType": "bytes", 180 | "name": "returnData", 181 | "type": "bytes" 182 | } 183 | ], 184 | "internalType": "struct Multicall3.Result[]", 185 | "name": "returnData", 186 | "type": "tuple[]" 187 | } 188 | ], 189 | "stateMutability": "payable", 190 | "type": "function" 191 | }, 192 | { 193 | "inputs": [], 194 | "name": "getBasefee", 195 | "outputs": [ 196 | { 197 | "internalType": "uint256", 198 | "name": "basefee", 199 | "type": "uint256" 200 | } 201 | ], 202 | "stateMutability": "view", 203 | "type": "function" 204 | }, 205 | { 206 | "inputs": [ 207 | { 208 | "internalType": "uint256", 209 | "name": "blockNumber", 210 | "type": "uint256" 211 | } 212 | ], 213 | "name": "getBlockHash", 214 | "outputs": [ 215 | { 216 | "internalType": "bytes32", 217 | "name": "blockHash", 218 | "type": "bytes32" 219 | } 220 | ], 221 | "stateMutability": "view", 222 | "type": "function" 223 | }, 224 | { 225 | "inputs": [], 226 | "name": "getBlockNumber", 227 | "outputs": [ 228 | { 229 | "internalType": "uint256", 230 | "name": "blockNumber", 231 | "type": "uint256" 232 | } 233 | ], 234 | "stateMutability": "view", 235 | "type": "function" 236 | }, 237 | { 238 | "inputs": [], 239 | "name": "getChainId", 240 | "outputs": [ 241 | { 242 | "internalType": "uint256", 243 | "name": "chainid", 244 | "type": "uint256" 245 | } 246 | ], 247 | "stateMutability": "view", 248 | "type": "function" 249 | }, 250 | { 251 | "inputs": [], 252 | "name": "getCurrentBlockCoinbase", 253 | "outputs": [ 254 | { 255 | "internalType": "address", 256 | "name": "coinbase", 257 | "type": "address" 258 | } 259 | ], 260 | "stateMutability": "view", 261 | "type": "function" 262 | }, 263 | { 264 | "inputs": [], 265 | "name": "getCurrentBlockDifficulty", 266 | "outputs": [ 267 | { 268 | "internalType": "uint256", 269 | "name": "difficulty", 270 | "type": "uint256" 271 | } 272 | ], 273 | "stateMutability": "view", 274 | "type": "function" 275 | }, 276 | { 277 | "inputs": [], 278 | "name": "getCurrentBlockGasLimit", 279 | "outputs": [ 280 | { 281 | "internalType": "uint256", 282 | "name": "gaslimit", 283 | "type": "uint256" 284 | } 285 | ], 286 | "stateMutability": "view", 287 | "type": "function" 288 | }, 289 | { 290 | "inputs": [], 291 | "name": "getCurrentBlockTimestamp", 292 | "outputs": [ 293 | { 294 | "internalType": "uint256", 295 | "name": "timestamp", 296 | "type": "uint256" 297 | } 298 | ], 299 | "stateMutability": "view", 300 | "type": "function" 301 | }, 302 | { 303 | "inputs": [ 304 | { 305 | "internalType": "address", 306 | "name": "addr", 307 | "type": "address" 308 | } 309 | ], 310 | "name": "getEthBalance", 311 | "outputs": [ 312 | { 313 | "internalType": "uint256", 314 | "name": "balance", 315 | "type": "uint256" 316 | } 317 | ], 318 | "stateMutability": "view", 319 | "type": "function" 320 | }, 321 | { 322 | "inputs": [], 323 | "name": "getLastBlockHash", 324 | "outputs": [ 325 | { 326 | "internalType": "bytes32", 327 | "name": "blockHash", 328 | "type": "bytes32" 329 | } 330 | ], 331 | "stateMutability": "view", 332 | "type": "function" 333 | }, 334 | { 335 | "inputs": [ 336 | { 337 | "internalType": "bool", 338 | "name": "requireSuccess", 339 | "type": "bool" 340 | }, 341 | { 342 | "components": [ 343 | { 344 | "internalType": "address", 345 | "name": "target", 346 | "type": "address" 347 | }, 348 | { 349 | "internalType": "bytes", 350 | "name": "callData", 351 | "type": "bytes" 352 | } 353 | ], 354 | "internalType": "struct Multicall3.Call[]", 355 | "name": "calls", 356 | "type": "tuple[]" 357 | } 358 | ], 359 | "name": "tryAggregate", 360 | "outputs": [ 361 | { 362 | "components": [ 363 | { 364 | "internalType": "bool", 365 | "name": "success", 366 | "type": "bool" 367 | }, 368 | { 369 | "internalType": "bytes", 370 | "name": "returnData", 371 | "type": "bytes" 372 | } 373 | ], 374 | "internalType": "struct Multicall3.Result[]", 375 | "name": "returnData", 376 | "type": "tuple[]" 377 | } 378 | ], 379 | "stateMutability": "payable", 380 | "type": "function" 381 | }, 382 | { 383 | "inputs": [ 384 | { 385 | "internalType": "bool", 386 | "name": "requireSuccess", 387 | "type": "bool" 388 | }, 389 | { 390 | "components": [ 391 | { 392 | "internalType": "address", 393 | "name": "target", 394 | "type": "address" 395 | }, 396 | { 397 | "internalType": "bytes", 398 | "name": "callData", 399 | "type": "bytes" 400 | } 401 | ], 402 | "internalType": "struct Multicall3.Call[]", 403 | "name": "calls", 404 | "type": "tuple[]" 405 | } 406 | ], 407 | "name": "tryBlockAndAggregate", 408 | "outputs": [ 409 | { 410 | "internalType": "uint256", 411 | "name": "blockNumber", 412 | "type": "uint256" 413 | }, 414 | { 415 | "internalType": "bytes32", 416 | "name": "blockHash", 417 | "type": "bytes32" 418 | }, 419 | { 420 | "components": [ 421 | { 422 | "internalType": "bool", 423 | "name": "success", 424 | "type": "bool" 425 | }, 426 | { 427 | "internalType": "bytes", 428 | "name": "returnData", 429 | "type": "bytes" 430 | } 431 | ], 432 | "internalType": "struct Multicall3.Result[]", 433 | "name": "returnData", 434 | "type": "tuple[]" 435 | } 436 | ], 437 | "stateMutability": "payable", 438 | "type": "function" 439 | } 440 | ] 441 | -------------------------------------------------------------------------------- /src/contracts/Multicall3.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | 3 | /* tslint:disable */ 4 | 5 | /* eslint-disable */ 6 | import type { 7 | TypedEventFilter, 8 | TypedEvent, 9 | TypedListener, 10 | OnEvent, 11 | PromiseOrValue, 12 | } from "./common"; 13 | import type { FunctionFragment, Result } from "@ethersproject/abi"; 14 | import type { Listener, Provider } from "@ethersproject/providers"; 15 | import type { 16 | BaseContract, 17 | BigNumber, 18 | BigNumberish, 19 | BytesLike, 20 | CallOverrides, 21 | ContractTransaction, 22 | PayableOverrides, 23 | PopulatedTransaction, 24 | Signer, 25 | utils, 26 | } from "ethers"; 27 | 28 | export declare namespace Multicall3 { 29 | export type CallStruct = { 30 | target: PromiseOrValue; 31 | callData: PromiseOrValue; 32 | }; 33 | 34 | export type CallStructOutput = [string, string] & { 35 | target: string; 36 | callData: string; 37 | }; 38 | 39 | export type Call3Struct = { 40 | target: PromiseOrValue; 41 | allowFailure: PromiseOrValue; 42 | callData: PromiseOrValue; 43 | }; 44 | 45 | export type Call3StructOutput = [string, boolean, string] & { 46 | target: string; 47 | allowFailure: boolean; 48 | callData: string; 49 | }; 50 | 51 | export type ResultStruct = { 52 | success: PromiseOrValue; 53 | returnData: PromiseOrValue; 54 | }; 55 | 56 | export type ResultStructOutput = [boolean, string] & { 57 | success: boolean; 58 | returnData: string; 59 | }; 60 | 61 | export type Call3ValueStruct = { 62 | target: PromiseOrValue; 63 | allowFailure: PromiseOrValue; 64 | value: PromiseOrValue; 65 | callData: PromiseOrValue; 66 | }; 67 | 68 | export type Call3ValueStructOutput = [string, boolean, BigNumber, string] & { 69 | target: string; 70 | allowFailure: boolean; 71 | value: BigNumber; 72 | callData: string; 73 | }; 74 | } 75 | 76 | export interface Multicall3Interface extends utils.Interface { 77 | functions: { 78 | "aggregate((address,bytes)[])": FunctionFragment; 79 | "aggregate3((address,bool,bytes)[])": FunctionFragment; 80 | "aggregate3Value((address,bool,uint256,bytes)[])": FunctionFragment; 81 | "blockAndAggregate((address,bytes)[])": FunctionFragment; 82 | "getBasefee()": FunctionFragment; 83 | "getBlockHash(uint256)": FunctionFragment; 84 | "getBlockNumber()": FunctionFragment; 85 | "getChainId()": FunctionFragment; 86 | "getCurrentBlockCoinbase()": FunctionFragment; 87 | "getCurrentBlockDifficulty()": FunctionFragment; 88 | "getCurrentBlockGasLimit()": FunctionFragment; 89 | "getCurrentBlockTimestamp()": FunctionFragment; 90 | "getEthBalance(address)": FunctionFragment; 91 | "getLastBlockHash()": FunctionFragment; 92 | "tryAggregate(bool,(address,bytes)[])": FunctionFragment; 93 | "tryBlockAndAggregate(bool,(address,bytes)[])": FunctionFragment; 94 | }; 95 | 96 | getFunction( 97 | nameOrSignatureOrTopic: 98 | | "aggregate" 99 | | "aggregate3" 100 | | "aggregate3Value" 101 | | "blockAndAggregate" 102 | | "getBasefee" 103 | | "getBlockHash" 104 | | "getBlockNumber" 105 | | "getChainId" 106 | | "getCurrentBlockCoinbase" 107 | | "getCurrentBlockDifficulty" 108 | | "getCurrentBlockGasLimit" 109 | | "getCurrentBlockTimestamp" 110 | | "getEthBalance" 111 | | "getLastBlockHash" 112 | | "tryAggregate" 113 | | "tryBlockAndAggregate" 114 | ): FunctionFragment; 115 | 116 | encodeFunctionData( 117 | functionFragment: "aggregate", 118 | values: [Multicall3.CallStruct[]] 119 | ): string; 120 | encodeFunctionData( 121 | functionFragment: "aggregate3", 122 | values: [Multicall3.Call3Struct[]] 123 | ): string; 124 | encodeFunctionData( 125 | functionFragment: "aggregate3Value", 126 | values: [Multicall3.Call3ValueStruct[]] 127 | ): string; 128 | encodeFunctionData( 129 | functionFragment: "blockAndAggregate", 130 | values: [Multicall3.CallStruct[]] 131 | ): string; 132 | encodeFunctionData( 133 | functionFragment: "getBasefee", 134 | values?: undefined 135 | ): string; 136 | encodeFunctionData( 137 | functionFragment: "getBlockHash", 138 | values: [PromiseOrValue] 139 | ): string; 140 | encodeFunctionData( 141 | functionFragment: "getBlockNumber", 142 | values?: undefined 143 | ): string; 144 | encodeFunctionData( 145 | functionFragment: "getChainId", 146 | values?: undefined 147 | ): string; 148 | encodeFunctionData( 149 | functionFragment: "getCurrentBlockCoinbase", 150 | values?: undefined 151 | ): string; 152 | encodeFunctionData( 153 | functionFragment: "getCurrentBlockDifficulty", 154 | values?: undefined 155 | ): string; 156 | encodeFunctionData( 157 | functionFragment: "getCurrentBlockGasLimit", 158 | values?: undefined 159 | ): string; 160 | encodeFunctionData( 161 | functionFragment: "getCurrentBlockTimestamp", 162 | values?: undefined 163 | ): string; 164 | encodeFunctionData( 165 | functionFragment: "getEthBalance", 166 | values: [PromiseOrValue] 167 | ): string; 168 | encodeFunctionData( 169 | functionFragment: "getLastBlockHash", 170 | values?: undefined 171 | ): string; 172 | encodeFunctionData( 173 | functionFragment: "tryAggregate", 174 | values: [PromiseOrValue, Multicall3.CallStruct[]] 175 | ): string; 176 | encodeFunctionData( 177 | functionFragment: "tryBlockAndAggregate", 178 | values: [PromiseOrValue, Multicall3.CallStruct[]] 179 | ): string; 180 | 181 | decodeFunctionResult(functionFragment: "aggregate", data: BytesLike): Result; 182 | decodeFunctionResult(functionFragment: "aggregate3", data: BytesLike): Result; 183 | decodeFunctionResult( 184 | functionFragment: "aggregate3Value", 185 | data: BytesLike 186 | ): Result; 187 | decodeFunctionResult( 188 | functionFragment: "blockAndAggregate", 189 | data: BytesLike 190 | ): Result; 191 | decodeFunctionResult(functionFragment: "getBasefee", data: BytesLike): Result; 192 | decodeFunctionResult( 193 | functionFragment: "getBlockHash", 194 | data: BytesLike 195 | ): Result; 196 | decodeFunctionResult( 197 | functionFragment: "getBlockNumber", 198 | data: BytesLike 199 | ): Result; 200 | decodeFunctionResult(functionFragment: "getChainId", data: BytesLike): Result; 201 | decodeFunctionResult( 202 | functionFragment: "getCurrentBlockCoinbase", 203 | data: BytesLike 204 | ): Result; 205 | decodeFunctionResult( 206 | functionFragment: "getCurrentBlockDifficulty", 207 | data: BytesLike 208 | ): Result; 209 | decodeFunctionResult( 210 | functionFragment: "getCurrentBlockGasLimit", 211 | data: BytesLike 212 | ): Result; 213 | decodeFunctionResult( 214 | functionFragment: "getCurrentBlockTimestamp", 215 | data: BytesLike 216 | ): Result; 217 | decodeFunctionResult( 218 | functionFragment: "getEthBalance", 219 | data: BytesLike 220 | ): Result; 221 | decodeFunctionResult( 222 | functionFragment: "getLastBlockHash", 223 | data: BytesLike 224 | ): Result; 225 | decodeFunctionResult( 226 | functionFragment: "tryAggregate", 227 | data: BytesLike 228 | ): Result; 229 | decodeFunctionResult( 230 | functionFragment: "tryBlockAndAggregate", 231 | data: BytesLike 232 | ): Result; 233 | 234 | events: {}; 235 | } 236 | 237 | export interface Multicall3 extends BaseContract { 238 | connect(signerOrProvider: Signer | Provider | string): this; 239 | attach(addressOrName: string): this; 240 | deployed(): Promise; 241 | 242 | interface: Multicall3Interface; 243 | 244 | queryFilter( 245 | event: TypedEventFilter, 246 | fromBlockOrBlockhash?: string | number | undefined, 247 | toBlock?: string | number | undefined 248 | ): Promise>; 249 | 250 | listeners( 251 | eventFilter?: TypedEventFilter 252 | ): Array>; 253 | listeners(eventName?: string): Array; 254 | removeAllListeners( 255 | eventFilter: TypedEventFilter 256 | ): this; 257 | removeAllListeners(eventName?: string): this; 258 | off: OnEvent; 259 | on: OnEvent; 260 | once: OnEvent; 261 | removeListener: OnEvent; 262 | 263 | functions: { 264 | aggregate( 265 | calls: Multicall3.CallStruct[], 266 | overrides?: PayableOverrides & { from?: PromiseOrValue } 267 | ): Promise; 268 | 269 | aggregate3( 270 | calls: Multicall3.Call3Struct[], 271 | overrides?: PayableOverrides & { from?: PromiseOrValue } 272 | ): Promise; 273 | 274 | aggregate3Value( 275 | calls: Multicall3.Call3ValueStruct[], 276 | overrides?: PayableOverrides & { from?: PromiseOrValue } 277 | ): Promise; 278 | 279 | blockAndAggregate( 280 | calls: Multicall3.CallStruct[], 281 | overrides?: PayableOverrides & { from?: PromiseOrValue } 282 | ): Promise; 283 | 284 | getBasefee( 285 | overrides?: CallOverrides 286 | ): Promise<[BigNumber] & { basefee: BigNumber }>; 287 | 288 | getBlockHash( 289 | blockNumber: PromiseOrValue, 290 | overrides?: CallOverrides 291 | ): Promise<[string] & { blockHash: string }>; 292 | 293 | getBlockNumber( 294 | overrides?: CallOverrides 295 | ): Promise<[BigNumber] & { blockNumber: BigNumber }>; 296 | 297 | getChainId( 298 | overrides?: CallOverrides 299 | ): Promise<[BigNumber] & { chainid: BigNumber }>; 300 | 301 | getCurrentBlockCoinbase( 302 | overrides?: CallOverrides 303 | ): Promise<[string] & { coinbase: string }>; 304 | 305 | getCurrentBlockDifficulty( 306 | overrides?: CallOverrides 307 | ): Promise<[BigNumber] & { difficulty: BigNumber }>; 308 | 309 | getCurrentBlockGasLimit( 310 | overrides?: CallOverrides 311 | ): Promise<[BigNumber] & { gaslimit: BigNumber }>; 312 | 313 | getCurrentBlockTimestamp( 314 | overrides?: CallOverrides 315 | ): Promise<[BigNumber] & { timestamp: BigNumber }>; 316 | 317 | getEthBalance( 318 | addr: PromiseOrValue, 319 | overrides?: CallOverrides 320 | ): Promise<[BigNumber] & { balance: BigNumber }>; 321 | 322 | getLastBlockHash( 323 | overrides?: CallOverrides 324 | ): Promise<[string] & { blockHash: string }>; 325 | 326 | tryAggregate( 327 | requireSuccess: PromiseOrValue, 328 | calls: Multicall3.CallStruct[], 329 | overrides?: PayableOverrides & { from?: PromiseOrValue } 330 | ): Promise; 331 | 332 | tryBlockAndAggregate( 333 | requireSuccess: PromiseOrValue, 334 | calls: Multicall3.CallStruct[], 335 | overrides?: PayableOverrides & { from?: PromiseOrValue } 336 | ): Promise; 337 | }; 338 | 339 | aggregate( 340 | calls: Multicall3.CallStruct[], 341 | overrides?: PayableOverrides & { from?: PromiseOrValue } 342 | ): Promise; 343 | 344 | aggregate3( 345 | calls: Multicall3.Call3Struct[], 346 | overrides?: PayableOverrides & { from?: PromiseOrValue } 347 | ): Promise; 348 | 349 | aggregate3Value( 350 | calls: Multicall3.Call3ValueStruct[], 351 | overrides?: PayableOverrides & { from?: PromiseOrValue } 352 | ): Promise; 353 | 354 | blockAndAggregate( 355 | calls: Multicall3.CallStruct[], 356 | overrides?: PayableOverrides & { from?: PromiseOrValue } 357 | ): Promise; 358 | 359 | getBasefee(overrides?: CallOverrides): Promise; 360 | 361 | getBlockHash( 362 | blockNumber: PromiseOrValue, 363 | overrides?: CallOverrides 364 | ): Promise; 365 | 366 | getBlockNumber(overrides?: CallOverrides): Promise; 367 | 368 | getChainId(overrides?: CallOverrides): Promise; 369 | 370 | getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; 371 | 372 | getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; 373 | 374 | getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; 375 | 376 | getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; 377 | 378 | getEthBalance( 379 | addr: PromiseOrValue, 380 | overrides?: CallOverrides 381 | ): Promise; 382 | 383 | getLastBlockHash(overrides?: CallOverrides): Promise; 384 | 385 | tryAggregate( 386 | requireSuccess: PromiseOrValue, 387 | calls: Multicall3.CallStruct[], 388 | overrides?: PayableOverrides & { from?: PromiseOrValue } 389 | ): Promise; 390 | 391 | tryBlockAndAggregate( 392 | requireSuccess: PromiseOrValue, 393 | calls: Multicall3.CallStruct[], 394 | overrides?: PayableOverrides & { from?: PromiseOrValue } 395 | ): Promise; 396 | 397 | callStatic: { 398 | aggregate( 399 | calls: Multicall3.CallStruct[], 400 | overrides?: CallOverrides 401 | ): Promise< 402 | [BigNumber, string[]] & { blockNumber: BigNumber; returnData: string[] } 403 | >; 404 | 405 | aggregate3( 406 | calls: Multicall3.Call3Struct[], 407 | overrides?: CallOverrides 408 | ): Promise; 409 | 410 | aggregate3Value( 411 | calls: Multicall3.Call3ValueStruct[], 412 | overrides?: CallOverrides 413 | ): Promise; 414 | 415 | blockAndAggregate( 416 | calls: Multicall3.CallStruct[], 417 | overrides?: CallOverrides 418 | ): Promise< 419 | [BigNumber, string, Multicall3.ResultStructOutput[]] & { 420 | blockNumber: BigNumber; 421 | blockHash: string; 422 | returnData: Multicall3.ResultStructOutput[]; 423 | } 424 | >; 425 | 426 | getBasefee(overrides?: CallOverrides): Promise; 427 | 428 | getBlockHash( 429 | blockNumber: PromiseOrValue, 430 | overrides?: CallOverrides 431 | ): Promise; 432 | 433 | getBlockNumber(overrides?: CallOverrides): Promise; 434 | 435 | getChainId(overrides?: CallOverrides): Promise; 436 | 437 | getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; 438 | 439 | getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; 440 | 441 | getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; 442 | 443 | getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; 444 | 445 | getEthBalance( 446 | addr: PromiseOrValue, 447 | overrides?: CallOverrides 448 | ): Promise; 449 | 450 | getLastBlockHash(overrides?: CallOverrides): Promise; 451 | 452 | tryAggregate( 453 | requireSuccess: PromiseOrValue, 454 | calls: Multicall3.CallStruct[], 455 | overrides?: CallOverrides 456 | ): Promise; 457 | 458 | tryBlockAndAggregate( 459 | requireSuccess: PromiseOrValue, 460 | calls: Multicall3.CallStruct[], 461 | overrides?: CallOverrides 462 | ): Promise< 463 | [BigNumber, string, Multicall3.ResultStructOutput[]] & { 464 | blockNumber: BigNumber; 465 | blockHash: string; 466 | returnData: Multicall3.ResultStructOutput[]; 467 | } 468 | >; 469 | }; 470 | 471 | filters: {}; 472 | 473 | estimateGas: { 474 | aggregate( 475 | calls: Multicall3.CallStruct[], 476 | overrides?: PayableOverrides & { from?: PromiseOrValue } 477 | ): Promise; 478 | 479 | aggregate3( 480 | calls: Multicall3.Call3Struct[], 481 | overrides?: PayableOverrides & { from?: PromiseOrValue } 482 | ): Promise; 483 | 484 | aggregate3Value( 485 | calls: Multicall3.Call3ValueStruct[], 486 | overrides?: PayableOverrides & { from?: PromiseOrValue } 487 | ): Promise; 488 | 489 | blockAndAggregate( 490 | calls: Multicall3.CallStruct[], 491 | overrides?: PayableOverrides & { from?: PromiseOrValue } 492 | ): Promise; 493 | 494 | getBasefee(overrides?: CallOverrides): Promise; 495 | 496 | getBlockHash( 497 | blockNumber: PromiseOrValue, 498 | overrides?: CallOverrides 499 | ): Promise; 500 | 501 | getBlockNumber(overrides?: CallOverrides): Promise; 502 | 503 | getChainId(overrides?: CallOverrides): Promise; 504 | 505 | getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; 506 | 507 | getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; 508 | 509 | getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; 510 | 511 | getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; 512 | 513 | getEthBalance( 514 | addr: PromiseOrValue, 515 | overrides?: CallOverrides 516 | ): Promise; 517 | 518 | getLastBlockHash(overrides?: CallOverrides): Promise; 519 | 520 | tryAggregate( 521 | requireSuccess: PromiseOrValue, 522 | calls: Multicall3.CallStruct[], 523 | overrides?: PayableOverrides & { from?: PromiseOrValue } 524 | ): Promise; 525 | 526 | tryBlockAndAggregate( 527 | requireSuccess: PromiseOrValue, 528 | calls: Multicall3.CallStruct[], 529 | overrides?: PayableOverrides & { from?: PromiseOrValue } 530 | ): Promise; 531 | }; 532 | 533 | populateTransaction: { 534 | aggregate( 535 | calls: Multicall3.CallStruct[], 536 | overrides?: PayableOverrides & { from?: PromiseOrValue } 537 | ): Promise; 538 | 539 | aggregate3( 540 | calls: Multicall3.Call3Struct[], 541 | overrides?: PayableOverrides & { from?: PromiseOrValue } 542 | ): Promise; 543 | 544 | aggregate3Value( 545 | calls: Multicall3.Call3ValueStruct[], 546 | overrides?: PayableOverrides & { from?: PromiseOrValue } 547 | ): Promise; 548 | 549 | blockAndAggregate( 550 | calls: Multicall3.CallStruct[], 551 | overrides?: PayableOverrides & { from?: PromiseOrValue } 552 | ): Promise; 553 | 554 | getBasefee(overrides?: CallOverrides): Promise; 555 | 556 | getBlockHash( 557 | blockNumber: PromiseOrValue, 558 | overrides?: CallOverrides 559 | ): Promise; 560 | 561 | getBlockNumber(overrides?: CallOverrides): Promise; 562 | 563 | getChainId(overrides?: CallOverrides): Promise; 564 | 565 | getCurrentBlockCoinbase( 566 | overrides?: CallOverrides 567 | ): Promise; 568 | 569 | getCurrentBlockDifficulty( 570 | overrides?: CallOverrides 571 | ): Promise; 572 | 573 | getCurrentBlockGasLimit( 574 | overrides?: CallOverrides 575 | ): Promise; 576 | 577 | getCurrentBlockTimestamp( 578 | overrides?: CallOverrides 579 | ): Promise; 580 | 581 | getEthBalance( 582 | addr: PromiseOrValue, 583 | overrides?: CallOverrides 584 | ): Promise; 585 | 586 | getLastBlockHash(overrides?: CallOverrides): Promise; 587 | 588 | tryAggregate( 589 | requireSuccess: PromiseOrValue, 590 | calls: Multicall3.CallStruct[], 591 | overrides?: PayableOverrides & { from?: PromiseOrValue } 592 | ): Promise; 593 | 594 | tryBlockAndAggregate( 595 | requireSuccess: PromiseOrValue, 596 | calls: Multicall3.CallStruct[], 597 | overrides?: PayableOverrides & { from?: PromiseOrValue } 598 | ): Promise; 599 | }; 600 | } 601 | -------------------------------------------------------------------------------- /src/contracts/common.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | 3 | /* tslint:disable */ 4 | 5 | /* eslint-disable */ 6 | import type { Listener } from "@ethersproject/providers"; 7 | import type { Event, EventFilter } from "ethers"; 8 | 9 | export interface TypedEvent< 10 | TArgsArray extends Array = any, 11 | TArgsObject = any 12 | > extends Event { 13 | args: TArgsArray & TArgsObject; 14 | } 15 | 16 | export interface TypedEventFilter<_TEvent extends TypedEvent> 17 | extends EventFilter {} 18 | 19 | export interface TypedListener { 20 | (...listenerArg: [...__TypechainArgsArray, TEvent]): void; 21 | } 22 | 23 | type __TypechainArgsArray = T extends TypedEvent ? U : never; 24 | 25 | export interface OnEvent { 26 | ( 27 | eventFilter: TypedEventFilter, 28 | listener: TypedListener 29 | ): TRes; 30 | (eventName: string, listener: Listener): TRes; 31 | } 32 | 33 | export type MinEthersFactory = { 34 | deploy(...a: ARGS[]): Promise; 35 | }; 36 | 37 | export type GetContractTypeFromFactory = F extends MinEthersFactory< 38 | infer C, 39 | any 40 | > 41 | ? C 42 | : never; 43 | 44 | export type GetARGsTypeFromFactory = F extends MinEthersFactory 45 | ? Parameters 46 | : never; 47 | 48 | export type PromiseOrValue = T | Promise; 49 | -------------------------------------------------------------------------------- /src/contracts/factories/Multicall3__factory.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | 3 | /* tslint:disable */ 4 | 5 | /* eslint-disable */ 6 | import type { Multicall3, Multicall3Interface } from "../Multicall3"; 7 | import type { Provider } from "@ethersproject/providers"; 8 | import { Contract, Signer, utils } from "ethers"; 9 | 10 | const _abi = [ 11 | { 12 | inputs: [ 13 | { 14 | components: [ 15 | { 16 | internalType: "address", 17 | name: "target", 18 | type: "address", 19 | }, 20 | { 21 | internalType: "bytes", 22 | name: "callData", 23 | type: "bytes", 24 | }, 25 | ], 26 | internalType: "struct Multicall3.Call[]", 27 | name: "calls", 28 | type: "tuple[]", 29 | }, 30 | ], 31 | name: "aggregate", 32 | outputs: [ 33 | { 34 | internalType: "uint256", 35 | name: "blockNumber", 36 | type: "uint256", 37 | }, 38 | { 39 | internalType: "bytes[]", 40 | name: "returnData", 41 | type: "bytes[]", 42 | }, 43 | ], 44 | stateMutability: "payable", 45 | type: "function", 46 | }, 47 | { 48 | inputs: [ 49 | { 50 | components: [ 51 | { 52 | internalType: "address", 53 | name: "target", 54 | type: "address", 55 | }, 56 | { 57 | internalType: "bool", 58 | name: "allowFailure", 59 | type: "bool", 60 | }, 61 | { 62 | internalType: "bytes", 63 | name: "callData", 64 | type: "bytes", 65 | }, 66 | ], 67 | internalType: "struct Multicall3.Call3[]", 68 | name: "calls", 69 | type: "tuple[]", 70 | }, 71 | ], 72 | name: "aggregate3", 73 | outputs: [ 74 | { 75 | components: [ 76 | { 77 | internalType: "bool", 78 | name: "success", 79 | type: "bool", 80 | }, 81 | { 82 | internalType: "bytes", 83 | name: "returnData", 84 | type: "bytes", 85 | }, 86 | ], 87 | internalType: "struct Multicall3.Result[]", 88 | name: "returnData", 89 | type: "tuple[]", 90 | }, 91 | ], 92 | stateMutability: "payable", 93 | type: "function", 94 | }, 95 | { 96 | inputs: [ 97 | { 98 | components: [ 99 | { 100 | internalType: "address", 101 | name: "target", 102 | type: "address", 103 | }, 104 | { 105 | internalType: "bool", 106 | name: "allowFailure", 107 | type: "bool", 108 | }, 109 | { 110 | internalType: "uint256", 111 | name: "value", 112 | type: "uint256", 113 | }, 114 | { 115 | internalType: "bytes", 116 | name: "callData", 117 | type: "bytes", 118 | }, 119 | ], 120 | internalType: "struct Multicall3.Call3Value[]", 121 | name: "calls", 122 | type: "tuple[]", 123 | }, 124 | ], 125 | name: "aggregate3Value", 126 | outputs: [ 127 | { 128 | components: [ 129 | { 130 | internalType: "bool", 131 | name: "success", 132 | type: "bool", 133 | }, 134 | { 135 | internalType: "bytes", 136 | name: "returnData", 137 | type: "bytes", 138 | }, 139 | ], 140 | internalType: "struct Multicall3.Result[]", 141 | name: "returnData", 142 | type: "tuple[]", 143 | }, 144 | ], 145 | stateMutability: "payable", 146 | type: "function", 147 | }, 148 | { 149 | inputs: [ 150 | { 151 | components: [ 152 | { 153 | internalType: "address", 154 | name: "target", 155 | type: "address", 156 | }, 157 | { 158 | internalType: "bytes", 159 | name: "callData", 160 | type: "bytes", 161 | }, 162 | ], 163 | internalType: "struct Multicall3.Call[]", 164 | name: "calls", 165 | type: "tuple[]", 166 | }, 167 | ], 168 | name: "blockAndAggregate", 169 | outputs: [ 170 | { 171 | internalType: "uint256", 172 | name: "blockNumber", 173 | type: "uint256", 174 | }, 175 | { 176 | internalType: "bytes32", 177 | name: "blockHash", 178 | type: "bytes32", 179 | }, 180 | { 181 | components: [ 182 | { 183 | internalType: "bool", 184 | name: "success", 185 | type: "bool", 186 | }, 187 | { 188 | internalType: "bytes", 189 | name: "returnData", 190 | type: "bytes", 191 | }, 192 | ], 193 | internalType: "struct Multicall3.Result[]", 194 | name: "returnData", 195 | type: "tuple[]", 196 | }, 197 | ], 198 | stateMutability: "payable", 199 | type: "function", 200 | }, 201 | { 202 | inputs: [], 203 | name: "getBasefee", 204 | outputs: [ 205 | { 206 | internalType: "uint256", 207 | name: "basefee", 208 | type: "uint256", 209 | }, 210 | ], 211 | stateMutability: "view", 212 | type: "function", 213 | }, 214 | { 215 | inputs: [ 216 | { 217 | internalType: "uint256", 218 | name: "blockNumber", 219 | type: "uint256", 220 | }, 221 | ], 222 | name: "getBlockHash", 223 | outputs: [ 224 | { 225 | internalType: "bytes32", 226 | name: "blockHash", 227 | type: "bytes32", 228 | }, 229 | ], 230 | stateMutability: "view", 231 | type: "function", 232 | }, 233 | { 234 | inputs: [], 235 | name: "getBlockNumber", 236 | outputs: [ 237 | { 238 | internalType: "uint256", 239 | name: "blockNumber", 240 | type: "uint256", 241 | }, 242 | ], 243 | stateMutability: "view", 244 | type: "function", 245 | }, 246 | { 247 | inputs: [], 248 | name: "getChainId", 249 | outputs: [ 250 | { 251 | internalType: "uint256", 252 | name: "chainid", 253 | type: "uint256", 254 | }, 255 | ], 256 | stateMutability: "view", 257 | type: "function", 258 | }, 259 | { 260 | inputs: [], 261 | name: "getCurrentBlockCoinbase", 262 | outputs: [ 263 | { 264 | internalType: "address", 265 | name: "coinbase", 266 | type: "address", 267 | }, 268 | ], 269 | stateMutability: "view", 270 | type: "function", 271 | }, 272 | { 273 | inputs: [], 274 | name: "getCurrentBlockDifficulty", 275 | outputs: [ 276 | { 277 | internalType: "uint256", 278 | name: "difficulty", 279 | type: "uint256", 280 | }, 281 | ], 282 | stateMutability: "view", 283 | type: "function", 284 | }, 285 | { 286 | inputs: [], 287 | name: "getCurrentBlockGasLimit", 288 | outputs: [ 289 | { 290 | internalType: "uint256", 291 | name: "gaslimit", 292 | type: "uint256", 293 | }, 294 | ], 295 | stateMutability: "view", 296 | type: "function", 297 | }, 298 | { 299 | inputs: [], 300 | name: "getCurrentBlockTimestamp", 301 | outputs: [ 302 | { 303 | internalType: "uint256", 304 | name: "timestamp", 305 | type: "uint256", 306 | }, 307 | ], 308 | stateMutability: "view", 309 | type: "function", 310 | }, 311 | { 312 | inputs: [ 313 | { 314 | internalType: "address", 315 | name: "addr", 316 | type: "address", 317 | }, 318 | ], 319 | name: "getEthBalance", 320 | outputs: [ 321 | { 322 | internalType: "uint256", 323 | name: "balance", 324 | type: "uint256", 325 | }, 326 | ], 327 | stateMutability: "view", 328 | type: "function", 329 | }, 330 | { 331 | inputs: [], 332 | name: "getLastBlockHash", 333 | outputs: [ 334 | { 335 | internalType: "bytes32", 336 | name: "blockHash", 337 | type: "bytes32", 338 | }, 339 | ], 340 | stateMutability: "view", 341 | type: "function", 342 | }, 343 | { 344 | inputs: [ 345 | { 346 | internalType: "bool", 347 | name: "requireSuccess", 348 | type: "bool", 349 | }, 350 | { 351 | components: [ 352 | { 353 | internalType: "address", 354 | name: "target", 355 | type: "address", 356 | }, 357 | { 358 | internalType: "bytes", 359 | name: "callData", 360 | type: "bytes", 361 | }, 362 | ], 363 | internalType: "struct Multicall3.Call[]", 364 | name: "calls", 365 | type: "tuple[]", 366 | }, 367 | ], 368 | name: "tryAggregate", 369 | outputs: [ 370 | { 371 | components: [ 372 | { 373 | internalType: "bool", 374 | name: "success", 375 | type: "bool", 376 | }, 377 | { 378 | internalType: "bytes", 379 | name: "returnData", 380 | type: "bytes", 381 | }, 382 | ], 383 | internalType: "struct Multicall3.Result[]", 384 | name: "returnData", 385 | type: "tuple[]", 386 | }, 387 | ], 388 | stateMutability: "payable", 389 | type: "function", 390 | }, 391 | { 392 | inputs: [ 393 | { 394 | internalType: "bool", 395 | name: "requireSuccess", 396 | type: "bool", 397 | }, 398 | { 399 | components: [ 400 | { 401 | internalType: "address", 402 | name: "target", 403 | type: "address", 404 | }, 405 | { 406 | internalType: "bytes", 407 | name: "callData", 408 | type: "bytes", 409 | }, 410 | ], 411 | internalType: "struct Multicall3.Call[]", 412 | name: "calls", 413 | type: "tuple[]", 414 | }, 415 | ], 416 | name: "tryBlockAndAggregate", 417 | outputs: [ 418 | { 419 | internalType: "uint256", 420 | name: "blockNumber", 421 | type: "uint256", 422 | }, 423 | { 424 | internalType: "bytes32", 425 | name: "blockHash", 426 | type: "bytes32", 427 | }, 428 | { 429 | components: [ 430 | { 431 | internalType: "bool", 432 | name: "success", 433 | type: "bool", 434 | }, 435 | { 436 | internalType: "bytes", 437 | name: "returnData", 438 | type: "bytes", 439 | }, 440 | ], 441 | internalType: "struct Multicall3.Result[]", 442 | name: "returnData", 443 | type: "tuple[]", 444 | }, 445 | ], 446 | stateMutability: "payable", 447 | type: "function", 448 | }, 449 | ]; 450 | 451 | export class Multicall3__factory { 452 | static readonly abi = _abi; 453 | static createInterface(): Multicall3Interface { 454 | return new utils.Interface(_abi) as Multicall3Interface; 455 | } 456 | static connect( 457 | address: string, 458 | signerOrProvider: Signer | Provider 459 | ): Multicall3 { 460 | return new Contract(address, _abi, signerOrProvider) as Multicall3; 461 | } 462 | } 463 | -------------------------------------------------------------------------------- /src/contracts/factories/index.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | export { Multicall3__factory } from "./Multicall3__factory"; 5 | -------------------------------------------------------------------------------- /src/contracts/index.ts: -------------------------------------------------------------------------------- 1 | /* Autogenerated file. Do not edit manually. */ 2 | /* tslint:disable */ 3 | /* eslint-disable */ 4 | export type { Multicall3 } from "./Multicall3"; 5 | export * as factories from "./factories"; 6 | export { Multicall3__factory } from "./factories/Multicall3__factory"; 7 | -------------------------------------------------------------------------------- /src/ethers.ts: -------------------------------------------------------------------------------- 1 | import DataLoader from "dataloader"; 2 | import { BaseContract, CallOverrides } from "ethers"; 3 | import { FunctionFragment, Interface, resolveProperties } from "ethers/lib/utils"; 4 | 5 | import { BlockTag, Provider } from "@ethersproject/providers"; 6 | 7 | import { Multicall3, Multicall3__factory } from "./contracts"; 8 | 9 | export type ContractCall = { 10 | fragment: FunctionFragment; 11 | address: string; 12 | params: any[]; 13 | overrides?: CallOverrides; 14 | }; 15 | 16 | export const isMulticallUnderlyingError = (err: Error) => 17 | err.message.includes("Multicall call failed for"); 18 | 19 | const DIGIT_REGEX = /^\d+$/; 20 | const DEFAULT_DATALOADER_OPTIONS = {}; 21 | 22 | export interface EthersMulticallOptions { 23 | chainId: number; 24 | defaultBlockTag: BlockTag; 25 | options: DataLoader.Options; 26 | } 27 | 28 | export type MulticallResult = Multicall3.ResultStructOutput | { error: any }; 29 | 30 | export class EthersMulticall { 31 | private multicall: Multicall3; 32 | private dataLoader: DataLoader; 33 | 34 | public defaultBlockTag: BlockTag; 35 | 36 | constructor( 37 | provider: Provider, 38 | { 39 | defaultBlockTag = "latest", 40 | options = DEFAULT_DATALOADER_OPTIONS, 41 | }: Partial = {} 42 | ) { 43 | this.multicall = Multicall3__factory.connect( 44 | // same address on all networks (cf. https://github.com/mds1/multicall#deployments) 45 | "0xcA11bde05977b3631167028862bE2a173976CA11", 46 | provider 47 | ); 48 | this.dataLoader = new DataLoader(this.doCalls.bind(this), options); 49 | 50 | this.defaultBlockTag = defaultBlockTag; 51 | } 52 | 53 | get contract() { 54 | return this.multicall; 55 | } 56 | 57 | async setProvider(provider: Provider, chainId?: number) { 58 | chainId ??= (await provider.getNetwork()).chainId; 59 | 60 | this.multicall = Multicall3__factory.connect(this.multicall.address, provider); 61 | } 62 | 63 | private async doCalls(allCalls: ReadonlyArray) { 64 | const resolvedCalls = await Promise.all( 65 | allCalls.map(async (call, index) => ({ 66 | ...call, 67 | index, 68 | overrides: call.overrides ? await resolveProperties(call.overrides) : undefined, 69 | })) 70 | ); 71 | 72 | const blockTagCalls = resolvedCalls.reduce((acc, call) => { 73 | const blockTag = (call.overrides?.blockTag ?? this.defaultBlockTag).toString(); 74 | 75 | return { 76 | ...acc, 77 | [blockTag]: [call].concat(acc[blockTag] ?? []), 78 | }; 79 | }, {} as { [blockTag: BlockTag]: typeof resolvedCalls }); 80 | 81 | const results: MulticallResult[] = []; 82 | 83 | await Promise.all( 84 | Object.entries(blockTagCalls).map(async ([blockTagStr, calls]) => { 85 | const callStructs = calls.map((call) => ({ 86 | target: call.address, 87 | callData: new Interface([]).encodeFunctionData(call.fragment, call.params), 88 | })); 89 | const overrides = calls.map(({ overrides }) => overrides).find(Boolean); 90 | const blockTag = DIGIT_REGEX.test(blockTagStr) ? parseInt(blockTagStr, 10) : blockTagStr; 91 | 92 | try { 93 | const res = await this.multicall.callStatic.tryAggregate(false, callStructs, { 94 | ...overrides, 95 | blockTag, 96 | }); 97 | 98 | if (res.length !== calls.length) 99 | throw new Error( 100 | `Unexpected multicall response length: received ${res.length}; expected ${calls.length}` 101 | ); 102 | 103 | calls.forEach((call, i) => { 104 | results[call.index] = res[i]; 105 | }); 106 | } catch (error: any) { 107 | calls.forEach((call) => { 108 | results[call.index] = { error }; 109 | }); 110 | } 111 | }) 112 | ); 113 | 114 | return results; 115 | } 116 | 117 | wrap(contract: T) { 118 | const copy = Object.setPrototypeOf({ ...contract }, Object.getPrototypeOf(contract)); 119 | copy.callStatic = { ...contract.callStatic }; 120 | copy.functions = { ...contract.functions }; 121 | 122 | const defineFunction = (property: string, fragment: FunctionFragment) => { 123 | const descriptor = { 124 | configurable: true, 125 | enumerable: true, 126 | writable: false, 127 | value: async (...params: any) => { 128 | const res = await this.dataLoader.load({ 129 | fragment, 130 | address: contract.address, 131 | params: params.slice(0, fragment.inputs.length), 132 | overrides: params[fragment.inputs.length], 133 | }); 134 | 135 | if ("error" in res) throw res.error; 136 | 137 | const signature = FunctionFragment.from(fragment).format(); 138 | const callIdentifier = [contract.address, signature].join(":"); 139 | 140 | if (!res.success) throw Error(`${callIdentifier} call revert exception`); 141 | if (res.returnData === "0x") throw Error(`${callIdentifier} empty return data exception`); 142 | 143 | try { 144 | const result = new Interface([]).decodeFunctionResult(fragment, res.returnData); 145 | 146 | return fragment.outputs?.length === 1 ? result[0] : result; 147 | } catch (err: any) { 148 | throw new Error(`Multicall decoding failed for ${callIdentifier}: ${err.message}`); 149 | } 150 | }, 151 | }; 152 | 153 | // Overwrite the function with a dataloader batched call 154 | Object.defineProperty(copy, property, descriptor); 155 | Object.defineProperty(copy.callStatic, property, descriptor); 156 | Object.defineProperty(copy.functions, property, descriptor); 157 | }; 158 | 159 | const uniqueNames: { [name: string]: FunctionFragment[] } = {}; 160 | 161 | Object.entries(contract.interface.functions).forEach(([signature, fragment]) => { 162 | if (!["view", "pure"].includes(fragment.stateMutability)) return; 163 | 164 | if (!uniqueNames[`%${fragment.name}`]) uniqueNames[`%${fragment.name}`] = []; 165 | uniqueNames[`%${fragment.name}`].push(fragment); 166 | 167 | defineFunction(signature, fragment); 168 | }); 169 | 170 | Object.entries(uniqueNames).forEach(([name, fragments]) => { 171 | // Ambiguous names to not get attached as bare names 172 | if (fragments.length > 1) return; 173 | 174 | // Strip off the leading "%" used for prototype protection 175 | defineFunction(name.substring(1), fragments[0]); 176 | }); 177 | 178 | return copy as T; 179 | } 180 | } 181 | 182 | export default EthersMulticall; 183 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { EthersMulticall } from "./ethers"; 2 | export type { ContractCall } from "./ethers"; 3 | -------------------------------------------------------------------------------- /test/abis/Morpho.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "AmountIsZero", 5 | "type": "error" 6 | }, 7 | { 8 | "inputs": [], 9 | "name": "ClaimRewardsPaused", 10 | "type": "error" 11 | }, 12 | { 13 | "inputs": [], 14 | "name": "CompoundOracleFailed", 15 | "type": "error" 16 | }, 17 | { 18 | "inputs": [], 19 | "name": "ExceedsMaxBasisPoints", 20 | "type": "error" 21 | }, 22 | { 23 | "inputs": [], 24 | "name": "LowLevelDelegateCallFailed", 25 | "type": "error" 26 | }, 27 | { 28 | "inputs": [], 29 | "name": "MarketAlreadyCreated", 30 | "type": "error" 31 | }, 32 | { 33 | "inputs": [], 34 | "name": "MarketCreationFailedOnCompound", 35 | "type": "error" 36 | }, 37 | { 38 | "inputs": [], 39 | "name": "MarketNotCreated", 40 | "type": "error" 41 | }, 42 | { 43 | "inputs": [], 44 | "name": "MarketPaused", 45 | "type": "error" 46 | }, 47 | { 48 | "inputs": [], 49 | "name": "ZeroAddress", 50 | "type": "error" 51 | }, 52 | { 53 | "anonymous": false, 54 | "inputs": [ 55 | { 56 | "indexed": false, 57 | "internalType": "bool", 58 | "name": "_newStatus", 59 | "type": "bool" 60 | } 61 | ], 62 | "name": "ClaimRewardsPauseStatusSet", 63 | "type": "event" 64 | }, 65 | { 66 | "anonymous": false, 67 | "inputs": [ 68 | { 69 | "components": [ 70 | { 71 | "internalType": "uint64", 72 | "name": "supply", 73 | "type": "uint64" 74 | }, 75 | { 76 | "internalType": "uint64", 77 | "name": "borrow", 78 | "type": "uint64" 79 | }, 80 | { 81 | "internalType": "uint64", 82 | "name": "withdraw", 83 | "type": "uint64" 84 | }, 85 | { 86 | "internalType": "uint64", 87 | "name": "repay", 88 | "type": "uint64" 89 | } 90 | ], 91 | "indexed": false, 92 | "internalType": "struct Types.MaxGasForMatching", 93 | "name": "_defaultMaxGasForMatching", 94 | "type": "tuple" 95 | } 96 | ], 97 | "name": "DefaultMaxGasForMatchingSet", 98 | "type": "event" 99 | }, 100 | { 101 | "anonymous": false, 102 | "inputs": [ 103 | { 104 | "indexed": false, 105 | "internalType": "uint256", 106 | "name": "_dustThreshold", 107 | "type": "uint256" 108 | } 109 | ], 110 | "name": "DustThresholdSet", 111 | "type": "event" 112 | }, 113 | { 114 | "anonymous": false, 115 | "inputs": [ 116 | { 117 | "indexed": true, 118 | "internalType": "address", 119 | "name": "_newIncentivesVaultAddress", 120 | "type": "address" 121 | } 122 | ], 123 | "name": "IncentivesVaultSet", 124 | "type": "event" 125 | }, 126 | { 127 | "anonymous": false, 128 | "inputs": [ 129 | { 130 | "indexed": true, 131 | "internalType": "address", 132 | "name": "_interestRatesManager", 133 | "type": "address" 134 | } 135 | ], 136 | "name": "InterestRatesSet", 137 | "type": "event" 138 | }, 139 | { 140 | "anonymous": false, 141 | "inputs": [ 142 | { 143 | "indexed": true, 144 | "internalType": "address", 145 | "name": "_poolTokenAddress", 146 | "type": "address" 147 | }, 148 | { 149 | "indexed": false, 150 | "internalType": "uint16", 151 | "name": "_reserveFactor", 152 | "type": "uint16" 153 | }, 154 | { 155 | "indexed": false, 156 | "internalType": "uint16", 157 | "name": "_p2pIndexCursor", 158 | "type": "uint16" 159 | } 160 | ], 161 | "name": "MarketCreated", 162 | "type": "event" 163 | }, 164 | { 165 | "anonymous": false, 166 | "inputs": [ 167 | { 168 | "indexed": false, 169 | "internalType": "uint256", 170 | "name": "_newValue", 171 | "type": "uint256" 172 | } 173 | ], 174 | "name": "MaxSortedUsersSet", 175 | "type": "event" 176 | }, 177 | { 178 | "anonymous": false, 179 | "inputs": [ 180 | { 181 | "indexed": true, 182 | "internalType": "address", 183 | "name": "previousOwner", 184 | "type": "address" 185 | }, 186 | { 187 | "indexed": true, 188 | "internalType": "address", 189 | "name": "newOwner", 190 | "type": "address" 191 | } 192 | ], 193 | "name": "OwnershipTransferred", 194 | "type": "event" 195 | }, 196 | { 197 | "anonymous": false, 198 | "inputs": [ 199 | { 200 | "indexed": true, 201 | "internalType": "address", 202 | "name": "_poolTokenAddress", 203 | "type": "address" 204 | }, 205 | { 206 | "indexed": false, 207 | "internalType": "uint16", 208 | "name": "_newValue", 209 | "type": "uint16" 210 | } 211 | ], 212 | "name": "P2PIndexCursorSet", 213 | "type": "event" 214 | }, 215 | { 216 | "anonymous": false, 217 | "inputs": [ 218 | { 219 | "indexed": true, 220 | "internalType": "address", 221 | "name": "_poolTokenAddress", 222 | "type": "address" 223 | }, 224 | { 225 | "indexed": false, 226 | "internalType": "bool", 227 | "name": "_p2pDisabled", 228 | "type": "bool" 229 | } 230 | ], 231 | "name": "P2PStatusSet", 232 | "type": "event" 233 | }, 234 | { 235 | "anonymous": false, 236 | "inputs": [ 237 | { 238 | "indexed": true, 239 | "internalType": "address", 240 | "name": "_poolTokenAddress", 241 | "type": "address" 242 | }, 243 | { 244 | "indexed": false, 245 | "internalType": "bool", 246 | "name": "_newStatus", 247 | "type": "bool" 248 | } 249 | ], 250 | "name": "PartialPauseStatusSet", 251 | "type": "event" 252 | }, 253 | { 254 | "anonymous": false, 255 | "inputs": [ 256 | { 257 | "indexed": true, 258 | "internalType": "address", 259 | "name": "_poolTokenAddress", 260 | "type": "address" 261 | }, 262 | { 263 | "indexed": false, 264 | "internalType": "bool", 265 | "name": "_newStatus", 266 | "type": "bool" 267 | } 268 | ], 269 | "name": "PauseStatusSet", 270 | "type": "event" 271 | }, 272 | { 273 | "anonymous": false, 274 | "inputs": [ 275 | { 276 | "indexed": true, 277 | "internalType": "address", 278 | "name": "_positionsManager", 279 | "type": "address" 280 | } 281 | ], 282 | "name": "PositionsManagerSet", 283 | "type": "event" 284 | }, 285 | { 286 | "anonymous": false, 287 | "inputs": [ 288 | { 289 | "indexed": true, 290 | "internalType": "address", 291 | "name": "_poolTokenAddress", 292 | "type": "address" 293 | }, 294 | { 295 | "indexed": false, 296 | "internalType": "uint16", 297 | "name": "_newValue", 298 | "type": "uint16" 299 | } 300 | ], 301 | "name": "ReserveFactorSet", 302 | "type": "event" 303 | }, 304 | { 305 | "anonymous": false, 306 | "inputs": [ 307 | { 308 | "indexed": true, 309 | "internalType": "address", 310 | "name": "_poolTokenAddress", 311 | "type": "address" 312 | }, 313 | { 314 | "indexed": false, 315 | "internalType": "uint256", 316 | "name": "_amountClaimed", 317 | "type": "uint256" 318 | } 319 | ], 320 | "name": "ReserveFeeClaimed", 321 | "type": "event" 322 | }, 323 | { 324 | "anonymous": false, 325 | "inputs": [ 326 | { 327 | "indexed": true, 328 | "internalType": "address", 329 | "name": "_user", 330 | "type": "address" 331 | }, 332 | { 333 | "indexed": false, 334 | "internalType": "uint256", 335 | "name": "_amountClaimed", 336 | "type": "uint256" 337 | }, 338 | { 339 | "indexed": true, 340 | "internalType": "bool", 341 | "name": "_traded", 342 | "type": "bool" 343 | } 344 | ], 345 | "name": "RewardsClaimed", 346 | "type": "event" 347 | }, 348 | { 349 | "anonymous": false, 350 | "inputs": [ 351 | { 352 | "indexed": true, 353 | "internalType": "address", 354 | "name": "_newRewardsManagerAddress", 355 | "type": "address" 356 | } 357 | ], 358 | "name": "RewardsManagerSet", 359 | "type": "event" 360 | }, 361 | { 362 | "anonymous": false, 363 | "inputs": [ 364 | { 365 | "indexed": true, 366 | "internalType": "address", 367 | "name": "_newTreasuryVaultAddress", 368 | "type": "address" 369 | } 370 | ], 371 | "name": "TreasuryVaultSet", 372 | "type": "event" 373 | }, 374 | { 375 | "inputs": [], 376 | "name": "CTOKEN_DECIMALS", 377 | "outputs": [ 378 | { 379 | "internalType": "uint8", 380 | "name": "", 381 | "type": "uint8" 382 | } 383 | ], 384 | "stateMutability": "view", 385 | "type": "function" 386 | }, 387 | { 388 | "inputs": [], 389 | "name": "MAX_BASIS_POINTS", 390 | "outputs": [ 391 | { 392 | "internalType": "uint16", 393 | "name": "", 394 | "type": "uint16" 395 | } 396 | ], 397 | "stateMutability": "view", 398 | "type": "function" 399 | }, 400 | { 401 | "inputs": [], 402 | "name": "WAD", 403 | "outputs": [ 404 | { 405 | "internalType": "uint256", 406 | "name": "", 407 | "type": "uint256" 408 | } 409 | ], 410 | "stateMutability": "view", 411 | "type": "function" 412 | }, 413 | { 414 | "inputs": [ 415 | { 416 | "internalType": "address", 417 | "name": "_poolTokenAddress", 418 | "type": "address" 419 | }, 420 | { 421 | "internalType": "uint256", 422 | "name": "_amount", 423 | "type": "uint256" 424 | } 425 | ], 426 | "name": "borrow", 427 | "outputs": [], 428 | "stateMutability": "nonpayable", 429 | "type": "function" 430 | }, 431 | { 432 | "inputs": [ 433 | { 434 | "internalType": "address", 435 | "name": "_poolTokenAddress", 436 | "type": "address" 437 | }, 438 | { 439 | "internalType": "uint256", 440 | "name": "_amount", 441 | "type": "uint256" 442 | }, 443 | { 444 | "internalType": "uint256", 445 | "name": "_maxGasForMatching", 446 | "type": "uint256" 447 | } 448 | ], 449 | "name": "borrow", 450 | "outputs": [], 451 | "stateMutability": "nonpayable", 452 | "type": "function" 453 | }, 454 | { 455 | "inputs": [ 456 | { 457 | "internalType": "address", 458 | "name": "", 459 | "type": "address" 460 | }, 461 | { 462 | "internalType": "address", 463 | "name": "", 464 | "type": "address" 465 | } 466 | ], 467 | "name": "borrowBalanceInOf", 468 | "outputs": [ 469 | { 470 | "internalType": "uint256", 471 | "name": "inP2P", 472 | "type": "uint256" 473 | }, 474 | { 475 | "internalType": "uint256", 476 | "name": "onPool", 477 | "type": "uint256" 478 | } 479 | ], 480 | "stateMutability": "view", 481 | "type": "function" 482 | }, 483 | { 484 | "inputs": [], 485 | "name": "cEth", 486 | "outputs": [ 487 | { 488 | "internalType": "address", 489 | "name": "", 490 | "type": "address" 491 | } 492 | ], 493 | "stateMutability": "view", 494 | "type": "function" 495 | }, 496 | { 497 | "inputs": [ 498 | { 499 | "internalType": "address[]", 500 | "name": "_cTokenAddresses", 501 | "type": "address[]" 502 | }, 503 | { 504 | "internalType": "bool", 505 | "name": "_tradeForMorphoToken", 506 | "type": "bool" 507 | } 508 | ], 509 | "name": "claimRewards", 510 | "outputs": [ 511 | { 512 | "internalType": "uint256", 513 | "name": "amountOfRewards", 514 | "type": "uint256" 515 | } 516 | ], 517 | "stateMutability": "nonpayable", 518 | "type": "function" 519 | }, 520 | { 521 | "inputs": [ 522 | { 523 | "internalType": "address[]", 524 | "name": "_poolTokenAddresses", 525 | "type": "address[]" 526 | }, 527 | { 528 | "internalType": "uint256[]", 529 | "name": "_amounts", 530 | "type": "uint256[]" 531 | } 532 | ], 533 | "name": "claimToTreasury", 534 | "outputs": [], 535 | "stateMutability": "nonpayable", 536 | "type": "function" 537 | }, 538 | { 539 | "inputs": [], 540 | "name": "comptroller", 541 | "outputs": [ 542 | { 543 | "internalType": "contract IComptroller", 544 | "name": "", 545 | "type": "address" 546 | } 547 | ], 548 | "stateMutability": "view", 549 | "type": "function" 550 | }, 551 | { 552 | "inputs": [ 553 | { 554 | "internalType": "address", 555 | "name": "_poolTokenAddress", 556 | "type": "address" 557 | }, 558 | { 559 | "components": [ 560 | { 561 | "internalType": "uint16", 562 | "name": "reserveFactor", 563 | "type": "uint16" 564 | }, 565 | { 566 | "internalType": "uint16", 567 | "name": "p2pIndexCursor", 568 | "type": "uint16" 569 | } 570 | ], 571 | "internalType": "struct Types.MarketParameters", 572 | "name": "_marketParams", 573 | "type": "tuple" 574 | } 575 | ], 576 | "name": "createMarket", 577 | "outputs": [], 578 | "stateMutability": "nonpayable", 579 | "type": "function" 580 | }, 581 | { 582 | "inputs": [], 583 | "name": "defaultMaxGasForMatching", 584 | "outputs": [ 585 | { 586 | "internalType": "uint64", 587 | "name": "supply", 588 | "type": "uint64" 589 | }, 590 | { 591 | "internalType": "uint64", 592 | "name": "borrow", 593 | "type": "uint64" 594 | }, 595 | { 596 | "internalType": "uint64", 597 | "name": "withdraw", 598 | "type": "uint64" 599 | }, 600 | { 601 | "internalType": "uint64", 602 | "name": "repay", 603 | "type": "uint64" 604 | } 605 | ], 606 | "stateMutability": "view", 607 | "type": "function" 608 | }, 609 | { 610 | "inputs": [ 611 | { 612 | "internalType": "address", 613 | "name": "", 614 | "type": "address" 615 | } 616 | ], 617 | "name": "deltas", 618 | "outputs": [ 619 | { 620 | "internalType": "uint256", 621 | "name": "p2pSupplyDelta", 622 | "type": "uint256" 623 | }, 624 | { 625 | "internalType": "uint256", 626 | "name": "p2pBorrowDelta", 627 | "type": "uint256" 628 | }, 629 | { 630 | "internalType": "uint256", 631 | "name": "p2pSupplyAmount", 632 | "type": "uint256" 633 | }, 634 | { 635 | "internalType": "uint256", 636 | "name": "p2pBorrowAmount", 637 | "type": "uint256" 638 | } 639 | ], 640 | "stateMutability": "view", 641 | "type": "function" 642 | }, 643 | { 644 | "inputs": [ 645 | { 646 | "internalType": "address", 647 | "name": "", 648 | "type": "address" 649 | }, 650 | { 651 | "internalType": "address", 652 | "name": "", 653 | "type": "address" 654 | } 655 | ], 656 | "name": "deltas", 657 | "outputs": [ 658 | { 659 | "internalType": "uint256", 660 | "name": "p2pSupplyDelta", 661 | "type": "uint256" 662 | }, 663 | { 664 | "internalType": "uint256", 665 | "name": "p2pBorrowDelta", 666 | "type": "uint256" 667 | }, 668 | { 669 | "internalType": "uint256", 670 | "name": "p2pSupplyAmount", 671 | "type": "uint256" 672 | }, 673 | { 674 | "internalType": "uint256", 675 | "name": "p2pBorrowAmount", 676 | "type": "uint256" 677 | } 678 | ], 679 | "stateMutability": "view", 680 | "type": "function" 681 | }, 682 | { 683 | "inputs": [], 684 | "name": "dustThreshold", 685 | "outputs": [ 686 | { 687 | "internalType": "uint256", 688 | "name": "", 689 | "type": "uint256" 690 | } 691 | ], 692 | "stateMutability": "view", 693 | "type": "function" 694 | }, 695 | { 696 | "inputs": [ 697 | { 698 | "internalType": "address", 699 | "name": "", 700 | "type": "address" 701 | }, 702 | { 703 | "internalType": "uint256", 704 | "name": "", 705 | "type": "uint256" 706 | } 707 | ], 708 | "name": "enteredMarkets", 709 | "outputs": [ 710 | { 711 | "internalType": "address", 712 | "name": "", 713 | "type": "address" 714 | } 715 | ], 716 | "stateMutability": "view", 717 | "type": "function" 718 | }, 719 | { 720 | "inputs": [], 721 | "name": "getAllMarkets", 722 | "outputs": [ 723 | { 724 | "internalType": "address[]", 725 | "name": "marketsCreated_", 726 | "type": "address[]" 727 | } 728 | ], 729 | "stateMutability": "view", 730 | "type": "function" 731 | }, 732 | { 733 | "inputs": [ 734 | { 735 | "internalType": "address", 736 | "name": "_user", 737 | "type": "address" 738 | } 739 | ], 740 | "name": "getEnteredMarkets", 741 | "outputs": [ 742 | { 743 | "internalType": "address[]", 744 | "name": "enteredMarkets_", 745 | "type": "address[]" 746 | } 747 | ], 748 | "stateMutability": "view", 749 | "type": "function" 750 | }, 751 | { 752 | "inputs": [ 753 | { 754 | "internalType": "address", 755 | "name": "_poolTokenAddress", 756 | "type": "address" 757 | }, 758 | { 759 | "internalType": "enum Types.PositionType", 760 | "name": "_positionType", 761 | "type": "uint8" 762 | } 763 | ], 764 | "name": "getHead", 765 | "outputs": [ 766 | { 767 | "internalType": "address", 768 | "name": "head", 769 | "type": "address" 770 | } 771 | ], 772 | "stateMutability": "view", 773 | "type": "function" 774 | }, 775 | { 776 | "inputs": [ 777 | { 778 | "internalType": "address", 779 | "name": "_poolTokenAddress", 780 | "type": "address" 781 | }, 782 | { 783 | "internalType": "enum Types.PositionType", 784 | "name": "_positionType", 785 | "type": "uint8" 786 | }, 787 | { 788 | "internalType": "address", 789 | "name": "_user", 790 | "type": "address" 791 | } 792 | ], 793 | "name": "getNext", 794 | "outputs": [ 795 | { 796 | "internalType": "address", 797 | "name": "next", 798 | "type": "address" 799 | } 800 | ], 801 | "stateMutability": "view", 802 | "type": "function" 803 | }, 804 | { 805 | "inputs": [], 806 | "name": "incentivesVault", 807 | "outputs": [ 808 | { 809 | "internalType": "contract IIncentivesVault", 810 | "name": "", 811 | "type": "address" 812 | } 813 | ], 814 | "stateMutability": "view", 815 | "type": "function" 816 | }, 817 | { 818 | "inputs": [ 819 | { 820 | "internalType": "contract IPositionsManager", 821 | "name": "_positionsManager", 822 | "type": "address" 823 | }, 824 | { 825 | "internalType": "contract IInterestRatesManager", 826 | "name": "_interestRatesManager", 827 | "type": "address" 828 | }, 829 | { 830 | "internalType": "contract IComptroller", 831 | "name": "_comptroller", 832 | "type": "address" 833 | }, 834 | { 835 | "components": [ 836 | { 837 | "internalType": "uint64", 838 | "name": "supply", 839 | "type": "uint64" 840 | }, 841 | { 842 | "internalType": "uint64", 843 | "name": "borrow", 844 | "type": "uint64" 845 | }, 846 | { 847 | "internalType": "uint64", 848 | "name": "withdraw", 849 | "type": "uint64" 850 | }, 851 | { 852 | "internalType": "uint64", 853 | "name": "repay", 854 | "type": "uint64" 855 | } 856 | ], 857 | "internalType": "struct Types.MaxGasForMatching", 858 | "name": "_defaultMaxGasForMatching", 859 | "type": "tuple" 860 | }, 861 | { 862 | "internalType": "uint256", 863 | "name": "_dustThreshold", 864 | "type": "uint256" 865 | }, 866 | { 867 | "internalType": "uint256", 868 | "name": "_maxSortedUsers", 869 | "type": "uint256" 870 | }, 871 | { 872 | "internalType": "address", 873 | "name": "_cEth", 874 | "type": "address" 875 | }, 876 | { 877 | "internalType": "address", 878 | "name": "_wEth", 879 | "type": "address" 880 | } 881 | ], 882 | "name": "initialize", 883 | "outputs": [], 884 | "stateMutability": "nonpayable", 885 | "type": "function" 886 | }, 887 | { 888 | "inputs": [], 889 | "name": "interestRatesManager", 890 | "outputs": [ 891 | { 892 | "internalType": "contract IInterestRatesManager", 893 | "name": "", 894 | "type": "address" 895 | } 896 | ], 897 | "stateMutability": "view", 898 | "type": "function" 899 | }, 900 | { 901 | "inputs": [], 902 | "name": "isClaimRewardsPaused", 903 | "outputs": [ 904 | { 905 | "internalType": "bool", 906 | "name": "", 907 | "type": "bool" 908 | } 909 | ], 910 | "stateMutability": "view", 911 | "type": "function" 912 | }, 913 | { 914 | "inputs": [ 915 | { 916 | "internalType": "address", 917 | "name": "", 918 | "type": "address" 919 | } 920 | ], 921 | "name": "lastBorrowBlock", 922 | "outputs": [ 923 | { 924 | "internalType": "uint256", 925 | "name": "", 926 | "type": "uint256" 927 | } 928 | ], 929 | "stateMutability": "view", 930 | "type": "function" 931 | }, 932 | { 933 | "inputs": [ 934 | { 935 | "internalType": "address", 936 | "name": "", 937 | "type": "address" 938 | } 939 | ], 940 | "name": "lastPoolIndexes", 941 | "outputs": [ 942 | { 943 | "internalType": "uint32", 944 | "name": "lastUpdateBlockNumber", 945 | "type": "uint32" 946 | }, 947 | { 948 | "internalType": "uint112", 949 | "name": "lastSupplyPoolIndex", 950 | "type": "uint112" 951 | }, 952 | { 953 | "internalType": "uint112", 954 | "name": "lastBorrowPoolIndex", 955 | "type": "uint112" 956 | } 957 | ], 958 | "stateMutability": "view", 959 | "type": "function" 960 | }, 961 | { 962 | "inputs": [ 963 | { 964 | "internalType": "address", 965 | "name": "_poolTokenBorrowedAddress", 966 | "type": "address" 967 | }, 968 | { 969 | "internalType": "address", 970 | "name": "_poolTokenCollateralAddress", 971 | "type": "address" 972 | }, 973 | { 974 | "internalType": "address", 975 | "name": "_borrower", 976 | "type": "address" 977 | }, 978 | { 979 | "internalType": "uint256", 980 | "name": "_amount", 981 | "type": "uint256" 982 | } 983 | ], 984 | "name": "liquidate", 985 | "outputs": [], 986 | "stateMutability": "nonpayable", 987 | "type": "function" 988 | }, 989 | { 990 | "inputs": [ 991 | { 992 | "internalType": "address", 993 | "name": "", 994 | "type": "address" 995 | } 996 | ], 997 | "name": "marketParameters", 998 | "outputs": [ 999 | { 1000 | "internalType": "uint16", 1001 | "name": "reserveFactor", 1002 | "type": "uint16" 1003 | }, 1004 | { 1005 | "internalType": "uint16", 1006 | "name": "p2pIndexCursor", 1007 | "type": "uint16" 1008 | } 1009 | ], 1010 | "stateMutability": "view", 1011 | "type": "function" 1012 | }, 1013 | { 1014 | "inputs": [ 1015 | { 1016 | "internalType": "address", 1017 | "name": "", 1018 | "type": "address" 1019 | } 1020 | ], 1021 | "name": "marketStatus", 1022 | "outputs": [ 1023 | { 1024 | "internalType": "bool", 1025 | "name": "isCreated", 1026 | "type": "bool" 1027 | }, 1028 | { 1029 | "internalType": "bool", 1030 | "name": "isPaused", 1031 | "type": "bool" 1032 | }, 1033 | { 1034 | "internalType": "bool", 1035 | "name": "isPartiallyPaused", 1036 | "type": "bool" 1037 | } 1038 | ], 1039 | "stateMutability": "view", 1040 | "type": "function" 1041 | }, 1042 | { 1043 | "inputs": [ 1044 | { 1045 | "internalType": "uint256", 1046 | "name": "", 1047 | "type": "uint256" 1048 | } 1049 | ], 1050 | "name": "marketsCreated", 1051 | "outputs": [ 1052 | { 1053 | "internalType": "address", 1054 | "name": "", 1055 | "type": "address" 1056 | } 1057 | ], 1058 | "stateMutability": "view", 1059 | "type": "function" 1060 | }, 1061 | { 1062 | "inputs": [], 1063 | "name": "maxSortedUsers", 1064 | "outputs": [ 1065 | { 1066 | "internalType": "uint256", 1067 | "name": "", 1068 | "type": "uint256" 1069 | } 1070 | ], 1071 | "stateMutability": "view", 1072 | "type": "function" 1073 | }, 1074 | { 1075 | "inputs": [], 1076 | "name": "owner", 1077 | "outputs": [ 1078 | { 1079 | "internalType": "address", 1080 | "name": "", 1081 | "type": "address" 1082 | } 1083 | ], 1084 | "stateMutability": "view", 1085 | "type": "function" 1086 | }, 1087 | { 1088 | "inputs": [ 1089 | { 1090 | "internalType": "address", 1091 | "name": "", 1092 | "type": "address" 1093 | } 1094 | ], 1095 | "name": "p2pBorrowIndex", 1096 | "outputs": [ 1097 | { 1098 | "internalType": "uint256", 1099 | "name": "", 1100 | "type": "uint256" 1101 | } 1102 | ], 1103 | "stateMutability": "view", 1104 | "type": "function" 1105 | }, 1106 | { 1107 | "inputs": [ 1108 | { 1109 | "internalType": "address", 1110 | "name": "", 1111 | "type": "address" 1112 | } 1113 | ], 1114 | "name": "p2pDisabled", 1115 | "outputs": [ 1116 | { 1117 | "internalType": "bool", 1118 | "name": "", 1119 | "type": "bool" 1120 | } 1121 | ], 1122 | "stateMutability": "view", 1123 | "type": "function" 1124 | }, 1125 | { 1126 | "inputs": [ 1127 | { 1128 | "internalType": "address", 1129 | "name": "", 1130 | "type": "address" 1131 | } 1132 | ], 1133 | "name": "p2pSupplyIndex", 1134 | "outputs": [ 1135 | { 1136 | "internalType": "uint256", 1137 | "name": "", 1138 | "type": "uint256" 1139 | } 1140 | ], 1141 | "stateMutability": "view", 1142 | "type": "function" 1143 | }, 1144 | { 1145 | "inputs": [], 1146 | "name": "positionsManager", 1147 | "outputs": [ 1148 | { 1149 | "internalType": "contract IPositionsManager", 1150 | "name": "", 1151 | "type": "address" 1152 | } 1153 | ], 1154 | "stateMutability": "view", 1155 | "type": "function" 1156 | }, 1157 | { 1158 | "inputs": [], 1159 | "name": "renounceOwnership", 1160 | "outputs": [], 1161 | "stateMutability": "nonpayable", 1162 | "type": "function" 1163 | }, 1164 | { 1165 | "inputs": [ 1166 | { 1167 | "internalType": "address", 1168 | "name": "_poolTokenAddress", 1169 | "type": "address" 1170 | }, 1171 | { 1172 | "internalType": "address", 1173 | "name": "_onBehalf", 1174 | "type": "address" 1175 | }, 1176 | { 1177 | "internalType": "uint256", 1178 | "name": "_amount", 1179 | "type": "uint256" 1180 | } 1181 | ], 1182 | "name": "repay", 1183 | "outputs": [], 1184 | "stateMutability": "nonpayable", 1185 | "type": "function" 1186 | }, 1187 | { 1188 | "inputs": [], 1189 | "name": "rewardsManager", 1190 | "outputs": [ 1191 | { 1192 | "internalType": "contract IRewardsManager", 1193 | "name": "", 1194 | "type": "address" 1195 | } 1196 | ], 1197 | "stateMutability": "view", 1198 | "type": "function" 1199 | }, 1200 | { 1201 | "inputs": [ 1202 | { 1203 | "internalType": "bool", 1204 | "name": "_newStatus", 1205 | "type": "bool" 1206 | } 1207 | ], 1208 | "name": "setClaimRewardsPauseStatus", 1209 | "outputs": [], 1210 | "stateMutability": "nonpayable", 1211 | "type": "function" 1212 | }, 1213 | { 1214 | "inputs": [ 1215 | { 1216 | "components": [ 1217 | { 1218 | "internalType": "uint64", 1219 | "name": "supply", 1220 | "type": "uint64" 1221 | }, 1222 | { 1223 | "internalType": "uint64", 1224 | "name": "borrow", 1225 | "type": "uint64" 1226 | }, 1227 | { 1228 | "internalType": "uint64", 1229 | "name": "withdraw", 1230 | "type": "uint64" 1231 | }, 1232 | { 1233 | "internalType": "uint64", 1234 | "name": "repay", 1235 | "type": "uint64" 1236 | } 1237 | ], 1238 | "internalType": "struct Types.MaxGasForMatching", 1239 | "name": "_defaultMaxGasForMatching", 1240 | "type": "tuple" 1241 | } 1242 | ], 1243 | "name": "setDefaultMaxGasForMatching", 1244 | "outputs": [], 1245 | "stateMutability": "nonpayable", 1246 | "type": "function" 1247 | }, 1248 | { 1249 | "inputs": [ 1250 | { 1251 | "internalType": "uint256", 1252 | "name": "_dustThreshold", 1253 | "type": "uint256" 1254 | } 1255 | ], 1256 | "name": "setDustThreshold", 1257 | "outputs": [], 1258 | "stateMutability": "nonpayable", 1259 | "type": "function" 1260 | }, 1261 | { 1262 | "inputs": [ 1263 | { 1264 | "internalType": "contract IIncentivesVault", 1265 | "name": "_incentivesVault", 1266 | "type": "address" 1267 | } 1268 | ], 1269 | "name": "setIncentivesVault", 1270 | "outputs": [], 1271 | "stateMutability": "nonpayable", 1272 | "type": "function" 1273 | }, 1274 | { 1275 | "inputs": [ 1276 | { 1277 | "internalType": "contract IInterestRatesManager", 1278 | "name": "_interestRatesManager", 1279 | "type": "address" 1280 | } 1281 | ], 1282 | "name": "setInterestRatesManager", 1283 | "outputs": [], 1284 | "stateMutability": "nonpayable", 1285 | "type": "function" 1286 | }, 1287 | { 1288 | "inputs": [ 1289 | { 1290 | "internalType": "uint256", 1291 | "name": "_newMaxSortedUsers", 1292 | "type": "uint256" 1293 | } 1294 | ], 1295 | "name": "setMaxSortedUsers", 1296 | "outputs": [], 1297 | "stateMutability": "nonpayable", 1298 | "type": "function" 1299 | }, 1300 | { 1301 | "inputs": [ 1302 | { 1303 | "internalType": "address", 1304 | "name": "_poolTokenAddress", 1305 | "type": "address" 1306 | }, 1307 | { 1308 | "internalType": "bool", 1309 | "name": "_newStatus", 1310 | "type": "bool" 1311 | } 1312 | ], 1313 | "name": "setP2PDisabled", 1314 | "outputs": [], 1315 | "stateMutability": "nonpayable", 1316 | "type": "function" 1317 | }, 1318 | { 1319 | "inputs": [ 1320 | { 1321 | "internalType": "address", 1322 | "name": "_poolTokenAddress", 1323 | "type": "address" 1324 | }, 1325 | { 1326 | "internalType": "uint16", 1327 | "name": "_p2pIndexCursor", 1328 | "type": "uint16" 1329 | } 1330 | ], 1331 | "name": "setP2PIndexCursor", 1332 | "outputs": [], 1333 | "stateMutability": "nonpayable", 1334 | "type": "function" 1335 | }, 1336 | { 1337 | "inputs": [ 1338 | { 1339 | "internalType": "address", 1340 | "name": "_poolTokenAddress", 1341 | "type": "address" 1342 | }, 1343 | { 1344 | "internalType": "bool", 1345 | "name": "_newStatus", 1346 | "type": "bool" 1347 | } 1348 | ], 1349 | "name": "setPartialPauseStatus", 1350 | "outputs": [], 1351 | "stateMutability": "nonpayable", 1352 | "type": "function" 1353 | }, 1354 | { 1355 | "inputs": [ 1356 | { 1357 | "internalType": "address", 1358 | "name": "_poolTokenAddress", 1359 | "type": "address" 1360 | }, 1361 | { 1362 | "internalType": "bool", 1363 | "name": "_newStatus", 1364 | "type": "bool" 1365 | } 1366 | ], 1367 | "name": "setPauseStatus", 1368 | "outputs": [], 1369 | "stateMutability": "nonpayable", 1370 | "type": "function" 1371 | }, 1372 | { 1373 | "inputs": [ 1374 | { 1375 | "internalType": "contract IPositionsManager", 1376 | "name": "_positionsManager", 1377 | "type": "address" 1378 | } 1379 | ], 1380 | "name": "setPositionsManager", 1381 | "outputs": [], 1382 | "stateMutability": "nonpayable", 1383 | "type": "function" 1384 | }, 1385 | { 1386 | "inputs": [ 1387 | { 1388 | "internalType": "address", 1389 | "name": "_poolTokenAddress", 1390 | "type": "address" 1391 | }, 1392 | { 1393 | "internalType": "uint16", 1394 | "name": "_newReserveFactor", 1395 | "type": "uint16" 1396 | } 1397 | ], 1398 | "name": "setReserveFactor", 1399 | "outputs": [], 1400 | "stateMutability": "nonpayable", 1401 | "type": "function" 1402 | }, 1403 | { 1404 | "inputs": [ 1405 | { 1406 | "internalType": "contract IRewardsManager", 1407 | "name": "_rewardsManager", 1408 | "type": "address" 1409 | } 1410 | ], 1411 | "name": "setRewardsManager", 1412 | "outputs": [], 1413 | "stateMutability": "nonpayable", 1414 | "type": "function" 1415 | }, 1416 | { 1417 | "inputs": [ 1418 | { 1419 | "internalType": "address", 1420 | "name": "_treasuryVault", 1421 | "type": "address" 1422 | } 1423 | ], 1424 | "name": "setTreasuryVault", 1425 | "outputs": [], 1426 | "stateMutability": "nonpayable", 1427 | "type": "function" 1428 | }, 1429 | { 1430 | "inputs": [ 1431 | { 1432 | "internalType": "address", 1433 | "name": "_poolTokenAddress", 1434 | "type": "address" 1435 | }, 1436 | { 1437 | "internalType": "address", 1438 | "name": "_onBehalf", 1439 | "type": "address" 1440 | }, 1441 | { 1442 | "internalType": "uint256", 1443 | "name": "_amount", 1444 | "type": "uint256" 1445 | } 1446 | ], 1447 | "name": "supply", 1448 | "outputs": [], 1449 | "stateMutability": "nonpayable", 1450 | "type": "function" 1451 | }, 1452 | { 1453 | "inputs": [ 1454 | { 1455 | "internalType": "address", 1456 | "name": "_poolTokenAddress", 1457 | "type": "address" 1458 | }, 1459 | { 1460 | "internalType": "address", 1461 | "name": "_onBehalf", 1462 | "type": "address" 1463 | }, 1464 | { 1465 | "internalType": "uint256", 1466 | "name": "_amount", 1467 | "type": "uint256" 1468 | }, 1469 | { 1470 | "internalType": "uint256", 1471 | "name": "_maxGasForMatching", 1472 | "type": "uint256" 1473 | } 1474 | ], 1475 | "name": "supply", 1476 | "outputs": [], 1477 | "stateMutability": "nonpayable", 1478 | "type": "function" 1479 | }, 1480 | { 1481 | "inputs": [ 1482 | { 1483 | "internalType": "address", 1484 | "name": "", 1485 | "type": "address" 1486 | }, 1487 | { 1488 | "internalType": "address", 1489 | "name": "", 1490 | "type": "address" 1491 | } 1492 | ], 1493 | "name": "supplyBalanceInOf", 1494 | "outputs": [ 1495 | { 1496 | "internalType": "uint256", 1497 | "name": "inP2P", 1498 | "type": "uint256" 1499 | }, 1500 | { 1501 | "internalType": "uint256", 1502 | "name": "onPool", 1503 | "type": "uint256" 1504 | } 1505 | ], 1506 | "stateMutability": "view", 1507 | "type": "function" 1508 | }, 1509 | { 1510 | "inputs": [ 1511 | { 1512 | "internalType": "address", 1513 | "name": "newOwner", 1514 | "type": "address" 1515 | } 1516 | ], 1517 | "name": "transferOwnership", 1518 | "outputs": [], 1519 | "stateMutability": "nonpayable", 1520 | "type": "function" 1521 | }, 1522 | { 1523 | "inputs": [], 1524 | "name": "treasuryVault", 1525 | "outputs": [ 1526 | { 1527 | "internalType": "address", 1528 | "name": "", 1529 | "type": "address" 1530 | } 1531 | ], 1532 | "stateMutability": "view", 1533 | "type": "function" 1534 | }, 1535 | { 1536 | "inputs": [ 1537 | { 1538 | "internalType": "address", 1539 | "name": "_poolTokenAddress", 1540 | "type": "address" 1541 | } 1542 | ], 1543 | "name": "updateP2PIndexes", 1544 | "outputs": [], 1545 | "stateMutability": "nonpayable", 1546 | "type": "function" 1547 | }, 1548 | { 1549 | "inputs": [ 1550 | { 1551 | "internalType": "address", 1552 | "name": "", 1553 | "type": "address" 1554 | }, 1555 | { 1556 | "internalType": "address", 1557 | "name": "", 1558 | "type": "address" 1559 | } 1560 | ], 1561 | "name": "userMembership", 1562 | "outputs": [ 1563 | { 1564 | "internalType": "bool", 1565 | "name": "", 1566 | "type": "bool" 1567 | } 1568 | ], 1569 | "stateMutability": "view", 1570 | "type": "function" 1571 | }, 1572 | { 1573 | "inputs": [], 1574 | "name": "wEth", 1575 | "outputs": [ 1576 | { 1577 | "internalType": "address", 1578 | "name": "", 1579 | "type": "address" 1580 | } 1581 | ], 1582 | "stateMutability": "view", 1583 | "type": "function" 1584 | }, 1585 | { 1586 | "inputs": [ 1587 | { 1588 | "internalType": "address", 1589 | "name": "_poolTokenAddress", 1590 | "type": "address" 1591 | }, 1592 | { 1593 | "internalType": "uint256", 1594 | "name": "_amount", 1595 | "type": "uint256" 1596 | } 1597 | ], 1598 | "name": "withdraw", 1599 | "outputs": [], 1600 | "stateMutability": "nonpayable", 1601 | "type": "function" 1602 | }, 1603 | { 1604 | "stateMutability": "payable", 1605 | "type": "receive" 1606 | } 1607 | ] 1608 | -------------------------------------------------------------------------------- /test/abis/Uni.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "account", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "minter_", 12 | "type": "address" 13 | }, 14 | { 15 | "internalType": "uint256", 16 | "name": "mintingAllowedAfter_", 17 | "type": "uint256" 18 | } 19 | ], 20 | "payable": false, 21 | "stateMutability": "nonpayable", 22 | "type": "constructor" 23 | }, 24 | { 25 | "anonymous": false, 26 | "inputs": [ 27 | { 28 | "indexed": true, 29 | "internalType": "address", 30 | "name": "owner", 31 | "type": "address" 32 | }, 33 | { 34 | "indexed": true, 35 | "internalType": "address", 36 | "name": "spender", 37 | "type": "address" 38 | }, 39 | { 40 | "indexed": false, 41 | "internalType": "uint256", 42 | "name": "amount", 43 | "type": "uint256" 44 | } 45 | ], 46 | "name": "Approval", 47 | "type": "event" 48 | }, 49 | { 50 | "anonymous": false, 51 | "inputs": [ 52 | { 53 | "indexed": true, 54 | "internalType": "address", 55 | "name": "delegator", 56 | "type": "address" 57 | }, 58 | { 59 | "indexed": true, 60 | "internalType": "address", 61 | "name": "fromDelegate", 62 | "type": "address" 63 | }, 64 | { 65 | "indexed": true, 66 | "internalType": "address", 67 | "name": "toDelegate", 68 | "type": "address" 69 | } 70 | ], 71 | "name": "DelegateChanged", 72 | "type": "event" 73 | }, 74 | { 75 | "anonymous": false, 76 | "inputs": [ 77 | { 78 | "indexed": true, 79 | "internalType": "address", 80 | "name": "delegate", 81 | "type": "address" 82 | }, 83 | { 84 | "indexed": false, 85 | "internalType": "uint256", 86 | "name": "previousBalance", 87 | "type": "uint256" 88 | }, 89 | { 90 | "indexed": false, 91 | "internalType": "uint256", 92 | "name": "newBalance", 93 | "type": "uint256" 94 | } 95 | ], 96 | "name": "DelegateVotesChanged", 97 | "type": "event" 98 | }, 99 | { 100 | "anonymous": false, 101 | "inputs": [ 102 | { 103 | "indexed": false, 104 | "internalType": "address", 105 | "name": "minter", 106 | "type": "address" 107 | }, 108 | { 109 | "indexed": false, 110 | "internalType": "address", 111 | "name": "newMinter", 112 | "type": "address" 113 | } 114 | ], 115 | "name": "MinterChanged", 116 | "type": "event" 117 | }, 118 | { 119 | "anonymous": false, 120 | "inputs": [ 121 | { 122 | "indexed": true, 123 | "internalType": "address", 124 | "name": "from", 125 | "type": "address" 126 | }, 127 | { 128 | "indexed": true, 129 | "internalType": "address", 130 | "name": "to", 131 | "type": "address" 132 | }, 133 | { 134 | "indexed": false, 135 | "internalType": "uint256", 136 | "name": "amount", 137 | "type": "uint256" 138 | } 139 | ], 140 | "name": "Transfer", 141 | "type": "event" 142 | }, 143 | { 144 | "constant": true, 145 | "inputs": [], 146 | "name": "DELEGATION_TYPEHASH", 147 | "outputs": [ 148 | { 149 | "internalType": "bytes32", 150 | "name": "", 151 | "type": "bytes32" 152 | } 153 | ], 154 | "payable": false, 155 | "stateMutability": "view", 156 | "type": "function" 157 | }, 158 | { 159 | "constant": true, 160 | "inputs": [], 161 | "name": "DOMAIN_TYPEHASH", 162 | "outputs": [ 163 | { 164 | "internalType": "bytes32", 165 | "name": "", 166 | "type": "bytes32" 167 | } 168 | ], 169 | "payable": false, 170 | "stateMutability": "view", 171 | "type": "function" 172 | }, 173 | { 174 | "constant": true, 175 | "inputs": [], 176 | "name": "PERMIT_TYPEHASH", 177 | "outputs": [ 178 | { 179 | "internalType": "bytes32", 180 | "name": "", 181 | "type": "bytes32" 182 | } 183 | ], 184 | "payable": false, 185 | "stateMutability": "view", 186 | "type": "function" 187 | }, 188 | { 189 | "constant": true, 190 | "inputs": [ 191 | { 192 | "internalType": "address", 193 | "name": "account", 194 | "type": "address" 195 | }, 196 | { 197 | "internalType": "address", 198 | "name": "spender", 199 | "type": "address" 200 | } 201 | ], 202 | "name": "allowance", 203 | "outputs": [ 204 | { 205 | "internalType": "uint256", 206 | "name": "", 207 | "type": "uint256" 208 | } 209 | ], 210 | "payable": false, 211 | "stateMutability": "view", 212 | "type": "function" 213 | }, 214 | { 215 | "constant": false, 216 | "inputs": [ 217 | { 218 | "internalType": "address", 219 | "name": "spender", 220 | "type": "address" 221 | }, 222 | { 223 | "internalType": "uint256", 224 | "name": "rawAmount", 225 | "type": "uint256" 226 | } 227 | ], 228 | "name": "approve", 229 | "outputs": [ 230 | { 231 | "internalType": "bool", 232 | "name": "", 233 | "type": "bool" 234 | } 235 | ], 236 | "payable": false, 237 | "stateMutability": "nonpayable", 238 | "type": "function" 239 | }, 240 | { 241 | "constant": true, 242 | "inputs": [ 243 | { 244 | "internalType": "address", 245 | "name": "account", 246 | "type": "address" 247 | } 248 | ], 249 | "name": "balanceOf", 250 | "outputs": [ 251 | { 252 | "internalType": "uint256", 253 | "name": "", 254 | "type": "uint256" 255 | } 256 | ], 257 | "payable": false, 258 | "stateMutability": "view", 259 | "type": "function" 260 | }, 261 | { 262 | "constant": true, 263 | "inputs": [ 264 | { 265 | "internalType": "address", 266 | "name": "", 267 | "type": "address" 268 | }, 269 | { 270 | "internalType": "uint32", 271 | "name": "", 272 | "type": "uint32" 273 | } 274 | ], 275 | "name": "checkpoints", 276 | "outputs": [ 277 | { 278 | "internalType": "uint32", 279 | "name": "fromBlock", 280 | "type": "uint32" 281 | }, 282 | { 283 | "internalType": "uint96", 284 | "name": "votes", 285 | "type": "uint96" 286 | } 287 | ], 288 | "payable": false, 289 | "stateMutability": "view", 290 | "type": "function" 291 | }, 292 | { 293 | "constant": true, 294 | "inputs": [], 295 | "name": "decimals", 296 | "outputs": [ 297 | { 298 | "internalType": "uint8", 299 | "name": "", 300 | "type": "uint8" 301 | } 302 | ], 303 | "payable": false, 304 | "stateMutability": "view", 305 | "type": "function" 306 | }, 307 | { 308 | "constant": false, 309 | "inputs": [ 310 | { 311 | "internalType": "address", 312 | "name": "delegatee", 313 | "type": "address" 314 | } 315 | ], 316 | "name": "delegate", 317 | "outputs": [], 318 | "payable": false, 319 | "stateMutability": "nonpayable", 320 | "type": "function" 321 | }, 322 | { 323 | "constant": false, 324 | "inputs": [ 325 | { 326 | "internalType": "address", 327 | "name": "delegatee", 328 | "type": "address" 329 | }, 330 | { 331 | "internalType": "uint256", 332 | "name": "nonce", 333 | "type": "uint256" 334 | }, 335 | { 336 | "internalType": "uint256", 337 | "name": "expiry", 338 | "type": "uint256" 339 | }, 340 | { 341 | "internalType": "uint8", 342 | "name": "v", 343 | "type": "uint8" 344 | }, 345 | { 346 | "internalType": "bytes32", 347 | "name": "r", 348 | "type": "bytes32" 349 | }, 350 | { 351 | "internalType": "bytes32", 352 | "name": "s", 353 | "type": "bytes32" 354 | } 355 | ], 356 | "name": "delegateBySig", 357 | "outputs": [], 358 | "payable": false, 359 | "stateMutability": "nonpayable", 360 | "type": "function" 361 | }, 362 | { 363 | "constant": true, 364 | "inputs": [ 365 | { 366 | "internalType": "address", 367 | "name": "", 368 | "type": "address" 369 | } 370 | ], 371 | "name": "delegates", 372 | "outputs": [ 373 | { 374 | "internalType": "address", 375 | "name": "", 376 | "type": "address" 377 | } 378 | ], 379 | "payable": false, 380 | "stateMutability": "view", 381 | "type": "function" 382 | }, 383 | { 384 | "constant": true, 385 | "inputs": [ 386 | { 387 | "internalType": "address", 388 | "name": "account", 389 | "type": "address" 390 | } 391 | ], 392 | "name": "getCurrentVotes", 393 | "outputs": [ 394 | { 395 | "internalType": "uint96", 396 | "name": "", 397 | "type": "uint96" 398 | } 399 | ], 400 | "payable": false, 401 | "stateMutability": "view", 402 | "type": "function" 403 | }, 404 | { 405 | "constant": true, 406 | "inputs": [ 407 | { 408 | "internalType": "address", 409 | "name": "account", 410 | "type": "address" 411 | }, 412 | { 413 | "internalType": "uint256", 414 | "name": "blockNumber", 415 | "type": "uint256" 416 | } 417 | ], 418 | "name": "getPriorVotes", 419 | "outputs": [ 420 | { 421 | "internalType": "uint96", 422 | "name": "", 423 | "type": "uint96" 424 | } 425 | ], 426 | "payable": false, 427 | "stateMutability": "view", 428 | "type": "function" 429 | }, 430 | { 431 | "constant": true, 432 | "inputs": [], 433 | "name": "minimumTimeBetweenMints", 434 | "outputs": [ 435 | { 436 | "internalType": "uint32", 437 | "name": "", 438 | "type": "uint32" 439 | } 440 | ], 441 | "payable": false, 442 | "stateMutability": "view", 443 | "type": "function" 444 | }, 445 | { 446 | "constant": false, 447 | "inputs": [ 448 | { 449 | "internalType": "address", 450 | "name": "dst", 451 | "type": "address" 452 | }, 453 | { 454 | "internalType": "uint256", 455 | "name": "rawAmount", 456 | "type": "uint256" 457 | } 458 | ], 459 | "name": "mint", 460 | "outputs": [], 461 | "payable": false, 462 | "stateMutability": "nonpayable", 463 | "type": "function" 464 | }, 465 | { 466 | "constant": true, 467 | "inputs": [], 468 | "name": "mintCap", 469 | "outputs": [ 470 | { 471 | "internalType": "uint8", 472 | "name": "", 473 | "type": "uint8" 474 | } 475 | ], 476 | "payable": false, 477 | "stateMutability": "view", 478 | "type": "function" 479 | }, 480 | { 481 | "constant": true, 482 | "inputs": [], 483 | "name": "minter", 484 | "outputs": [ 485 | { 486 | "internalType": "address", 487 | "name": "", 488 | "type": "address" 489 | } 490 | ], 491 | "payable": false, 492 | "stateMutability": "view", 493 | "type": "function" 494 | }, 495 | { 496 | "constant": true, 497 | "inputs": [], 498 | "name": "mintingAllowedAfter", 499 | "outputs": [ 500 | { 501 | "internalType": "uint256", 502 | "name": "", 503 | "type": "uint256" 504 | } 505 | ], 506 | "payable": false, 507 | "stateMutability": "view", 508 | "type": "function" 509 | }, 510 | { 511 | "constant": true, 512 | "inputs": [], 513 | "name": "name", 514 | "outputs": [ 515 | { 516 | "internalType": "string", 517 | "name": "", 518 | "type": "string" 519 | } 520 | ], 521 | "payable": false, 522 | "stateMutability": "view", 523 | "type": "function" 524 | }, 525 | { 526 | "constant": true, 527 | "inputs": [ 528 | { 529 | "internalType": "address", 530 | "name": "", 531 | "type": "address" 532 | } 533 | ], 534 | "name": "nonces", 535 | "outputs": [ 536 | { 537 | "internalType": "uint256", 538 | "name": "", 539 | "type": "uint256" 540 | } 541 | ], 542 | "payable": false, 543 | "stateMutability": "view", 544 | "type": "function" 545 | }, 546 | { 547 | "constant": true, 548 | "inputs": [ 549 | { 550 | "internalType": "address", 551 | "name": "", 552 | "type": "address" 553 | } 554 | ], 555 | "name": "numCheckpoints", 556 | "outputs": [ 557 | { 558 | "internalType": "uint32", 559 | "name": "", 560 | "type": "uint32" 561 | } 562 | ], 563 | "payable": false, 564 | "stateMutability": "view", 565 | "type": "function" 566 | }, 567 | { 568 | "constant": false, 569 | "inputs": [ 570 | { 571 | "internalType": "address", 572 | "name": "owner", 573 | "type": "address" 574 | }, 575 | { 576 | "internalType": "address", 577 | "name": "spender", 578 | "type": "address" 579 | }, 580 | { 581 | "internalType": "uint256", 582 | "name": "rawAmount", 583 | "type": "uint256" 584 | }, 585 | { 586 | "internalType": "uint256", 587 | "name": "deadline", 588 | "type": "uint256" 589 | }, 590 | { 591 | "internalType": "uint8", 592 | "name": "v", 593 | "type": "uint8" 594 | }, 595 | { 596 | "internalType": "bytes32", 597 | "name": "r", 598 | "type": "bytes32" 599 | }, 600 | { 601 | "internalType": "bytes32", 602 | "name": "s", 603 | "type": "bytes32" 604 | } 605 | ], 606 | "name": "permit", 607 | "outputs": [], 608 | "payable": false, 609 | "stateMutability": "nonpayable", 610 | "type": "function" 611 | }, 612 | { 613 | "constant": false, 614 | "inputs": [ 615 | { 616 | "internalType": "address", 617 | "name": "minter_", 618 | "type": "address" 619 | } 620 | ], 621 | "name": "setMinter", 622 | "outputs": [], 623 | "payable": false, 624 | "stateMutability": "nonpayable", 625 | "type": "function" 626 | }, 627 | { 628 | "constant": true, 629 | "inputs": [], 630 | "name": "symbol", 631 | "outputs": [ 632 | { 633 | "internalType": "string", 634 | "name": "", 635 | "type": "string" 636 | } 637 | ], 638 | "payable": false, 639 | "stateMutability": "view", 640 | "type": "function" 641 | }, 642 | { 643 | "constant": true, 644 | "inputs": [], 645 | "name": "totalSupply", 646 | "outputs": [ 647 | { 648 | "internalType": "uint256", 649 | "name": "", 650 | "type": "uint256" 651 | } 652 | ], 653 | "payable": false, 654 | "stateMutability": "view", 655 | "type": "function" 656 | }, 657 | { 658 | "constant": false, 659 | "inputs": [ 660 | { 661 | "internalType": "address", 662 | "name": "dst", 663 | "type": "address" 664 | }, 665 | { 666 | "internalType": "uint256", 667 | "name": "rawAmount", 668 | "type": "uint256" 669 | } 670 | ], 671 | "name": "transfer", 672 | "outputs": [ 673 | { 674 | "internalType": "bool", 675 | "name": "", 676 | "type": "bool" 677 | } 678 | ], 679 | "payable": false, 680 | "stateMutability": "nonpayable", 681 | "type": "function" 682 | }, 683 | { 684 | "constant": false, 685 | "inputs": [ 686 | { 687 | "internalType": "address", 688 | "name": "src", 689 | "type": "address" 690 | }, 691 | { 692 | "internalType": "address", 693 | "name": "dst", 694 | "type": "address" 695 | }, 696 | { 697 | "internalType": "uint256", 698 | "name": "rawAmount", 699 | "type": "uint256" 700 | } 701 | ], 702 | "name": "transferFrom", 703 | "outputs": [ 704 | { 705 | "internalType": "bool", 706 | "name": "", 707 | "type": "bool" 708 | } 709 | ], 710 | "payable": false, 711 | "stateMutability": "nonpayable", 712 | "type": "function" 713 | } 714 | ] -------------------------------------------------------------------------------- /test/index.spec.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from "dotenv"; 2 | import { ethers } from "ethers"; 3 | import _range from "lodash/range"; 4 | 5 | import { EthersMulticall } from "../src"; 6 | 7 | import MorphoAbi from "./abis/Morpho.json"; 8 | import UniAbi from "./abis/Uni.json"; 9 | 10 | dotenv.config({ path: ".env.local" }); 11 | 12 | const httpRpcUrl = process.env.HTTP_RPC_URL || "https://rpc.ankr.com/eth"; 13 | 14 | describe("ethers-multicall", () => { 15 | let rpcProvider: ethers.providers.JsonRpcProvider; 16 | let signer: ethers.Signer; 17 | 18 | let morpho: ethers.Contract; 19 | let uni: ethers.Contract; 20 | 21 | beforeEach(() => { 22 | rpcProvider = new ethers.providers.JsonRpcProvider(httpRpcUrl, 1); 23 | signer = new ethers.Wallet(ethers.Wallet.createRandom().privateKey, rpcProvider); 24 | 25 | morpho = new ethers.Contract("0x8888882f8f843896699869179fB6E4f7e3B58888", MorphoAbi, signer); 26 | uni = new ethers.Contract("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", UniAbi, signer); 27 | }); 28 | 29 | describe("Providers integration", () => { 30 | it("should work given a JsonRpcProvider", async () => { 31 | const multicall = new EthersMulticall(rpcProvider); 32 | 33 | expect(multicall.contract.provider).toBe(rpcProvider); 34 | expect(multicall.contract.address).toBe("0xcA11bde05977b3631167028862bE2a173976CA11"); 35 | 36 | const wrappedMorpho = multicall.wrap(morpho); 37 | 38 | expect(wrappedMorpho.address).toBe(morpho.address); 39 | expect(await wrappedMorpho.cEth()).toBe("0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5"); 40 | }); 41 | 42 | it("should work given a JsonRpcBatchProvider", async () => { 43 | const rpcBatchProvider = new ethers.providers.JsonRpcBatchProvider(httpRpcUrl, 1); 44 | const multicall = new EthersMulticall(rpcBatchProvider); 45 | 46 | expect(multicall.contract.provider).toBe(rpcBatchProvider); 47 | expect(multicall.contract.address).toBe("0xcA11bde05977b3631167028862bE2a173976CA11"); 48 | 49 | const wrappedMorpho = multicall.wrap(morpho); 50 | 51 | expect(wrappedMorpho.address).toBe(morpho.address); 52 | expect(await wrappedMorpho.cEth()).toBe("0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5"); 53 | }); 54 | }); 55 | 56 | describe("Calls batching", () => { 57 | it("should batch UNI calls inside Promise.all", async () => { 58 | const multicall = new EthersMulticall(rpcProvider); 59 | const wrappedUni = multicall.wrap(uni); 60 | 61 | const send = rpcProvider.send.bind(rpcProvider); 62 | 63 | jest 64 | .spyOn(rpcProvider, "send") 65 | .mockImplementation(async (method, ...args) => send(method, ...args)); 66 | 67 | await Promise.all([wrappedUni.name(), wrappedUni.symbol(), wrappedUni.decimals()]).then( 68 | ([name, symbol, decimals]: [string, string, ethers.BigNumber]) => { 69 | expect(name).toBe("Uniswap"); 70 | expect(symbol).toBe("UNI"); 71 | expect(decimals.toString()).toBe("18"); 72 | } 73 | ); 74 | 75 | expect(rpcProvider.send).toBeCalledTimes(2); 76 | expect(rpcProvider.send).toBeCalledWith("eth_chainId", []); 77 | expect(rpcProvider.send).toBeCalledWith("eth_call", [ 78 | { 79 | data: "0xbce38bd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001600000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004313ce567000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000495d89b41000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000406fdde0300000000000000000000000000000000000000000000000000000000", 80 | to: "0xca11bde05977b3631167028862be2a173976ca11", 81 | }, 82 | "latest", 83 | ]); 84 | }); 85 | 86 | it("should batch UNI calls without Promise.all", async () => { 87 | const multicall = new EthersMulticall(rpcProvider); 88 | const wrappedUni = multicall.wrap(uni); 89 | 90 | const send = rpcProvider.send.bind(rpcProvider); 91 | 92 | jest 93 | .spyOn(rpcProvider, "send") 94 | .mockImplementation(async (method, ...args) => send(method, ...args)); 95 | 96 | wrappedUni.name().then((name: string) => expect(name).toBe("Uniswap")); 97 | wrappedUni.symbol().then((symbol: string) => expect(symbol).toBe("UNI")); 98 | await wrappedUni 99 | .decimals() 100 | .then((decimals: ethers.BigNumber) => expect(decimals.toString()).toBe("18")); 101 | 102 | expect(rpcProvider.send).toBeCalledTimes(2); 103 | expect(rpcProvider.send).toBeCalledWith("eth_chainId", []); 104 | expect(rpcProvider.send).toBeCalledWith("eth_call", [ 105 | { 106 | data: "0xbce38bd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001600000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f98400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004313ce567000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000495d89b41000000000000000000000000000000000000000000000000000000000000000000000000000000001f9840a85d5af5bf1d1762f925bdaddc4201f9840000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000406fdde0300000000000000000000000000000000000000000000000000000000", 107 | to: "0xca11bde05977b3631167028862be2a173976ca11", 108 | }, 109 | "latest", 110 | ]); 111 | }); 112 | 113 | it("should fetch UNI.balanceOf(cUNI) at block 14_500_000", async () => { 114 | const multicall = new EthersMulticall(rpcProvider); 115 | const wrappedUni = multicall.wrap(uni); 116 | 117 | const balance = await wrappedUni.balanceOf("0x35A18000230DA775CAc24873d00Ff85BccdeD550", { 118 | blockTag: 14_500_000, 119 | }); 120 | 121 | expect(balance.toString()).toEqual("9765621447608616146796922"); 122 | }); 123 | 124 | it("should fetch UNI.balanceOf(cUNI) at default block 14_500_000", async () => { 125 | const multicall = new EthersMulticall(rpcProvider, { defaultBlockTag: 14_500_000 }); 126 | const wrappedUni = multicall.wrap(uni); 127 | 128 | const balance = await wrappedUni.balanceOf("0x35A18000230DA775CAc24873d00Ff85BccdeD550"); 129 | 130 | expect(balance.toString()).toEqual("9765621447608616146796922"); 131 | }); 132 | 133 | it("should fetch UNI.numCheckpoints at block 14_400_000 with changing provider", async () => { 134 | const rpcProvider2 = new ethers.providers.JsonRpcProvider(httpRpcUrl, 1); 135 | 136 | const multicall = new EthersMulticall(rpcProvider); 137 | const wrappedUni = multicall.wrap(uni); 138 | 139 | const send = rpcProvider.send.bind(rpcProvider); 140 | const send2 = rpcProvider2.send.bind(rpcProvider2); 141 | 142 | jest 143 | .spyOn(rpcProvider, "send") 144 | .mockImplementation(async (method, ...args) => send(method, ...args)); 145 | jest 146 | .spyOn(rpcProvider2, "send") 147 | .mockImplementation(async (method, ...args) => send2(method, ...args)); 148 | 149 | const numCheckpointsBefore = await wrappedUni.balanceOf( 150 | "0x35A18000230DA775CAc24873d00Ff85BccdeD550", 151 | { blockTag: 14_400_000 } 152 | ); 153 | 154 | expect(rpcProvider.send).toBeCalledTimes(2); 155 | 156 | await multicall.setProvider(rpcProvider2, 1); 157 | const numCheckpointsAfter = await wrappedUni.balanceOf( 158 | "0x35A18000230DA775CAc24873d00Ff85BccdeD550", 159 | { blockTag: 14_400_000 } 160 | ); 161 | 162 | expect(rpcProvider2.send).toBeCalledTimes(2); 163 | 164 | expect(numCheckpointsBefore.toString()).toEqual(numCheckpointsAfter.toString()); 165 | }); 166 | 167 | it("should throw a descriptive Error when querying unknown contract", async () => { 168 | const multicall = new EthersMulticall(rpcProvider); 169 | const wrappedUnknown = multicall.wrap( 170 | new ethers.Contract("0xd6409e50c05879c5B9E091EB01E9Dd776d00A151", UniAbi, signer) 171 | ); 172 | 173 | expect(wrappedUnknown.symbol()).rejects.toThrow( 174 | new Error(`0xd6409e50c05879c5B9E091EB01E9Dd776d00A151:symbol() empty return data exception`) 175 | ); 176 | }); 177 | 178 | it("should query filters", async () => { 179 | const multicall = new EthersMulticall(rpcProvider); 180 | const wrappedUni = multicall.wrap(uni); 181 | 182 | const events = await wrappedUni.queryFilter( 183 | wrappedUni.filters.Transfer(), 184 | 14_000_000, 185 | 14_002_000 186 | ); 187 | 188 | expect(events).toHaveLength(269); 189 | }); 190 | 191 | it("should only fail the failing call promise when querying incorrect contract", async () => { 192 | const multicall = new EthersMulticall(rpcProvider); 193 | const wrappedUni = multicall.wrap(uni); 194 | const wrappedUnknown = multicall.wrap( 195 | new ethers.Contract("0xd6409e50c05879c5B9E091EB01E9Dd776d00A151", UniAbi, signer) 196 | ); 197 | 198 | expect(wrappedUni.symbol()).resolves.toBe("UNI"); 199 | expect(wrappedUnknown.symbol()).rejects.toThrow( 200 | "0xd6409e50c05879c5B9E091EB01E9Dd776d00A151:symbol() empty return data exception" 201 | ); 202 | expect(await wrappedUnknown.symbol().catch(() => "DEFAULT")).toBe("DEFAULT"); 203 | }); 204 | 205 | it("should only fail the failing call promise when querying before multicall deployment", async () => { 206 | const multicall = new EthersMulticall(rpcProvider); 207 | const wrappedUni = multicall.wrap(uni); 208 | 209 | expect(wrappedUni.symbol({ blockTag: 14_500_000 })).resolves.toBe("UNI"); 210 | expect(wrappedUni.symbol({ blockTag: 14_000_000 })).rejects.toThrow( 211 | 'call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="tryAggregate(bool,(address,bytes)[])", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.7.0)' 212 | ); 213 | expect(await wrappedUni.symbol({ blockTag: 14_000_000 }).catch(() => "UNI")).toBe("UNI"); 214 | }); 215 | }); 216 | }); 217 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "src" 5 | }, 6 | "include": ["src"] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "target": "es6", 5 | "module": "commonjs", 6 | "declaration": true, 7 | "outDir": "lib", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "resolveJsonModule": true 13 | }, 14 | "include": ["src", "test"] 15 | } 16 | --------------------------------------------------------------------------------