Skip to content

Commit

Permalink
fix: round up for burn
Browse files Browse the repository at this point in the history
  • Loading branch information
jparklev committed Apr 23, 2024
1 parent 997e37e commit 850c562
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 8 deletions.
5 changes: 3 additions & 2 deletions contracts/PointTokenVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {ERC20} from "solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";

import {LibString} from "solady/utils/LibString.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";

import {PToken} from "./PToken.sol";

Expand Down Expand Up @@ -146,8 +147,8 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
_verifyClaimAndUpdateClaimed(_claim, claimHash, msg.sender, claimedRedemptionRights);
}

// Will fail if the user doesn't also have enough point tokens.
pTokens[pointsId].burn(msg.sender, amountToClaim * 1e18 / rewardsPerPToken);
// Will fail if the user doesn't also have enough point tokens. Assume rewardsPerPToken is 18 decimals.
pTokens[pointsId].burn(msg.sender, FixedPointMathLib.divWadUp(amountToClaim, rewardsPerPToken)); // Round up for burn.
rewardToken.safeTransfer(_receiver, amountToClaim);
emit RewardsClaimed(msg.sender, _receiver, pointsId, amountToClaim);
}
Expand Down
4 changes: 1 addition & 3 deletions contracts/script/PointTokenVault.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@ contract PointTokenVaultScripts is BatchScript {
return address(pointTokenVault);
}

function deployPointTokenVault(address admin) public returns (PointTokenVault) {
string memory version = vm.envString("VERSION");

function deployPointTokenVault(address admin, string memory version) public returns (PointTokenVault) {
PointTokenVault pointTokenVaultImplementation = PointTokenVault(
CREATE3.deploy(
keccak256(bytes(string.concat("PointTokenVault", "-v", version))), type(PointTokenVault).creationCode, 0
Expand Down
32 changes: 29 additions & 3 deletions contracts/test/PointTokenVault.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ contract PointTokenVaultTest is Test {
PointTokenVaultScripts scripts = new PointTokenVaultScripts();

// Deploy the PointTokenVault
pointTokenVault = scripts.deployPointTokenVault(address(this));
pointTokenVault = scripts.deployPointTokenVault(address(this), "0.0.1");

pointTokenVault.grantRole(pointTokenVault.DEFAULT_ADMIN_ROLE(), admin);
pointTokenVault.grantRole(pointTokenVault.MERKLE_UPDATER_ROLE(), merkleUpdater);
Expand Down Expand Up @@ -362,6 +362,32 @@ contract PointTokenVaultTest is Test {
assertEq(rewardToken.balanceOf(vitalik), 2e18);
}

function test_RedeemRounding() 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, 1, empty), vitalik);

assertEq(rewardToken.balanceOf(vitalik), 1);
// Even the smallest redemption results in a burn.
assertEq(pointTokenVault.pTokens(eigenPointsId).balanceOf(vitalik), 1e18 - 1);
}

event RewardsClaimed(address indexed owner, address indexed receiver, bytes32 indexed pointsId, uint256 amount);

function test_MerkleBasedRedemption() public {
Expand All @@ -385,7 +411,7 @@ contract PointTokenVaultTest is Test {
vm.prank(vitalik);
pointTokenVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, validProofVitalikPToken), vitalik);

// Must use a merkle proof to redeem rewards
// Redeem the tokens for rewards with the wrong proof should fail
bytes32[] memory empty = new bytes32[](0);
vm.prank(vitalik);
vm.expectRevert(PointTokenVault.ProofInvalidOrExpired.selector);
Expand All @@ -394,7 +420,7 @@ contract PointTokenVaultTest is Test {
bytes32[] memory validProofVitalikRedemption = new bytes32[](1);
validProofVitalikRedemption[0] = 0x4e40a10ce33f33a4786960a8bb843fe0e170b651acd83da27abc97176c4bed3c;

// Redeem the tokens for rewards with the right proof
// Redeem the tokens for rewards with the right proof should succeed
vm.prank(vitalik);
vm.expectEmit(true, true, true, true);
emit RewardsClaimed(vitalik, vitalik, eigenPointsId, 2e18);
Expand Down

0 comments on commit 850c562

Please sign in to comment.