Skip to content

Instantly share code, notes, and snippets.

@cyborgdennett
Last active November 3, 2022 14:38
Show Gist options
  • Save cyborgdennett/f5b80caaf072386dc4a3a91f810e1424 to your computer and use it in GitHub Desktop.
Save cyborgdennett/f5b80caaf072386dc4a3a91f810e1424 to your computer and use it in GitHub Desktop.
OpenZeppelin Multicall
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
pragma experimental ABIEncoderV2;
/// @title Multicall - Aggregate results from multiple read-only function calls
/// @author Michael Elliot <[email protected]>
/// @author Joshua Levine <[email protected]>
/// @author Nick Johnson <[email protected]>
contract Multicall {
struct Call {
address target;
bytes callData;
}
function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) {
blockNumber = block.number;
returnData = new bytes[](calls.length);
for(uint256 i = 0; i < calls.length; i++) {
(bool success, bytes memory ret) = calls[i].target.call(calls[i].callData);
require(success);
returnData[i] = ret;
}
}
// Helper functions
function getEthBalance(address addr) public view returns (uint256 balance) {
balance = addr.balance;
}
function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) {
blockHash = blockhash(blockNumber);
}
function getLastBlockHash() public view returns (bytes32 blockHash) {
blockHash = blockhash(block.number - 1);
}
function getCurrentBlockTimestamp() public view returns (uint256 timestamp) {
timestamp = block.timestamp;
}
function getCurrentBlockDifficulty() public view returns (uint256 difficulty) {
difficulty = block.difficulty;
}
function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) {
gaslimit = block.gaslimit;
}
function getCurrentBlockCoinbase() public view returns (address coinbase) {
coinbase = block.coinbase;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol)
pragma solidity ^0.8.0;
import "./Address.sol";
/**
* @dev Provides a function to batch together multiple calls in a single external call.
*
* _Available since v4.1._
*/
abstract contract Multicall {
/**
* @dev Receives and executes a batch of function calls on this contract.
*/
function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = Address.functionDelegateCall(address(this), data[i]);
}
return results;
}
}
// An example using hardhat to create a contract and multicall the increment function n-times in a single transaction.
import { artifacts, ethers } from "hardhat";
async function main() {
const Clicker = await ethers.getContractFactory("CookieClicker");
const clicker = await Clicker.deploy()
await clicker.deployed()
const amt = 10 // times to multicall the same smart contract function
// get the abi of the function you wish to call
const inc = await getIncAbi()
// call the multicall function
var tx = await clicker.multicall(
Array(amt).fill(inc) // makes an array with n-times the same element
)
}
async function getIncAbi() {
const artifact = await ethers.getContractFactory("CookieClicker");
var functions = Object.keys(artifact.interface.functions)
functions.forEach(function (part, index) {
this[index] = "function " + part;
}, functions);
let iface = new ethers.utils.Interface(functions);
return iface.encodeFunctionData("inc")
}
main()
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Multicall.sol";
contract CookieClicker is Multicall {
int public cookies = 0;
function inc() public {
cookies++;
}
}
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/Multicall.sol";
contract Token is ERC20, Multicall {
constructor(uint256 initialSupply) ERC20("Gold", "GLD") {
_mint(msg.sender, initialSupply);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment