Transaction Hash:
Block:
22196978 at Apr-04-2025 05:14:11 PM +UTC
Transaction Fee:
0.00003383082218797 ETH
$0.07
Gas Used:
47,185 Gas / 0.716982562 Gwei
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 16.301537775626826106 Eth | 16.301540234118866096 Eth | 0.00000245849203999 | |
| 0xe4468D6f...979A32558 |
0.0002 Eth
Nonce: 0
|
0.00016616917781203 Eth
Nonce: 1
| 0.00003383082218797 |
Execution Trace
ETH 0.000051094193
Multicaller.66e0daa0( )
ETH 0.000051094193
Multicaller.aggregate( targets=[0x49048044D57e1C92A77f79988d21Fa8fAF74E97e], data=[6eBcQgAAAAAAAAAAAAAAAORGjW8J5qTtjbBt9mRa7Il5oyVYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0FHeqYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGGoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==], values=[198000000000000], refundTo=0x0000000000000000000000000000000000000001 )- ETH 0.000198
Proxy.e9e05c42( )
- ETH 0.000198
File 1 of 2: Multicaller
File 2 of 2: Proxy
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/**
* @title Multicaller
* @author vectorized.eth
* @notice Contract that allows for efficient aggregation
* of multiple calls in a single transaction.
*/
contract Multicaller {
// =============================================================
// ERRORS
// =============================================================
/**
* @dev The lengths of the input arrays are not the same.
*/
error ArrayLengthsMismatch();
// =============================================================
// AGGREGATION OPERATIONS
// =============================================================
/**
* @dev Aggregates multiple calls in a single transaction.
* @param targets An array of addresses to call.
* @param data An array of calldata to forward to the targets.
* @param values How much ETH to forward to each target.
* @param refundTo The address to transfer any remaining ETH in the contract after the calls.
* If `address(0)`, remaining ETH will NOT be refunded.
* If `address(1)`, remaining ETH will be refunded to `msg.sender`.
* If anything else, remaining ETH will be refunded to `refundTo`.
* @return An array of the returndata from each call.
*/
function aggregate(
address[] calldata targets,
bytes[] calldata data,
uint256[] calldata values,
address refundTo
) external payable returns (bytes[] memory) {
assembly {
if iszero(and(eq(targets.length, data.length), eq(data.length, values.length))) {
// Store the function selector of `ArrayLengthsMismatch()`.
mstore(returndatasize(), 0x3b800a46)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
let resultsSize := 0x40
if data.length {
let results := 0x40
// Left shift by 5 is equivalent to multiplying by 0x20.
data.length := shl(5, data.length)
// Copy the offsets from calldata into memory.
calldatacopy(results, data.offset, data.length)
// Offset into `results`.
let resultsOffset := data.length
// Pointer to the end of `results`.
let end := add(results, data.length)
// For deriving the calldata offsets from the `results` pointer.
let valuesOffsetDiff := sub(values.offset, results)
let targetsOffsetDiff := sub(targets.offset, results)
for {} 1 {} {
// The offset of the current bytes in the calldata.
let o := add(data.offset, mload(results))
let memPtr := add(resultsOffset, 0x40)
// Copy the current bytes from calldata to the memory.
calldatacopy(
memPtr,
add(o, 0x20), // The offset of the current bytes' bytes.
calldataload(o) // The length of the current bytes.
)
if iszero(
call(
gas(), // Remaining gas.
calldataload(add(targetsOffsetDiff, results)), // Address to call.
calldataload(add(valuesOffsetDiff, results)), // ETH to send.
memPtr, // Start of input calldata in memory.
calldataload(o), // Size of input calldata.
0x00, // We will use returndatacopy instead.
0x00 // We will use returndatacopy instead.
)
) {
// Bubble up the revert if the call reverts.
returndatacopy(0x00, 0x00, returndatasize())
revert(0x00, returndatasize())
}
// Append the current `resultsOffset` into `results`.
mstore(results, resultsOffset)
// Append the returndatasize, and the returndata.
mstore(memPtr, returndatasize())
returndatacopy(add(memPtr, 0x20), 0x00, returndatasize())
// Advance the `resultsOffset` by `returndatasize() + 0x20`,
// rounded up to the next multiple of 0x20.
resultsOffset := and(add(add(resultsOffset, returndatasize()), 0x3f), not(0x1f))
// Advance the `results` pointer.
results := add(results, 0x20)
if eq(results, end) { break }
}
resultsSize := add(resultsOffset, 0x40)
}
if refundTo {
// Force transfers all the remaining ETH in the contract to `refundTo`,
// with a gas stipend of 100000, which should be enough for most use cases.
// If sending via a regular call fails, force sends the ETH by
// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
if selfbalance() {
// If `refundTo` is `address(1)`, replace it with the `msg.sender`.
refundTo := xor(refundTo, mul(eq(refundTo, 1), xor(refundTo, caller())))
// Transfer the ETH and check if it succeeded or not.
if iszero(
call(100000, refundTo, selfbalance(), codesize(), 0x00, codesize(), 0x00)
) {
mstore(0x00, refundTo) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
// We can directly use `SELFDESTRUCT` in the contract creation.
// Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758
if iszero(create(selfbalance(), 0x0b, 0x16)) {
// Coerce gas estimation to provide enough gas for the `create` above.
revert(codesize(), codesize())
}
}
}
}
mstore(0x00, 0x20) // Store the memory offset of the `results`.
mstore(0x20, targets.length) // Store `targets.length` into `results`.
// Direct return.
return(0x00, resultsSize)
}
}
/**
* @dev For receiving ETH.
* Does nothing and returns nothing.
* Called instead of `fallback()` if the calldatasize is zero.
*/
receive() external payable {}
/**
* @dev Decompresses the calldata and performs a delegatecall
* with the decompressed calldata to itself.
*
* Accompanying JavaScript library to compress the calldata:
* https://github.com/vectorized/solady/blob/main/js/solady.js
* (See: `LibZip.cdCompress`)
*/
fallback() external payable {
assembly {
// If the calldata starts with the bitwise negation of
// `bytes4(keccak256("aggregate(address[],bytes[],uint256[],address)"))`.
let s := calldataload(returndatasize())
if eq(shr(224, s), 0x66e0daa0) {
mstore(returndatasize(), not(s))
let o := 4
for { let i := o } lt(i, calldatasize()) {} {
let c := byte(returndatasize(), calldataload(i))
i := add(i, 1)
if iszero(c) {
let d := byte(returndatasize(), calldataload(i))
i := add(i, 1)
// Fill with either 0xff or 0x00.
mstore(o, not(returndatasize()))
if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) }
o := add(o, add(and(d, 0x7f), 1))
continue
}
mstore8(o, c)
o := add(o, 1)
}
let success := delegatecall(gas(), address(), 0x00, o, 0x00, 0x00)
returndatacopy(0x00, 0x00, returndatasize())
if iszero(success) { revert(0x00, returndatasize()) }
return(0x00, returndatasize())
}
revert(returndatasize(), returndatasize())
}
}
}
File 2 of 2: Proxy
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/**
* @title Proxy
* @notice Proxy is a transparent proxy that passes through the call if the caller is the owner or
* if the caller is address(0), meaning that the call originated from an off-chain
* simulation.
*/
contract Proxy {
/**
* @notice The storage slot that holds the address of the implementation.
* bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
*/
bytes32 internal constant IMPLEMENTATION_KEY =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @notice The storage slot that holds the address of the owner.
* bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
*/
bytes32 internal constant OWNER_KEY =
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @notice An event that is emitted each time the implementation is changed. This event is part
* of the EIP-1967 specification.
*
* @param implementation The address of the implementation contract
*/
event Upgraded(address indexed implementation);
/**
* @notice An event that is emitted each time the owner is upgraded. This event is part of the
* EIP-1967 specification.
*
* @param previousAdmin The previous owner of the contract
* @param newAdmin The new owner of the contract
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @notice A modifier that reverts if not called by the owner or by address(0) to allow
* eth_call to interact with this proxy without needing to use low-level storage
* inspection. We assume that nobody is able to trigger calls from address(0) during
* normal EVM execution.
*/
modifier proxyCallIfNotAdmin() {
if (msg.sender == _getAdmin() || msg.sender == address(0)) {
_;
} else {
// This WILL halt the call frame on completion.
_doProxyCall();
}
}
/**
* @notice Sets the initial admin during contract deployment. Admin address is stored at the
* EIP-1967 admin storage slot so that accidental storage collision with the
* implementation is not possible.
*
* @param _admin Address of the initial contract admin. Admin as the ability to access the
* transparent proxy interface.
*/
constructor(address _admin) {
_changeAdmin(_admin);
}
// slither-disable-next-line locked-ether
receive() external payable {
// Proxy call by default.
_doProxyCall();
}
// slither-disable-next-line locked-ether
fallback() external payable {
// Proxy call by default.
_doProxyCall();
}
/**
* @notice Set the implementation contract address. The code at the given address will execute
* when this contract is called.
*
* @param _implementation Address of the implementation contract.
*/
function upgradeTo(address _implementation) public virtual proxyCallIfNotAdmin {
_setImplementation(_implementation);
}
/**
* @notice Set the implementation and call a function in a single transaction. Useful to ensure
* atomic execution of initialization-based upgrades.
*
* @param _implementation Address of the implementation contract.
* @param _data Calldata to delegatecall the new implementation with.
*/
function upgradeToAndCall(address _implementation, bytes calldata _data)
public
payable
virtual
proxyCallIfNotAdmin
returns (bytes memory)
{
_setImplementation(_implementation);
(bool success, bytes memory returndata) = _implementation.delegatecall(_data);
require(success, "Proxy: delegatecall to new implementation contract failed");
return returndata;
}
/**
* @notice Changes the owner of the proxy contract. Only callable by the owner.
*
* @param _admin New owner of the proxy contract.
*/
function changeAdmin(address _admin) public virtual proxyCallIfNotAdmin {
_changeAdmin(_admin);
}
/**
* @notice Gets the owner of the proxy contract.
*
* @return Owner address.
*/
function admin() public virtual proxyCallIfNotAdmin returns (address) {
return _getAdmin();
}
/**
* @notice Queries the implementation address.
*
* @return Implementation address.
*/
function implementation() public virtual proxyCallIfNotAdmin returns (address) {
return _getImplementation();
}
/**
* @notice Sets the implementation address.
*
* @param _implementation New implementation address.
*/
function _setImplementation(address _implementation) internal {
assembly {
sstore(IMPLEMENTATION_KEY, _implementation)
}
emit Upgraded(_implementation);
}
/**
* @notice Changes the owner of the proxy contract.
*
* @param _admin New owner of the proxy contract.
*/
function _changeAdmin(address _admin) internal {
address previous = _getAdmin();
assembly {
sstore(OWNER_KEY, _admin)
}
emit AdminChanged(previous, _admin);
}
/**
* @notice Performs the proxy call via a delegatecall.
*/
function _doProxyCall() internal {
address impl = _getImplementation();
require(impl != address(0), "Proxy: implementation not initialized");
assembly {
// Copy calldata into memory at 0x0....calldatasize.
calldatacopy(0x0, 0x0, calldatasize())
// Perform the delegatecall, make sure to pass all available gas.
let success := delegatecall(gas(), impl, 0x0, calldatasize(), 0x0, 0x0)
// Copy returndata into memory at 0x0....returndatasize. Note that this *will*
// overwrite the calldata that we just copied into memory but that doesn't really
// matter because we'll be returning in a second anyway.
returndatacopy(0x0, 0x0, returndatasize())
// Success == 0 means a revert. We'll revert too and pass the data up.
if iszero(success) {
revert(0x0, returndatasize())
}
// Otherwise we'll just return and pass the data up.
return(0x0, returndatasize())
}
}
/**
* @notice Queries the implementation address.
*
* @return Implementation address.
*/
function _getImplementation() internal view returns (address) {
address impl;
assembly {
impl := sload(IMPLEMENTATION_KEY)
}
return impl;
}
/**
* @notice Queries the owner of the proxy contract.
*
* @return Owner address.
*/
function _getAdmin() internal view returns (address) {
address owner;
assembly {
owner := sload(OWNER_KEY)
}
return owner;
}
}