Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refs #454 -- Added multicall-in-router.md to general/build/smart-contracts/gas-optimization #619

Merged
merged 5 commits into from
Jun 28, 2024
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
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 calls into a single transaction. This is a common feature in contracts like the Uniswap Router and the Compound Bulker. Multicall allows users to execute a sequence of calls within a single transaction, thereby optimizing gas usage and improving efficiency.

**Demo Code**

Below, we have a sample contract `MulticallRouter` that demonstrates how to implement multicall functionality. This contract includes a `multicall` function that accepts an array of encoded function calls and executes them in sequence.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract MulticallRouter {
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;
}
}

// Example function to demonstrate usage
function exampleFunction1(uint256 x) external pure returns (uint256) {
return x * 2;
}

function exampleFunction2(uint256 y) external pure returns (uint256) {
return y + 3;
}
}
```

In this example, the `multicall` function uses `delegatecall` to execute each function call in the context of the current contract. This ensures that the state changes and storage modifications occur within the same contract.

### Usage Example

To use this `MulticallRouter` contract, you can encode the function calls and pass them to the `multicall` function. Here's an example of how to encode and call the functions using Solidity:

```solidity
contract MulticallExample {
MulticallRouter public router;

constructor(address _router) {
router = MulticallRouter(_router);
}

function performMulticall() external {
bytes[] memory callData = new bytes[](2);
callData[0] = abi.encodeWithSelector(router.exampleFunction1.selector, 42);
callData[1] = abi.encodeWithSelector(router.exampleFunction2.selector, 21);

bytes[] memory results = router.multicall(callData);

// Handle the results
uint256 result1 = abi.decode(results[0], (uint256));
uint256 result2 = abi.decode(results[1], (uint256));

// Do something with the results
}
}
```

**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.
Loading