@@ -7,6 +7,12 @@ pragma solidity ^0.8.20;
77import { Ownable } from "openzeppelin-contracts/access/Ownable.sol " ;
88import { IERC20 , SafeERC20 } from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol " ;
99
10+ // @audit-info consider making this contract a clone for gas efficiency
11+ // @audit-info 2-step ownership?
12+ // @audit-info missing interface with errors and events?
13+ // @audit-info "total vested Amount" is not stored. Any concern regarding this design choice and that
14+ // `token.balanceOf(address(this))` can be increased anytime (which modifies `_vestingSchedule` return value)? All OK by
15+ // me btw!
1016contract EnsoVestingWallet is Ownable {
1117 using SafeERC20 for IERC20 ;
1218
@@ -15,10 +21,13 @@ contract EnsoVestingWallet is Ownable {
1521
1622 uint256 public released;
1723 bool public revoked;
24+ // @audit-info `revoker == address(0)` means non-revocable forever.
1825 bool public immutable revocable;
1926
2027 IERC20 private immutable _token;
28+ // @audit-info revoker immutable? risks?
2129 address private immutable _revoker;
30+ // @audit-info consider using `uint48` (safe for timestamps), which will pack 3 timestamps in 12 bytes
2231 uint64 private immutable _start;
2332 uint64 private immutable _duration;
2433 uint64 private immutable _cliff;
@@ -45,6 +54,7 @@ contract EnsoVestingWallet is Ownable {
4554 _duration = durationSeconds;
4655 _cliff = startTimestamp + cliffSeconds;
4756 _token = token;
57+ // @audit-info simplify to `_revoker = revoker` if `address(0)` means non-revocable forever
4858 if (revoker != address (0 )) {
4959 _revoker = revoker;
5060 revocable = true ;
@@ -69,7 +79,6 @@ contract EnsoVestingWallet is Ownable {
6979 * @dev Getter for the end timestamp.
7080 */
7181 function end () public view returns (uint256 ) {
72- // @audit return _start + _duration?
7382 return start () + duration ();
7483 }
7584
@@ -98,7 +107,6 @@ contract EnsoVestingWallet is Ownable {
98107 * @dev Getter for the amount of releasable tokens.
99108 */
100109 function releasable () public view returns (uint256 ) {
101- // @audit return `_vestingSchedule(...)`?
102110 return vestedAmount (uint64 (block .timestamp )) - released;
103111 }
104112
@@ -116,7 +124,9 @@ contract EnsoVestingWallet is Ownable {
116124 */
117125 function release () public {
118126 if (revoked) revert Revoked ();
127+ // @audit-info call `_vestingSchedule(...)`?
119128 uint256 amount = releasable ();
129+ // @audit-info skip checking amount for gas efficiency (and allow 0 transfers)
120130 if (amount > 0 ) {
121131 released += amount;
122132 emit TokenReleased (amount);
@@ -145,6 +155,10 @@ contract EnsoVestingWallet is Ownable {
145155 * an asset given its total historical allocation. Returns 0 if the {cliff} timestamp is not met.
146156 */
147157 function _vestingSchedule (uint256 totalAllocation , uint64 timestamp ) internal view returns (uint256 ) {
158+ // @audit-info if revoked revert with Revoked?
159+ // @audit-info if `timestamp < _cliff` revert with BlockTimestampLtCliff(uint256 blockTimestamp, uint256 cliff)
160+ // or `CliffNotReached(uint256 blockTimestamp, uint256 cliff)`?
161+ // @audit-info no need for `if..else if..else`
148162 if (revoked || timestamp < cliff ()) {
149163 return 0 ;
150164 } else if (timestamp >= end ()) {
0 commit comments