Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| 0x669a7d5e | 7766993 | 124 days ago | IN | 2 wei | 0.00141379 |
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
MultiCall
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;
/// Each call issued has a revert policy. This controls the behavior of the batch if the call
/// reverts.
enum RevertPolicy {
REVERT, // Bubble the revert, undoing the entire multicall/batch. `contextdepth` is ignored
HALT, // Don't revert, but end the multicall/batch immediately. Subsequent calls are not
// executed. An OOG revert is always bubbled
CONTINUE // Ignore the revert and continue with the batch. The corresponding `Result` will have
// `success = false`. An OOG revert is always bubbled
}
struct Call {
address payable target;
RevertPolicy revertPolicy;
uint256 value;
bytes data;
}
struct Result {
bool success;
bytes data;
}
interface IMultiCall {
/// @param contextdepth determines the depth of the context stack that we inspect (the number of
/// all-but-one-64th iterations applied) when determining whether a call
/// reverted due to OOG. Setting this too high is gas-wasteful during revert
/// handling. OOG checking only works when the revert reason is empty. If an
/// intervening context applies its own revert reason, OOG checking will not
/// be applied.
/// Mismatches between `msg.value` and each `calls[i].value` is not checked or handled
/// specially. If this contract has nonzero `address(this).balance`, you can get some free ETH
/// by setting `value` to nonzero. If you set `msg.value` lower than the sum of
/// `calls[i].value`, then the creation of one of the call contexts may fail and you'll get a
/// failure (possibly a bubbled revert, depending on the value of `revertPolicy`) with no
/// reason. If you set `revertPolicy` to something other than `REVERT` and a call with nonzero
/// value reverts, the extra ETH is kept in this contract. You must make other arrangements for
/// value refund.
function multicall(Call[] calldata calls, uint256 contextdepth) external payable returns (Result[] memory);
receive() external payable;
}
///////////////////// ABANDON ALL HOPE, YE WHO ENTER HERE //////////////////////
// But seriously, everything that comes after this is a pile of gas golfing. All
// you need to know is the interface above.
library SafeCall {
/// Call `target` with `data` sending `value` ETH. `sender` (as 20 bytes) is appeneded to the
/// end of `data`. Returns the `success` of the call as well as any `returndata`/revert
/// data. *HOWEVER*, if an out-of-gas occurs at `contextdepth` frames away from `target`, we
/// will instead revert with an OOG (`invalid()`). We will also revert when calling a `target`
/// without code.
/// @dev Out-of-gas is detected by the absence of returndata as well as a `gasleft()` at or
/// below what the `contextdepth + 1` times iterated all-but-one-64th rule would
/// indicate. The all-but-one-64th rule is applied naïvely, not accounting for the gas
/// costs of setting up the stack or the caller-paid costs of `call`ing. This means that in
/// order to avoid a false-positive OOG detection, gas must be slightly overprovisioned.
/// @dev This does not align the free memory pointer to a slot/word boundary.
/// @dev Calling a precompile will not result in a revert, even though it contains no code.
/// @dev Sending ETH and no data to an EOA will not result in a revert.
function safeCall(address target, uint256 value, bytes calldata data, address sender, uint256 contextdepth)
internal
returns (bool success, bytes memory returndata)
{
assembly ("memory-safe") {
returndata := mload(0x40)
calldatacopy(returndata, data.offset, data.length)
// Append the ERC-2771 forwarded caller
mstore(add(returndata, data.length), shl(0x60, sender))
// Only append the ERC-2771 forwarded caller if the selector is also present
let length := add(mul(0x14, lt(0x03, data.length)), data.length)
let beforeGas := gas()
success := call(gas(), target, value, returndata, length, codesize(), 0x00)
// `verbatim` can't work in inline assembly. Assignment of a value to a variable costs
// gas (although how much is unpredictable because it depends on the Yul/IR optimizer),
// as does the `GAS` opcode itself. Therefore, the `gas()` below returns less than the
// actual amount of gas available for computation at the end of the call. Also
// `beforeGas` above is exclusive of the preparing of the stack for `call` as well as
// the gas costs of the `call` paid by the caller (e.g. cold account access). All this
// makes the check below slightly too conservative. However, we do not correct this
// because the correction would become outdated (possibly too permissive) if the opcodes
// are repriced.
let afterGas := gas()
if iszero(returndatasize()) {
// The absence of returndata means that it's possible that either we called an
// address without code or that the call reverted due to out-of-gas. We must check.
for {} true {} {
if success {
// Success with no returndata could indicate calling an address with no code
// (potentially an EOA). Disallow calling an EOA unless sending no data and some
// ETH.
if or(iszero(value), data.length) {
if iszero(extcodesize(target)) { revert(codesize(), 0x00) }
}
break
}
// Apply the "all but one 64th" rule `contextdepth + 1` times.
let remainingGas := shr(0x06, beforeGas)
for {} contextdepth { contextdepth := sub(contextdepth, 0x01) } {
remainingGas := add(remainingGas, shr(0x06, sub(beforeGas, remainingGas)))
}
// Check that the revert was not due to OOG.
if iszero(lt(remainingGas, afterGas)) { invalid() }
break
}
}
// Copy returndata into memory, ignoring whether it's a result or a revert reason.
mstore(returndata, returndatasize())
let dst := add(0x20, returndata)
returndatacopy(dst, 0x00, returndatasize())
mstore(0x40, add(returndatasize(), dst))
}
}
/// This version of `safeCall` omits the OOG check because it bubbles the revert if the call
/// reverts. Therefore, `success` is always `true`.
/// @dev This does not align the free memory pointer to a slot boundary.
function safeCall(address target, uint256 value, bytes calldata data, address sender)
internal
returns (bool success, bytes memory returndata)
{
assembly ("memory-safe") {
returndata := mload(0x40)
calldatacopy(returndata, data.offset, data.length)
// Append the ERC-2771 forwarded caller
mstore(add(returndata, data.length), shl(0x60, sender))
// Only append the ERC-2771 forwarded caller if the selector is also present
success :=
call(gas(), target, value, returndata, add(mul(0x14, lt(0x03, data.length)), data.length), codesize(), 0x00)
let dst := add(0x20, returndata)
returndatacopy(dst, 0x00, returndatasize())
if iszero(success) { revert(dst, returndatasize()) }
if iszero(returndatasize()) {
if or(iszero(value), data.length) { if iszero(extcodesize(target)) { revert(codesize(), 0x00) } }
}
mstore(returndata, returndatasize())
mstore(0x40, add(returndatasize(), dst))
}
}
}
type CallArrayIterator is uint256;
library LibCallArrayIterator {
/// Advance the iterator one position down the array. Out-of-bounds is not checked.
function next(CallArrayIterator i) internal pure returns (CallArrayIterator) {
unchecked {
return CallArrayIterator.wrap(32 + CallArrayIterator.unwrap(i));
}
}
}
using LibCallArrayIterator for CallArrayIterator global;
function __eq(CallArrayIterator a, CallArrayIterator b) pure returns (bool) {
return CallArrayIterator.unwrap(a) == CallArrayIterator.unwrap(b);
}
function __ne(CallArrayIterator a, CallArrayIterator b) pure returns (bool) {
return CallArrayIterator.unwrap(a) != CallArrayIterator.unwrap(b);
}
using {__eq as ==, __ne as !=} for CallArrayIterator global;
library UnsafeCallArray {
/// Create an iterator pointing to the first element of the `calls` array. Out-of-bounds is not
/// checked.
function iter(Call[] calldata calls) internal pure returns (CallArrayIterator r) {
assembly ("memory-safe") {
r := calls.offset
}
}
/// Create an iterator pointing to the one-past-the-end element of the `calls`
/// array. Dereferencing this iterator will result in out-of-bounds access.
function end(Call[] calldata calls) internal pure returns (CallArrayIterator r) {
unchecked {
return CallArrayIterator.wrap((calls.length << 5) + CallArrayIterator.unwrap(iter(calls)));
}
}
/// Dereference the iterator `i` and return the values in the struct. This is *roughly*
/// equivalent to:
/// Call calldata call = calls[i];
/// (target, data, revertPolicy) = (call.target, call.data, call.revertPolicy);
/// Of course `i` isn't an integer, so the analogy is a bit loose. There are a lot of bounds
/// checks that are omitted here. While we apply a relaxed ABI encoding (there are some
/// encodings that we accept that Solidity would not), any valid ABI encoding accepted by
/// Solidity is decoded identically.
/// @dev `revertPolicy` is returned as `uint256` because it optimizes gas
function get(Call[] calldata calls, CallArrayIterator i)
internal
pure
returns (address target, uint256 value, bytes calldata data, uint256 revertPolicy)
{
assembly ("memory-safe") {
// `s` points at the `Call` struct. This is 96 bytes before the offset to the `data`
// array length. We allow the indirection/offset relative to `calls` to be negative.
let s := add(calls.offset, calldataload(i))
// `s` points to `target`; load it.
target := calldataload(s)
// Check for dirty bits in `target`.
let err := shr(0xa0, target)
// Load `revertPolicy`
revertPolicy := calldataload(add(0x20, s))
// and check it for dirty bits too.
err := or(err, gt(revertPolicy, 0x02))
// 2 is the limit for the `RevertPolicy` enum. Violating this _should_ result in a
// revert with a reason of `Panic(33)` for strict compatibility with Solidity, but we
// gas-optimize this by lumping it in with the normal "malformed calldata" revert reason
// (empty).
// Revert if any calldata is unclean.
if err { revert(codesize(), 0x00) }
// Load `value`. No range checking is required.
value := calldataload(add(0x40, s))
// Indirect `data.offset` to get the `bytes` payload.
data.offset :=
add(
s,
// We allow the offset stored in the `Call` struct to be negative.
calldataload(
// Can't overflow; `s` is in-bounds of `calldata`.
add(0x60, s)
)
)
// `data.offset` now points to the length field 32 bytes before the start of the actual array.
// Now we load `data.length` and set `data.offset` to the start of the actual array.
data.length := calldataload(data.offset)
data.offset := add(0x20, data.offset)
}
}
}
type ResultArrayIterator is uint256;
library LibResultArrayIterator {
/// Advance the iterator one position down the array. Out-of-bounds is not checked.
function next(ResultArrayIterator i) internal pure returns (ResultArrayIterator r) {
unchecked {
return ResultArrayIterator.wrap(32 + ResultArrayIterator.unwrap(i));
}
}
}
using LibResultArrayIterator for ResultArrayIterator global;
library UnsafeResultArray {
/// Create an iterator pointing to the first element of the `results` array. Out-of-bounds is
/// not checked.
function iter(Result[] memory results) internal pure returns (ResultArrayIterator r) {
assembly ("memory-safe") {
r := add(0x20, results)
}
}
/// Dereference the iterator `i` and set the values in the returned struct (`Result
/// memory`). This is *roughly* equivalent to:
/// Result memory result = results[i];
/// (result.success, result.data) = (success, data);
/// Of course `i` isn't an integer, so the analogy is a bit loose. We omit bounds checking on
/// `i`, so if it is out-of-bounds, memory will be corrupted.
function set(Result[] memory, ResultArrayIterator i, bool success, bytes memory data) internal pure {
assembly ("memory-safe") {
let dst := mload(i)
mstore(dst, success)
mstore(add(0x20, dst), data)
}
}
/// This is roughly equivalent to `results.length = i.next()`. Of course `i` is not an integer
/// and settings `results.length` is illegal. Thus, it's written in Yul.
function unsafeTruncate(Result[] memory results, ResultArrayIterator i) internal pure {
assembly ("memory-safe") {
mstore(results, shr(0x05, sub(i, results)))
}
}
/// This is equivalent to `result = new Result[](length)`. While the array itself is populated
/// correctly, the memory pointed *AT* by the slots of the array is not zeroed.
function unsafeAlloc(uint256 length) internal pure returns (Result[] memory result) {
assembly ("memory-safe") {
result := mload(0x40)
mstore(result, length)
mstore(0x40, add(0x20, add(mul(0x60, length), result)))
for {
let baseArray := add(0x20, result)
let lenArrayBytes := shl(0x05, length)
let baseResults := add(baseArray, lenArrayBytes)
let i
} lt(i, lenArrayBytes) { i := add(0x20, i) } { mstore(add(baseArray, i), add(baseResults, add(i, i))) }
}
}
}
library UnsafeReturn {
/// This is *ROUGHLY* equivalent to `return(abi.encode(r))`.
/// @dev This *DOES NOT* produce the so-called "Strict Encoding Mode" specified by the formal
/// ABI encoding specification
/// https://docs.soliditylang.org/en/v0.8.25/abi-spec.html#strict-encoding-mode . However,
/// it is compatible with the non-strict ABI *decoder* employed by Solidity. In particular,
/// it does not pad the encoding of each value to a multiple of 32 bytes, and it does not
/// contiguously encode all values reachable from some tuple/struct before moving on to
/// another tuple/struct. (e.g. the encoding of an array of 2 `Result`s first encodes each
/// `Result` then encodes each `bytes data`)
function unsafeReturn(Result[] memory r) internal pure {
// We assume (and our use in this file obeys) that all these objects in memory are laid out
// contiguously and in a sensible order.
assembly ("memory-safe") {
// This is not technically memory safe, but manual verification of the emitted bytecode
// demonstrates that this does not clobber any compiler-generated temporaries.
let returndatastart := sub(r, 0x20)
mstore(returndatastart, 0x20)
// Because *all* the structs/tuples involved here are dynamic types according to the ABI
// specification, the layout in memory is identical to the layout in returndata except
// that memory uses pointers and returndata uses offsets. Convert pointers to offsets.
for {
let base := add(0x20, r)
let i := base
let end := add(base, shl(0x05, mload(r)))
} lt(i, end) { i := add(0x20, i) } {
let ri := mload(i) // Load the pointer to the `Result` object.
mstore(i, sub(ri, base)) // Replace the pointer with an offset.
let j := add(0x20, ri) // Point at the pointer the pointer to the `bytes data`.
let rj := mload(j) // Load the pointer to the `bytes data`.
mstore(j, sub(rj, ri)) // Replace the pointer with an offset.
}
// We assume (and our use in this file obeys) that there aren't any other objects in
// memory after the end of `r` (and all the objects it references, recursively)
return(returndatastart, sub(mload(0x40), returndatastart))
}
}
}
contract MultiCall {
using SafeCall for address;
using UnsafeCallArray for Call[];
using UnsafeResultArray for Result[];
using UnsafeReturn for Result[];
constructor() {
assert(
(msg.sender == 0x4e59b44847b379578588920cA78FbF26c0B4956C && uint160(address(this)) >> 104 == 0)
|| block.chainid == 31337
);
}
/// Returns `msg.sender`, unless `msg.sender` is `address(this)`, in which case it returns the
/// unpacked ERC-2771 forwarded caller (the next-outermost non-MultiCall context).
function _msgSender() private view returns (address sender) {
if ((sender = msg.sender) == address(this)) {
// Unpack the ERC-2771-packed sender/caller.
assembly ("memory-safe") {
sender := shr(0x60, calldataload(sub(calldatasize(), 0x14)))
}
}
}
function multicall(Call[] calldata calls, uint256 contextdepth) internal returns (Result[] memory result) {
// Allocate memory for our eventual return. This does not allocate memory for the returndata
// from each of the calls of the multicall/batch.
result = UnsafeResultArray.unsafeAlloc(calls.length);
address sender = _msgSender();
for (
(CallArrayIterator i, CallArrayIterator end, ResultArrayIterator j) =
(calls.iter(), calls.end(), result.iter());
i != end;
(i, j) = (i.next(), j.next())
) {
// Decode and load the call.
(address target, uint256 value, bytes calldata data, uint256 revertPolicy) = calls.get(i);
// Each iteration of this loop allocates some memory for the returndata, but everything
// ends up packed in memory because neither implementation of `safeCall` aligns the free
// memory pointer to a word boundary.
if (revertPolicy == uint8(RevertPolicy.REVERT)) {
// We don't need to use the OOG-protected `safeCall` here because an OOG will result
// in a bubbled revert anyways.
(bool success, bytes memory returndata) = target.safeCall(value, data, sender);
result.set(j, success, returndata);
} else {
(bool success, bytes memory returndata) = target.safeCall(value, data, sender, contextdepth);
result.set(j, success, returndata);
if (!success) {
if (revertPolicy == uint8(RevertPolicy.HALT)) {
result.unsafeTruncate(j); // This results in `returndata` with gaps.
break;
}
}
}
}
}
fallback() external payable {
bytes32 selector = IMultiCall.multicall.selector;
Call[] calldata calls;
uint256 contextdepth;
assembly ("memory-safe") {
// Check the selector. This implicitly prohibits a `calls.offset` greater than 4GiB.
if xor(selector, calldataload(0x00)) {
for {} true {} {
// Unrecognized selector
if calldatasize() { revert(codesize(), 0x00) }
// Receive ETH
return(codesize(), 0x00)
}
}
calls.offset := add(0x04, calldataload(0x04)) // Can't overflow without clobbering selector.
calls.length := calldataload(calls.offset)
calls.offset := add(0x20, calls.offset) // Can't overflow without clobbering selector.
contextdepth := calldataload(0x24)
}
multicall(calls, contextdepth).unsafeReturn();
}
}{
"remappings": [
"@solmate/=lib/solmate/src/",
"@permit2/=lib/permit2/src/",
"@forge-std/=lib/forge-std/src/",
"@forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
"@uniswapv4/=lib/v4-core/src/",
"@eulerswap/=lib/euler-swap/src/",
"forge-std/src/=lib/forge-std/src/",
"solmate/=lib/solmate/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 1000000,
"details": {
"constantOptimizer": true,
"yul": true
}
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"stateMutability":"payable","type":"fallback"}]Contract Creation Code
60808060405234606557734e59b44847b379578588920ca78fbf26c0b4956c331480605b575b80156051575b15603b5761032e908161006b8239f35b634e487b7160e01b600052600160045260246000fd5b50617a694614602b565b503060681c156025565b600080fdfe60806000357f669a7d5e000000000000000000000000000000000000000000000000000000001861032757600480359081013580835260206060820284010160405260051b919060243583830160005b85811061031057505033933033146102e2575b8260249193929301019183602001946024830192865b858503610108575b5050505050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810191602083526020825160051b830101905b8181106100cd5783602084604051030190f35b80517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848203018252806020019081510390526020016100ba565b84358201602481013590604481013591600283118160a01c176101bf576024606483013592608481013501018a8135916020019480156000146101c8575050806040519485378660601b818501526000388280600310601402018686865af192846020013d6000823e84156101c457503d156101a5575b5050503d82526020823d01016040528251908152602001525b6020019360200193610078565b15176101b3575b808061017f565b3b156101bf57386101ac565b600080fd5b3d90fd5b93909491928990846040519485378960601b858501525a906000388780600310601402018787855af1955a943d15610250575b5050505050503d81523d6000826020013e6020813d01016040528451828152602001521561022b575b5050610198565b6001146102385738610224565b955093505050500360051c8152388080808080610080565b9083949596999291889460061c946102bb5750505050908291925b61028757505010156102855789925b3880808080806101fb565bfe5b9091807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91830360061c019201908161026b565b93509350935096935015176102d1575b5061027a565b9093503b156101bf578992386102cb565b367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec013560601c9450610062565b60208180018301016020828701015260200161004f565b366101bf5700
Deployed Bytecode
0x60806000357f669a7d5e000000000000000000000000000000000000000000000000000000001861032757600480359081013580835260206060820284010160405260051b919060243583830160005b85811061031057505033933033146102e2575b8260249193929301019183602001946024830192865b858503610108575b5050505050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810191602083526020825160051b830101905b8181106100cd5783602084604051030190f35b80517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848203018252806020019081510390526020016100ba565b84358201602481013590604481013591600283118160a01c176101bf576024606483013592608481013501018a8135916020019480156000146101c8575050806040519485378660601b818501526000388280600310601402018686865af192846020013d6000823e84156101c457503d156101a5575b5050503d82526020823d01016040528251908152602001525b6020019360200193610078565b15176101b3575b808061017f565b3b156101bf57386101ac565b600080fd5b3d90fd5b93909491928990846040519485378960601b858501525a906000388780600310601402018787855af1955a943d15610250575b5050505050503d81523d6000826020013e6020813d01016040528451828152602001521561022b575b5050610198565b6001146102385738610224565b955093505050500360051c8152388080808080610080565b9083949596999291889460061c946102bb5750505050908291925b61028757505010156102855789925b3880808080806101fb565bfe5b9091807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91830360061c019201908161026b565b93509350935096935015176102d1575b5061027a565b9093503b156101bf578992386102cb565b367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec013560601c9450610062565b60208180018301016020828701015260200161004f565b366101bf5700
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.