Skip to content

Commit

Permalink
chore: point token -> p token
Browse files Browse the repository at this point in the history
  • Loading branch information
jparklev committed Apr 18, 2024
1 parent 38ca388 commit c7a7fd7
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 42 deletions.
28 changes: 14 additions & 14 deletions contracts/PointTokenVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
mapping(address => mapping(ERC20 => uint256)) public balances; // user => point-earning token => balance

// Merkle root distribution.
mapping(address => mapping(bytes32 => uint256)) public claimedPTokens; // user => pointsId => claimed
bytes32 public currRoot;
bytes32 public prevRoot;
mapping(address => mapping(bytes32 => uint256)) public claimedPTokens; // user => pointsId => claimed
mapping(address => mapping(bytes32 => uint256)) public claimedRedemptionRights; // user => pointsId => claimed

mapping(bytes32 => PToken) public pointTokens; // pointsId => pointTokens
mapping(bytes32 => PToken) public pTokens; // pointsId => pTokens

mapping(bytes32 => RedemptionParams) public redemptions; // pointsId => redemptionParams

Expand All @@ -46,7 +46,7 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall

struct RedemptionParams {
ERC20 rewardToken;
uint256 rewardsPerPointToken; // Assume 18 decimals.
uint256 rewardsPerPToken; // Assume 18 decimals.
bool isMerkleBased;
}

Expand All @@ -56,7 +56,7 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
event PTokensClaimed(address indexed account, bytes32 indexed pointsId, uint256 amount);
event RewardsClaimed(address indexed owner, address indexed receiver, bytes32 indexed pointsId, uint256 amount);
event RewardRedemptionSet(
bytes32 indexed pointsId, ERC20 rewardToken, uint256 rewardsPerPointToken, bool isMerkleBased
bytes32 indexed pointsId, ERC20 rewardToken, uint256 rewardsPerPToken, bool isMerkleBased
);

error ProofInvalidOrExpired();
Expand Down Expand Up @@ -95,13 +95,13 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
/// @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)
function claimPointToken(Claim calldata _claim, address _account) public {
function claimPTokens(Claim calldata _claim, address _account) public {
bytes32 pointsId = _claim.pointsId;

bytes32 claimHash = keccak256(abi.encodePacked(_account, pointsId, _claim.totalClaimable));
_verifyClaimAndUpdateClaimed(_claim, claimHash, _account, claimedPTokens);

pointTokens[pointsId].mint(_account, _claim.amountToClaim);
pTokens[pointsId].mint(_account, _claim.amountToClaim);

emit PTokensClaimed(_account, pointsId, _claim.amountToClaim);
}
Expand All @@ -113,8 +113,8 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
(bytes32 pointsId, uint256 amountToClaim) = (_claim.pointsId, _claim.amountToClaim);

RedemptionParams memory params = redemptions[pointsId];
(ERC20 rewardToken, uint256 rewardsPerPointToken, bool isMerkleBased) =
(params.rewardToken, params.rewardsPerPointToken, params.isMerkleBased);
(ERC20 rewardToken, uint256 rewardsPerPToken, bool isMerkleBased) =
(params.rewardToken, params.rewardsPerPToken, params.isMerkleBased);

if (address(rewardToken) == address(0)) {
revert RewardsNotReleased();
Expand All @@ -129,18 +129,18 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
}

// Will fail if the user doesn't also have enough point tokens.
pointTokens[pointsId].burn(msg.sender, amountToClaim * 1e18 / rewardsPerPointToken);
pTokens[pointsId].burn(msg.sender, amountToClaim * 1e18 / rewardsPerPToken);
rewardToken.safeTransfer(_receiver, amountToClaim);
emit RewardsClaimed(msg.sender, _receiver, pointsId, amountToClaim);
}

function deployPToken(bytes32 _pointsId) public {
if (address(pointTokens[_pointsId]) != address(0)) {
if (address(pTokens[_pointsId]) != address(0)) {
revert PTokenAlreadyDeployed();
}

(string memory name, string memory symbol) = LibString.unpackTwo(_pointsId); // Assume the points id was created using LibString.packTwo.
pointTokens[_pointsId] = new PToken{salt: _pointsId}(name, symbol, 18);
pTokens[_pointsId] = new PToken{salt: _pointsId}(name, symbol, 18);
}

// Internal ---
Expand Down Expand Up @@ -181,12 +181,12 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
}

// Can be used to unlock reward token redemption (can also modify a live redemption, so use with care).
function setRedemption(bytes32 _pointsId, ERC20 _rewardToken, uint256 _rewardsPerPointToken, bool _isMerkleBased)
function setRedemption(bytes32 _pointsId, ERC20 _rewardToken, uint256 _rewardsPerPToken, bool _isMerkleBased)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
redemptions[_pointsId] = RedemptionParams(_rewardToken, _rewardsPerPointToken, _isMerkleBased);
emit RewardRedemptionSet(_pointsId, _rewardToken, _rewardsPerPointToken, _isMerkleBased);
redemptions[_pointsId] = RedemptionParams(_rewardToken, _rewardsPerPToken, _isMerkleBased);
emit RewardRedemptionSet(_pointsId, _rewardToken, _rewardsPerPToken, _isMerkleBased);
}

// To handle arbitrary reward claiming logic.
Expand Down
54 changes: 26 additions & 28 deletions contracts/test/PointTokenVault.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ contract PointTokenVaultTest is Test {
pointTokenVault.deployPToken(eigenPointsId);

// Name and symbol are set correctly
assertEq(pointTokenVault.pointTokens(eigenPointsId).name(), "Eigen Layer Point");
assertEq(pointTokenVault.pointTokens(eigenPointsId).symbol(), "pEL");
assertEq(pointTokenVault.pTokens(eigenPointsId).name(), "Eigen Layer Point");
assertEq(pointTokenVault.pTokens(eigenPointsId).symbol(), "pEL");
}

function test_ProxyUpgrade() public {
PointTokenVault newPointTokenVault = new PointTokenVault();
address eigenPointTokenPre = address(pointTokenVault.pointTokens(eigenPointsId));
address eigenPointTokenPre = address(pointTokenVault.pTokens(eigenPointsId));

// Only admin role can upgrade
vm.expectRevert(
Expand All @@ -117,7 +117,7 @@ contract PointTokenVaultTest is Test {
pointTokenVault.upgradeToAndCall(address(newPointTokenVault), bytes(""));

// Check that the state is still there.
assertEq(address(pointTokenVault.pointTokens(eigenPointsId)), eigenPointTokenPre);
assertEq(address(pointTokenVault.pTokens(eigenPointsId)), eigenPointTokenPre);
// Check that the implementation has been updated.
address implementation = address(
uint160(
Expand Down Expand Up @@ -195,27 +195,27 @@ contract PointTokenVaultTest is Test {
// Can't claim with the wrong proof
vm.prank(vitalik);
vm.expectRevert(PointTokenVault.ProofInvalidOrExpired.selector);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, badProof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, badProof), vitalik);

// Can't claim with the wrong claimable amount
vm.prank(vitalik);
vm.expectRevert(PointTokenVault.ProofInvalidOrExpired.selector);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 0.9e18, 0.9e18, goodProof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 0.9e18, 0.9e18, goodProof), vitalik);

// Can't claim with the wrong pointsId
vm.prank(vitalik);
vm.expectRevert(PointTokenVault.ProofInvalidOrExpired.selector);
pointTokenVault.claimPointToken(PointTokenVault.Claim(bytes32("123"), 1e18, 1e18, goodProof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(bytes32("123"), 1e18, 1e18, goodProof), vitalik);

// Can claim with the right proof
vm.prank(vitalik);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, goodProof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, goodProof), vitalik);

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

// Can't use the same proof twice
vm.expectRevert(PointTokenVault.ClaimTooLarge.selector);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, goodProof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, goodProof), vitalik);
}

function test_DistributionTwoRecipients() public {
Expand All @@ -230,21 +230,21 @@ contract PointTokenVaultTest is Test {

// Vitalik can claim
vm.prank(vitalik);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, vitalikProof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, vitalikProof), vitalik);

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

bytes32[] memory tolyProof = new bytes32[](1);
tolyProof[0] = 0x77ec2184ee10de8d8164b15f7f9e734a985dbe8a49e28feb2793ab17c9ed215c;

// Illia can execute toly's claim, but can only send the tokens to toly
vm.prank(illia);
vm.expectRevert(PointTokenVault.ProofInvalidOrExpired.selector);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 0.5e18, 0.5e18, tolyProof), illia);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 0.5e18, 0.5e18, tolyProof), illia);

pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 0.5e18, 0.5e18, tolyProof), toly);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 0.5e18, 0.5e18, tolyProof), toly);

assertEq(pointTokenVault.pointTokens(eigenPointsId).balanceOf(toly), 0.5e18);
assertEq(pointTokenVault.pTokens(eigenPointsId).balanceOf(toly), 0.5e18);
}

function test_MultiClaim() public {
Expand All @@ -262,17 +262,17 @@ contract PointTokenVaultTest is Test {

bytes[] memory calls = new bytes[](2);
calls[0] = abi.encodeCall(
pointTokenVault.claimPointToken, (PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, vitalikProof), vitalik)
pointTokenVault.claimPTokens, (PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, vitalikProof), vitalik)
);
calls[1] = abi.encodeCall(
pointTokenVault.claimPointToken, (PointTokenVault.Claim(eigenPointsId, 0.5e18, 0.5e18, tolyProof), toly)
pointTokenVault.claimPTokens, (PointTokenVault.Claim(eigenPointsId, 0.5e18, 0.5e18, tolyProof), toly)
);

pointTokenVault.multicall(calls);

// Claimed for both vitalik and toly at once.
assertEq(pointTokenVault.pointTokens(eigenPointsId).balanceOf(vitalik), 1e18);
assertEq(pointTokenVault.pointTokens(eigenPointsId).balanceOf(toly), 0.5e18);
assertEq(pointTokenVault.pTokens(eigenPointsId).balanceOf(vitalik), 1e18);
assertEq(pointTokenVault.pTokens(eigenPointsId).balanceOf(toly), 0.5e18);
}

function test_MulticallAuth(address lad) public {
Expand Down Expand Up @@ -302,7 +302,7 @@ contract PointTokenVaultTest is Test {
pointTokenVault.updateRoot(root);

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

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

Expand Down Expand Up @@ -337,9 +337,7 @@ contract PointTokenVaultTest is Test {

// Vitalik redeems with a valid proof
vm.prank(vitalik);
pointTokenVault.claimPointToken(
PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, validProofVitalikPToken), vitalik
);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, validProofVitalikPToken), vitalik);

// Must use a merkle proof to redeem rewards
bytes32[] memory empty = new bytes32[](0);
Expand Down Expand Up @@ -371,20 +369,20 @@ contract PointTokenVaultTest is Test {

// Can do a partial claim
vm.prank(vitalik);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 1e18, 0.5e18, proof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 0.5e18, proof), vitalik);

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

// Can only claim the remainder, no more
vm.prank(vitalik);
vm.expectRevert(PointTokenVault.ClaimTooLarge.selector);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 1e18, 0.75e18, proof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 0.75e18, proof), vitalik);

// Can claim the rest
vm.prank(vitalik);
pointTokenVault.claimPointToken(PointTokenVault.Claim(eigenPointsId, 1e18, 0.5e18, proof), vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 0.5e18, proof), vitalik);

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

Expand Down

0 comments on commit c7a7fd7

Please sign in to comment.