@@ -4,8 +4,8 @@ pragma solidity ^0.8.20;
44// Based on OpenZeppelin's VestingWallet & VestingWalletCliff contracts:
55// https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/finance
66
7- import { SafeERC20, IERC20 } from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol " ;
87import { Ownable } from "openzeppelin-contracts/access/Ownable.sol " ;
8+ import { IERC20 , SafeERC20 } from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol " ;
99
1010contract EnsoVestingWallet is Ownable {
1111 using SafeERC20 for IERC20 ;
@@ -16,7 +16,7 @@ contract EnsoVestingWallet is Ownable {
1616 uint256 public released;
1717 bool public revoked;
1818 bool public immutable revocable;
19-
19+
2020 IERC20 private immutable _token;
2121 address private immutable _revoker;
2222 uint64 private immutable _start;
@@ -28,7 +28,16 @@ contract EnsoVestingWallet is Ownable {
2828 error NotRevocable ();
2929 error NotRevoker (address sender , address revoker );
3030
31- constructor (IERC20 token , address revoker , address beneficiary , uint64 startTimestamp , uint64 durationSeconds , uint64 cliffSeconds ) Ownable (beneficiary) {
31+ constructor (
32+ IERC20 token ,
33+ address revoker ,
34+ address beneficiary ,
35+ uint64 startTimestamp ,
36+ uint64 durationSeconds ,
37+ uint64 cliffSeconds
38+ )
39+ Ownable (beneficiary)
40+ {
3241 if (cliffSeconds > durationSeconds) {
3342 revert InvalidCliffDuration (cliffSeconds, durationSeconds);
3443 }
@@ -60,10 +69,11 @@ contract EnsoVestingWallet is Ownable {
6069 * @dev Getter for the end timestamp.
6170 */
6271 function end () public view returns (uint256 ) {
72+ // @audit return _start + _duration?
6373 return start () + duration ();
6474 }
6575
66- /**
76+ /**
6777 * @dev Getter for the cliff timestamp.
6878 */
6979 function cliff () public view virtual returns (uint256 ) {
@@ -87,7 +97,8 @@ contract EnsoVestingWallet is Ownable {
8797 /**
8898 * @dev Getter for the amount of releasable tokens.
8999 */
90- function releasable () public view returns (uint256 ) {
100+ function releasable () public view returns (uint256 ) {
101+ // @audit return `_vestingSchedule(...)`?
91102 return vestedAmount (uint64 (block .timestamp )) - released;
92103 }
93104
@@ -122,6 +133,7 @@ contract EnsoVestingWallet is Ownable {
122133 if (! revocable) revert NotRevocable ();
123134 if (msg .sender != _revoker) revert NotRevoker (msg .sender , _revoker);
124135 release (); // first, release funds beneficiary is entitled to up to this point
136+ // @audit CEI pattern violated, create a private `_relase()` that skips checking `revoked`
125137 revoked = true ;
126138 uint256 amount = _token.balanceOf (address (this ));
127139 _token.safeTransfer (receiver, amount);
@@ -132,10 +144,7 @@ contract EnsoVestingWallet is Ownable {
132144 * @dev Implementation of the vesting formula. This returns the amount vested, as a function of time, for
133145 * an asset given its total historical allocation. Returns 0 if the {cliff} timestamp is not met.
134146 */
135- function _vestingSchedule (
136- uint256 totalAllocation ,
137- uint64 timestamp
138- ) internal view returns (uint256 ) {
147+ function _vestingSchedule (uint256 totalAllocation , uint64 timestamp ) internal view returns (uint256 ) {
139148 if (revoked || timestamp < cliff ()) {
140149 return 0 ;
141150 } else if (timestamp >= end ()) {
@@ -144,4 +153,4 @@ contract EnsoVestingWallet is Ownable {
144153 return (totalAllocation * (timestamp - start ())) / duration ();
145154 }
146155 }
147- }
156+ }
0 commit comments