{"id":875,"date":"2023-10-28T14:01:50","date_gmt":"2023-10-28T06:01:50","guid":{"rendered":"https:\/\/vinta.ws\/code\/?p=875"},"modified":"2026-03-17T01:18:33","modified_gmt":"2026-03-16T17:18:33","slug":"solidity-multicall-aggregate-multiple-contract-calls","status":"publish","type":"post","link":"https:\/\/vinta.ws\/code\/solidity-multicall-aggregate-multiple-contract-calls.html","title":{"rendered":"Solidity: Multicall - Aggregate Multiple Contract Calls"},"content":{"rendered":"<p>There are different implementations of multicall:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/Vectorized\/multicaller\">https:\/\/github.com\/Vectorized\/multicaller<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/mds1\/multicall\">https:\/\/github.com\/mds1\/multicall<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/AmazingAng\/WTF-Solidity\/tree\/main\/55_MultiCall\">https:\/\/github.com\/AmazingAng\/WTF-Solidity\/tree\/main\/55_MultiCall<\/a><\/li>\n<\/ul>\n<p>In the following section, we will use <code>Multicaller<\/code> as an example to illustrate the process.<\/p>\n<p>The main idea of <code>Multicaller<\/code> is to aggregate multiple contract function calls into a single one. It's usually used to batch contract reads from off-chain apps. However, it could also be used to batch contract writes.<\/p>\n<h2>Multiple Contract Reads<\/h2>\n<pre class=\"line-numbers\"><code class=\"language-typescript\">import { defaultAbiCoder } from \"ethers\/lib\/utils\"\n\nclass Liquidator {\n    async fetchIsLiquidatableResults(\n        marketId: number,\n        positions: Position[],\n    ) {\n        const price = await this.pythService.fetchPythOraclePrice(marketId)\n\n        const targets = new Array(positions.length).fill(this.exchange.address)\n        const data = positions.map(position =&gt;\n            this.exchange.interface.encodeFunctionData(\"isLiquidatable\", [\n                marketId,\n                position.account,\n                price,\n            ]),\n        )\n        const values = new Array(accountMarkets.length).fill(0)\n\n        return await this.multicaller.callStatic.aggregate(targets, data, values)\n    }\n\n    async start() {\n        const positions = await this.fetchPositions(marketId)\n        const results = await this.fetchIsLiquidatableResults(marketId, positions)\n\n        for (const [i, result] of results.entries()) {\n            const isLiquidatable = defaultAbiCoder.decode([\"bool\"], result)[0]\n            const position = positions[i]\n            console.log(<code>${position.account} isLiquidatable: ${isLiquidatable}<\/code>)\n        }\n    }\n}<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/github.com\/Vectorized\/multicaller\/blob\/main\/API.md#aggregate\">https:\/\/github.com\/Vectorized\/multicaller\/blob\/main\/API.md#aggregate<\/a><\/p>\n<h2>Multiple Contract Writes<\/h2>\n<p>It requires the target contract is compatible with <code>Multicaller<\/code> if the target contract needs to read <code>msg.sender<\/code>.<\/p>\n<pre class=\"line-numbers\"><code class=\"language-solidity\">\/\/ SPDX-License-Identifier: MIT\npragma solidity &gt;=0.8.0;\n\nimport { LibMulticaller } from \"multicaller\/LibMulticaller.sol\";\n\ncontract MulticallerSenderCompatible {\n    function _sender() internal view virtual returns (address) {\n        return LibMulticaller.sender();\n    }\n}\n\ncontract Exchange is MulticallerSenderCompatible {\n    function openPosition(OpenPositionParams calldata params) external returns (int256, int256) {\n        address taker = _sender();\n        return _openPositionFor(taker, params);\n    }\n}<\/code><\/pre>\n<pre class=\"line-numbers\"><code class=\"language-typescript\">class Bot {\n    async openPosition() {\n        const targets = [\n            this.oracleAdapter.address,\n            this.exchange.address,\n        ]\n        const data = [\n            this.oracleAdapter.interface.encodeFunctionData(\"updatePrice\", [priceId, priceData]),\n            this.exchange.interface.encodeFunctionData(\"openPosition\", [params]),\n        ]\n        const values = [\n            BigNumber.from(0),\n            BigNumber.from(0),\n        ]\n\n        \/\/ update oracle price first, then open position\n        const tx = await this.multicaller.connect(taker).aggregateWithSender(targets, data, values)\n        await tx.wait()\n    }\n}<\/code><\/pre>\n<p>ref:<br \/>\n<a href=\"https:\/\/github.com\/Vectorized\/multicaller\/blob\/main\/API.md#aggregatewithsender\">https:\/\/github.com\/Vectorized\/multicaller\/blob\/main\/API.md#aggregatewithsender<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The main idea of Multicaller is to aggregate multiple contract function calls into a single one. It's usually to batch contract reads from off-chain apps. However, it could also be used to batch contract writes.<\/p>\n","protected":false},"author":1,"featured_media":876,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[137],"tags":[138,147,143],"class_list":["post-875","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blockchain","tag-ethereum","tag-smart-contract","tag-solidity"],"_links":{"self":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/875","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/comments?post=875"}],"version-history":[{"count":0,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/posts\/875\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media\/876"}],"wp:attachment":[{"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/media?parent=875"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/categories?post=875"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vinta.ws\/code\/wp-json\/wp\/v2\/tags?post=875"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}