Skip to content
Merged
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Compiler files
cache/
out/**/
!out/VaultImplementation.sol/
!out/VaultTokenizedImplementation.sol/
!out/VaultVotesImplementation.sol/
!out/v1.1/
!out/v1.1/Vault.sol/
!out/v1.1/VaultTokenized.sol/
!out/VaultVotes.sol/
!out/Vault.sol/
!out/VaultTokenized.sol/
!out/NetworkRestakeDelegator.sol/
Expand Down
2 changes: 1 addition & 1 deletion out/DelegatorHints.sol/BaseDelegatorHints.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/DelegatorHints.sol/FullRestakeDelegatorHints.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/DelegatorHints.sol/NetworkRestakeDelegatorHints.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/DelegatorHints.sol/OperatorSpecificDelegatorHints.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/SlasherHints.sol/BaseSlasherHints.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/SlasherHints.sol/SlasherHints.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/SlasherHints.sol/VetoSlasherHints.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/Vault.sol/Vault.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/VaultConfigurator.sol/VaultConfigurator.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/VaultHints.sol/VaultHints.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions out/VaultImplementation.sol/VaultImplementation.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion out/VaultTokenized.sol/VaultTokenized.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions out/VaultVotes.sol/VaultVotes.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions out/v1.1/Vault.sol/Vault.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions out/v1.1/VaultTokenized.sol/VaultTokenized.json

Large diffs are not rendered by default.

22 changes: 13 additions & 9 deletions src/contracts/vault/v1.1/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ contract Vault is VaultStorage, MigratableEntity, AccessControlUpgradeable, Prox
using SafeERC20 for IERC20;
using Address for address;

/**
* @notice The minimum period of time that must be available to exit in case of epoch increase after migration.
*/
uint256 public constant MIN_EXIT_WINDOW = 7 days;

address private immutable IMPLEMENTATION;

constructor(
address delegatorFactory,
address slasherFactory,
address vaultFactory,
address implementation
) VaultStorage(delegatorFactory, slasherFactory) MigratableEntity(vaultFactory) {
constructor(address vaultFactory, address implementation) MigratableEntity(vaultFactory) {
IMPLEMENTATION = implementation;
}

Expand All @@ -52,7 +52,7 @@ contract Vault is VaultStorage, MigratableEntity, AccessControlUpgradeable, Prox
revert IVault.InvalidFlashParams();
}

epochDurationSetEpochsDelay = params.epochDurationSetEpochsDelay;
_epochDurationSetEpochsDelay = params.epochDurationSetEpochsDelay;

flashFeeRate = params.flashFeeRate;
flashFeeReceiver = params.flashFeeReceiver;
Expand Down Expand Up @@ -146,8 +146,8 @@ contract Vault is VaultStorage, MigratableEntity, AccessControlUpgradeable, Prox

burner = params.burner;

epochDurationInit = Time.timestamp();
epochDuration = params.epochDuration;
_epochDurationInit = Time.timestamp();
_epochDuration = params.epochDuration;

depositWhitelist = params.depositWhitelist;

Expand Down Expand Up @@ -175,5 +175,9 @@ contract Vault is VaultStorage, MigratableEntity, AccessControlUpgradeable, Prox
(IVault.MigrateParams memory params) = abi.decode(data, (IVault.MigrateParams));

_processMigrateParams(params);

if ((params.epochDurationSetEpochsDelay - 2) * _epochDuration < MIN_EXIT_WINDOW) {
revert IVault.InsufficientExitWindow();
}
}
}
159 changes: 98 additions & 61 deletions src/contracts/vault/v1.1/VaultImplementation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,100 @@ contract VaultImplementation is VaultStorage, AccessControlUpgradeable, Reentran
using SafeCast for uint256;
using SafeERC20 for IERC20;

constructor(address delegatorFactory, address slasherFactory) VaultStorage(delegatorFactory, slasherFactory) {}
/**
* @inheritdoc IVault
*/
address public immutable DELEGATOR_FACTORY;

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

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

/**
* @inheritdoc IVault
*/
function epochDurationSetEpochsDelay() external view returns (uint256) {
if (_nextEpochDurationInit == 0 || Time.timestamp() < _nextEpochDurationInit) {
return _epochDurationSetEpochsDelay;
}
return _nextEpochDurationSetEpochsDelay;
}

/**
* @inheritdoc IVault
*/
function epochDuration() public view returns (uint48) {
if (_nextEpochDurationInit == 0 || Time.timestamp() < _nextEpochDurationInit) {
return _epochDuration;
}
return _nextEpochDuration;
}

/**
* @inheritdoc IVault
*/
function epochDurationInit() public view returns (uint48) {
if (_nextEpochDurationInit == 0 || Time.timestamp() < _nextEpochDurationInit) {
return _epochDurationInit;
}
return _nextEpochDurationInit;
}

/**
* @inheritdoc IVault
*/
function epochAt(
uint48 timestamp
) public view returns (uint256) {
if (timestamp < epochDurationInit) {
if (previousEpochDurationInit == 0 || timestamp < previousEpochDurationInit) {
if (timestamp < _epochDurationInit) {
if (_prevEpochDurationInit == 0 || timestamp < _prevEpochDurationInit) {
revert InvalidTimestamp();
}
return epochInit - (epochDurationInit - timestamp).ceilDiv(previousEpochDuration);
return _prevEpochDurationInitIndex + (timestamp - _prevEpochDurationInit) / _prevEpochDuration;
} else if (_nextEpochDurationInit == 0 || timestamp < _nextEpochDurationInit) {
return _epochDurationInitIndex + (timestamp - _epochDurationInit) / _epochDuration;
} else {
return _nextEpochInitIndex + (timestamp - _nextEpochDurationInit) / _nextEpochDuration;
}
}

/**
* @inheritdoc IVault
*/
function epochStart(
uint256 epoch
) public view returns (uint48) {
if (epoch < _prevEpochDurationInitIndex) {
revert InvalidEpoch();
}

if (epoch < _epochDurationInitIndex) {
return (_prevEpochDurationInit + (epoch - _prevEpochDurationInitIndex) * _prevEpochDuration).toUint48();
} else if (_nextEpochInitIndex == 0 || epoch < _nextEpochInitIndex) {
return (_epochDurationInit + (epoch - _epochDurationInitIndex) * _epochDuration).toUint48();
} else {
return (_nextEpochDurationInit + (epoch - _nextEpochInitIndex) * _nextEpochDuration).toUint48();
}
return epochInit + (timestamp - epochDurationInit) / epochDuration;
}

/**
* @inheritdoc IVault
*/
function currentEpoch() public view returns (uint256) {
return epochInit + (Time.timestamp() - epochDurationInit) / epochDuration;
return epochAt(Time.timestamp());
}

/**
* @inheritdoc IVault
*/
function currentEpochStart() public view returns (uint48) {
return (epochDurationInit + (currentEpoch() - epochInit) * epochDuration).toUint48();
return epochStart(currentEpoch());
}

/**
Expand All @@ -66,17 +131,14 @@ contract VaultImplementation is VaultStorage, AccessControlUpgradeable, Reentran
if (epoch == 0) {
revert NoPreviousEpoch();
}
if (epoch == epochInit) {
return epochDurationInit - previousEpochDuration;
}
return (epochDurationInit + (epoch - epochInit - 1) * epochDuration).toUint48();
return epochStart(epoch - 1);
}

/**
* @inheritdoc IVault
*/
function nextEpochStart() public view returns (uint48) {
return currentEpochStart() + epochDuration;
return epochStart(currentEpoch() + 1);
}

/**
Expand Down Expand Up @@ -197,7 +259,7 @@ contract VaultImplementation is VaultStorage, AccessControlUpgradeable, Reentran
if (token != collateral) {
revert UnsupportedToken();
}
return value.mulDiv(flashFeeRate, FLASH_FEE_BASE);
return flashFeeReceiver == address(0) ? 0 : value.mulDiv(flashFeeRate, FLASH_FEE_BASE);
}

/**
Expand All @@ -215,8 +277,6 @@ contract VaultImplementation is VaultStorage, AccessControlUpgradeable, Reentran
revert NotWhitelistedDepositor();
}

_tryAcceptEpochDuration();

uint256 balanceBefore = IERC20(collateral).balanceOf(address(this));
IERC20(collateral).safeTransferFrom(msg.sender, address(this), amount);
depositedAmount = IERC20(collateral).balanceOf(address(this)) - balanceBefore;
Expand Down Expand Up @@ -352,7 +412,7 @@ contract VaultImplementation is VaultStorage, AccessControlUpgradeable, Reentran
revert InvalidReturnAmount();
}

if (flashFeeReceiver != address(0)) {
if (fee > 0) {
IERC20(collateral_).safeTransfer(flashFeeReceiver, fee);
}

Expand Down Expand Up @@ -481,37 +541,37 @@ contract VaultImplementation is VaultStorage, AccessControlUpgradeable, Reentran
* @inheritdoc IVault
*/
function setEpochDuration(
uint48 epochDuration_
uint48 epochDuration_,
uint256 epochDurationSetEpochsDelay_
) external nonReentrant onlyRole(EPOCH_DURATION_SET_ROLE) {
_tryAcceptEpochDuration();
if (epochDurationSetEpochsDelay_ < 3) {
revert InvalidEpochDurationSetEpochsDelay();
}

if (epochDuration > epochDuration_) {
revert InvalidNewEpochDuration();
if (_nextEpochDurationInit != 0 && _nextEpochDurationInit <= Time.timestamp()) {
_prevEpochDurationInitIndex = _epochDurationInitIndex;
_prevEpochDuration = _epochDuration;
_prevEpochDurationInit = _epochDurationInit;
_epochDurationInitIndex = _nextEpochInitIndex;
_epochDuration = _nextEpochDuration;
_epochDurationInit = _nextEpochDurationInit;
_epochDurationSetEpochsDelay = _nextEpochDurationSetEpochsDelay;
}

if (nextEpochDurationInit != 0) {
nextEpochDuration = 0;
nextEpochDurationInit = 0;
} else if (epochDuration == epochDuration_) {
revert AlreadySet();
if (_epochDuration > epochDuration_) {
revert InvalidNewEpochDuration();
}

if (epochDuration != epochDuration_) {
nextEpochDuration = epochDuration_;
nextEpochDurationInit = (currentEpochStart() + epochDurationSetEpochsDelay * epochDuration).toUint48();
if (_epochDuration == epochDuration_ && _epochDurationSetEpochsDelay == epochDurationSetEpochsDelay_) {
revert AlreadySet();
}

emit SetEpochDuration(epochDuration_);
}
_nextEpochInitIndex = currentEpoch() + _epochDurationSetEpochsDelay;
_nextEpochDuration = epochDuration_;
_nextEpochDurationInit = (currentEpochStart() + _epochDurationSetEpochsDelay * _epochDuration).toUint48();
_nextEpochDurationSetEpochsDelay = epochDurationSetEpochsDelay_;

/**
* @inheritdoc IVault
*/
function acceptEpochDuration() external nonReentrant {
if (nextEpochDurationInit == 0 || nextEpochDurationInit > Time.timestamp()) {
revert NewEpochDurationNotReady();
}
_acceptEpochDuration();
emit SetEpochDuration(epochDuration_, epochDurationSetEpochsDelay_);
}

/**
Expand Down Expand Up @@ -599,8 +659,6 @@ contract VaultImplementation is VaultStorage, AccessControlUpgradeable, Reentran
uint256 withdrawnAssets,
uint256 burnedShares
) internal returns (uint256 mintedShares) {
_tryAcceptEpochDuration();

_activeSharesOf[msg.sender].push(Time.timestamp(), activeSharesOf(msg.sender) - burnedShares);
_activeShares.push(Time.timestamp(), activeShares() - burnedShares);
_activeStake.push(Time.timestamp(), activeStake() - withdrawnAssets);
Expand Down Expand Up @@ -638,26 +696,5 @@ contract VaultImplementation is VaultStorage, AccessControlUpgradeable, Reentran
isWithdrawalsClaimed[epoch][msg.sender] = true;
}

function _tryAcceptEpochDuration() internal {
if (nextEpochDurationInit != 0 && nextEpochDurationInit <= Time.timestamp()) {
_acceptEpochDuration();
}
}

function _acceptEpochDuration() internal {
uint256 currentEpoch_ = currentEpoch();
uint48 currentEpochStart_ = currentEpochStart();

previousEpochDuration = epochDuration;
previousEpochDurationInit = epochDurationInit;
epochInit = currentEpoch_;
epochDuration = nextEpochDuration;
epochDurationInit = currentEpochStart_;
nextEpochDuration = 0;
nextEpochDurationInit = 0;

emit AcceptEpochDuration();
}

function _Vault_init() external {}
}
Loading
Loading