Skip to content

Commit

Permalink
update multicall script
Browse files Browse the repository at this point in the history
  • Loading branch information
EREN authored and EREN committed Dec 16, 2024
1 parent e3f1345 commit 2d609c3
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 11 deletions.
57 changes: 57 additions & 0 deletions contracts/BIFI/infra/BeefyMulticall.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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]>
/// @author Bogdan Dumitru <[email protected]>

contract Multicall {
struct Call {
address target;
bytes callData;
}
struct Return {
bool success;
bytes data;
}
function aggregate(
Call[] memory calls,
bool strict
) public returns (uint256 blockNumber, Return[] memory returnData) {
blockNumber = block.number;
returnData = new Return[](calls.length);
for (uint256 i = 0; i < calls.length; i++) {
(bool success, bytes memory ret) = calls[i].target.call(calls[i].callData);
if (strict) {
require(success);
}
returnData[i] = Return(success, 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;
}
}
235 changes: 235 additions & 0 deletions contracts/BIFI/infra/BeefyOracle/BeefyMulticall3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.12;

/// @title Multicall3
/// @notice Aggregate results from multiple function calls
/// @dev Multicall & Multicall2 backwards-compatible
/// @dev Aggregate methods are marked `payable` to save 24 gas per call
/// @author Michael Elliot <[email protected]>
/// @author Joshua Levine <[email protected]>
/// @author Nick Johnson <[email protected]>
/// @author Andreas Bigger <[email protected]>
/// @author Matt Solomon <[email protected]>
contract Multicall3 {
struct Call {
address target;
bytes callData;
}

struct Call3 {
address target;
bool allowFailure;
bytes callData;
}

struct Call3Value {
address target;
bool allowFailure;
uint256 value;
bytes callData;
}

struct Result {
bool success;
bytes returnData;
}

/// @notice Backwards-compatible call aggregation with Multicall
/// @param calls An array of Call structs
/// @return blockNumber The block number where the calls were executed
/// @return returnData An array of bytes containing the responses
function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData) {
blockNumber = block.number;
uint256 length = calls.length;
returnData = new bytes[](length);
Call calldata call;
for (uint256 i = 0; i < length; ) {
bool success;
call = calls[i];
(success, returnData[i]) = call.target.call(call.callData);
require(success, "Multicall3: call failed");
unchecked {
++i;
}
}
}

/// @notice Backwards-compatible with Multicall2
/// @notice Aggregate calls without requiring success
/// @param requireSuccess If true, require all calls to succeed
/// @param calls An array of Call structs
/// @return returnData An array of Result structs
function tryAggregate(
bool requireSuccess,
Call[] calldata calls
) public payable returns (Result[] memory returnData) {
uint256 length = calls.length;
returnData = new Result[](length);
Call calldata call;
for (uint256 i = 0; i < length; ) {
Result memory result = returnData[i];
call = calls[i];
(result.success, result.returnData) = call.target.call(call.callData);
if (requireSuccess) require(result.success, "Multicall3: call failed");
unchecked {
++i;
}
}
}

/// @notice Backwards-compatible with Multicall2
/// @notice Aggregate calls and allow failures using tryAggregate
/// @param calls An array of Call structs
/// @return blockNumber The block number where the calls were executed
/// @return blockHash The hash of the block where the calls were executed
/// @return returnData An array of Result structs
function tryBlockAndAggregate(
bool requireSuccess,
Call[] calldata calls
) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) {
blockNumber = block.number;
blockHash = blockhash(block.number);
returnData = tryAggregate(requireSuccess, calls);
}

/// @notice Backwards-compatible with Multicall2
/// @notice Aggregate calls and allow failures using tryAggregate
/// @param calls An array of Call structs
/// @return blockNumber The block number where the calls were executed
/// @return blockHash The hash of the block where the calls were executed
/// @return returnData An array of Result structs
function blockAndAggregate(
Call[] calldata calls
) public payable returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) {
(blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls);
}

/// @notice Aggregate calls, ensuring each returns success if required
/// @param calls An array of Call3 structs
/// @return returnData An array of Result structs
function aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData) {
uint256 length = calls.length;
returnData = new Result[](length);
Call3 calldata calli;
for (uint256 i = 0; i < length; ) {
Result memory result = returnData[i];
calli = calls[i];
(result.success, result.returnData) = calli.target.call(calli.callData);
assembly {
// Revert if the call fails and failure is not allowed
// `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)`
if iszero(or(calldataload(add(calli, 0x20)), mload(result))) {
// set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)")))
mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
// set data offset
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
// set length of revert string
mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017)
// set revert string: bytes32(abi.encodePacked("Multicall3: call failed"))
mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000)
revert(0x00, 0x64)
}
}
unchecked {
++i;
}
}
}

/// @notice Aggregate calls with a msg value
/// @notice Reverts if msg.value is less than the sum of the call values
/// @param calls An array of Call3Value structs
/// @return returnData An array of Result structs
function aggregate3Value(Call3Value[] calldata calls) public payable returns (Result[] memory returnData) {
uint256 valAccumulator;
uint256 length = calls.length;
returnData = new Result[](length);
Call3Value calldata calli;
for (uint256 i = 0; i < length; ) {
Result memory result = returnData[i];
calli = calls[i];
uint256 val = calli.value;
// Humanity will be a Type V Kardashev Civilization before this overflows - andreas
// ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256
unchecked {
valAccumulator += val;
}
(result.success, result.returnData) = calli.target.call{value: val}(calli.callData);
assembly {
// Revert if the call fails and failure is not allowed
// `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)`
if iszero(or(calldataload(add(calli, 0x20)), mload(result))) {
// set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)")))
mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
// set data offset
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
// set length of revert string
mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017)
// set revert string: bytes32(abi.encodePacked("Multicall3: call failed"))
mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000)
revert(0x00, 0x84)
}
}
unchecked {
++i;
}
}
// Finally, make sure the msg.value = SUM(call[0...i].value)
require(msg.value == valAccumulator, "Multicall3: value mismatch");
}

/// @notice Returns the block hash for the given block number
/// @param blockNumber The block number
function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) {
blockHash = blockhash(blockNumber);
}

/// @notice Returns the block number
function getBlockNumber() public view returns (uint256 blockNumber) {
blockNumber = block.number;
}

/// @notice Returns the block coinbase
function getCurrentBlockCoinbase() public view returns (address coinbase) {
coinbase = block.coinbase;
}

/// @notice Returns the block difficulty
function getCurrentBlockDifficulty() public view returns (uint256 difficulty) {
difficulty = block.difficulty;
}

/// @notice Returns the block gas limit
function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) {
gaslimit = block.gaslimit;
}

/// @notice Returns the block timestamp
function getCurrentBlockTimestamp() public view returns (uint256 timestamp) {
timestamp = block.timestamp;
}

/// @notice Returns the (ETH) balance of a given address
function getEthBalance(address addr) public view returns (uint256 balance) {
balance = addr.balance;
}

/// @notice Returns the block hash of the last block
function getLastBlockHash() public view returns (bytes32 blockHash) {
unchecked {
blockHash = blockhash(block.number - 1);
}
}

/// @notice Gets the base fee of the given block
/// @notice Can revert if the BASEFEE opcode is not implemented by the given chain
function getBasefee() public view returns (uint256 basefee) {
basefee = block.basefee;
}

/// @notice Returns the chain id
function getChainId() public view returns (uint256 chainid) {
chainid = block.chainid;
}
}
22 changes: 14 additions & 8 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ const config: DeploymentConfig = {
url: "https://public-node.rsk.co",
chainId: 30,
accounts,
gasPrice: 72000000
gasPrice: 72000000,
},
manta: {
url: process.env.MANTA_RPC || "https://manta-pacific.drpc.org",
Expand All @@ -201,7 +201,12 @@ const config: DeploymentConfig = {
url: process.env.SEI_RPC || "https://evm-rpc.sei-apis.com",
chainId: 1329,
accounts,
}
},
sonic: {
url: process.env.SONIC_RPC || "https://rpc.soniclabs.com",
chainId: 146,
accounts,
},
},
etherscan: {
// Your API key for Etherscan
Expand All @@ -223,10 +228,11 @@ const config: DeploymentConfig = {
fraxtal: process.env.FRAXTAL_API_KEY!,
mode: "api key is not required by the Kava explorer, but can't be empty",
scroll: process.env.SCROLL_API_KEY!,
rootstock: 'abc',
rootstock: "abc",
avax: process.env.AVAX_API_KEY!,
manta: 'someKey',
sei: 'sei',
manta: "someKey",
sei: "sei",
sonic: process.env.SONIC_API_KEY!,
},
customChains: [
{
Expand Down Expand Up @@ -322,7 +328,7 @@ const config: DeploymentConfig = {
chainId: 30,
urls: {
apiURL: "https://rootstock.blockscout.com/api",
browserURL: "https://rootstock.blockscout.com/"
browserURL: "https://rootstock.blockscout.com/",
},
},
{
Expand All @@ -338,8 +344,8 @@ const config: DeploymentConfig = {
chainId: 1329,
urls: {
apiURL: "https://seitrace.com/pacific-1/api",
browserURL: "https://seitrace.com"
}
browserURL: "https://seitrace.com",
},
},
],
},
Expand Down
15 changes: 12 additions & 3 deletions scripts/infra/deployAppMulticall.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,26 @@ const ethers = hardhat.ethers;
async function main() {
await hardhat.run("compile");

const Multicall = await ethers.getContractFactory("BeefyV2AppMulticall");
const MulticallV2 = await ethers.getContractFactory("BeefyV2AppMulticall");
const Multicall = await ethers.getContractFactory("Multicall");
const Multicall3 = await ethers.getContractFactory("Multicall3");

const multicallV2 = await MulticallV2.deploy();
const multicall = await Multicall.deploy();
const multicall3 = await Multicall3.deploy();

await multicallV2.deployed();
await multicall.deployed();
await multicall3.deployed();

console.log("App v2 multicall deployed:", multicall.address);
console.log("Multicall deployed:", multicall.address);
console.log("Multicall3 deployed:", multicall3.address);
console.log("App v2 multicall deployed:", multicallV2.address);
}

main()
.then(() => process.exit(0))
.catch((error) => {
.catch(error => {
console.error(error);
process.exit(1);
});

0 comments on commit 2d609c3

Please sign in to comment.