Skip to content

Commit

Permalink
Refs #454 -- Added multicall-in-router.md to general/build/smart-cont…
Browse files Browse the repository at this point in the history
…racts/gas-optimization (#619)

* added multicall-in-router to gas-optimization

* updated multicall-in-router.md

* update multicall-in-router.md

* update title

* update demo code
  • Loading branch information
jackleeio authored Jun 28, 2024
1 parent f818148 commit b067d9a
Showing 1 changed file with 111 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@

---
displayed_sidebar: generalSidebar
---

# Implement multicall in router-like contracts

In Solidity, implementing multicall functionality in router-like contracts can significantly reduce gas costs by batching multiple state-modifying calls into a single transaction. This technique is invaluable in contracts similar to those used by platforms like Uniswap and Compound.

**Demo Code**

Below, we have a sample contract `MulticallRouter` that demonstrates how to implement multicall functionality with state-modifying operations. This contract includes a `multicall` function that executes an array of encoded function calls, modifying contract state in an efficient manner.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract MulticallRouter {
uint256 public counter; // State variable to demonstrate state changes
mapping(uint256 => uint256) public data; // Mapping to store arbitrary data
function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(data[i]);
require(success, "Multicall execution failed");
results[i] = result;
}
}
function incrementCounter(uint256 amount) external {
counter += amount;
}
function updateData(uint256 key, uint256 value) external {
data[key] = value;
}
}
```

To verify the functionality and efficiency of the `MulticallRouter`, here is the corresponding testing script:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "forge-std/Test.sol";
import "./MulticallRouter.sol";
contract MulticallTest is Test {
MulticallRouter public router;
bytes[] callData;
function setUp() public {
router = new MulticallRouter();
callData = new bytes[](4);
callData[0] = abi.encodeWithSelector(
router.incrementCounter.selector,
1
);
callData[1] = abi.encodeWithSelector(
router.updateData.selector,
0,
100
);
callData[2] = abi.encodeWithSelector(
router.incrementCounter.selector,
2
);
callData[3] = abi.encodeWithSelector(
router.updateData.selector,
1,
200
);
}
function testIndividualCalls() public {
uint256 gasStart = gasleft();
router.incrementCounter(1);
router.updateData(0, 100);
router.incrementCounter(2);
router.updateData(1, 200);
uint256 gasEnd = gasleft();
uint256 gasUsed = gasStart - gasEnd;
emit log_named_uint("Gas used for individual calls", gasUsed);
}
function testMulticall() public {
uint256 gasStart = gasleft();
router.multicall(callData);
uint256 gasEnd = gasleft();
uint256 gasUsed = gasStart - gasEnd;
emit log_named_uint("Gas used for multicall", gasUsed);
}
}
```

By running the tests in the Foundry project, we found that `testIndividualCalls()` consumes `166259` gas, while `testMulticall()` consumes `139753` gas, indicating that using Multicall can save gas to some extent.

**Gas Optimization Analysis**

The primary advantage of using multicall is the reduction in gas costs by avoiding multiple transaction overheads. Here’s a comparison of gas usage between individual transactions and a single multicall:

- **Individual Transactions**: Each call incurs base transaction costs plus the gas for executing the function.
- **Single Multicall**: Incurs only one base transaction cost plus the gas for executing each function within a loop.

By batching calls, multicall can significantly reduce the cumulative gas cost, especially when performing multiple operations.

**Recommendations for Gas Optimization**

Implementing multicall in router-like contracts can save gas by reducing the number of transactions and leveraging the lower cumulative gas cost of executing multiple operations in a single transaction.

0 comments on commit b067d9a

Please sign in to comment.