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: add StakeVault and implements StakeManager interface into RewardsStreamerMP #39

Closed
wants to merge 1 commit into from

Conversation

3esmit
Copy link
Contributor

@3esmit 3esmit commented Oct 8, 2024

Description

This commit adds the following changes:

  • Add the contract StakeVault so funds can be stored safely by the user. Move StakeVault into staking-reward-streamer repository #14
  • Added the interface ITrustedCodehashAccess and contract TrustedCodehashAccess in the src/access directory, which implements the ITrustedCodehashAccess interface and provides functionality to set or update the trust status for a contract's codehash and implemented it on RewardStreamerMP. Add stake vault whitelist capabilities #15
  • added the interface IStakeManager and implemented it on RewardStreamerMP Merging existing solutions #13 These changes are necessary to enforce security measures and restrict access based on the codehash of the caller, and allow for better reuse of code between StakeManager and RewardStreamerMP.

Checklist

Ensure you completed all of the steps below before submitting your pull request:

  • Added natspec comments?
  • Ran pnpm adorno?
  • Ran pnpm verify?

…dsStreamerMP

This commit adds the following changes:
- Add the contract `StakeVault` so funds can be stored safely by the user. #14
- Added the interface `ITrustedCodehashAccess`  and contract `TrustedCodehashAccess` in the `src/access` directory, which implements the `ITrustedCodehashAccess` interface and provides functionality to set or update the trust status for a contract's codehash and implemented it on `RewardStreamerMP`. #15
- added the interface `IStakeManager` and implemented it on `RewardStreamerMP`  #13
These changes are necessary to enforce security measures and restrict access based on the codehash of the caller, and allow for better reuse of code between StakeManager and RewardStreamerMP.
function unstake(uint256 _amount) external;
function lock(uint256 _secondsIncrease) external;
function leave() external returns (bool _leaveAccepted);
function acceptUpdate() external returns (address _migrated);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's leave upgradeability out and tackle it once we have #13 done.
We'll do #20 after that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would like to leave it here in PR, we don't have to implement it yet, but just define the interface.

It has a return (address _migrated) which in case of upgradabilty through proxy, it would return the address of itself. In case the upgradabiltiy is to a new address, it would return the new address - so this manage the upgradability for migration style and proxy style.

function totalSupply() external view returns (uint256 _totalSupply);
function totalSupplyMinted() external view returns (uint256 _totalSupply);
function pendingReward() external view returns (uint256);
function getStakedBalance(address _vault) external view returns (uint256 _balance);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think here we can drop some as well.

pendingReward() is not necessary as the won't be any rewards.
totalSupplyMinted() currently says totalStaked + totalMP + potentialMP. I don't think we want that. potentialMP is the maximum MP that can exist in the system based on the stake amount (it's basicallly maxMP from the other system).

So we only need:

  • potentialMP (and userPotentialMP I guess)
  • totalMP (all minted MPs)
  • totalStaked (all staked balance)
  • totalSupply (totalStaked + totalMP)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

pendingReward() is not necessary as the won't be any rewards.

I would leave it here, because the contract being updated STILL have rewarding. Once the rewarding is fully removed, we can remove it there afterwards.

potentialMP (and userPotentialMP I guess)

This shouldn't be part of the interface because is not common to StakeManager.sol

totalSupply (totalStaked + totalMP)

I'll update the logic to remove potentialMPs from here. And seems like totalSupplyMinted() should be dropped from the interface because its something related just to StakeManager? Or maybe we can change it so:

totalSupply() => totalStaked + totalMP + calcMP(totalStaked, block.timestamp - lastMPUpdatedTime)

Copy link
Collaborator

Choose a reason for hiding this comment

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

At the end it depends on what we want totalSupply() to represent.
Is it the actual supply that is in existence (totalMP + totalStaked) or is it whatever is in existence + whatever there is left to mint as per potentialMP

@gravityblast what are your thougths on this

Copy link
Contributor Author

@3esmit 3esmit Oct 9, 2024

Choose a reason for hiding this comment

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

totalSupply() => totalStaked + totalMP + calcMP(totalStaked, block.timestamp - lastMPUpdatedTime) is actually wrong, as its not considering potentialMP, but it should be something like that.

The scenario is:

For an external system, which wants to read the "current balance" of a user, and compare for how much of "total supply" exists, it would want that both values, for user balance, and for total supply, to represent how much it would have if the contract is updated to last mint.

If we dont have this, than, an external UI would not be able to read the values as if the contact would be updated. It would always have the values from last mint.

Copy link
Member

Choose a reason for hiding this comment

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

At the end it depends on what we want totalSupply() to represent.

@0x-r4bbit given that we are not sure, and it's not a token, I think we don't need a method called totalSupply

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yea very good point. The totalSupply in original StakeManager I think is a relict from the past where we weren't yet sure if the token will be represented by the contract as well.

Now that we're working on xp-token contract, we'll have a dedicated totalSupply there.

function MIN_LOCKUP_PERIOD() external view returns (uint256);
function MAX_LOCKUP_PERIOD() external view returns (uint256);
function MP_APY() external view returns (uint256);
function MAX_BOOST() external view returns (uint256);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Currently MAX_BOOST is known as MAX_MULTIPLIER in this code (which I think we can also keep as it is a better fitting name)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I'll use it as MAX_MULTIPLIER

function acceptUpdate() external onlyTrustedCodehash returns (address _migrated) {
//TODO: handle update/migration
revert("Not implemented");
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

As mentioned above, let's tackle that in #20

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, we can leave it as Not Implemented here for now and later we implement the logic #20

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sounds good to me, but are we sure we'll end up with an acceptUpdate function?
If yes, then it's fine

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we want to keep compatibility for StakeVault with both systems, yes, but for this contact, acceptUpdate might be just a return address(this), if users don't need to accept updates. But that discussion is far more complex, as a Proxy Update means a breach of contract, and morally it should need to accept the change - however I don't see other developers caring about the morals of contract breaching.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If we want to keep compatibility for StakeVault with both systems, yes,

This is not a priority atm.

revert StakingManager__AmountCannotBeZero();
function stake(uint256 _amount, uint256 _seconds) external onlyTrustedCodehash nonReentrant {
if (_amount == 0) {
revert StakeManager__StakeIsTooLow();
Copy link
Member

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 the previous __AmountCannotBeZero? I happy with both in the end, but more too low sounds like there's a minimum while cannot be zero feels more like any positive amount

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I am chaning to StakeIsTooLow because it would return the idea that cannot be zero and I want to keep the same error messages as possible from StakeManager.sol so we can reuse tests in both systems.

Actually, we need to verify your minimum is actually 1 token.

Copy link
Member

Choose a reason for hiding this comment

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

1 wei or 1e18?
if it's 1e18, then it makes sense to use too low, but if the minimum is 1 it means it cannot be zero, and I would avoid not rename it just not to rename tests

}
}

function getStakedBalance(address userAddress) external view returns (uint256) {
return users[userAddress].stakedBalance;
function calculateMP(uint256 _balance, uint256 _deltaTime) public pure returns (uint256) {
Copy link
Member

Choose a reason for hiding this comment

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

given that it's used only in one point, doesn't it makes sense to have it internal or hardcoded like before?
I don't see a reason to have a function like that called externally, unless you call it for a specific user

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's important for UI and tests. we can have an internal that is called by this public function (and make it external) for gas sake.

function getUserInfo(address userAddress) external view returns (UserInfo memory) {
return users[userAddress];
function pendingReward() external view returns (uint256 _pendingReward) {
return STAKE_TOKEN().balanceOf(address(this)) - accountedRewards;
Copy link
Member

Choose a reason for hiding this comment

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

I think the pending rewards are actually potentialMP. Otherwise if we only use balanceOf we lose the initial MPs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll revist that.

@0x-r4bbit
Copy link
Collaborator

@3esmit how do you feel about breaking this down a bit.
It'd be cool if we had a commit that introduces the StakeVault, at least in so far that it talks to the RewardStreamer.
The StakeVault only needs to provide the functionality listed in #14

Then another PR could introduce the whitelisting (or at least a separate commit.

I feel like the StakeVault could've already been in a mergable state by now.

What do you think?

@3esmit
Copy link
Contributor Author

3esmit commented Oct 12, 2024

StakeVault and TrustedCodehashAccess are part of the same functionality. Without the trusted code hash access the stake vault would not work properly.

@0x-r4bbit
Copy link
Collaborator

StakeVault and TrustedCodehashAccess are part of the same functionality. Without the trusted code hash access the stake vault would not work properly.

As I understand, the TrustedCodehashAccess just enables the StakeManager to control who can call certain methods.

If, as a first step, we're simply adding StakeVault and leave TrustedCodeHashAccess out of the equation, it can just talk to the RewardStreamer contract like any other account.
But okay, I see that this might be unnecessary.

Then at least make it so that this PR:

  1. Adds StakeVault (again only the functionality that overlaps with RewardStreamer)
  2. Adds TrustedCodeHashAccess
  3. Make sure RewardStreamer make use of it
  4. Adjust tests, as now only StakeVault can talk to it

Add sub issues in #13 for things left to port over.
All refactor related things we put in a separate PR.

0x-r4bbit added a commit that referenced this pull request Oct 17, 2024
This introduces a first version of `IStakeManager`, highly inspired by
the changes done in
#39.

However, in this commit, it only adds the methods that are currently
supported by both, `StakeManager` and `RewardStreamerMP`.

Future commits will add APIs for locking and leaving.
0x-r4bbit added a commit that referenced this pull request Oct 17, 2024
This introduces a first version of `IStakeManager`, highly inspired by
the changes done in
#39.

However, in this commit, it only adds the methods that are currently
supported by both, `StakeManager` and `RewardStreamerMP`.

Future commits will add APIs for locking and leaving.
0x-r4bbit added a commit that referenced this pull request Oct 17, 2024
This introduces a first version of `IStakeManager`, highly inspired by
the changes done in
#39.

However, in this commit, it only adds the methods that are currently
supported by both, `StakeManager` and `RewardStreamerMP`.

Future commits will add APIs for locking and leaving.
0x-r4bbit added a commit that referenced this pull request Oct 17, 2024
This enables whitelisting in the staking manager contract using the
`TrustedCodehashAccess` interface.

These changes were largely taken from #39 with few changes:

- Due to different OZ versions, `Ownable()` constructor needs to be
  called with owner

Closes #15
0x-r4bbit added a commit that referenced this pull request Oct 17, 2024
This introduces a first version of `IStakeManager`, highly inspired by
the changes done in
#39.

However, in this commit, it only adds the methods that are currently
supported by both, `StakeManager` and `RewardStreamerMP`.

Future commits will add APIs for locking and leaving.
0x-r4bbit added a commit that referenced this pull request Oct 17, 2024
This enables whitelisting in the staking manager contract using the
`TrustedCodehashAccess` interface.

These changes were largely taken from #39 with few changes:

- Due to different OZ versions, `Ownable()` constructor needs to be
  called with owner

Closes #15
@0x-r4bbit
Copy link
Collaborator

Hey @3esmit

I since I'd like to get your changes in, I started splitting up the changes into dedicated PRs that address the issues.
You can check them here:

  1. feat: introduce StakeVault and IStakeManager #61
  2. feat: add TrustedCodehashAccess contract and interface #63

Prior to these two, I've also done #62

All PRs should be passing CI.

I left out the functionality that's not yet working in reward streamer (upgradeability, exiting and locking after staking).
We can address those next week then.

@0x-r4bbit 0x-r4bbit changed the base branch from main to refactor/user-account October 17, 2024 19:10
@0x-r4bbit 0x-r4bbit changed the base branch from refactor/user-account to main October 17, 2024 19:10
0x-r4bbit added a commit that referenced this pull request Oct 21, 2024
This introduces a first version of `IStakeManager`, highly inspired by
the changes done in
#39.

However, in this commit, it only adds the methods that are currently
supported by both, `StakeManager` and `RewardStreamerMP`.

Future commits will add APIs for locking and leaving.
0x-r4bbit added a commit that referenced this pull request Oct 21, 2024
This enables whitelisting in the staking manager contract using the
`TrustedCodehashAccess` interface.

These changes were largely taken from #39 with few changes:

- Due to different OZ versions, `Ownable()` constructor needs to be
  called with owner

Closes #15
0x-r4bbit added a commit that referenced this pull request Oct 22, 2024
This introduces a first version of `IStakeManager`, highly inspired by
the changes done in
#39.

However, in this commit, it only adds the methods that are currently
supported by both, `StakeManager` and `RewardStreamerMP`.

Future commits will add APIs for locking and leaving.
0x-r4bbit added a commit that referenced this pull request Oct 22, 2024
This enables whitelisting in the staking manager contract using the
`TrustedCodehashAccess` interface.

These changes were largely taken from #39 with few changes:

- Due to different OZ versions, `Ownable()` constructor needs to be
  called with owner

Closes #15
0x-r4bbit added a commit that referenced this pull request Oct 22, 2024
This enables whitelisting in the staking manager contract using the
`TrustedCodehashAccess` interface.

These changes were largely taken from #39 with few changes:

- Due to different OZ versions, `Ownable()` constructor needs to be
  called with owner

Closes #15
@0x-r4bbit
Copy link
Collaborator

Closing this in favor of #61 and #63

@0x-r4bbit 0x-r4bbit closed this Oct 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

3 participants