Blockchain / Global / Address

Contract

0x0CDab740d1aA2f8ED0055C69769Ee2ac48554140

Balance
0 SOMI
Transactions sent
1
Type
Contract · 5,400 bytes of code

MultiCallUtils Verified

Compiler
solc 0.8.30+commit.73712a01
Language
Solidity
Optimization
No
EVM version
prague
License
—
Verified
2026-10-12

src/MultiCallUtils.sol

and 1 more files

Solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.22;

import "./interfaces/IModuleCalls.sol";

contract MultiCallUtils {
    // Errors
    error DelegateCallNotAllowed(uint256 _index);
    error CallReverted(uint256 _index, bytes _result);

    function multiCall(
        IModuleCalls.Transaction[] memory _txs
    )
        public
        payable
        returns (bool[] memory _successes, bytes[] memory _results)
    {
        _successes = new bool[](_txs.length);
        _results = new bytes[](_txs.length);

        for (uint256 i = 0; i < _txs.length; i++) {
            IModuleCalls.Transaction memory transaction = _txs[i];

            if (transaction.delegateCall) revert DelegateCallNotAllowed(i);
            if (gasleft() < transaction.gasLimit)
                revert IModuleCalls.NotEnoughGas(
                    i,
                    transaction.gasLimit,
                    gasleft()
                );

            // solhint-disable
            (_successes[i], _results[i]) = transaction.target.call{
                value: transaction.value,
                gas: transaction.gasLimit == 0
                    ? gasleft()
                    : transaction.gasLimit
            }(transaction.data);
            // solhint-enable

            if (!_successes[i] && _txs[i].revertOnError)
                revert CallReverted(i, _results[i]);
        }
    }

    function getBalances(
        address user,
        address[] calldata tokens
    )
        external
        view
        returns (bool[] memory _successes, uint256[] memory _balances)
    {
        _successes = new bool[](tokens.length + 1);
        _balances = new uint256[](tokens.length + 1);

        for (uint i = 0; i < tokens.length; i++) {
            (_successes[i], _balances[i]) = _getBalance(user, tokens[i]);
        }

        // last element is the native balance
        (_successes[tokens.length], _balances[tokens.length]) = (
            true,
            address(user).balance
        );
    }

    // ///
    // Globals
    // ///

    function callBlockhash(uint256 _i) external view returns (bytes32) {
        return blockhash(_i);
    }

    function callCoinbase() external view returns (address) {
        return block.coinbase;
    }

    function callDifficulty() external view returns (uint256) {
        return block.prevrandao; // old block.difficulty
    }

    function callPrevrandao() external view returns (uint256) {
        return block.prevrandao;
    }

    function callGasLimit() external view returns (uint256) {
        return block.gaslimit;
    }

    function callBlockNumber() external view returns (uint256) {
        return block.number;
    }

    function callTimestamp() external view returns (uint256) {
        return block.timestamp;
    }

    function callGasLeft() external view returns (uint256) {
        return gasleft();
    }

    function callGasPrice() external view returns (uint256) {
        return tx.gasprice;
    }

    function callOrigin() external view returns (address) {
        return tx.origin;
    }

    function callBalanceOf(address _addr) external view returns (uint256) {
        return _addr.balance;
    }

    function callCodeSize(address _addr) external view returns (uint256 size) {
        assembly {
            size := extcodesize(_addr)
        }
    }

    function callCode(address _addr) external view returns (bytes memory code) {
        assembly {
            let size := extcodesize(_addr)
            code := mload(0x40)
            mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            mstore(code, size)
            extcodecopy(_addr, add(code, 0x20), 0, size)
        }
    }

    function callCodeHash(
        address _addr
    ) external view returns (bytes32 codeHash) {
        assembly {
            codeHash := extcodehash(_addr)
        }
    }

    function callChainId() external view returns (uint256 id) {
        assembly {
            id := chainid()
        }
    }

    // internal

    function _getBalance(
        address user,
        address token
    ) internal view returns (bool txSuccess, uint256 balance) {
        uint256 size;
        assembly {
            size := extcodesize(token)
        }
        if (size == 0) {
            return (txSuccess, balance);
        }

        (bool success, bytes memory data) = token.staticcall(
            abi.encodeWithSelector(0x70a08231, user)
        );

        if (success) {
            balance = abi.decode(data, (uint256));
            txSuccess = true;
        }
    }
}

Other files

  • src/interfaces/IModuleCalls.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity ^0.8.22;
    
    interface IModuleCalls {
        // Events
        event TxFailed(bytes32 indexed _tx, uint256 _index, bytes _reason);
        event TxExecuted(bytes32 indexed _tx, uint256 _index);
    
        // Errors
        error NotEnoughGas(uint256 _index, uint256 _requested, uint256 _available);
        error InvalidSignature(bytes32 _hash, bytes _signature);
    
        // Transaction structure
        struct Transaction {
            bool delegateCall; // Performs delegatecall
            bool revertOnError; // Reverts transaction bundle if tx fails
            uint256 gasLimit; // Maximum gas to be forwarded
            address target; // Address of the contract to call
            uint256 value; // Amount of ETH to pass with the call
            bytes data; // calldata to pass
        }
    
        /**
         * @notice Allow wallet owner to execute an action
         * @param _txs        Transactions to process
         * @param _nonce      Signature nonce (may contain an encoded space)
         * @param _signature  Encoded signature
         */
        function execute(
            Transaction[] calldata _txs,
            uint256 _nonce,
            bytes calldata _signature
        ) external;
    
        /**
         * @notice Allow wallet to execute an action
         *   without signing the message
         * @param _txs  Transactions to execute
         */
        function selfExecute(Transaction[] calldata _txs) external;
    }
    
ABI · 20 entries
json
[
  {
    "name": "CallReverted",
    "type": "error",
    "inputs": [
      {
        "name": "_index",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_result",
        "type": "bytes",
        "internalType": "bytes"
      }
    ]
  },
  {
    "name": "DelegateCallNotAllowed",
    "type": "error",
    "inputs": [
      {
        "name": "_index",
        "type": "uint256",
        "internalType": "uint256"
      }
    ]
  },
  {
    "name": "NotEnoughGas",
    "type": "error",
    "inputs": [
      {
        "name": "_index",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_requested",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "_available",
        "type": "uint256",
        "internalType": "uint256"
      }
    ]
  },
  {
    "name": "callBalanceOf",
    "type": "function",
    "inputs": [
      {
        "name": "_addr",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callBlockNumber",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callBlockhash",
    "type": "function",
    "inputs": [
      {
        "name": "_i",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callChainId",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "id",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callCode",
    "type": "function",
    "inputs": [
      {
        "name": "_addr",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "code",
        "type": "bytes",
        "internalType": "bytes"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callCodeHash",
    "type": "function",
    "inputs": [
      {
        "name": "_addr",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "codeHash",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callCodeSize",
    "type": "function",
    "inputs": [
      {
        "name": "_addr",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "size",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callCoinbase",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callDifficulty",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callGasLeft",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callGasLimit",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callGasPrice",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callOrigin",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callPrevrandao",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "callTimestamp",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getBalances",
    "type": "function",
    "inputs": [
      {
        "name": "user",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "tokens",
        "type": "address[]",
        "internalType": "address[]"
      }
    ],
    "outputs": [
      {
        "name": "_successes",
        "type": "bool[]",
        "internalType": "bool[]"
      },
      {
        "name": "_balances",
        "type": "uint256[]",
        "internalType": "uint256[]"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "multiCall",
    "type": "function",
    "inputs": [
      {
        "name": "_txs",
        "type": "tuple[]",
        "components": [
          {
            "name": "delegateCall",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "revertOnError",
            "type": "bool",
            "internalType": "bool"
          },
          {
            "name": "gasLimit",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "target",
            "type": "address",
            "internalType": "address"
          },
          {
            "name": "value",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "data",
            "type": "bytes",
            "internalType": "bytes"
          }
        ],
        "internalType": "struct IModuleCalls.Transaction[]"
      }
    ],
    "outputs": [
      {
        "name": "_successes",
        "type": "bool[]",
        "internalType": "bool[]"
      },
      {
        "name": "_results",
        "type": "bytes[]",
        "internalType": "bytes[]"
      }
    ],
    "stateMutability": "payable"
  }
]

Send feedback

Agents: POST the same to /api/feedback.