dexorder
This commit is contained in:
116
src/core/Vault.sol
Normal file
116
src/core/Vault.sol
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
pragma solidity 0.8.26;
|
||||
|
||||
import {IVaultFactory} from "../interface/IVaultFactory.sol";
|
||||
import {IVaultProxy,IVaultImpl} from "../interface/IVault.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol";
|
||||
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
|
||||
import "./OrderSpec.sol";
|
||||
|
||||
|
||||
// All state in Vault is declared in VaultStorage so it will be identical in VaultImpl
|
||||
|
||||
contract VaultStorage is ReentrancyGuard { // The re-entrancy lock is part of the state
|
||||
address internal _impl;
|
||||
address internal _owner;
|
||||
bool internal _killed; // each Vault may be independently killed by its owner at any time
|
||||
OrdersInfo internal _ordersInfo;
|
||||
}
|
||||
|
||||
// Vault is implemented in three parts:
|
||||
// 1. VaultStorage contains the data members, which cannot be upgraded. The number of data slots is fixed upon
|
||||
// construction of the Vault contract.
|
||||
// 2. Vault itself inherits from the state and adds several "top-level" methods for receiving and withdrawing funds and
|
||||
// for upgrading the VaultImpl delegate. These vault methods may not be changed or upgraded.
|
||||
// 3. VaultImpl is a deployed contract shared by Vaults. If a method call is not found on Vault directly, the call
|
||||
// is delegated to the contract address stored in the `_impl` variable. The VaultImpl contract is basically the
|
||||
// OrderLib, implementing the common order manipulation methods. Each Vault may be independently upgraded to point
|
||||
// to a new VaultImpl contract by the owner calling their vault's `upgrade()` method with the correct argument.
|
||||
|
||||
contract Vault is IVaultProxy, VaultStorage, Proxy {
|
||||
//REV putting all variable decls together so we can more easily see visibility and immutability errors
|
||||
IVaultFactory immutable private _factory;
|
||||
uint8 immutable private _num;
|
||||
|
||||
function implementation() external view override returns(address) {return _impl;}
|
||||
|
||||
function factory() external view override returns(address) {return address(_factory);}
|
||||
|
||||
function killed() external view override returns(bool) {return _killed;}
|
||||
|
||||
function owner() external view override returns(address) {return _owner;}
|
||||
|
||||
function num() external view override returns(uint8) {return _num;}
|
||||
|
||||
// for OpenZeppelin Proxy to call implementation contract via fallback
|
||||
function _implementation() internal view override returns (address) {
|
||||
// If the VaultFactory that created this vault has had its kill switch activated, do not trust the implementation.
|
||||
// local _killed var allows individual users to put their vaults into "killed" mode, where Dexorder functionality
|
||||
// is disabled, but funds can still be moved.
|
||||
require(!_killed && !_factory.killed(), 'K');
|
||||
return _impl;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
_factory = IVaultFactory(msg.sender);
|
||||
(_owner, _num, _impl) = _factory.parameters();
|
||||
emit VaultCreated( _owner, _num );
|
||||
emit VaultImplChanged(_impl);
|
||||
}
|
||||
|
||||
// "Killing" a Vault prevents this proxy from forwarding any calls to the VaultImpl delegate contract. This means
|
||||
// all executions are stopped. Orders cannot be placed or canceled.
|
||||
function kill() external override onlyOwner {
|
||||
emit Killed();
|
||||
_killed = true;
|
||||
}
|
||||
|
||||
function upgrade(address newImpl) external override onlyOwner {
|
||||
// we force the upgrader to explicitly pass in the implementation contract address, then we
|
||||
// ensure that it matches the factory's current version.
|
||||
require( newImpl == _factory.implementation(), 'UV' );
|
||||
address oldImpl = _impl;
|
||||
if(oldImpl==newImpl){
|
||||
return;
|
||||
}
|
||||
_impl = newImpl;
|
||||
IVaultImpl(address(this)).vaultImplDidChange(oldImpl);
|
||||
emit VaultImplChanged(newImpl);
|
||||
}
|
||||
|
||||
receive() external payable override {
|
||||
emit Deposit(msg.sender, msg.value);
|
||||
}
|
||||
|
||||
function withdraw(uint256 amount) external override {
|
||||
_withdrawNative(payable(_owner), amount);
|
||||
}
|
||||
|
||||
function withdrawTo(address payable recipient, uint256 amount) external override {
|
||||
_withdrawNative(recipient, amount);
|
||||
}
|
||||
|
||||
function _withdrawNative(address payable recipient, uint256 amount) internal onlyOwner {
|
||||
recipient.transfer(amount);
|
||||
emit Withdrawal(recipient, msg.value);
|
||||
}
|
||||
|
||||
function withdraw(IERC20 token, uint256 amount) external override {
|
||||
_withdraw(token, _owner, amount);
|
||||
}
|
||||
|
||||
function withdrawTo(IERC20 token, address recipient, uint256 amount) external override {
|
||||
_withdraw(token, recipient, amount);
|
||||
}
|
||||
|
||||
function _withdraw(IERC20 token, address recipient, uint256 amount) internal onlyOwner nonReentrant {
|
||||
token.transfer(recipient, amount);
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(msg.sender == _owner, "not owner");
|
||||
_;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user