Skip to content

Commit

Permalink
feat: add function to go from rewards back to ptokens after redemptio…
Browse files Browse the repository at this point in the history
…n has been enabled
  • Loading branch information
jparklev committed Apr 23, 2024
1 parent 850c562 commit aed4f4a
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 1 deletion.
15 changes: 14 additions & 1 deletion contracts/PointTokenVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
/// @notice Claims point tokens after verifying the merkle proof
/// @param _claim The claim details including the merkle proof
/// @param _account The account to claim for
// Adapted from Morpho's RewardsDistributor.sol (https://github.com/morpho-org/morpho-optimizers/blob/main/src/common/rewards-distribution/RewardsDistributor.sol)
// Adapted from Morpho's RewardsDistributor.sol (https://github.com/morpho-org/morpho-optimizers/blob/ffd702f045d24b911d6c8c6c2194dd15cf9387ff/src/common/rewards-distribution/RewardsDistributor.sol)
function claimPTokens(Claim calldata _claim, address _account) public {
bytes32 pointsId = _claim.pointsId;

Expand Down Expand Up @@ -153,6 +153,19 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
emit RewardsClaimed(msg.sender, _receiver, pointsId, amountToClaim);
}

/// @notice Mints point tokens for rewards after redemption has been enabled
function convertRewardsToPTokens(address _receiver, bytes32 _pointsId, uint256 _amountToConvert) public {
RedemptionParams memory params = redemptions[_pointsId];
(ERC20 rewardToken, uint256 rewardsPerPToken) = (params.rewardToken, params.rewardsPerPToken);

if (address(rewardToken) == address(0)) {
revert RewardsNotReleased();
}

rewardToken.safeTransferFrom(msg.sender, address(this), _amountToConvert);
pTokens[_pointsId].mint(_receiver, FixedPointMathLib.divWadDown(_amountToConvert, rewardsPerPToken)); // Round down for mint.
}

function deployPToken(bytes32 _pointsId) public {
if (address(pTokens[_pointsId]) != address(0)) {
revert PTokenAlreadyDeployed();
Expand Down
41 changes: 41 additions & 0 deletions contracts/test/PointTokenVault.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,47 @@ contract PointTokenVaultTest is Test {

assertEq(pointTokenVault.pTokens(eigenPointsId).balanceOf(vitalik), 1e18);
}

function test_MintPTokensForRewards() public {
bytes32 root = 0x4e40a10ce33f33a4786960a8bb843fe0e170b651acd83da27abc97176c4bed3c;

bytes32[] memory proof = new bytes32[](1);
proof[0] = 0x6d0fcb8de12b1f57f81e49fa18b641487b932cdba4f064409fde3b05d3824ca2;

vm.prank(merkleUpdater);
pointTokenVault.updateRoot(root);

vm.prank(vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, proof), vitalik);

rewardToken.mint(address(pointTokenVault), 3e18);

vm.prank(operator);
pointTokenVault.setRedemption(eigenPointsId, rewardToken, 2e18, false);

bytes32[] memory empty = new bytes32[](0);
vm.prank(vitalik);
pointTokenVault.redeemRewards(PointTokenVault.Claim(eigenPointsId, 2e18, 2e18, empty), vitalik);

assertEq(rewardToken.balanceOf(vitalik), 2e18);
assertEq(pointTokenVault.pTokens(eigenPointsId).balanceOf(vitalik), 0);

// Mint pTokens with reward tokens
vm.prank(vitalik);
rewardToken.approve(address(pointTokenVault), 1e18);
vm.prank(vitalik);
pointTokenVault.convertRewardsToPTokens(vitalik, eigenPointsId, 1e18);

assertEq(rewardToken.balanceOf(vitalik), 1e18);
assertEq(pointTokenVault.pTokens(eigenPointsId).balanceOf(vitalik), 0.5e18);

// Can go the other way again
vm.prank(vitalik);
pointTokenVault.redeemRewards(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, empty), vitalik);

assertEq(rewardToken.balanceOf(vitalik), 2e18);
assertEq(pointTokenVault.pTokens(eigenPointsId).balanceOf(vitalik), 0);
}
}

contract Echo {
Expand Down

0 comments on commit aed4f4a

Please sign in to comment.