|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +// |
| 3 | +// █████████████▌ ▐█████████████ |
| 4 | +// █████████████▌ ▐█████████████ |
| 5 | +// █████████████▌ ▐█████████████ |
| 6 | +// █████████████▌ ▐█████████████ |
| 7 | +// █████████████▌ ▐█████████████ |
| 8 | +// █████████████▌ ▐█████████████ |
| 9 | +// █████████████▌ ▐█████████████ |
| 10 | +// █████████████▌ ▐█████████████ |
| 11 | +// ██████████████ ██████████████ |
| 12 | +// ██████████████ ▄▄████████████████▄▄ ▐█████████████▌ |
| 13 | +// ██████████████ ▄█████████████████████████████▄ ██████████████ |
| 14 | +// ██████████▀ ▄█████████████████████████████████ ██████████████▌ |
| 15 | +// ██████▀ ▄██████████████████████████████████▀ ▄███████████████ |
| 16 | +// ███▀ ██████████████████████████████████▀ ▄████████████████ |
| 17 | +// ▀▀ ████████████████████████████████▀▀ ▄█████████████████▌ |
| 18 | +// █████████████████████▀▀▀▀▀▀▀ ▄▄███████████████████▀ |
| 19 | +// ██████████████████▀ ▄▄▄█████████████████████████████▀ |
| 20 | +// ████████████████▀ ▄█████████████████████████████████▀ ██▄ |
| 21 | +// ▐███████████████▀ ▄██████████████████████████████████▀ █████▄ |
| 22 | +// ██████████████▀ ▄█████████████████████████████████▀ ▄████████ |
| 23 | +// ██████████████▀ ███████████████████████████████▀ ▄████████████ |
| 24 | +// ▐█████████████▌ ▀▀▀▀████████████████████▀▀▀▀ █████████████▌ |
| 25 | +// ██████████████ ██████████████ |
| 26 | +// █████████████▌ ██████████████ |
| 27 | +// █████████████▌ ██████████████ |
| 28 | +// █████████████▌ ██████████████ |
| 29 | +// █████████████▌ ██████████████ |
| 30 | +// █████████████▌ ██████████████ |
| 31 | +// █████████████▌ ██████████████ |
| 32 | +// █████████████▌ ██████████████ |
| 33 | +// █████████████▌ ██████████████ |
| 34 | + |
| 35 | +pragma solidity ^0.8.10; |
| 36 | + |
| 37 | +import "@openzeppelin/contracts/utils/Create2.sol"; |
| 38 | + |
| 39 | +import "./HookBeaconProxy.sol"; |
| 40 | + |
| 41 | +import "./interfaces/IHookERC20VaultFactory.sol"; |
| 42 | +import "./interfaces/IHookERC20Vault.sol"; |
| 43 | +import "./interfaces/IHookProtocol.sol"; |
| 44 | +import "./interfaces/IInitializeableBeacon.sol"; |
| 45 | + |
| 46 | +import "./mixin/PermissionConstants.sol"; |
| 47 | + |
| 48 | +import "./lib/BeaconSalts.sol"; |
| 49 | + |
| 50 | +/// @title Hook Vault Factory |
| 51 | +/// @author Jake Nyquist-j@hook.xyz |
| 52 | +/// @dev See {IHookERC20VaultFactory}. |
| 53 | +/// @dev The factory itself is non-upgradeable; however, each vault is upgradeable (i.e. all vaults) |
| 54 | +/// created by this factory can be upgraded at one time via the beacon pattern. |
| 55 | +contract HookER20VaultFactory is IHookERC20VaultFactory, PermissionConstants { |
| 56 | + /// @notice Registry of all of the active multi-vaults within the protocol |
| 57 | + mapping(address => IHookERC20Vault) public override getVault; |
| 58 | + |
| 59 | + address private immutable _hookProtocol; |
| 60 | + address private immutable _beacon; |
| 61 | + |
| 62 | + constructor(address hookProtocolAddress, address beaconAddress) { |
| 63 | + require(Address.isContract(hookProtocolAddress), "hook protocol must be a contract"); |
| 64 | + require(Address.isContract(beaconAddress), "beacon address must be a contract"); |
| 65 | + _hookProtocol = hookProtocolAddress; |
| 66 | + _beacon = beaconAddress; |
| 67 | + } |
| 68 | + |
| 69 | + /// @notice See {IHookERC29VaultFactory-makeVault}. |
| 70 | + function makeVault(address tokenAddress) public returns (IHookERC20Vault) { |
| 71 | + require( |
| 72 | + IHookProtocol(_hookProtocol).hasRole(ALLOWLISTER_ROLE, msg.sender) |
| 73 | + || IHookProtocol(_hookProtocol).hasRole(ALLOWLISTER_ROLE, address(0)), |
| 74 | + "makeVault-Only accounts with the ALLOWLISTER role can make new vaults" |
| 75 | + ); |
| 76 | + |
| 77 | + require(getVault[tokenAddress] == IHookERC20Vault(address(0)), "makeVault-vault cannot already exist"); |
| 78 | + |
| 79 | + IInitializeableBeacon bp = IInitializeableBeacon( |
| 80 | + Create2.deploy(0, BeaconSalts.erc20VaultSalt(tokenAddress), type(HookBeaconProxy).creationCode) |
| 81 | + ); |
| 82 | + |
| 83 | + bp.initializeBeacon( |
| 84 | + _beacon, |
| 85 | + /// This is the ABI encoded initializer on the IHookERC20Vault.sol |
| 86 | + abi.encodeWithSignature("initialize(address,address)", tokenAddress, _hookProtocol) |
| 87 | + ); |
| 88 | + |
| 89 | + IHookERC20Vault vault = IHookERC20Vault(address(bp)); |
| 90 | + getVault[tokenAddress] = vault; |
| 91 | + emit ERC20VaultCreated(tokenAddress, address(bp)); |
| 92 | + |
| 93 | + return vault; |
| 94 | + } |
| 95 | + |
| 96 | + /// @notice See {IHookERC20VaultFactory-findOrCreateVault}. |
| 97 | + function findOrCreateVault(address tokenAddress) external returns (IHookERC20Vault) { |
| 98 | + if (getVault[tokenAddress] != IHookERC20Vault(address(0))) { |
| 99 | + return getVault[tokenAddress]; |
| 100 | + } |
| 101 | + |
| 102 | + return makeVault(tokenAddress); |
| 103 | + } |
| 104 | +} |
0 commit comments