Omniscia Steer Protocol Audit
TreasuryVester Manual Review Findings
TreasuryVester Manual Review Findings
TVR-01M: Improper Change of Recipient
Type | Severity | Location |
---|---|---|
Logical Fault | TreasuryVester.sol:L46-L56 |
Description:
The setRecipient
function is meant to change the recipient of the vesting process, however, this is done improperly so as the funds are not re-delegated to the new recipient.
Impact:
It is currently possible to "sell" a treasury vest to another user whilst retaining the delegated voting power if the buyer is an unsuspecting user.
Example:
46/// @dev Change the recipient address. Can only be called by current recipient.47/// @param _recipient is the new recipient address48function setRecipient(address _recipient) external {49 require(_recipient != address(0), "Zero address, Invalid!");50 require(51 // Make sure current recipient is sending this52 msg.sender == recipient,53 "R"54 );55 recipient = _recipient;56}57
58function claim() external {59 require(msg.sender == recipient, 'R');60 _claim();61}62
63/// @dev If the user leaves steer then steer can cut off the user's funds from that point on.64function cutOffFunds() external {65 require(msg.sender == owner);66 if (block.timestamp >= vestingCliff) {67 _claim();68 }69
70 IERC20(steerToken).safeTransfer(71 owner,72 IERC20(steerToken).balanceOf(address(this))73 );74}75
76/// @dev User can call this function to get the voting power of the tokens that are vested.77function getVotingPowerForVestedTokens() external {78 ISteerToken(steerToken).delegate(recipient);79}
Recommendation:
We advise the setRecipient
function to also invoke the getVotingPowerForVestedTokens
function to ensure that the tokens do not remain incorrectly delegated to the previous recipient
.
Alleviation (200f275c40cbd4798f4a416c044ea726755d4741):
The setRecipient
function now properly invokes getVotingPowerForVestedTokens
, ensuring that the voting power is transferred whenever a recipient changes.
TVR-02M: Inexistent Guarantee of Vested Funds
Type | Severity | Location |
---|---|---|
Logical Fault | TreasuryVester.sol:L26 |
Description:
The TreasuryVester
contract does not pull any funds from its creator thus providing no guarantee that the vest will be claimable.
Impact:
If the vesting contract hasn't been sufficiently funded, any funds that were not claimed until the vested amount exceeded the contract's owned amount will not be claimable.
Example:
22constructor(23 address steerToken_,24 address recipient_,25 address _owner, // Intended to be multisig. This address can cut off funding if user leaves Steer.26 uint256 vestingAmount_,27 uint256 vestingBegin_,28 uint256 vestingCliff_,29 uint256 vestingEnd_30) {31 require(vestingCliff_ >= vestingBegin_, "C");32 require(vestingEnd_ > vestingCliff_, "E");33
34 steerToken = steerToken_;35 recipient = recipient_;36 owner = _owner;37
38 vestingAmount = vestingAmount_;39 vestingBegin = vestingBegin_;40 vestingCliff = vestingCliff_;41 vestingEnd = vestingEnd_;42
43 lastUpdate = vestingBegin;44}
Recommendation:
We advise the constructor
of the contract to instead execute a safeTransferFrom
invocation from its creator ensuring that the contract has been initialized with the vestingAmount_
properly.
Alleviation (200f275c40cbd4798f4a416c044ea726755d4741):
The Steer Protocol team stated that they will make sure to fund the contract accordingly. As a result, we consider this exhibit acknowledged.