Skip to content

Commit

Permalink
remove upgradeable feature
Browse files Browse the repository at this point in the history
store vaults addresses in factory
use admin address instead of separate emergency withdraw addr
  • Loading branch information
pum committed Aug 30, 2023
1 parent 9b328ad commit 2552c73
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 158 deletions.
4 changes: 0 additions & 4 deletions contracts/IVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,5 @@ pragma solidity ^0.8.0;
import "./IVaultsFactory.sol";

interface IVault {
function initialize(address underlyingToken_, IVaultsFactory factory_, bool isEth, string memory name_, string memory symbol_) external;
function emergencyWithdraw(uint256 amount_) external;

// must return keccak256("Vaults.Vault") ^ bytes32(uint256(uint160(address(VaultsFactory))))
function isVault() external view returns (bytes32);
}
2 changes: 1 addition & 1 deletion contracts/IVaultsFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "./IVault.sol";
interface IVaultsFactory {
function feeReceiver() external view returns(address);
function feeBasisPoints() external view returns (uint256);
function emergencyWithdrawAddress() external view returns(address);
function emergencyWithdrawAddress() external view returns (address);

function unwrapDelay() external view returns (uint256);
function isPaused(IVault vault) external view returns (bool);
Expand Down
31 changes: 14 additions & 17 deletions contracts/VaultImplementation.sol → contracts/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./IVaultsFactory.sol";
import "./IVault.sol";
import "./IWETH.sol";


contract VaultImplementation is IVault, Initializable, ERC20PermitUpgradeable, ReentrancyGuardUpgradeable {
using SafeERC20Upgradeable for IERC20MetadataUpgradeable;
contract Vault is IVault, ERC20Permit, ReentrancyGuard {
using SafeERC20 for IERC20Metadata;

IERC20MetadataUpgradeable public underlyingToken;
IVaultsFactory public factory;
bool public isEth;
IERC20Metadata public immutable underlyingToken;
IVaultsFactory public immutable factory;
bool public immutable isEth;

bool public emergency = false;

Expand All @@ -37,13 +37,14 @@ contract VaultImplementation is IVault, Initializable, ERC20PermitUpgradeable, R
_;
}

function initialize(address underlyingToken_, IVaultsFactory factory_, bool isEth_, string memory name_, string memory symbol_) public initializer {
underlyingToken = IERC20MetadataUpgradeable(underlyingToken_);
constructor(IERC20Metadata underlyingToken_, IVaultsFactory factory_, bool isEth_, string memory name_, string memory symbol_)
ERC20Permit(name_)
ERC20(name_, symbol_)
ReentrancyGuard()
{
underlyingToken = underlyingToken_;
factory = factory_;
isEth = isEth_;
__ERC20_init(name_, symbol_);
__ERC20Permit_init(name_);
__ReentrancyGuard_init();
}

// only accept ETH via fallback from the WETH contract
Expand Down Expand Up @@ -138,8 +139,4 @@ contract VaultImplementation is IVault, Initializable, ERC20PermitUpgradeable, R
require(balanceOf(from) >= amount + pendingUnwraps[from].amount, "VAULTS: TRANSFER_EXCEEDS_BALANCE");
}
}

function isVault() public view returns (bytes32) {
return keccak256("Vaults.Vault") ^ bytes32(uint256(uint160(address(factory))));
}
}
71 changes: 27 additions & 44 deletions contracts/VaultsFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IVaultsFactory.sol";
import "./IVault.sol";
import "./Vault.sol";

contract VaultsFactory is IVaultsFactory, AccessControlEnumerable {
address public immutable weth;
address public immutable emergencyWithdrawAddress;

address public defaultVaultImplementation;
uint256 public unwrapDelay;

address public feeReceiver;
uint256 public feeBasisPoints;

mapping(IVault => bool) public isVault;

mapping(IVault => bool) public pausedVaults;
bool public allVaultsPaused = false;

Expand All @@ -30,30 +28,16 @@ contract VaultsFactory is IVaultsFactory, AccessControlEnumerable {
event AllVaultsPaused();
event AllVaultsUnpaused();

modifier isVault(IVault vault_) {
try vault_.isVault() returns (bytes32 result) {
require(result == keccak256("Vaults.Vault") ^ bytes32(uint256(uint160(address(this)))), "VAULTS: NOT_VAULT");
} catch {
revert("VAULTS: NOT_VAULT");
}
_;
}

constructor(
address weth_,
address vaultImplementationAddress_,
uint256 unwrapDelay_,
address rolesAddr_,
address initialFeeReceiver_,
uint256 initialFeeBasisPoints_,
address emergencyWithdrawAddress_
uint256 initialFeeBasisPoints_
) {
require(weth_ != address(0), "VAULTS: ZERO_ADDRESS");
require(vaultImplementationAddress_ != address(0), "VAULTS: ZERO_ADDRESS");
require(emergencyWithdrawAddress_ != address(0), "VAULTS: ZERO_ADDRESS");

weth = weth_;
defaultVaultImplementation = vaultImplementationAddress_;
unwrapDelay = unwrapDelay_;

_setupRole(DEFAULT_ADMIN_ROLE, rolesAddr_);
Expand All @@ -62,35 +46,34 @@ contract VaultsFactory is IVaultsFactory, AccessControlEnumerable {

_setFeeReceiver(initialFeeReceiver_);
_setFeeBasisPoints(initialFeeBasisPoints_);

emergencyWithdrawAddress = emergencyWithdrawAddress_;
}

function deployVault(address underlyingToken_, string memory name_, string memory symbol_) external onlyRole(TEAM_ROLE) returns (IVault result) {
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
defaultVaultImplementation,
getRoleMember(DEFAULT_ADMIN_ROLE, 0),
""
);
result = IVault(address(proxy));
result.initialize(
function deployVault(IERC20Metadata underlyingToken_, string memory name_, string memory symbol_) external onlyRole(TEAM_ROLE) returns (IVault result) {
result = new Vault(
underlyingToken_,
this,
underlyingToken_ == weth,
bytes(name_).length != 0 ? name_ : string(abi.encodePacked("Vaulted ", IERC20Metadata(underlyingToken_).symbol())),
bytes(symbol_).length != 0 ? symbol_ : string(abi.encodePacked("v", IERC20Metadata(underlyingToken_).symbol()))
address(underlyingToken_) == weth,
bytes(name_).length != 0 ? name_ : string(abi.encodePacked("Vaulted ", underlyingToken_.symbol())),
bytes(symbol_).length != 0 ? symbol_ : string(abi.encodePacked("v", underlyingToken_.symbol()))
);

isVault[result] = true;

emit VaultDeployed(result);
}

function pauseVault(IVault vault_) external onlyRole(PAUSE_ROLE) isVault(vault_) {
function pauseVault(IVault vault_) external onlyRole(PAUSE_ROLE) {
require(isVault[vault_], "VAULTS: NOT_VAULT");

pausedVaults[vault_] = true;
emit VaultPaused(vault_);
}

function unpauseVault(IVault vaultAddress_) external onlyRole(DEFAULT_ADMIN_ROLE) isVault(vaultAddress_) {
delete pausedVaults[vaultAddress_];
emit VaultUnpaused(vaultAddress_);
function unpauseVault(IVault vault_) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(isVault[vault_], "VAULTS: NOT_VAULT");

delete pausedVaults[vault_];
emit VaultUnpaused(vault_);
}

function pauseAllVaults() external onlyRole(PAUSE_ROLE) {
Expand All @@ -103,21 +86,21 @@ contract VaultsFactory is IVaultsFactory, AccessControlEnumerable {
emit AllVaultsUnpaused();
}

function isPaused(IVault vaultAddress_) public view returns (bool) {
return allVaultsPaused || pausedVaults[vaultAddress_];
function isPaused(IVault vault_) public view returns (bool) {
return allVaultsPaused || pausedVaults[vault_];
}

function setUnwrapDelay(uint256 unwrapDelay_) external onlyRole(DEFAULT_ADMIN_ROLE) {
unwrapDelay = unwrapDelay_;
}

function setDefaultVaultImplementation(address vaultImplementation_) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(vaultImplementation_ != address(0), "VAULTS: ZERO_ADDRESS");
defaultVaultImplementation = vaultImplementation_;
function emergencyWithdrawAddress() external view returns (address addr_) {
addr_ = getRoleMember(DEFAULT_ADMIN_ROLE, 0);
require(addr_ != address(0), "VAULTS: BROKEN_LOGIC");
}

function emergencyWithdrawFromVault(IVault vaultAddress_, uint256 amount_) external onlyRole(DEFAULT_ADMIN_ROLE) {
vaultAddress_.emergencyWithdraw(amount_);
function emergencyWithdrawFromVault(IVault vault_, uint256 amount_) external onlyRole(DEFAULT_ADMIN_ROLE) {
vault_.emergencyWithdraw(amount_);
}

function _setFeeReceiver(address feeReceiver_) internal {
Expand Down
15 changes: 2 additions & 13 deletions scripts/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,17 @@ async function main() {
const FEE_RECEIVER = '0x0000000000000000000000000000000000000000';
const FEE = 0;

const VaultFactory = await ethers.getContractFactory("VaultImplementation");
const vault = await VaultFactory.deploy();
await vault.deployed();
console.log("VaultImplementation: ", vault.address);

const VaultsFactoryFactory = await ethers.getContractFactory("VaultsFactory");
const factory = await VaultsFactoryFactory.deploy(WETH, vault.address, DELAY, ADMIN, FEE_RECEIVER, FEE);
const factory = await VaultsFactoryFactory.deploy(WETH, DELAY, ADMIN, FEE_RECEIVER, FEE);
await factory.deployed();
console.log("Factory: ", factory.address);

await new Promise(r => setTimeout(r, 100000)); // time to index new contracts

await hre.run("verify:verify", {
address: vault.address,
constructorArguments: [],
});

await hre.run("verify:verify", {
address: factory.address,
constructorArguments: [WETH, vault.address, DELAY, ADMIN, FEE_RECEIVER, FEE],
constructorArguments: [WETH, DELAY, ADMIN, FEE_RECEIVER, FEE],
});

}

// We recommend this pattern to be able to use async/await everywhere
Expand Down

0 comments on commit 2552c73

Please sign in to comment.