docs: complete natspec comments

This commit is contained in:
r4bbit
2025-02-21 10:12:48 +01:00
parent a51d5199ae
commit 48db1bffb6
8 changed files with 204 additions and 32 deletions

View File

@@ -17,32 +17,30 @@ import { IStakeVault } from "./interfaces/IStakeVault.sol";
* to create stake vault instances. Hence, we need to use `Initializeable` to set the owner.
*/
contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/// @notice Emitted when not enough balance to withdraw
error StakeVault__NotEnoughAvailableBalance();
/// @notice Emitted when destination address is invalid
error StakeVault__InvalidDestinationAddress();
error StakeVault__UpdateNotAvailable();
/// @notice Emitted when staking was unsuccessful
error StakeVault__StakingFailed();
/// @notice Emitted when unstaking was unsuccessful
error StakeVault__UnstakingFailed();
/// @notice Emitted when not allowed to exit the system
error StakeVault__NotAllowedToExit();
/// @notice Emitted when not allowed to leave the system
error StakeVault__NotAllowedToLeave();
/// @notice Emitted when the configured stake manager is not trusted
error StakeVault__StakeManagerImplementationNotTrusted();
/// @notice Emitted when migration failed
error StakeVault__MigrationFailed();
//STAKING_TOKEN must be kept as an immutable, otherwise, StakeManager would accept StakeVaults with any token
//if is needed that STAKING_TOKEN to be a variable, StakeManager should be changed to check codehash and
//StakeVault(msg.sender).STAKING_TOKEN()
/// @notice Staking token - must be set immutable due to codehash check in StakeManager
IERC20 public immutable STAKING_TOKEN;
/// @notice Stake manager proxy contract
IStakeManagerProxy public stakeManager;
/// @notice Address of the trusted stake manager implementation
address public stakeManagerImplementationAddress;
/**
* @dev Emitted when tokens are staked.
* @param from The address from which tokens are transferred.
* @param to The address receiving the staked tokens (this contract).
* @param amount The amount of tokens staked.
* @param time The time period for which tokens are staked.
*/
event Staked(address indexed from, address indexed to, uint256 amount, uint256 time);
modifier validDestination(address _destination) {
if (_destination == address(0)) {
revert StakeVault__InvalidDestinationAddress();
@@ -58,7 +56,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
}
/**
* @notice Initializes the contract with the owner, staked token, and stake manager.
* @notice Initializes the contract with the staking token address.
* @dev The staking token address is immutable and cannot be changed after deployment.
* @dev Contract will be initialized via `initialize` function.
* @param token The address of the staking token.
*/
constructor(IERC20 token) {
STAKING_TOKEN = token;
@@ -66,6 +67,9 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
}
/**
* @notice Initializes the contract with the owner and the stake manager.
* @dev Ensures that the stake manager implementation is trusted.
* @dev Initializion is done on proxy clones.
* @param _owner The address of the owner.
* @param _stakeManager The address of the StakeManager contract.
*/
@@ -77,6 +81,7 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Allows the owner to trust a new stake manager implementation.
* @dev This function is only callable by the owner.
* @param stakeManagerAddress The address of the new stake manager implementation.
*/
function trustStakeManager(address stakeManagerAddress) external onlyOwner {
@@ -85,6 +90,7 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Registers the vault with the stake manager.
* @dev This is necessary to allow the stake manager to interact with the vault.
*/
function register() public {
stakeManager.registerVault();
@@ -92,6 +98,7 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Returns the address of the current owner.
* @return The address of the owner.
*/
function owner() public view override(OwnableUpgradeable, IStakeVault) returns (address) {
return super.owner();
@@ -99,6 +106,9 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Stake tokens for a specified time.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to stake.
* @param _seconds The time period to stake for.
*/
@@ -108,6 +118,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Stake tokens from a specified address for a specified time.
* @dev Overloads the `stake` function to allow staking from a specified address.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to stake.
* @param _seconds The time period to stake for.
* @param _from The address from which tokens will be transferred.
@@ -118,6 +132,8 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Lock the staked amount for a specified time.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @param _seconds The time period to lock the staked amount for.
*/
function lock(uint256 _seconds) external onlyOwner onlyTrustedStakeManager {
@@ -126,6 +142,9 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Unstake a specified amount of tokens and send to the owner.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to unstake.
*/
function unstake(uint256 _amount) external onlyOwner onlyTrustedStakeManager {
@@ -134,6 +153,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Unstake a specified amount of tokens and send to a destination address.
* @dev Overloads the `unstake` function to allow unstaking to a specified address.
* @dev This function is only callable by the owner.
* @dev Can only be called if the stake manager is trusted.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to unstake.
* @param _destination The address to receive the unstaked tokens.
*/
@@ -150,7 +173,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
}
/**
* @notice Withdraw all tokens from the contract to the owner.
* @notice Allows the vault to leave the system and withdraw all funds.
* @dev This function is only callable by the owner.
* @dev Vaults can only leave the system if the stake manager is not trusted.
* @param _destination The address to receive the funds.
*/
function leave(address _destination) external onlyOwner validDestination(_destination) {
if (_stakeManagerImplementationTrusted()) {
@@ -177,6 +203,8 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Withdraw tokens from the contract.
* @dev This function is only callable by the owner.
* @dev Only withdraws excess staking token amounts.
* @param _token The IERC20 token to withdraw.
* @param _amount The amount of tokens to withdraw.
*/
@@ -186,6 +214,9 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Withdraw tokens from the contract to a destination address.
* @dev Overloads the `withdraw` function to allow withdrawing to a specified address.
* @dev This function is only callable by the owner.
* @dev Only withdraws excess staking token amounts.
* @param _token The IERC20 token to withdraw.
* @param _amount The amount of tokens to withdraw.
* @param _destination The address to receive the tokens.
@@ -204,6 +235,7 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
/**
* @notice Returns the available amount of a token that can be withdrawn.
* @dev Returns only excess amount if token is staking token.
* @param _token The IERC20 token to check.
* @return The amount of token available for withdrawal.
*/
@@ -214,15 +246,27 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
return _token.balanceOf(address(this));
}
/**
* @notice Stakes tokens for a specified time.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to stake.
* @param _seconds The time period to stake for.
* @param _source The address from which tokens will be transferred.
*/
function _stake(uint256 _amount, uint256 _seconds, address _source) internal {
stakeManager.stake(_amount, _seconds);
bool success = STAKING_TOKEN.transferFrom(_source, address(this), _amount);
if (!success) {
revert StakeVault__StakingFailed();
}
emit Staked(_source, address(this), _amount, _seconds);
}
/**
* @notice Unstakes tokens to a specified address.
* @dev Reverts if the staking token transfer fails.
* @param _amount The amount of tokens to unstake.
* @param _destination The address to receive the unstaked tokens.
*/
function _unstake(uint256 _amount, address _destination) internal {
stakeManager.unstake(_amount);
bool success = STAKING_TOKEN.transfer(_destination, _amount);
@@ -231,6 +275,14 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
}
}
/**
* @notice Withdraws tokens to a specified address.
* @dev Reverts if the staking token transfer fails.
* @dev Only withdraws excess staking token amounts.
* @param _token The IERC20 token to withdraw.
* @param _amount The amount of tokens to withdraw.
* @param _destination The address to receive the tokens.
*/
function _withdraw(IERC20 _token, uint256 _amount, address _destination) internal {
if (_token == STAKING_TOKEN && STAKING_TOKEN.balanceOf(address(this)) - amountStaked() < _amount) {
revert StakeVault__NotEnoughAvailableBalance();
@@ -238,6 +290,10 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
_token.transfer(_destination, _amount);
}
/**
* @notice Returns the amount of tokens staked by the vault.
* @return The amount of tokens staked.
*/
function amountStaked() public view returns (uint256) {
return stakeManager.getStakedBalance(address(this));
}
@@ -262,16 +318,22 @@ contract StakeVault is IStakeVault, Initializable, OwnableUpgradeable {
}
}
/**
* @notice Checks if the current stake manager implementation is trusted.
* @dev Trusted implementation address is set during initialization.
* @dev Trusted implementation address can be changed by owner.
* @return True if the current stake manager implementation is trusted, otherwise false.
*/
function _stakeManagerImplementationTrusted() internal view virtual returns (bool) {
return stakeManagerImplementationAddress == stakeManager.implementation();
}
/**
* @notice Migrate all funds to a new vault.
* @param migrateTo The address of the new vault.
* @dev This function is only callable by the owner.
* @dev This function is only callable if the current stake manager is trusted.
* @dev Reverts when the stake manager reverts or the funds can't be transferred.
* @param migrateTo The address of the new vault.
*/
function migrateToVault(address migrateTo) external onlyOwner onlyTrustedStakeManager {
stakeManager.migrateToVault(migrateTo);

View File

@@ -3,9 +3,25 @@ pragma solidity ^0.8.26;
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
/**
* @title TransparentProxy
* @author 0x-r4bbit
* @notice ERC1967Proxy contract wrapper to expose implementation address.
* @dev Transparent Proxy contract
*/
contract TransparentProxy is ERC1967Proxy {
/**
* @notice Creates a new TransparentProxy contract.
* @param _implementation Address of the contract implementation.
* @param _data Data to be passed to the contract initialization.
*/
constructor(address _implementation, bytes memory _data) ERC1967Proxy(_implementation, _data) { }
/**
* @notice Returns the address of the contract implementation.
* @dev Default ERC1967Proxy doesn't expose this.
* @return Address of the contract implementation.
*/
function implementation() external view returns (address) {
return _implementation();
}

View File

@@ -3,14 +3,16 @@ pragma solidity ^0.8.26;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { ITrustedCodehashAccess } from "./interfaces/ITrustedCodehashAccess.sol";
/**
* @title TrustedCodehashAccess
* @author Ricardo Guilherme Schmidt <ricardo3@status.im>
* @notice Ensures that only specific contract bytecode hashes are trusted to
* interact with the functions using the `onlyTrustedCodehash` modifier.
* @dev This contract is used to restrict access to functions based on the codehash of the caller.
*/
abstract contract TrustedCodehashAccess is ITrustedCodehashAccess, OwnableUpgradeable {
/// @notice Whidelisted codehashes.
mapping(bytes32 codehash => bool permission) private trustedCodehashes;
/**
@@ -25,6 +27,11 @@ abstract contract TrustedCodehashAccess is ITrustedCodehashAccess, OwnableUpgrad
_;
}
/**
* @notice Initializes the contract with the provided owner address.
* @dev This function is called only once during the contract deployment.
* @param _initialOwner The address of the owner.
*/
function __TrustedCodehashAccess_init(address _initialOwner) public onlyInitializing {
__Ownable_init(_initialOwner);
}

View File

@@ -3,7 +3,6 @@
pragma solidity ^0.8.26;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
// import { TransparentClones } from "./TransparentClones.sol";
import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol";
import { StakeVault } from "./StakeVault.sol";
@@ -25,10 +24,14 @@ import { StakeVault } from "./StakeVault.sol";
* @dev The `StakeManager` contract address can be changed by the owner.
*/
contract VaultFactory is Ownable {
/// @notice Emitted when the provided `StakeManager` address is zero.
error VaultFactory__InvalidStakeManagerAddress();
/// @notice Emitted when a new vault is created.
event VaultCreated(address indexed vault, address indexed owner);
/// @notice Emitted when the `StakeManager` contract address is changed.
event StakeManagerAddressChanged(address indexed newStakeManagerAddress);
/// @notice Emitted when the `StakeVault` implementation contract address is changed.
event VaultImplementationChanged(address indexed newVaultImplementation);
/// @dev Address of the `StakeManager` contract instance.
@@ -36,7 +39,13 @@ contract VaultFactory is Ownable {
/// @dev Address of the `StakeVault` implementation contract.
address public vaultImplementation;
/// @param _stakeManager Address of the `StakeManager` contract instance.
/**
* @notice Creates a new `VaultFactory` contract.
* @dev Reverts if the provided `_stakeManager` address is zero.
* @param _owner Address of the owner of the contract.
* @param _stakeManager Address of the `StakeManager` contract instance.
* @param _vaultImplementation Address of the `StakeVault` implementation contract.
*/
constructor(address _owner, address _stakeManager, address _vaultImplementation) Ownable(_owner) {
if (_stakeManager == address(0)) {
revert VaultFactory__InvalidStakeManagerAddress();
@@ -45,28 +54,33 @@ contract VaultFactory is Ownable {
vaultImplementation = _vaultImplementation;
}
/// @notice Sets the `StakeManager` contract address.
/// @dev Only the owner can call this function.
/// @dev Emits a {StakeManagerAddressChanged} event.
/// @param _stakeManager Address of the `StakeManager` contract instance.
/**
* @notice Sets the `StakeManager` contract address.
* @dev Only the owner can call this function.
* @dev Emits a {StakeManagerAddressChanged} event.
* @param _stakeManager Address of the `StakeManager` contract instance.
*/
function setStakeManager(address _stakeManager) external onlyOwner {
stakeManager = _stakeManager;
emit StakeManagerAddressChanged(_stakeManager);
}
/// @notice Sets the `StakeVault` implementation contract address.
/// @dev Only the owner can call this function.
/// @dev Emits a {VaultImplementationChanged} event.
/// @param _vaultImplementation Address of the `StakeVault` implementation contract.
/// @dev This function is used to change the implementation of the `StakeVault` contract.
/**
* @notice Sets the `StakeVault` implementation contract address.
* @dev Only the owner can call this function.
* @dev Emits a {VaultImplementationChanged} event.
* @param _vaultImplementation Address of the `StakeVault` implementation contract.
*/
function setVaultImplementation(address _vaultImplementation) external onlyOwner {
vaultImplementation = _vaultImplementation;
emit VaultImplementationChanged(_vaultImplementation);
}
/// @notice Creates an instance of a `StakeVault` contract.
/// @dev Anyone can call this function.
/// @dev Emits a {VaultCreated} event.
/**
* @notice Creates an instance of a `StakeVault` contract.
* @dev Also takes care of registering the newly created `StakeVault` contract.
* @return clone Address of the newly created `StakeVault` contract.
*/
function createVault() external returns (StakeVault clone) {
clone = StakeVault(Clones.clone(vaultImplementation));
clone.initialize(msg.sender, stakeManager);

View File

@@ -1,8 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @title IRewardProvider
* @notice Interface for Reward Provider
* @dev This interface is necessary to unify reward provider contracts.
* @dev Karma token contract makes use of this to aggregate rewards.
*/
interface IRewardProvider {
/**
* @notice Returns the total supply of rewards.
* @return Total supply of rewards.
*/
function totalRewardsSupply() external view returns (uint256);
/**
* @notice Returns the balance of rewards for a vault
* @param account Address of the vault.
* @return Balance of rewards for the vault.
*/
function rewardsBalanceOf(address account) external view returns (uint256);
/**
* @notice Returns the balance of rewards for an account.
* @param user Address of the account.
* @return Balance of rewards for the account.
*/
function rewardsBalanceOfAccount(address user) external view returns (uint256);
}

View File

@@ -8,8 +8,23 @@ pragma solidity ^0.8.26;
* @dev This interface is necessary to linearize the inheritance of StakeMath and MultiplierPointMath
*/
interface IStakeConstants {
/**
* @return Minimum lockup period
*/
function MIN_LOCKUP_PERIOD() external view returns (uint256);
/**
* @return Maximum lockup period
*/
function MAX_LOCKUP_PERIOD() external view returns (uint256);
/**
* @return Multiplier points APY
*/
function MP_APY() external view returns (uint256);
/**
* @return Maximum multiplier
*/
function MAX_MULTIPLIER() external view returns (uint256);
}

View File

@@ -5,26 +5,52 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ITrustedCodehashAccess } from "./ITrustedCodehashAccess.sol";
import { IStakeConstants } from "./IStakeConstants.sol";
/**
* @title IStakeManager
* @notice StakeManager interface for staking and unstaking funds.
* @dev StakeManager is a contract that allows users to stake and unstake funds
* for a determined period of time. It also allows users to lock their
* funds for a determined period of time.
*/
interface IStakeManager is ITrustedCodehashAccess, IStakeConstants {
/// @notice Emitted when a vault isn't registered.
error StakingManager__VaultNotRegistered();
/// @notice Emitted when a vault is already registered.
error StakingManager__VaultAlreadyRegistered();
/// @notice Emitted when the vault is invalid
error StakingManager__InvalidVault();
/// @notice Emitted when the amount to stake is zero.
error StakingManager__AmountCannotBeZero();
/// @notice Emitted when the lock period is not zero.
error StakingManager__CannotRestakeWithLockedFunds();
/// @notice Emitted when the vault is already locked.
error StakingManager__AlreadyLocked();
/// @notice Emitted when emergency mode is enabled.
error StakingManager__EmergencyModeEnabled();
/// @notice Emitted trying to migrate to non empty vault
error StakingManager__MigrationTargetHasFunds();
/// @notice Emitted when the caller is not the owner of the vault.
error StakingManager__Unauthorized();
/// @notice Emitted when the duration is zero.
error StakingManager__DurationCannotBeZero();
/// @notice Emitted when there are insufficient funds to stake.
error StakingManager__InsufficientBalance();
/// @notice Emitted when a vault is registered.
event VaultRegistered(address indexed vault, address indexed owner);
/// @notice Emitted when a vault is migrated.
event VaultMigrated(address indexed from, address indexed to);
/// @notice Emitted when funds are staked.
event Staked(address indexed vault, uint256 amount, uint256 lockPeriod);
/// @notice Emitted when funds are locked.
event Locked(address indexed vault, uint256 lockPeriod, uint256 lockUntil);
/// @notice Emitted when funds are unstaked.
event Unstaked(address indexed vault, uint256 amount);
/// @notice Emitted when emergency mode is enabled.
event EmergencyModeEnabled();
/// @notice Emitted when an account leaves the system
event AccountLeft(address indexed vault);
/// @notice Emited when accounts compound their MP
event Compound(address indexed vault, uint256 amount);
function registerVault() external;

View File

@@ -1,6 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @title ITransparentProxy
* @notice Interface for the TransparentProxy contract.
* @dev ERC1967Proxy contract wrapper to expose implementation address.
*/
interface ITransparentProxy {
/**
* @notice Returns the address of the contract implementation.
* @dev Default ERC1967Proxy doesn't expose this.
* @return Address of the contract implementation.
*/
function implementation() external view returns (address);
}