Skip to content

Commit 451ab81

Browse files
committed
add multicall task
1 parent cc5850e commit 451ab81

File tree

15 files changed

+243
-6
lines changed

15 files changed

+243
-6
lines changed

basic/07-hardhat/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ Hardhat Runner 是与 Hardhat 交互的 CLI 命令,是一个可扩展的任务
2020

2121
## 项目结构和配置 hardhat
2222

23+
```sh
24+
npm install --save-dev hardhat // 安装hardhat
25+
npx hardhat // 创建hardhat项目
26+
```
27+
2328
### 项目结构
2429

2530
一个标准的使用 hardhat 构建的项目通常是这样的:

basic/39-Ethlend/README.md

Lines changed: 0 additions & 5 deletions
This file was deleted.
-211 KB
Binary file not shown.

basic/39-Multicall/.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules
2+
.env
3+
coverage
4+
coverage.json
5+
typechain
6+
7+
#Hardhat files
8+
cache
9+
artifacts

basic/39-Multicall/README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Multicall
2+
3+
Multicall aggregates results from multiple contract **constant function calls**.
4+
5+
This reduces the number of separate JSON RPC requests that need to be sent (especially useful if using remote nodes like Infura), while also providing the guarantee that all values returned are from the same block (like an atomic read) and returning the block number the values are from (giving them important context so that results from old blocks can be ignored if they're from an out-of-date node).
6+
7+
This smart contract is intended to be used with **Multicall.js** in front-end dapps.
8+
9+
10+
## Multicall.js
11+
project url: https://github.com/makerdao/multicall.js
12+
- Get the return value(s) of multiple smart contract function calls in a single call
13+
- Guarantee that all values are from the same block
14+
- Use watchers to poll for multiple blockchain state variables/functions
15+
- Get updates when a watcher detects state has changed
16+
- Results from out of sync nodes are automatically ignored
17+
- Get new block updates
18+
19+
20+
## 参考链接
21+
- github 仓库地址: https://github.com/ETHLend/Microstaking/blob/master/contracts/StakingContract.sol
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
4+
pragma solidity ^0.8.0;
5+
6+
/// @title Multicall - Aggregate results from multiple read-only function calls
7+
/// @author Michael Elliot <[email protected]>
8+
/// @author Joshua Levine <[email protected]>
9+
/// @author Nick Johnson <[email protected]>
10+
11+
contract Multicall {
12+
struct Call {
13+
address target;
14+
bytes callData;
15+
}
16+
struct Result {
17+
bool success;
18+
bytes returnData;
19+
}
20+
21+
function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) {
22+
blockNumber = block.number;
23+
returnData = new bytes[](calls.length);
24+
for(uint256 i = 0; i < calls.length; i++) {
25+
(bool success, bytes memory ret) = calls[i].target.call(calls[i].callData);
26+
require(success, "Multicall aggregate: call failed");
27+
returnData[i] = ret;
28+
}
29+
}
30+
function blockAndAggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) {
31+
(blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls);
32+
}
33+
function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) {
34+
blockHash = blockhash(blockNumber);
35+
}
36+
function getBlockNumber() public view returns (uint256 blockNumber) {
37+
blockNumber = block.number;
38+
}
39+
function getCurrentBlockCoinbase() public view returns (address coinbase) {
40+
coinbase = block.coinbase;
41+
}
42+
function getCurrentBlockDifficulty() public view returns (uint256 difficulty) {
43+
difficulty = block.difficulty;
44+
}
45+
function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) {
46+
gaslimit = block.gaslimit;
47+
}
48+
function getCurrentBlockTimestamp() public view returns (uint256 timestamp) {
49+
timestamp = block.timestamp;
50+
}
51+
function getEthBalance(address addr) public view returns (uint256 balance) {
52+
balance = addr.balance;
53+
}
54+
function getLastBlockHash() public view returns (bytes32 blockHash) {
55+
blockHash = blockhash(block.number - 1);
56+
}
57+
function tryAggregate(bool requireSuccess, Call[] memory calls) public returns (Result[] memory returnData) {
58+
returnData = new Result[](calls.length);
59+
for(uint256 i = 0; i < calls.length; i++) {
60+
(bool success, bytes memory ret) = calls[i].target.call(calls[i].callData);
61+
62+
if (requireSuccess) {
63+
require(success, "Multicall2 aggregate: call failed");
64+
}
65+
66+
returnData[i] = Result(success, ret);
67+
}
68+
}
69+
function tryBlockAndAggregate(bool requireSuccess, Call[] memory calls) public returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) {
70+
blockNumber = block.number;
71+
blockHash = blockhash(block.number);
72+
returnData = tryAggregate(requireSuccess, calls);
73+
}
74+
}

basic/39-Multicall/hardhat.config.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require("@nomiclabs/hardhat-waffle");
2+
3+
// This is a sample Hardhat task. To learn how to create your own go to
4+
// https://hardhat.org/guides/create-task.html
5+
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
6+
const accounts = await hre.ethers.getSigners();
7+
8+
for (const account of accounts) {
9+
console.log(account.address);
10+
}
11+
});
12+
13+
// You need to export an object to set up your config
14+
// Go to https://hardhat.org/config/ to learn more
15+
16+
/**
17+
* @type import('hardhat/config').HardhatUserConfig
18+
*/
19+
module.exports = {
20+
solidity: "0.8.4",
21+
};

basic/39-Multicall/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "hardhat-project",
3+
"devDependencies": {
4+
"@nomiclabs/hardhat-ethers": "^2.0.3",
5+
"@nomiclabs/hardhat-waffle": "^2.0.1",
6+
"chai": "^4.3.4",
7+
"ethereum-waffle": "^3.4.0",
8+
"ethers": "^5.5.2",
9+
"hardhat": "^2.8.0",
10+
"@makerdao/multicall": "0.12.0"
11+
}
12+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// We require the Hardhat Runtime Environment explicitly here. This is optional
2+
// but useful for running the script in a standalone fashion through `node <script>`.
3+
//
4+
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
5+
// Runtime Environment's members available in the global scope.
6+
const hre = require("hardhat");
7+
8+
async function main() {
9+
// Hardhat always runs the compile task when running scripts with its command
10+
// line interface.
11+
//
12+
// If this script is run directly using `node` you may want to call compile
13+
// manually to make sure everything is compiled
14+
// await hre.run('compile');
15+
16+
// We get the contract to deploy
17+
const Greeter = await hre.ethers.getContractFactory("Greeter");
18+
const greeter = await Greeter.deploy("Hello, Hardhat!");
19+
20+
await greeter.deployed();
21+
22+
console.log("Greeter deployed to:", greeter.address);
23+
}
24+
25+
// We recommend this pattern to be able to use async/await everywhere
26+
// and properly handle errors.
27+
main()
28+
.then(() => process.exit(0))
29+
.catch((error) => {
30+
console.error(error);
31+
process.exit(1);
32+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const { expect } = require("chai");
2+
const { ethers } = require("hardhat");
3+
4+
describe("Greeter", function () {
5+
it("Should return the new greeting once it's changed", async function () {
6+
const Greeter = await ethers.getContractFactory("Greeter");
7+
const greeter = await Greeter.deploy("Hello, world!");
8+
await greeter.deployed();
9+
10+
expect(await greeter.greet()).to.equal("Hello, world!");
11+
12+
const setGreetingTx = await greeter.setGreeting("Hola, mundo!");
13+
14+
// wait until the transaction is mined
15+
await setGreetingTx.wait();
16+
17+
expect(await greeter.greet()).to.equal("Hola, mundo!");
18+
});
19+
});

0 commit comments

Comments
 (0)