Skip to content

Commit

Permalink
Merge pull request #6 from symbioticfi/tests
Browse files Browse the repository at this point in the history
Add vault configurator
  • Loading branch information
1kresh authored Jul 2, 2024
2 parents 20c8603 + d7277d2 commit 5298117
Show file tree
Hide file tree
Showing 37 changed files with 3,389 additions and 192 deletions.
53 changes: 53 additions & 0 deletions src/contracts/VaultConfigurator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;

import {VaultFactory} from "src/contracts/VaultFactory.sol";
import {DelegatorFactory} from "src/contracts/DelegatorFactory.sol";
import {SlasherFactory} from "src/contracts/SlasherFactory.sol";
import {Vault} from "src/contracts/vault/Vault.sol";

import {IVaultConfigurator} from "src/interfaces/IVaultConfigurator.sol";

contract VaultConfigurator is IVaultConfigurator {
/**
* @inheritdoc IVaultConfigurator
*/
address public immutable VAULT_FACTORY;

/**
* @inheritdoc IVaultConfigurator
*/
address public immutable DELEGATOR_FACTORY;

/**
* @inheritdoc IVaultConfigurator
*/
address public immutable SLASHER_FACTORY;

constructor(address vaultFactory, address delegatorFactory, address slasherFactory) {
VAULT_FACTORY = vaultFactory;
DELEGATOR_FACTORY = delegatorFactory;
SLASHER_FACTORY = slasherFactory;
}

/**
* @inheritdoc IVaultConfigurator
*/
function create(InitParams memory params) public returns (address, address, address) {
address vault = VaultFactory(VAULT_FACTORY).create(params.version, params.owner, false, "");

params.vaultParams.delegator = DelegatorFactory(DELEGATOR_FACTORY).create(
params.delegatorIndex, true, abi.encode(vault, params.delegatorParams)
);

if (params.withSlasher) {
params.vaultParams.slasher = SlasherFactory(SLASHER_FACTORY).create(
params.slasherIndex, true, abi.encode(vault, params.slasherParams)
);
}

Vault(vault).initialize(params.version, params.owner, abi.encode(params.vaultParams));

return (vault, params.vaultParams.delegator, params.vaultParams.slasher);
}
}
7 changes: 5 additions & 2 deletions src/contracts/common/Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ contract Factory is Registry, Ownable, IFactory {
/**
* @inheritdoc IFactory
*/
function create(uint64 index, bytes memory data) external returns (address entity_) {
function create(uint64 index, bool withInitialize, bytes memory data) external returns (address entity_) {
entity_ = implementation(index).cloneDeterministic(keccak256(abi.encode(totalEntities(), index, data)));
IEntity(entity_).initialize(data);

_addEntity(entity_);

if (withInitialize) {
IEntity(entity_).initialize(data);
}
}
}
23 changes: 18 additions & 5 deletions src/contracts/common/MigratableEntity.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.25;

import {IMigratableEntity} from "src/interfaces/common/IMigratableEntity.sol";
import {IMigratablesFactory} from "src/interfaces/common/IMigratablesFactory.sol";

import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
Expand All @@ -12,17 +13,21 @@ abstract contract MigratableEntity is Initializable, OwnableUpgradeable, IMigrat
*/
address public immutable FACTORY;

modifier onlyFactory() {
if (msg.sender != FACTORY) {
revert NotFactory();
address private immutable SELF;

modifier uninitialized() {
if (_getInitializedVersion() != 0) {
revert AlreadyInitialized();
}

_;
}

constructor(address factory) {
_disableInitializers();

FACTORY = factory;
SELF = address(this);
}

/**
Expand All @@ -39,7 +44,11 @@ abstract contract MigratableEntity is Initializable, OwnableUpgradeable, IMigrat
uint64 initialVersion,
address owner_,
bytes memory data
) external onlyFactory reinitializer(initialVersion) {
) external uninitialized reinitializer(initialVersion) {
if (SELF != IMigratablesFactory(FACTORY).implementation(initialVersion)) {
revert InvalidInitialVersion();
}

__Ownable_init(owner_);

_initialize(initialVersion, owner_, data);
Expand All @@ -48,7 +57,11 @@ abstract contract MigratableEntity is Initializable, OwnableUpgradeable, IMigrat
/**
* @inheritdoc IMigratableEntity
*/
function migrate(uint64 newVersion, bytes memory data) external onlyFactory reinitializer(newVersion) {
function migrate(uint64 newVersion, bytes memory data) external reinitializer(newVersion) {
if (msg.sender != FACTORY) {
revert NotFactory();
}

_migrate(newVersion, data);
}

Expand Down
11 changes: 9 additions & 2 deletions src/contracts/common/MigratablesFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,18 @@ contract MigratablesFactory is Registry, Ownable, IMigratablesFactory {
/**
* @inheritdoc IMigratablesFactory
*/
function create(uint64 version, address owner_, bytes memory data) external returns (address entity_) {
function create(
uint64 version,
address owner_,
bool withInitialize,
bytes memory data
) external returns (address entity_) {
entity_ = address(
new MigratableEntityProxy{salt: keccak256(abi.encode(totalEntities(), version, owner_, data))}(
implementation(version),
abi.encodeWithSelector(IMigratableEntity.initialize.selector, version, owner_, data)
withInitialize
? abi.encodeWithSelector(IMigratableEntity.initialize.selector, version, owner_, data)
: new bytes(0)
)
);

Expand Down
14 changes: 10 additions & 4 deletions src/contracts/delegator/BaseDelegator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {IOptInService} from "src/interfaces/service/IOptInService.sol";

import {Checkpoints} from "src/contracts/libraries/Checkpoints.sol";

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
Expand Down Expand Up @@ -161,17 +160,24 @@ contract BaseDelegator is Entity, AccessControlUpgradeable, IBaseDelegator {

function _onSlash(address network, address operator, uint256 slashedAmount) internal virtual {}

function _initializeDelegator(bytes memory data) internal virtual returns (address) {}
function _initializeInternal(
address vault_,
bytes memory data
) internal virtual returns (IBaseDelegator.BaseParams memory) {}

function _initialize(bytes memory data) internal override {
address vault_ = _initializeDelegator(data);
(address vault_, bytes memory data_) = abi.decode(data, (address, bytes));

if (!IRegistry(VAULT_FACTORY).isEntity(vault_)) {
revert NotVault();
}

vault = vault_;

_grantRole(DEFAULT_ADMIN_ROLE, Ownable(vault_).owner());
IBaseDelegator.BaseParams memory baseParams = _initializeInternal(vault_, data_);

if (baseParams.defaultAdminRoleHolder != address(0)) {
_grantRole(DEFAULT_ADMIN_ROLE, baseParams.defaultAdminRoleHolder);
}
}
}
28 changes: 21 additions & 7 deletions src/contracts/delegator/FullRestakeDelegator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {IVault} from "src/interfaces/vault/IVault.sol";

import {Checkpoints} from "src/contracts/libraries/Checkpoints.sol";

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

Expand Down Expand Up @@ -209,13 +208,28 @@ contract FullRestakeDelegator is BaseDelegator, IFullRestakeDelegator {
);
}

function _initializeDelegator(bytes memory data) internal override returns (address) {
(InitParams memory params) = abi.decode(data, (InitParams));
function _initializeInternal(
address,
bytes memory data
) internal override returns (IBaseDelegator.BaseParams memory) {
InitParams memory params = abi.decode(data, (InitParams));

if (
params.baseParams.defaultAdminRoleHolder == address(0)
&& (
params.networkLimitSetRoleHolder == address(0) || params.operatorNetworkLimitSetRoleHolder == address(0)
)
) {
revert MissingRoleHolders();
}

address vaultOwner = Ownable(params.vault).owner();
_grantRole(NETWORK_LIMIT_SET_ROLE, vaultOwner);
_grantRole(OPERATOR_NETWORK_LIMIT_SET_ROLE, vaultOwner);
if (params.networkLimitSetRoleHolder != address(0)) {
_grantRole(NETWORK_LIMIT_SET_ROLE, params.networkLimitSetRoleHolder);
}
if (params.operatorNetworkLimitSetRoleHolder != address(0)) {
_grantRole(OPERATOR_NETWORK_LIMIT_SET_ROLE, params.operatorNetworkLimitSetRoleHolder);
}

return params.vault;
return params.baseParams;
}
}
29 changes: 22 additions & 7 deletions src/contracts/delegator/NetworkRestakeDelegator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {IVault} from "src/interfaces/vault/IVault.sol";

import {Checkpoints} from "src/contracts/libraries/Checkpoints.sol";

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Time} from "@openzeppelin/contracts/utils/types/Time.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

Expand Down Expand Up @@ -209,13 +208,29 @@ contract NetworkRestakeDelegator is BaseDelegator, INetworkRestakeDelegator {
_operatorNetworkShares[network][operator].push(Time.timestamp(), operatorNetworkShares_ - operatorSlashedShares);
}

function _initializeDelegator(bytes memory data) internal override returns (address) {
(InitParams memory params) = abi.decode(data, (InitParams));
function _initializeInternal(
address,
bytes memory data
) internal override returns (IBaseDelegator.BaseParams memory) {
InitParams memory params = abi.decode(data, (InitParams));

if (
params.baseParams.defaultAdminRoleHolder == address(0)
&& (
params.networkLimitSetRoleHolder == address(0)
|| params.operatorNetworkSharesSetRoleHolder == address(0)
)
) {
revert MissingRoleHolders();
}

address vaultOwner = Ownable(params.vault).owner();
_grantRole(NETWORK_LIMIT_SET_ROLE, vaultOwner);
_grantRole(OPERATOR_NETWORK_SHARES_SET_ROLE, vaultOwner);
if (params.networkLimitSetRoleHolder != address(0)) {
_grantRole(NETWORK_LIMIT_SET_ROLE, params.networkLimitSetRoleHolder);
}
if (params.operatorNetworkSharesSetRoleHolder != address(0)) {
_grantRole(OPERATOR_NETWORK_SHARES_SET_ROLE, params.operatorNetworkSharesSetRoleHolder);
}

return params.vault;
return params.baseParams;
}
}
8 changes: 5 additions & 3 deletions src/contracts/slasher/BaseSlasher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ abstract contract BaseSlasher is Entity, IBaseSlasher {
OPERATOR_NETWORK_OPT_IN_SERVICE = operatorNetworkOptInService;
}

function _checkOptIns(address network, address operator) internal {
function _checkOptIns(address network, address operator) internal view {
address vault_ = vault;
uint48 timestamp = IVault(vault_).currentEpoch() != 0
? IVault(vault_).previousEpochStart()
Expand All @@ -93,15 +93,17 @@ abstract contract BaseSlasher is Entity, IBaseSlasher {
IVault(vault_).onSlash(amount);
}

function _initializeSlasher(bytes memory data) internal virtual returns (address) {}
function _initializeInternal(address vault_, bytes memory data) internal virtual {}

function _initialize(bytes memory data) internal override {
address vault_ = _initializeSlasher(data);
(address vault_, bytes memory data_) = abi.decode(data, (address, bytes));

if (!IRegistry(VAULT_FACTORY).isEntity(vault_)) {
revert NotVault();
}

vault = vault_;

_initializeInternal(vault_, data_);
}
}
6 changes: 0 additions & 6 deletions src/contracts/slasher/Slasher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,4 @@ contract Slasher is BaseSlasher, ISlasher {

return amount;
}

function _initializeSlasher(bytes memory data) internal override returns (address) {
(InitParams memory params) = abi.decode(data, (InitParams));

return params.vault;
}
}
14 changes: 6 additions & 8 deletions src/contracts/slasher/VetoSlasher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ contract VetoSlasher is BaseSlasher, AccessControlUpgradeable, IVetoSlasher {
/**
* @inheritdoc IVetoSlasher
*/
uint48 public resolverSetDelay;
uint256 public resolverSetEpochsDelay;

mapping(address network => mapping(address resolver => Checkpoints.Trace256 shares)) private _resolverShares;

Expand Down Expand Up @@ -215,7 +215,7 @@ contract VetoSlasher is BaseSlasher, AccessControlUpgradeable, IVetoSlasher {

uint48 timestamp = shares > resolverShares(msg.sender, resolver)
? Time.timestamp()
: IVault(vault).currentEpochStart() + resolverSetDelay;
: (IVault(vault).currentEpochStart() + resolverSetEpochsDelay * IVault(vault).epochDuration()).toUint48();

Checkpoints.Trace256 storage _resolverShares_ = _resolverShares[msg.sender][resolver];
(, uint48 latestTimestamp,) = _resolverShares_.latestCheckpoint();
Expand All @@ -228,15 +228,15 @@ contract VetoSlasher is BaseSlasher, AccessControlUpgradeable, IVetoSlasher {
emit SetResolver(msg.sender, resolver, shares);
}

function _initializeSlasher(bytes memory data) internal override returns (address) {
function _initializeInternal(address vault_, bytes memory data) internal override {
(InitParams memory params) = abi.decode(data, (InitParams));

if (params.executeDuration == 0) {
revert InvalidExecuteDuration();
}

uint48 epochDuration = IVault(params.vault).epochDuration();
if (params.vetoDuration + params.executeDuration > epochDuration) {
uint48 epochDuration = IVault(vault_).epochDuration();
if (epochDuration != 0 && params.vetoDuration + params.executeDuration > epochDuration) {
revert InvalidSlashDuration();
}

Expand All @@ -247,8 +247,6 @@ contract VetoSlasher is BaseSlasher, AccessControlUpgradeable, IVetoSlasher {
vetoDuration = params.vetoDuration;
executeDuration = params.executeDuration;

resolverSetDelay = (params.resolverSetEpochsDelay * epochDuration).toUint48();

return params.vault;
resolverSetEpochsDelay = params.resolverSetEpochsDelay;
}
}
Loading

0 comments on commit 5298117

Please sign in to comment.