// File: lib/solmate/src/auth/Owned.sol



// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnershipTransferred(address indexed user, address indexed newOwner);

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnershipTransferred(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function transferOwnership(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnershipTransferred(msg.sender, newOwner);
    }
}

// File: src/auths/OwnedMulticall3.sol



// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import "solmate/auth/Owned.sol";

/// @title OwnedMulticall3
/// @notice Aggregate results from multiple function calls
/// @dev Fork of Multicall3 that can only be used by an owner (for msg.sender guarded contracts)
/// @dev Aggregate methods are marked `payable` to save 24 gas per call
/// @author https://github.com/mds1/multicall
contract OwnedMulticall3 is Owned {
  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;
  }

  constructor(address _owner) Owned(_owner) {}

  /// @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
    onlyOwner
    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
    onlyOwner
    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
    onlyOwner
    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
    onlyOwner
    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 onlyOwner 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 onlyOwner 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;
  }
}