Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
ignore = dirty
[submodule "lib/narya-contracts"]
path = lib/narya-contracts
url = https://github.com/NaryaAI/narya-contracts
url = https://github.com/NaryaAI/narya-contracts
2 changes: 1 addition & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
@openzeppelin/contracts=node_modules/@openzeppelin/contracts
@narya-ai/contracts/=lib/narya-contracts/
forge-std/=lib/forge-std/src/
forge-std/=lib/forge-std/src/
104 changes: 104 additions & 0 deletions src/HookERC20VaultFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: MIT
//
// █████████████▌ ▐█████████████
// █████████████▌ ▐█████████████
// █████████████▌ ▐█████████████
// █████████████▌ ▐█████████████
// █████████████▌ ▐█████████████
// █████████████▌ ▐█████████████
// █████████████▌ ▐█████████████
// █████████████▌ ▐█████████████
// ██████████████ ██████████████
// ██████████████ ▄▄████████████████▄▄ ▐█████████████▌
// ██████████████ ▄█████████████████████████████▄ ██████████████
// ██████████▀ ▄█████████████████████████████████ ██████████████▌
// ██████▀ ▄██████████████████████████████████▀ ▄███████████████
// ███▀ ██████████████████████████████████▀ ▄████████████████
// ▀▀ ████████████████████████████████▀▀ ▄█████████████████▌
// █████████████████████▀▀▀▀▀▀▀ ▄▄███████████████████▀
// ██████████████████▀ ▄▄▄█████████████████████████████▀
// ████████████████▀ ▄█████████████████████████████████▀ ██▄
// ▐███████████████▀ ▄██████████████████████████████████▀ █████▄
// ██████████████▀ ▄█████████████████████████████████▀ ▄████████
// ██████████████▀ ███████████████████████████████▀ ▄████████████
// ▐█████████████▌ ▀▀▀▀████████████████████▀▀▀▀ █████████████▌
// ██████████████ ██████████████
// █████████████▌ ██████████████
// █████████████▌ ██████████████
// █████████████▌ ██████████████
// █████████████▌ ██████████████
// █████████████▌ ██████████████
// █████████████▌ ██████████████
// █████████████▌ ██████████████
// █████████████▌ ██████████████

pragma solidity ^0.8.10;

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

import "./HookBeaconProxy.sol";

import "./interfaces/IHookERC20VaultFactory.sol";
import "./interfaces/IHookERC20Vault.sol";
import "./interfaces/IHookProtocol.sol";
import "./interfaces/IInitializeableBeacon.sol";

import "./mixin/PermissionConstants.sol";

import "./lib/BeaconSalts.sol";

/// @title Hook Vault Factory
/// @author Jake Nyquist-j@hook.xyz
/// @dev See {IHookERC20VaultFactory}.
/// @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 HookER20VaultFactory is IHookERC20VaultFactory, PermissionConstants {
/// @notice Registry of all of the active multi-vaults within the protocol
mapping(address => IHookERC20Vault) public override getVault;

address private immutable _hookProtocol;
address private immutable _beacon;

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

/// @notice See {IHookERC29VaultFactory-makeVault}.
function makeVault(address tokenAddress) public returns (IHookERC20Vault) {
require(
IHookProtocol(_hookProtocol).hasRole(ALLOWLISTER_ROLE, msg.sender)
|| IHookProtocol(_hookProtocol).hasRole(ALLOWLISTER_ROLE, address(0)),
"makeVault-Only accounts with the ALLOWLISTER role can make new vaults"
);

require(getVault[tokenAddress] == IHookERC20Vault(address(0)), "makeVault-vault cannot already exist");

IInitializeableBeacon bp = IInitializeableBeacon(
Create2.deploy(0, BeaconSalts.erc20VaultSalt(tokenAddress), type(HookBeaconProxy).creationCode)
);

bp.initializeBeacon(
_beacon,
/// This is the ABI encoded initializer on the IHookERC20Vault.sol
abi.encodeWithSignature("initialize(address,address)", tokenAddress, _hookProtocol)
);

IHookERC20Vault vault = IHookERC20Vault(address(bp));
getVault[tokenAddress] = vault;
emit ERC20VaultCreated(tokenAddress, address(bp));

return vault;
}

/// @notice See {IHookERC20VaultFactory-findOrCreateVault}.
function findOrCreateVault(address tokenAddress) external returns (IHookERC20Vault) {
if (getVault[tokenAddress] != IHookERC20Vault(address(0))) {
return getVault[tokenAddress];
}

return makeVault(tokenAddress);
}
}
Loading