Skip to content

Commit

Permalink
feat: add full natspec
Browse files Browse the repository at this point in the history
  • Loading branch information
QEDK committed May 3, 2024
1 parent 69a044e commit e646c86
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/DeqRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,24 @@ import {SafeERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/utils/
import {IDeqRouter} from "src/interfaces/IDeqRouter.sol";
import {IStakedAvail} from "src/interfaces/IStakedAvail.sol";

/// @title DeqRouter
/// @author Deq Protocol
/// @notice Router contract for swapping ERC20 tokens to staked Avail
/// @dev The contract is immutable
contract DeqRouter is IDeqRouter {
using SafeERC20 for IERC20;

/// @notice Address of the 0x proxy swap router contract
address public immutable swapRouter;
/// @notice Address of the Avail ERC20 token
IERC20 public immutable avail;
/// @notice Address of the staked Avail contract
IStakedAvail public immutable stAvail;

/// @notice Constructor for the DeqRouter contract
/// @param newSwapRouter Address of the 0x proxy swap router contract
/// @param newAvail Address of the Avail ERC20 token
/// @param newStAvail Address of the staked Avail contract
constructor(address newSwapRouter, IERC20 newAvail, IStakedAvail newStAvail) {
if (newSwapRouter == address(0) || address(newAvail) == address(0) || address(newStAvail) == address(0)) {
revert ZeroAddress();
Expand All @@ -24,6 +35,9 @@ contract DeqRouter is IDeqRouter {
stAvail = newStAvail;
}

/// @notice Swaps an ERC20 token to staked Avail
/// @param allowanceTarget Address of the allowance target from 0x API
/// @param data Data for the swap from 0x API
function swapERC20ToStAvail(address allowanceTarget, bytes calldata data) external {
(IERC20 tokenIn, IERC20 tokenOut, uint256 inAmount, uint256 minOutAmount,) =
abi.decode(data[4:], (IERC20, IERC20, uint256, uint256, Transformation[]));
Expand All @@ -40,6 +54,9 @@ contract DeqRouter is IDeqRouter {
stAvail.mintTo(msg.sender, outAmount);
}

/// @notice Swaps an ERC20 token to staked Avail with permit
/// @param allowanceTarget Address of the allowance target from 0x API
/// @param data Data for the swap from 0x API
function swapERC20ToStAvailWithPermit(
address allowanceTarget,
bytes calldata data,
Expand All @@ -65,6 +82,8 @@ contract DeqRouter is IDeqRouter {
stAvail.mintTo(msg.sender, outAmount);
}

/// @notice Swaps ETH to staked Avail
/// @param data Data for the swap from 0x API
function swapETHtoStAvail(bytes calldata data) external payable {
(address tokenIn, IERC20 tokenOut, uint256 inAmount, uint256 minOutAmount,) =
abi.decode(data[4:], (address, IERC20, uint256, uint256, Transformation[]));
Expand Down
47 changes: 47 additions & 0 deletions src/StakedAvail.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import {SignedMath} from "lib/openzeppelin-contracts/contracts/utils/math/Signed
import {IStakedAvail} from "src/interfaces/IStakedAvail.sol";
import {IAvailWithdrawalHelper} from "src/interfaces/IAvailWithdrawalHelper.sol";

/// @title StakedAvail
/// @author Deq Protocol
/// @notice Contract for staking Avail ERC20 tokens and minting an equivalent LST
contract StakedAvail is ERC20PermitUpgradeable, AccessControlDefaultAdminRulesUpgradeable, IStakedAvail {
using Math for uint256;
using SignedMath for int256;
Expand All @@ -32,11 +35,18 @@ contract StakedAvail is ERC20PermitUpgradeable, AccessControlDefaultAdminRulesUp
/// @notice Amount of assets staked (in wei)
uint256 public assets;

/// @notice Constructor for the StakedAvail contract
/// @param newAvail Address of the Avail ERC20 token
constructor(IERC20 newAvail) {
if (address(newAvail) == address(0)) revert ZeroAddress();
avail = newAvail;
}

/// @notice Initializes the StakedAvail contract with governance, updater, depository, and withdrawal helper
/// @param governance Address of the governance role
/// @param newUpdater Address of the updater role
/// @param newDepository Address of the depository contract
/// @param newWithdrawalHelper Minimum withdrawal amount required for an exit through protocol
function initialize(
address governance,
address newUpdater,
Expand All @@ -57,6 +67,9 @@ contract StakedAvail is ERC20PermitUpgradeable, AccessControlDefaultAdminRulesUp
_grantRole(UPDATER_ROLE, newUpdater);
}

/// @notice Allows updater role to update assets based on staking rewards
/// @dev Negative delta decreases assets, positive delta increases assets
/// @param delta Amount to update assets by
function updateAssets(int256 delta) external onlyRole(UPDATER_ROLE) {
if (delta == 0) revert InvalidUpdate();
uint256 _assets;
Expand All @@ -71,6 +84,10 @@ contract StakedAvail is ERC20PermitUpgradeable, AccessControlDefaultAdminRulesUp
emit AssetsUpdated(_assets);
}

/// @notice Allows withdrawal helper to update assets and supply based on withdrawals
/// @dev Decreases assets and supply based on amount and shares stored at time of exit
/// @param amount Amount of Avail withdrawn
/// @param shares Amount of staked Avail burned
function updateAssetsFromWithdrawals(uint256 amount, uint256 shares) external {
if (msg.sender != address(withdrawalHelper)) revert OnlyWithdrawalHelper();
uint256 _assets = assets - amount;
Expand All @@ -80,35 +97,55 @@ contract StakedAvail is ERC20PermitUpgradeable, AccessControlDefaultAdminRulesUp
emit AssetsUpdated(_assets);
}

/// @notice Allows governance to force update assets in case of incidents
/// @dev Reverts if newAssets is 0
/// @param newAssets New amount of assets
function forceUpdateAssets(uint256 newAssets) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (newAssets == 0) revert InvalidUpdate();
assets = newAssets;

emit AssetsUpdated(newAssets);
}

/// @notice Allows governance to update the depository address
/// @dev Reverts if newDepository is the zero address
/// @param newDepository Address of the new depository contract
function updateDepository(address newDepository) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (newDepository == address(0)) revert ZeroAddress();
depository = newDepository;

emit DepositoryUpdated(newDepository);
}

/// @notice Allows governance to update the withdrawal helper contract
/// @dev Reverts if newWithdrawalHelper is the zero address
/// @param newWithdrawalHelper Address of the new withdrawal helper contract
function updateWithdrawalHelper(IAvailWithdrawalHelper newWithdrawalHelper) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (address(newWithdrawalHelper) == address(0)) revert ZeroAddress();
withdrawalHelper = newWithdrawalHelper;

emit WithdrawalHelperUpdated(address(newWithdrawalHelper));
}

/// @notice Returns the amount of LST to mint based on the amount of Avail staked
/// @dev Rounds down to the nearest integer
function previewMint(uint256 amount) public view returns (uint256 shares) {
return amount.mulDiv(totalSupply() + 1, assets + 1, Math.Rounding.Floor);
}

/// @notice Returns the amount of Avail to withdraw based on the amount of LST burned
/// @dev Rounds down to the nearest integer
function previewBurn(uint256 shares) public view returns (uint256 amount) {
return shares.mulDiv(assets + 1, totalSupply() + 1, Math.Rounding.Floor);
}

/// @notice Mints LST based on the amount of Avail staked with permit
/// @dev Reverts if amount is 0
/// @param amount Amount of Avail to stake
/// @param deadline Deadline for the permit
/// @param v Signature v
/// @param r Signature r
/// @param s Signature s
function mintWithPermit(uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
if (amount == 0) revert ZeroAmount();
uint256 shares = previewMint(amount);
Expand All @@ -119,6 +156,9 @@ contract StakedAvail is ERC20PermitUpgradeable, AccessControlDefaultAdminRulesUp
avail.safeTransferFrom(msg.sender, depository, amount);
}

/// @notice Mints LST based on the amount of Avail staked
/// @dev Reverts if amount is 0
/// @param amount Amount of Avail to stake
function mint(uint256 amount) external {
if (amount == 0) revert ZeroAmount();
uint256 shares = previewMint(amount);
Expand All @@ -128,6 +168,10 @@ contract StakedAvail is ERC20PermitUpgradeable, AccessControlDefaultAdminRulesUp
avail.safeTransferFrom(msg.sender, depository, amount);
}

/// @notice Mints LST to a recipient address based on the amount of Avail staked
/// @dev Reverts if amount is 0
/// @param to Address of the recipient
/// @param amount Amount of Avail to stake
function mintTo(address to, uint256 amount) external {
if (amount == 0) revert ZeroAmount();
uint256 shares = previewMint(amount);
Expand All @@ -137,6 +181,9 @@ contract StakedAvail is ERC20PermitUpgradeable, AccessControlDefaultAdminRulesUp
avail.safeTransferFrom(msg.sender, depository, amount);
}

/// @notice Burns LST based on the amount of Avail withdrawn
/// @dev Reverts if shares is 0
/// @param shares Amount of LST to burn
function burn(uint256 shares) external {
if (shares == 0) revert ZeroAmount();
uint256 amount = previewBurn(shares);
Expand Down

0 comments on commit e646c86

Please sign in to comment.