Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/vesting work #357

Closed
wants to merge 13 commits into from
Closed

Feat/vesting work #357

wants to merge 13 commits into from

Conversation

philbow61
Copy link
Contributor

@philbow61 philbow61 commented Jan 26, 2024

Description

This PR adds the new VestingLock contract between a hedgey vesting plan and a beneficiary.
The contract will lock/relock all tokens released in Years 1&2 into the veMento contract, redeem all potential withdrawable tokens from a lock and transfer them with redeemable tokens from Year 3&4 to the beneficiary.

Other changes

  • Extended the ILocking interface
  • Added ITokenVestingPlans interface

Tested

  • unit tests for the VEstingLock contract
  • fork test to test/verify the actual interaction between the 3 contracts are designed and will be written in the next step

Open Questions:

  • Not sure whether we want this contract to emit any Events e.g redeemed(amountLocked, amountWithdrawn, lockID)
  • So far the lock calculation is not 100% perfect e.g if someone does the first redemption after year 3 this contract would lock up the whole 50% of tokens with a slope of 1 year. This is not super bad but we could add a step in the calculation that: when a redeem with a lock happens after the cliffPeriodEnd, it calculates the amount that would be redeemable from the lock by now and transfers that amount to the beneficiary and only locks the remainder.
    Let me know what you think @bowd @baroooo
    this could look something like this:
    if(amountToLock > 0 && lockingCliffEndWeek < currentWeek):
    uint256 denominator = lockingSlopeEnd - lockingCliffEnd
    uint256 numerator = lockingSlopeEnd - currentWeek
    amountToLock = (amountToLock * numerator) / denominator

Related issues

Backwards compatibility

Documentation

@philbow61 philbow61 requested review from baroooo and bowd January 26, 2024 10:32
Copy link

openzeppelin-code bot commented Jan 26, 2024

Feat/vesting work

Generated at commit: 677fc679ac0b1dd4e929d524cea66a0a9ae4814a

🚨 Report Summary

Severity Level Results
Contracts Critical
High
Medium
Low
Note
Total
2
1
0
16
40
59
Dependencies Critical
High
Medium
Low
Note
Total
0
0
0
0
0
0

For more details view the full report in OpenZeppelin Code Inspector

test/vesting/VestingLock.t.sol Outdated Show resolved Hide resolved
uint256 public totalAmountToLock;
uint256 public totalUnlockedTokens;

constructor(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think about deploying VestingLock contracts from a factory? So we can keep track of all contracts in a single place and don't need to pass _hedgeyVestingContract and _veMentoLockingContract everytime, we can call with mentoToken address from the factory. And deploying a new contract is simple as calling a function.

@@ -10,3 +19,63 @@ interface ILocking {
uint32 cliff
) external returns (uint256);
}

interface ILockingExtended {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is fine to just add these function in ILocking, instead of creating ILockingExtended

contracts/vesting/VestingLock.sol Show resolved Hide resolved
contracts/vesting/VestingLock.sol Outdated Show resolved Hide resolved

function setWithdraw(uint256 amount, address token) external {
withdrawAmount = amount;
withdrawToken = token;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this line to constructor. because of this, we call setWithdraw with 0 amount in every skipWeek()

import { ILockingExtended } from "../governance/locking/interfaces/ILocking.sol";
import { IERC20 } from "openzeppelin-contracts-next/contracts/token/ERC20/IERC20.sol";

contract VestingLock {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add natspec comments that explains the contract and also function params

mockTokenVestingPlans.setRedeemableTokens(withdrawable);
mockLocking.setWeek(numberOfWeeks);

mockLocking.setWithdraw(0, mentoTokenAddr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this. see my comment on the MockLocking.sol

uint256 public totalUnlockedTokens;

constructor(
address _beneficiary,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets change params to have trailing underscore for convention

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the underscore in front of internal functions I was trying to follow how it's done in other Mento contracts e.g BreakerBox and the breakers but I am more than happy to change it if we want trailing underscores

function initializeVestingPlan() public {
require(planId == 0, "VestingLock: plan id already set");
require(
ITokenVestingPlans(hedgeyVestingContract).balanceOf(address(this)) == 1,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as we discussed, this is vulnerable to griefing as initializeVestingPlan can be frontrunned by creating a vesting plan for this contract. I don't see any problems with this since it has no financial impact or gain for the attacker as long as we can revoke any plans we have on hedgey side.
a straightforward solution would be, we make this function to take planId as param and is onlyOwner but not sure if it worths it

@baroooo
Copy link
Contributor

baroooo commented Jan 30, 2024

Not sure whether we want this contract to emit any Events e.g redeemed(amountLocked, amountWithdrawn, lockID)

Yes, generally we should emit events for all non-view operations

@bayological
Copy link
Member

Closing this as we will no longer need this contract. If it turns out we do need this then we can re-open.
@philbow61 @bowd

@bayological bayological closed this Feb 5, 2024
@chapati23 chapati23 deleted the feat/vestingWork branch October 14, 2024 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants