ETH Price: $2,412.59 (+1.45%)

Contract

0x28239Ba20bB458cB050D0cBf541315b1b9aDB935
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60e06040153947002022-08-23 5:14:58774 days ago1661231698IN
 Create: HookERC721VaultFactory
0 ETH0.006287565.1170151

Latest 23 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
182284352023-09-27 16:58:23373 days ago1695833903
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
181707502023-09-19 15:08:11381 days ago1695136091
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
177155372023-07-17 21:04:23445 days ago1689627863
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
174797392023-06-14 17:44:47478 days ago1686764687
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
174797312023-06-14 17:43:11478 days ago1686764591
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
165440002023-02-02 22:09:35610 days ago1675375775
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
165367802023-02-01 21:54:11611 days ago1675288451
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
165354432023-02-01 17:25:47611 days ago1675272347
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
165352992023-02-01 16:56:59611 days ago1675270619
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
165351172023-02-01 16:20:23611 days ago1675268423
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
165351112023-02-01 16:19:11611 days ago1675268351
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
159832672022-11-16 14:45:35688 days ago1668609935
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
159707142022-11-14 20:38:23690 days ago1668458303
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
159707092022-11-14 20:37:23690 days ago1668458243
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
158781102022-11-01 22:18:11703 days ago1667341091
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
158780842022-11-01 22:12:59703 days ago1667340779
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
158646092022-10-31 0:58:11705 days ago1667177891
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
155830142022-09-21 16:44:23744 days ago1663778663
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
155827712022-09-21 15:55:11744 days ago1663775711
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
155827302022-09-21 15:46:59744 days ago1663775219
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
155827232022-09-21 15:45:35744 days ago1663775135
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
153996272022-08-23 23:54:30773 days ago1661298870
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
153996022022-08-23 23:48:55773 days ago1661298535
0x28239Ba2...1b9aDB935
 Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
HookERC721VaultFactory

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 10 runs

Other Settings:
default evmVersion, MIT license
File 1 of 21 : HookERC721VaultFactory.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

import "@openzeppelin/contracts/utils/Create2.sol";

import "./HookBeaconProxy.sol";

import "./interfaces/IHookERC721VaultFactory.sol";
import "./interfaces/IHookERC721Vault.sol";
import "./interfaces/IHookProtocol.sol";
import "./interfaces/IInitializeableBeacon.sol";

import "./mixin/PermissionConstants.sol";

import "./lib/BeaconSalts.sol";

/// @title Hook Vault Factory
/// @author Jake [email protected]
/// @dev See {IHookERC721VaultFactory}.
/// @dev The factory itself is non-upgradeable; however, each vault is upgradeable (i.e. all vaults)
/// created by this factory can be upgraded at one time via the beacon pattern.
contract HookERC721VaultFactory is
  IHookERC721VaultFactory,
  PermissionConstants
{
  /// @notice Registry of all of the active vaults within the protocol, allowing users to find vaults by
  /// project address and tokenId;
  /// @dev From this view, we do not know if a vault is empty or full
  mapping(address => mapping(uint256 => IHookERC721Vault))
    public
    override getVault;

  /// @notice Registry of all of the active multi-vaults within the protocol
  mapping(address => IHookERC721Vault) public override getMultiVault;

  address private immutable _hookProtocol;
  address private immutable _beacon;
  address private immutable _multiBeacon;

  constructor(
    address hookProtocolAddress,
    address beaconAddress,
    address multiBeaconAddress
  ) {
    require(
      Address.isContract(hookProtocolAddress),
      "hook protocol must be a contract"
    );
    require(
      Address.isContract(beaconAddress),
      "beacon address must be a contract"
    );
    require(
      Address.isContract(multiBeaconAddress),
      "multi beacon address must be a contract"
    );
    _hookProtocol = hookProtocolAddress;
    _beacon = beaconAddress;
    _multiBeacon = multiBeaconAddress;
  }

  /// @notice See {IHookERC721VaultFactory-makeMultiVault}.
  function makeMultiVault(address nftAddress)
    external
    returns (IHookERC721Vault)
  {
    require(
      IHookProtocol(_hookProtocol).hasRole(ALLOWLISTER_ROLE, msg.sender) ||
        IHookProtocol(_hookProtocol).hasRole(ALLOWLISTER_ROLE, address(0)),
      "makeMultiVault-Only accounts with the ALLOWLISTER role can make new multiVaults"
    );

    require(
      getMultiVault[nftAddress] == IHookERC721Vault(address(0)),
      "makeMultiVault-vault cannot already exist"
    );

    IInitializeableBeacon bp = IInitializeableBeacon(
      Create2.deploy(
        0,
        BeaconSalts.multiVaultSalt(nftAddress),
        type(HookBeaconProxy).creationCode
      )
    );

    bp.initializeBeacon(
      _multiBeacon,
      /// This is the ABI encoded initializer on the IHookERC721Vault.sol
      abi.encodeWithSignature(
        "initialize(address,address)",
        nftAddress,
        _hookProtocol
      )
    );

    IHookERC721Vault vault = IHookERC721Vault(address(bp));
    getMultiVault[nftAddress] = vault;
    emit ERC721MultiVaultCreated(nftAddress, address(bp));

    return vault;
  }

  /// @notice See {IHookERC721VaultFactory-makeSoloVault}.
  function makeSoloVault(address nftAddress, uint256 tokenId)
    public
    override
    returns (IHookERC721Vault)
  {
    require(
      getVault[nftAddress][tokenId] == IHookERC721Vault(address(0)),
      "makeVault-a vault cannot already exist"
    );

    IInitializeableBeacon bp = IInitializeableBeacon(
      Create2.deploy(
        0,
        BeaconSalts.soloVaultSalt(nftAddress, tokenId),
        type(HookBeaconProxy).creationCode
      )
    );

    bp.initializeBeacon(
      _beacon,
      /// This is the ABI encoded initializer on the IHookERC721MultiVault.sol
      abi.encodeWithSignature(
        "initialize(address,uint256,address)",
        nftAddress,
        tokenId,
        _hookProtocol
      )
    );
    IHookERC721Vault vault = IHookERC721Vault(address(bp));
    getVault[nftAddress][tokenId] = vault;

    emit ERC721VaultCreated(nftAddress, tokenId, address(vault));

    return vault;
  }

  /// @notice See {IHookERC721VaultFactory-findOrCreateVault}.
  function findOrCreateVault(address nftAddress, uint256 tokenId)
    external
    returns (IHookERC721Vault)
  {
    if (getMultiVault[nftAddress] != IHookERC721Vault(address(0))) {
      return getMultiVault[nftAddress];
    }

    if (getVault[nftAddress][tokenId] != IHookERC721Vault(address(0))) {
      return getVault[nftAddress][tokenId];
    }

    return makeSoloVault(nftAddress, tokenId);
  }
}

File 2 of 21 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 3 of 21 : draft-IERC1822.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822Proxiable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

File 4 of 21 : ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967Upgrade {
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            Address.isContract(IBeacon(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        }
    }
}

File 5 of 21 : Proxy.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)

pragma solidity ^0.8.0;

/**
 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
 * be specified by overriding the virtual {_implementation} function.
 *
 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
 * different contract through the {_delegate} function.
 *
 * The success and return data of the delegated call will be returned back to the caller of the proxy.
 */
abstract contract Proxy {
    /**
     * @dev Delegates the current call to `implementation`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /**
     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
     * and {_fallback} should delegate.
     */
    function _implementation() internal view virtual returns (address);

    /**
     * @dev Delegates the current call to the address returned by `_implementation()`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _fallback() internal virtual {
        _beforeFallback();
        _delegate(_implementation());
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
     * function in the contract matches the call data.
     */
    fallback() external payable virtual {
        _fallback();
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
     * is empty.
     */
    receive() external payable virtual {
        _fallback();
    }

    /**
     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
     * call, or as part of the Solidity `fallback` or `receive` functions.
     *
     * If overridden should call `super._beforeFallback()`.
     */
    function _beforeFallback() internal virtual {}
}

File 6 of 21 : IBeacon.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

File 7 of 21 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 8 of 21 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 9 of 21 : Create2.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Create2.sol)

pragma solidity ^0.8.0;

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(
        uint256 amount,
        bytes32 salt,
        bytes memory bytecode
    ) internal returns (address) {
        address addr;
        require(address(this).balance >= amount, "Create2: insufficient balance");
        require(bytecode.length != 0, "Create2: bytecode length is zero");
        assembly {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
        }
        require(addr != address(0), "Create2: Failed on deploy");
        return addr;
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(
        bytes32 salt,
        bytes32 bytecodeHash,
        address deployer
    ) internal pure returns (address) {
        bytes32 _data = keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash));
        return address(uint160(uint256(_data)));
    }
}

File 10 of 21 : StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly {
            r.slot := slot
        }
    }
}

File 11 of 21 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 12 of 21 : HookBeaconProxy.sol
// SPDX-License-Identifier: MIT
// Modified version of : OpenZeppelin Contracts v4.4.1 (proxy/beacon/BeaconProxy.sol)

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import "@openzeppelin/contracts/proxy/Proxy.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";

/// @title HookBeaconProxy a proxy contract that points to an implementation provided by a Beacon
/// @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}.
///
/// The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
/// conflict with the storage layout of the implementation behind the proxy.
///
/// This is an extension of the OpenZeppelin beacon proxy, however differs in that it is initializeable, which means
/// it is usable with Create2.
contract HookBeaconProxy is Proxy, ERC1967Upgrade {
  /// @dev  The constructor is empty in this case because the proxy is initializeable
  constructor() {}

  bytes32 constant _INITIALIZED_SLOT =
    bytes32(uint256(keccak256("initializeable.beacon.version")) - 1);
  bytes32 constant _INITIALIZING_SLOT =
    bytes32(uint256(keccak256("initializeable.beacon.initializing")) - 1);

  ///
  /// @dev Triggered when the contract has been initialized or reinitialized.
  ///
  event Initialized(uint8 version);

  /// @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
  /// `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
  modifier initializer() {
    bool isTopLevelCall = _setInitializedVersion(1);
    if (isTopLevelCall) {
      StorageSlot.getBooleanSlot(_INITIALIZING_SLOT).value = true;
    }
    _;
    if (isTopLevelCall) {
      StorageSlot.getBooleanSlot(_INITIALIZING_SLOT).value = false;
      emit Initialized(1);
    }
  }

  function _setInitializedVersion(uint8 version) private returns (bool) {
    // If the contract is initializing we ignore whether _initialized is set in order to support multiple
    // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level
    // of initializers, because in other contexts the contract may have been reentered.
    if (StorageSlot.getBooleanSlot(_INITIALIZING_SLOT).value) {
      require(
        version == 1 && !Address.isContract(address(this)),
        "contract is already initialized"
      );
      return false;
    } else {
      require(
        StorageSlot.getUint256Slot(_INITIALIZED_SLOT).value < version,
        "contract is already initialized"
      );
      StorageSlot.getUint256Slot(_INITIALIZED_SLOT).value = version;
      return true;
    }
  }

  /// @dev Initializes the proxy with `beacon`.
  ///
  /// If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
  /// will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
  /// constructor.
  ///
  /// Requirements:
  ///
  ///- `beacon` must be a contract with the interface {IBeacon}.
  ///
  function initializeBeacon(address beacon, bytes memory data)
    public
    initializer
  {
    assert(
      _BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1)
    );
    _upgradeBeaconToAndCall(beacon, data, false);
  }

  ///
  /// @dev Returns the current implementation address of the associated beacon.
  ///
  function _implementation() internal view virtual override returns (address) {
    return IBeacon(_getBeacon()).implementation();
  }
}

File 13 of 21 : IHookERC721Vault.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

import "./IHookVault.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";

/// @title Hook ERC-721 Vault interface
/// @author Jake [email protected]
/// @custom:coauthor Regynald [email protected]
///
/// @dev the IHookERC721 vault is an extension of the standard IHookVault
/// specifically designed to hold and receive ERC721 Tokens.
///
/// FLASH LOAN -
///     (1) beneficial owners are able to borrow the vaulted asset for a single function call
///     (2) to borrow the asset, they must implement and deploy a {IERC721FlashLoanReceiver}
///         contract, and then call the flashLoan method.
///     (3) At the end of the flashLoan, we ensure the asset is still owned by the vault.
interface IHookERC721Vault is IHookVault, IERC721Receiver {
  /// @notice emitted after an asset is flash loaned by its beneficial owner.
  /// @dev only one asset can be flash loaned at a time, and that asset is
  /// denoted by the tokenId emitted.
  event AssetFlashLoaned(address owner, uint256 tokenId, address flashLoanImpl);

  /// @notice the tokenID of the underlying ERC721 token;
  function assetTokenId(uint32 assetId) external view returns (uint256);

  /// @notice flashLoans the vaulted asset to another contract for use and return to the vault. Only the owner
  /// may perform the flashloan
  /// @dev the flashloan receiver can perform arbitrary logic, but must approve the vault as an operator
  /// before returning.
  /// @param receiverAddress the contract which implements the {IERC721FlashLoanReceiver} interface to utilize the
  /// asset while it is loaned out
  /// @param params calldata params to forward to the receiver
  function flashLoan(
    uint32 assetId,
    address receiverAddress,
    bytes calldata params
  ) external;
}

File 14 of 21 : IHookERC721VaultFactory.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

import "./IHookERC721Vault.sol";

/// @title HookERC721Factory-factory for instances of the hook vault
/// @author Jake [email protected]
/// @custom:coauthor Regynald [email protected]
///
/// @notice The Factory creates a specific vault for ERC721s.
interface IHookERC721VaultFactory {
  event ERC721VaultCreated(
    address nftAddress,
    uint256 tokenId,
    address vaultAddress
  );

  /// @notice emitted when a new MultiVault is deployed by the protocol
  /// @param nftAddress the address of the nft contract that may be deposited into the new vault
  /// @param vaultAddress address of the newly deployed vault
  event ERC721MultiVaultCreated(address nftAddress, address vaultAddress);

  /// @notice gets the address of a vault for a particular ERC-721 token
  /// @param nftAddress the contract address for the ERC-721
  /// @param tokenId the tokenId for the ERC-721
  /// @return the address of a {IERC721Vault} if one exists that supports the particular ERC-721, or the null address otherwise
  function getVault(address nftAddress, uint256 tokenId)
    external
    view
    returns (IHookERC721Vault);

  /// @notice gets the address of a multi-asset vault for a particular ERC-721 contract, if one exists
  /// @param nftAddress the contract address for the ERC-721
  /// @return the address of the {IERC721Vault} multi asset vault, or the null address if one does not exist
  function getMultiVault(address nftAddress)
    external
    view
    returns (IHookERC721Vault);

  /// @notice deploy a multi-asset vault if one has not already been deployed
  /// @param nftAddress the contract address for the ERC-721 to be supported by the vault
  /// @return the address of the newly deployed {IERC721Vault} multi asset vault
  function makeMultiVault(address nftAddress)
    external
    returns (IHookERC721Vault);

  /// @notice creates a vault for a specific tokenId. If there
  /// is a multi-vault in existence which supports that address
  /// the address for that vault is returned as a new one
  /// does not need to be made.
  /// @param nftAddress the contract address for the ERC-721
  /// @param tokenId the tokenId for the ERC-721
  function findOrCreateVault(address nftAddress, uint256 tokenId)
    external
    returns (IHookERC721Vault);

  /// @notice make a new vault that can contain a single asset only
  /// @dev the only valid asset id in this vault is = 0
  /// @param nftAddress the address of the underlying nft contract
  /// @param tokenId the individual token that can be deposited into this vault
  function makeSoloVault(address nftAddress, uint256 tokenId)
    external
    returns (IHookERC721Vault);
}

File 15 of 21 : IHookProtocol.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

import "@openzeppelin/contracts/access/IAccessControl.sol";

/// @title HookProtocol configuration and access control repository
/// @author Jake [email protected]
/// @custom:coauthor Regynald [email protected]
///
/// @dev it is critically important that the particular protocol implementation
/// is correct as, if it is not, all assets contained within protocol contracts
/// can be easily compromised.
interface IHookProtocol is IAccessControl {
  /// @notice the address of the deployed CoveredCallFactory used by the protocol
  function coveredCallContract() external view returns (address);

  /// @notice the address of the deployed VaultFactory used by the protocol
  function vaultContract() external view returns (address);

  /// @notice callable function that reverts when the protocol is paused
  function throwWhenPaused() external;

  /// @notice the standard weth address on this chain
  /// @dev these are values for popular chains:
  /// mainnet: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
  /// kovan: 0xd0a1e359811322d97991e03f863a0c30c2cf029c
  /// ropsten: 0xc778417e063141139fce010982780140aa0cd5ab
  /// rinkeby: 0xc778417e063141139fce010982780140aa0cd5ab
  /// @return the weth address
  function getWETHAddress() external view returns (address);

  /// @notice get a configuration flag with a specific key for a collection
  /// @param collectionAddress the collection for which to lookup a configuration flag
  /// @param conf the config identifier for the configuration flag
  /// @return the true or false value of the config
  function getCollectionConfig(address collectionAddress, bytes32 conf)
    external
    view
    returns (bool);
}

File 16 of 21 : IHookVault.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

import "../lib/Entitlements.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/// @title Generic Hook Vault-a vault designed to contain a single asset to be used as escrow.
/// @author Jake [email protected]
/// @custom:coauthor Regynald [email protected]
///
/// @notice The Vault holds an asset on behalf of the owner. The owner is able to post this
/// asset as collateral to other protocols by signing a message, called an "entitlement", that gives
/// a specific account the ability to change the owner.
///
/// The vault can work with multiple assets via the assetId, where the asset or set of assets covered by
/// each segment is granted an individual id.
/// Every asset must be identified by an assetId to comply with this interface, even if the vault only contains
/// one asset.
///
/// ENTITLEMENTS -
///     (1) only one entitlement can be placed at a time.
///     (2) entitlements must expire, but can also be cleared by the entitled party
///     (3) if an entitlement expires, the current beneficial owner gains immediate sole control over the
///        asset
///     (4) the entitled entity can modify the beneficial owner of the asset, but cannot withdrawal.
///     (5) the beneficial owner cannot modify the beneficial owner while an entitlement is in place
///
interface IHookVault is IERC165 {
  /// @notice emitted when an entitlement is placed on an asset
  event EntitlementImposed(
    uint32 assetId,
    address entitledAccount,
    uint32 expiry,
    address beneficialOwner
  );

  /// @notice emitted when an entitlement is cleared from an asset
  event EntitlementCleared(uint256 assetId, address beneficialOwner);

  /// @notice emitted when the beneficial owner of an asset changes
  /// @dev it is not required that this event is emitted when an entitlement is
  /// imposed that also modifies the beneficial owner.
  event BeneficialOwnerSet(
    uint32 assetId,
    address beneficialOwner,
    address setBy
  );

  /// @notice emitted when an asset is added into the vault
  event AssetReceived(
    address owner,
    address sender,
    address contractAddress,
    uint32 assetId
  );

  /// @notice Emitted when `beneficialOwner` enables `approved` to manage the `assetId` asset.
  event Approval(
    address indexed beneficialOwner,
    address indexed approved,
    uint32 indexed assetId
  );

  /// @notice emitted when an asset is withdrawn from the vault
  event AssetWithdrawn(uint32 assetId, address to, address beneficialOwner);

  /// @notice Withdrawal an unencumbered asset from this vault
  /// @param assetId the asset to remove from the vault
  function withdrawalAsset(uint32 assetId) external;

  /// @notice setBeneficialOwner updates the current address that can claim the asset when it is free of entitlements.
  /// @param assetId the id of the subject asset to impose the entitlement
  /// @param newBeneficialOwner the account of the person who is able to withdrawal when there are no entitlements.
  function setBeneficialOwner(uint32 assetId, address newBeneficialOwner)
    external;

  /// @notice Add an entitlement claim to the asset held within the contract
  /// @param operator the operator to entitle
  /// @param expiry the duration of the entitlement
  /// @param assetId the id of the asset within the vault
  /// @param v sig v
  /// @param r sig r
  /// @param s sig s
  function imposeEntitlement(
    address operator,
    uint32 expiry,
    uint32 assetId,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external;

  /// @notice Allows the beneficial owner to grant an entitlement to an asset within the contract
  /// @dev this function call is signed by the sender per the EVM, so we know the entitlement is authentic
  /// @param entitlement The entitlement to impose onto the contract
  function grantEntitlement(Entitlements.Entitlement calldata entitlement)
    external;

  /// @notice Allows the entitled address to release their claim on the asset
  /// @param assetId the id of the asset to clear
  function clearEntitlement(uint32 assetId) external;

  /// @notice Removes the active entitlement from a vault and returns the asset to the beneficial owner
  /// @param receiver the intended receiver of the asset
  /// @param assetId the Id of the asset to clear
  function clearEntitlementAndDistribute(uint32 assetId, address receiver)
    external;

  /// @notice looks up the current beneficial owner of the asset
  /// @param assetId the referenced asset
  /// @return the address of the beneficial owner of the asset
  function getBeneficialOwner(uint32 assetId) external view returns (address);

  /// @notice checks if the asset is currently stored in the vault
  /// @param assetId the referenced asset
  /// @return true if the asset is currently within the vault, false otherwise
  function getHoldsAsset(uint32 assetId) external view returns (bool);

  /// @notice the contract address of the vaulted asset
  /// @param assetId the referenced asset
  /// @return the contract address of the vaulted asset
  function assetAddress(uint32 assetId) external view returns (address);

  /// @notice looks up the current operator of an entitlement on an asset
  /// @param assetId the id of the underlying asset
  function getCurrentEntitlementOperator(uint32 assetId)
    external
    view
    returns (bool, address);

  /// @notice Looks up the expiration timestamp of the current entitlement
  /// @dev returns the 0 if no entitlement is set
  /// @return the block timestamp after which the entitlement expires
  function entitlementExpiration(uint32 assetId) external view returns (uint32);

  /// @notice Gives permission to `to` to impose an entitlement upon `assetId`
  ///
  /// @dev Only a single account can be approved at a time, so approving the zero address clears previous approvals.
  ///   * Requirements:
  ///
  /// -  The caller must be the beneficial owner
  /// - `tokenId` must exist.
  ///
  /// Emits an {Approval} event.
  function approveOperator(address to, uint32 assetId) external;

  /// @dev Returns the account approved for `tokenId` token.
  ///
  /// Requirements:
  ///
  /// - `assetId` must exist.
  ///
  function getApprovedOperator(uint32 assetId) external view returns (address);
}

File 17 of 21 : IInitializeableBeacon.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

/// @title Interface for a beacon with an initializer function
/// @author Jake [email protected]
/// @custom:coauthor Regynald [email protected]
///
/// @dev the Hook Beacons conform to this interface, and can be called
/// with this initializer in order to start a beacon
interface IInitializeableBeacon {
  function initializeBeacon(address beacon, bytes memory data) external;
}

File 18 of 21 : BeaconSalts.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

import "../HookBeaconProxy.sol";

library BeaconSalts {
  // keep functions internal to prevent the need for library linking
  // and to reduce gas costs
  bytes32 internal constant ByteCodeHash =
    keccak256(type(HookBeaconProxy).creationCode);

  function soloVaultSalt(address nftAddress, uint256 tokenId)
    internal
    pure
    returns (bytes32)
  {
    return keccak256(abi.encode(nftAddress, tokenId));
  }

  function multiVaultSalt(address nftAddress) internal pure returns (bytes32) {
    return keccak256(abi.encode(nftAddress));
  }
}

File 19 of 21 : Entitlements.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

import "./Signatures.sol";

library Entitlements {
  uint256 private constant _ENTITLEMENT_TYPEHASH =
    uint256(
      keccak256(
        abi.encodePacked(
          "Entitlement(",
          "address beneficialOwner,",
          "address operator,",
          "address vaultAddress,",
          "uint32 assetId,",
          "uint32 expiry",
          ")"
        )
      )
    );

  /// ---- STRUCTS -----
  struct Entitlement {
    /// @notice the beneficial owner address this entitlement applies to. This address will also be the signer.
    address beneficialOwner;
    /// @notice the operating contract that can change ownership during the entitlement period.
    address operator;
    /// @notice the contract address for the vault that contains the underlying assets
    address vaultAddress;
    /// @notice the assetId of the asset or assets within the vault
    uint32 assetId;
    /// @notice the block timestamp after which the asset is free of the entitlement
    uint32 expiry;
  }

  function getEntitlementStructHash(Entitlement memory entitlement)
    internal
    pure
    returns (bytes32)
  {
    // TODO: Hash in place to save gas.
    return
      keccak256(
        abi.encode(
          _ENTITLEMENT_TYPEHASH,
          entitlement.beneficialOwner,
          entitlement.operator,
          entitlement.vaultAddress,
          entitlement.assetId,
          entitlement.expiry
        )
      );
  }
}

File 20 of 21 : Signatures.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

/// @dev A library for validating signatures from ZeroEx
library Signatures {
  /// @dev Allowed signature types.
  enum SignatureType {
    EIP712
  }

  /// @dev Encoded EC signature.
  struct Signature {
    // How to validate the signature.
    SignatureType signatureType;
    // EC Signature data.
    uint8 v;
    // EC Signature data.
    bytes32 r;
    // EC Signature data.
    bytes32 s;
  }
}

File 21 of 21 : PermissionConstants.sol
// SPDX-License-Identifier: MIT
//
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        █████████████▌                                        ▐█████████████
//        ██████████████                                        ██████████████
//        ██████████████          ▄▄████████████████▄▄         ▐█████████████▌
//        ██████████████    ▄█████████████████████████████▄    ██████████████
//         ██████████▀   ▄█████████████████████████████████   ██████████████▌
//          ██████▀   ▄██████████████████████████████████▀  ▄███████████████
//           ███▀   ██████████████████████████████████▀   ▄████████████████
//            ▀▀  ████████████████████████████████▀▀   ▄█████████████████▌
//              █████████████████████▀▀▀▀▀▀▀      ▄▄███████████████████▀
//             ██████████████████▀    ▄▄▄█████████████████████████████▀
//            ████████████████▀   ▄█████████████████████████████████▀  ██▄
//          ▐███████████████▀  ▄██████████████████████████████████▀   █████▄
//          ██████████████▀  ▄█████████████████████████████████▀   ▄████████
//         ██████████████▀   ███████████████████████████████▀   ▄████████████
//        ▐█████████████▌     ▀▀▀▀████████████████████▀▀▀▀      █████████████▌
//        ██████████████                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████
//        █████████████▌                                        ██████████████

pragma solidity ^0.8.10;

/// @notice roles on the hook protocol that can be read by other contract
/// @dev new roles here should be initialized in the constructor of the protocol
abstract contract PermissionConstants {
  /// ----- ROLES --------

  /// @notice the allowlister is able to enable and disable projects to mint instruments
  bytes32 public constant ALLOWLISTER_ROLE = keccak256("ALLOWLISTER_ROLE");

  /// @notice the pauser is able to start and pause various components of the protocol
  bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

  /// @notice the vault upgrader role is able to upgrade the implementation for all vaults
  bytes32 public constant VAULT_UPGRADER = keccak256("VAULT_UPGRADER");

  /// @notice the call upgrader role is able to upgrade the implementation of the covered call options
  bytes32 public constant CALL_UPGRADER = keccak256("CALL_UPGRADER");

  /// @notice the market configuration role allows the actor to make changes to how the market operates
  bytes32 public constant MARKET_CONF = keccak256("MARKET_CONF");

  /// @notice the collection configuration role allows the actor to make changes the collection
  /// configs on the protocol contract
  bytes32 public constant COLLECTION_CONF = keccak256("COLLECTION_CONF");
}

Settings
{
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 10
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"hookProtocolAddress","type":"address"},{"internalType":"address","name":"beaconAddress","type":"address"},{"internalType":"address","name":"multiBeaconAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":false,"internalType":"address","name":"vaultAddress","type":"address"}],"name":"ERC721MultiVaultCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"vaultAddress","type":"address"}],"name":"ERC721VaultCreated","type":"event"},{"inputs":[],"name":"ALLOWLISTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALL_UPGRADER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COLLECTION_CONF","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MARKET_CONF","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT_UPGRADER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"findOrCreateVault","outputs":[{"internalType":"contract IHookERC721Vault","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getMultiVault","outputs":[{"internalType":"contract IHookERC721Vault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"getVault","outputs":[{"internalType":"contract IHookERC721Vault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"}],"name":"makeMultiVault","outputs":[{"internalType":"contract IHookERC721Vault","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"makeSoloVault","outputs":[{"internalType":"contract IHookERC721Vault","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b5060405162001752380380620017528339810160408190526200003491620001c8565b6200004a836200019c60201b620008cd1760201c565b6200009c5760405162461bcd60e51b815260206004820181905260248201527f686f6f6b2070726f746f636f6c206d757374206265206120636f6e747261637460448201526064015b60405180910390fd5b620000b2826200019c60201b620008cd1760201c565b6200010a5760405162461bcd60e51b815260206004820152602160248201527f626561636f6e2061646472657373206d757374206265206120636f6e747261636044820152601d60fa1b606482015260840162000093565b62000120816200019c60201b620008cd1760201c565b6200017e5760405162461bcd60e51b815260206004820152602760248201527f6d756c746920626561636f6e2061646472657373206d757374206265206120636044820152661bdb9d1c9858dd60ca1b606482015260840162000093565b6001600160a01b0392831660805290821660a0521660c05262000212565b6001600160a01b03163b151590565b80516001600160a01b0381168114620001c357600080fd5b919050565b600080600060608486031215620001de57600080fd5b620001e984620001ab565b9250620001f960208501620001ab565b91506200020960408501620001ab565b90509250925092565b60805160a05160c0516114fb6200025760003960006106e60152600061032b01526000818161034e0152818161049501528181610538015261070801526114fb6000f3fe608060405234801561001057600080fd5b50600436106100995760003560e01c80630bc0d3fa1461009e5780630d5e67ec146100c7578063435b51de146100fc5780636fe76da61461010f578063a34fd3fb14610138578063acca68381461015f578063b6f3fa3f14610174578063bb31173a14610187578063d99d13f5146101ae578063e63ab1e9146101df578063f23c19e814610206575b600080fd5b6100b16100ac366004610a3b565b61022d565b6040516100be9190610a65565b60405180910390f35b6100ee7f945438d5e976f17e0d00cb2997cf8951c55e12977d86234d6738d1865abe006e81565b6040519081526020016100be565b6100b161010a366004610a79565b61047b565b6100b161011d366004610a79565b6001602052600090815260409020546001600160a01b031681565b6100ee7f657f307dfada290937bc821a25e2da10feb07809ba9560b816723e8b47fe379a81565b6100ee6000805160206114a683398151915281565b6100b1610182366004610a3b565b610826565b6100ee7ff7e0191f3657a6da7569740b1cdeac8c3425bcbfd257d4fdc6d2241598f4de8b81565b6100b16101bc366004610a3b565b60006020818152928152604080822090935290815220546001600160a01b031681565b6100ee7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b6100ee7f8de11a8d956993287a5b6a74c069984045abc1b621d651081c4c77c05c3cb7af81565b6001600160a01b03828116600090815260208181526040808320858452909152812054909116156102b45760405162461bcd60e51b815260206004820152602660248201527f6d616b655661756c742d61207661756c742063616e6e6f7420616c726561647960448201526508195e1a5cdd60d21b60648201526084015b60405180910390fd5b604080516001600160a01b038516602080830191909152818301859052825180830384018152606090920190925280519101206000906103189082905b60405161030060208201610a12565b601f1982820381018352601f909101166040526108dc565b9050806001600160a01b0316637fe8e72c7f000000000000000000000000000000000000000000000000000000000000000086867f000000000000000000000000000000000000000000000000000000000000000060405160240161037f93929190610a94565b60408051601f198184030181529181526020820180516001600160e01b031663c350a1b560e01b1790525160e084901b6001600160e01b03191681526103c9929190600401610ab7565b600060405180830381600087803b1580156103e357600080fd5b505af11580156103f7573d6000803e3d6000fd5b505050506001600160a01b038481166000908152602081815260408083208784529091529081902080546001600160a01b031916928416929092179091555181907fec1cb694178d064cbb440cc15ed37f43d60f55db3e5c1aa3b16f3da853812e579061046990879087908590610a94565b60405180910390a19150505b92915050565b604051632474521560e21b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d14854906104da906000805160206114a6833981519152903390600401610b1c565b602060405180830381865afa1580156104f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051b9190610b33565b806105bf5750604051632474521560e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d148549061057e906000805160206114a683398151915290600090600401610b1c565b602060405180830381865afa15801561059b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bf9190610b33565b6106495760405162461bcd60e51b815260206004820152604f60248201527f6d616b654d756c74695661756c742d4f6e6c79206163636f756e74732077697460448201527f682074686520414c4c4f574c495354455220726f6c652063616e206d616b652060648201526e6e6577206d756c74695661756c747360881b608482015260a4016102ab565b6001600160a01b0382811660009081526001602052604090205416156106c35760405162461bcd60e51b815260206004820152602960248201527f6d616b654d756c74695661756c742d7661756c742063616e6e6f7420616c726560448201526818591e48195e1a5cdd60ba1b60648201526084016102ab565b60006106d360006102f1856109e2565b9050806001600160a01b0316637fe8e72c7f0000000000000000000000000000000000000000000000000000000000000000857f0000000000000000000000000000000000000000000000000000000000000000604051602401610738929190610b55565b60408051601f198184030181529181526020820180516001600160e01b031663485cc95560e01b1790525160e084901b6001600160e01b0319168152610782929190600401610ab7565b600060405180830381600087803b15801561079c57600080fd5b505af11580156107b0573d6000803e3d6000fd5b505050506001600160a01b038381166000908152600160205260409081902080546001600160a01b031916928416929092179091555181907f4576e6da87b352d9168729d519d6b20717c930bc4aca52cd876b1c797227acc7906108179086908490610b55565b60405180910390a19392505050565b6001600160a01b038281166000908152600160205260408120549091161561086957506001600160a01b0380831660009081526001602052604090205416610475565b6001600160a01b0383811660009081526020818152604080832086845290915290205416156108bc57506001600160a01b0380831660009081526020818152604080832085845290915290205416610475565b6108c6838361022d565b9392505050565b6001600160a01b03163b151590565b6000808447101561092f5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064016102ab565b825161097d5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016102ab565b8383516020850187f590506001600160a01b0381166109da5760405162461bcd60e51b8152602060048201526019602482015278437265617465323a204661696c6564206f6e206465706c6f7960381b60448201526064016102ab565b949350505050565b6000816040516020016109f59190610a65565b604051602081830303815290604052805190602001209050919050565b61093680610b7083390190565b80356001600160a01b0381168114610a3657600080fd5b919050565b60008060408385031215610a4e57600080fd5b610a5783610a1f565b946020939093013593505050565b6001600160a01b0391909116815260200190565b600060208284031215610a8b57600080fd5b6108c682610a1f565b6001600160a01b0393841681526020810192909252909116604082015260600190565b60018060a01b038316815260006020604081840152835180604085015260005b81811015610af357858101830151858201606001528201610ad7565b81811115610b05576000606083870101525b50601f01601f191692909201606001949350505050565b9182526001600160a01b0316602082015260400190565b600060208284031215610b4557600080fd5b815180151581146108c657600080fd5b6001600160a01b039283168152911660208201526040019056fe608060405234801561001057600080fd5b50610916806100206000396000f3fe6080604052600436106100225760003560e01c80637fe8e72c1461003957610031565b366100315761002f610059565b005b61002f610059565b34801561004557600080fd5b5061002f61005436600461068c565b61006b565b61006961006461016f565b6101f6565b565b6000610077600161021a565b905080156100af57600161009f61009c8260008051602061087a83398151915261074f565b90565b805460ff19169115159190911790555b6100da60017fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5161074f565b60008051602061085a833981519152146100f6576100f6610774565b610102838360006102ee565b801561016a57600061012661009c600160008051602061087a83398151915261074f565b805460ff1916911515919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b600061019060008051602061085a833981519152546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f1919061078a565b905090565b3660008037600080366000845af43d6000803e808015610215573d6000f35b3d6000fd5b600061023861009c600160008051602061087a83398151915261074f565b5460ff1615610287578160ff16600114801561025a5750610258306103ae565b155b61027f5760405162461bcd60e51b8152600401610276906107a7565b60405180910390fd5b506000919050565b60ff82166102a761009c600160008051602061089a83398151915261074f565b54106102c55760405162461bcd60e51b8152600401610276906107a7565b60ff82166102e561009c600160008051602061089a83398151915261074f565b55506001919050565b6102f7836103bd565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a26000825111806103385750805b1561016a576103a8836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561037e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a2919061078a565b8361051e565b50505050565b6001600160a01b03163b151590565b6103c6816103ae565b6104205760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b6064820152608401610276565b61048a816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610461573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610485919061078a565b6103ae565b6104ef5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610276565b60008051602061085a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b606061054383836040518060600160405280602781526020016108ba6027913961054a565b9392505050565b6060610555846103ae565b6105b05760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610276565b600080856001600160a01b0316856040516105cb919061080a565b600060405180830381855af49150503d8060008114610606576040519150601f19603f3d011682016040523d82523d6000602084013e61060b565b606091505b509150915061061b828286610625565b9695505050505050565b60608315610634575081610543565b8251156106445782518084602001fd5b8160405162461bcd60e51b81526004016102769190610826565b6001600160a01b038116811461067357600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561069f57600080fd5b82356106aa8161065e565b915060208301356001600160401b03808211156106c657600080fd5b818501915085601f8301126106da57600080fd5b8135818111156106ec576106ec610676565b604051601f8201601f19908116603f0116810190838211818310171561071457610714610676565b8160405282815288602084870101111561072d57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008282101561076f57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b60006020828403121561079c57600080fd5b81516105438161065e565b6020808252601f908201527f636f6e747261637420697320616c726561647920696e697469616c697a656400604082015260600190565b60005b838110156107f95781810151838201526020016107e1565b838111156103a85750506000910152565b6000825161081c8184602087016107de565b9190910192915050565b60208152600082518060208401526108458160408501602087016107de565b601f01601f1916919091016040019291505056fea3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50ba701f97ffd09be973ab0487da5ef9921c2bd0aad55202b3c0b41745a8ecda29021cb2f443fd62c4cb6b5d341f5eb8cd045222fc4183f8753d3725ac19741805416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b9160d7d2c1102ca8191ecd78f04d42a9f497feb44eb9ea5596cee55560cbe9964736f6c634300080a0033fba4f6dd992a27a814ee807eb2f9332d6d01312041726966a540cf4a4a891553a264697066735822122019be1da81becabca6aee761807b52ec3189fae2f73d55a554df96cc3f2c4f44564736f6c634300080a0033000000000000000000000000e11cced3e6555a1bcba2e19b9cf161f040186069000000000000000000000000f8d40ad159ebe0314a07e2d0d6f73a486ecf8520000000000000000000000000f70c0b90cc65aadc2a6a70fe0d86b2a05e15b85f

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100995760003560e01c80630bc0d3fa1461009e5780630d5e67ec146100c7578063435b51de146100fc5780636fe76da61461010f578063a34fd3fb14610138578063acca68381461015f578063b6f3fa3f14610174578063bb31173a14610187578063d99d13f5146101ae578063e63ab1e9146101df578063f23c19e814610206575b600080fd5b6100b16100ac366004610a3b565b61022d565b6040516100be9190610a65565b60405180910390f35b6100ee7f945438d5e976f17e0d00cb2997cf8951c55e12977d86234d6738d1865abe006e81565b6040519081526020016100be565b6100b161010a366004610a79565b61047b565b6100b161011d366004610a79565b6001602052600090815260409020546001600160a01b031681565b6100ee7f657f307dfada290937bc821a25e2da10feb07809ba9560b816723e8b47fe379a81565b6100ee6000805160206114a683398151915281565b6100b1610182366004610a3b565b610826565b6100ee7ff7e0191f3657a6da7569740b1cdeac8c3425bcbfd257d4fdc6d2241598f4de8b81565b6100b16101bc366004610a3b565b60006020818152928152604080822090935290815220546001600160a01b031681565b6100ee7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b6100ee7f8de11a8d956993287a5b6a74c069984045abc1b621d651081c4c77c05c3cb7af81565b6001600160a01b03828116600090815260208181526040808320858452909152812054909116156102b45760405162461bcd60e51b815260206004820152602660248201527f6d616b655661756c742d61207661756c742063616e6e6f7420616c726561647960448201526508195e1a5cdd60d21b60648201526084015b60405180910390fd5b604080516001600160a01b038516602080830191909152818301859052825180830384018152606090920190925280519101206000906103189082905b60405161030060208201610a12565b601f1982820381018352601f909101166040526108dc565b9050806001600160a01b0316637fe8e72c7f000000000000000000000000f8d40ad159ebe0314a07e2d0d6f73a486ecf852086867f000000000000000000000000e11cced3e6555a1bcba2e19b9cf161f04018606960405160240161037f93929190610a94565b60408051601f198184030181529181526020820180516001600160e01b031663c350a1b560e01b1790525160e084901b6001600160e01b03191681526103c9929190600401610ab7565b600060405180830381600087803b1580156103e357600080fd5b505af11580156103f7573d6000803e3d6000fd5b505050506001600160a01b038481166000908152602081815260408083208784529091529081902080546001600160a01b031916928416929092179091555181907fec1cb694178d064cbb440cc15ed37f43d60f55db3e5c1aa3b16f3da853812e579061046990879087908590610a94565b60405180910390a19150505b92915050565b604051632474521560e21b81526000906001600160a01b037f000000000000000000000000e11cced3e6555a1bcba2e19b9cf161f04018606916906391d14854906104da906000805160206114a6833981519152903390600401610b1c565b602060405180830381865afa1580156104f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051b9190610b33565b806105bf5750604051632474521560e21b81526001600160a01b037f000000000000000000000000e11cced3e6555a1bcba2e19b9cf161f04018606916906391d148549061057e906000805160206114a683398151915290600090600401610b1c565b602060405180830381865afa15801561059b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bf9190610b33565b6106495760405162461bcd60e51b815260206004820152604f60248201527f6d616b654d756c74695661756c742d4f6e6c79206163636f756e74732077697460448201527f682074686520414c4c4f574c495354455220726f6c652063616e206d616b652060648201526e6e6577206d756c74695661756c747360881b608482015260a4016102ab565b6001600160a01b0382811660009081526001602052604090205416156106c35760405162461bcd60e51b815260206004820152602960248201527f6d616b654d756c74695661756c742d7661756c742063616e6e6f7420616c726560448201526818591e48195e1a5cdd60ba1b60648201526084016102ab565b60006106d360006102f1856109e2565b9050806001600160a01b0316637fe8e72c7f000000000000000000000000f70c0b90cc65aadc2a6a70fe0d86b2a05e15b85f857f000000000000000000000000e11cced3e6555a1bcba2e19b9cf161f040186069604051602401610738929190610b55565b60408051601f198184030181529181526020820180516001600160e01b031663485cc95560e01b1790525160e084901b6001600160e01b0319168152610782929190600401610ab7565b600060405180830381600087803b15801561079c57600080fd5b505af11580156107b0573d6000803e3d6000fd5b505050506001600160a01b038381166000908152600160205260409081902080546001600160a01b031916928416929092179091555181907f4576e6da87b352d9168729d519d6b20717c930bc4aca52cd876b1c797227acc7906108179086908490610b55565b60405180910390a19392505050565b6001600160a01b038281166000908152600160205260408120549091161561086957506001600160a01b0380831660009081526001602052604090205416610475565b6001600160a01b0383811660009081526020818152604080832086845290915290205416156108bc57506001600160a01b0380831660009081526020818152604080832085845290915290205416610475565b6108c6838361022d565b9392505050565b6001600160a01b03163b151590565b6000808447101561092f5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064016102ab565b825161097d5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016102ab565b8383516020850187f590506001600160a01b0381166109da5760405162461bcd60e51b8152602060048201526019602482015278437265617465323a204661696c6564206f6e206465706c6f7960381b60448201526064016102ab565b949350505050565b6000816040516020016109f59190610a65565b604051602081830303815290604052805190602001209050919050565b61093680610b7083390190565b80356001600160a01b0381168114610a3657600080fd5b919050565b60008060408385031215610a4e57600080fd5b610a5783610a1f565b946020939093013593505050565b6001600160a01b0391909116815260200190565b600060208284031215610a8b57600080fd5b6108c682610a1f565b6001600160a01b0393841681526020810192909252909116604082015260600190565b60018060a01b038316815260006020604081840152835180604085015260005b81811015610af357858101830151858201606001528201610ad7565b81811115610b05576000606083870101525b50601f01601f191692909201606001949350505050565b9182526001600160a01b0316602082015260400190565b600060208284031215610b4557600080fd5b815180151581146108c657600080fd5b6001600160a01b039283168152911660208201526040019056fe608060405234801561001057600080fd5b50610916806100206000396000f3fe6080604052600436106100225760003560e01c80637fe8e72c1461003957610031565b366100315761002f610059565b005b61002f610059565b34801561004557600080fd5b5061002f61005436600461068c565b61006b565b61006961006461016f565b6101f6565b565b6000610077600161021a565b905080156100af57600161009f61009c8260008051602061087a83398151915261074f565b90565b805460ff19169115159190911790555b6100da60017fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5161074f565b60008051602061085a833981519152146100f6576100f6610774565b610102838360006102ee565b801561016a57600061012661009c600160008051602061087a83398151915261074f565b805460ff1916911515919091179055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b600061019060008051602061085a833981519152546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f1919061078a565b905090565b3660008037600080366000845af43d6000803e808015610215573d6000f35b3d6000fd5b600061023861009c600160008051602061087a83398151915261074f565b5460ff1615610287578160ff16600114801561025a5750610258306103ae565b155b61027f5760405162461bcd60e51b8152600401610276906107a7565b60405180910390fd5b506000919050565b60ff82166102a761009c600160008051602061089a83398151915261074f565b54106102c55760405162461bcd60e51b8152600401610276906107a7565b60ff82166102e561009c600160008051602061089a83398151915261074f565b55506001919050565b6102f7836103bd565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a26000825111806103385750805b1561016a576103a8836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561037e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a2919061078a565b8361051e565b50505050565b6001600160a01b03163b151590565b6103c6816103ae565b6104205760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b6064820152608401610276565b61048a816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610461573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610485919061078a565b6103ae565b6104ef5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b6064820152608401610276565b60008051602061085a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b606061054383836040518060600160405280602781526020016108ba6027913961054a565b9392505050565b6060610555846103ae565b6105b05760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610276565b600080856001600160a01b0316856040516105cb919061080a565b600060405180830381855af49150503d8060008114610606576040519150601f19603f3d011682016040523d82523d6000602084013e61060b565b606091505b509150915061061b828286610625565b9695505050505050565b60608315610634575081610543565b8251156106445782518084602001fd5b8160405162461bcd60e51b81526004016102769190610826565b6001600160a01b038116811461067357600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561069f57600080fd5b82356106aa8161065e565b915060208301356001600160401b03808211156106c657600080fd5b818501915085601f8301126106da57600080fd5b8135818111156106ec576106ec610676565b604051601f8201601f19908116603f0116810190838211818310171561071457610714610676565b8160405282815288602084870101111561072d57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008282101561076f57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b60006020828403121561079c57600080fd5b81516105438161065e565b6020808252601f908201527f636f6e747261637420697320616c726561647920696e697469616c697a656400604082015260600190565b60005b838110156107f95781810151838201526020016107e1565b838111156103a85750506000910152565b6000825161081c8184602087016107de565b9190910192915050565b60208152600082518060208401526108458160408501602087016107de565b601f01601f1916919091016040019291505056fea3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50ba701f97ffd09be973ab0487da5ef9921c2bd0aad55202b3c0b41745a8ecda29021cb2f443fd62c4cb6b5d341f5eb8cd045222fc4183f8753d3725ac19741805416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b9160d7d2c1102ca8191ecd78f04d42a9f497feb44eb9ea5596cee55560cbe9964736f6c634300080a0033fba4f6dd992a27a814ee807eb2f9332d6d01312041726966a540cf4a4a891553a264697066735822122019be1da81becabca6aee761807b52ec3189fae2f73d55a554df96cc3f2c4f44564736f6c634300080a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000e11cced3e6555a1bcba2e19b9cf161f040186069000000000000000000000000f8d40ad159ebe0314a07e2d0d6f73a486ecf8520000000000000000000000000f70c0b90cc65aadc2a6a70fe0d86b2a05e15b85f

-----Decoded View---------------
Arg [0] : hookProtocolAddress (address): 0xE11CCED3E6555A1BcbA2E19b9Cf161f040186069
Arg [1] : beaconAddress (address): 0xF8d40AD159EBE0314a07E2D0d6F73A486ECF8520
Arg [2] : multiBeaconAddress (address): 0xF70C0b90cC65AadC2A6A70fE0d86B2A05E15B85F

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000e11cced3e6555a1bcba2e19b9cf161f040186069
Arg [1] : 000000000000000000000000f8d40ad159ebe0314a07e2d0d6f73a486ecf8520
Arg [2] : 000000000000000000000000f70c0b90cc65aadc2a6a70fe0d86b2a05e15b85f


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.