Skip to content

Commit

Permalink
feat: make pTokens pausable
Browse files Browse the repository at this point in the history
  • Loading branch information
jparklev committed Jul 9, 2024
1 parent 26a847f commit f29027c
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 5 deletions.
19 changes: 18 additions & 1 deletion contracts/PToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ pragma solidity ^0.8.13;
import {ERC20} from "solmate/tokens/ERC20.sol";

import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";

contract PToken is ERC20, AccessControl {
contract PToken is ERC20, AccessControl, Pausable {
bytes32 public constant MINT_ROLE = keccak256("MINT_ROLE");
bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE");

Expand All @@ -25,4 +26,20 @@ contract PToken is ERC20, AccessControl {
function burn(address from, uint256 value) public virtual onlyRole(BURN_ROLE) {
_burn(from, value);
}

function transferFrom(address from, address to, uint256 amount) public override whenNotPaused returns (bool) {
return super.transferFrom(from, to, amount);
}

function transfer(address to, uint256 amount) public override whenNotPaused returns (bool) {
return super.transfer(to, amount);
}

function pause() public onlyRole(DEFAULT_ADMIN_ROLE) {
_pause();
}

function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
}
14 changes: 12 additions & 2 deletions contracts/PointTokenVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
// Rebasing and fee-on-transfer tokens must be wrapped before depositing.
function deposit(ERC20 _token, uint256 _amount, address _receiver) public {
uint256 cap = caps[address(_token)];

if (cap != type(uint256).max) {
if (_amount + _token.balanceOf(address(this)) > cap) {
revert DepositExceedsCap();
Expand Down Expand Up @@ -187,14 +187,16 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
emit RewardsConverted(msg.sender, _receiver, _pointsId, _amountToConvert);
}

function deployPToken(bytes32 _pointsId) public {
function deployPToken(bytes32 _pointsId) public returns (PToken) {
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.
pTokens[_pointsId] = new PToken{salt: _pointsId}(name, symbol, 18);
emit PTokenDeployed(_pointsId, address(pTokens[_pointsId]));

return pTokens[_pointsId];
}

// Internal ---
Expand Down Expand Up @@ -249,6 +251,14 @@ contract PointTokenVault is UUPSUpgradeable, AccessControlUpgradeable, Multicall
emit RewardRedemptionSet(_pointsId, _rewardToken, _rewardsPerPToken, _isMerkleBased);
}

function pausePToken(bytes32 _pointsId) external onlyRole(OPERATOR_ROLE) {
pTokens[_pointsId].pause();
}

function unpausePToken(bytes32 _pointsId) external onlyRole(OPERATOR_ROLE) {
pTokens[_pointsId].unpause();
}

// To handle arbitrary reward claiming logic.
function execute(address _to, bytes memory _data, uint256 _txGas)
external
Expand Down
38 changes: 36 additions & 2 deletions contracts/test/PointTokenVault.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ pragma solidity ^0.8.13;

import {Test, console} from "forge-std/Test.sol";
import {PointTokenVault} from "../PointTokenVault.sol";
import {PToken} from "../PToken.sol";

import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {ERC1967Utils} from "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";

import {MockERC20} from "solmate/test/utils/mocks/MockERC20.sol";
Expand Down Expand Up @@ -137,7 +139,7 @@ contract PointTokenVaultTest is Test {

// Set deposit cap to max
vm.prank(operator);
pointTokenVault.setCap(address(newMockToken), 2**256 - 1);
pointTokenVault.setCap(address(newMockToken), 2 ** 256 - 1);

// Approve and deposit more than the previous cap
vm.startPrank(vitalik);
Expand Down Expand Up @@ -625,7 +627,39 @@ contract PointTokenVaultTest is Test {
vm.prank(vitalik);
vm.expectRevert(PointTokenVault.PTokenNotDeployed.selector);
mockVault.claimPTokens(PointTokenVault.Claim(eigenPointsId, 1e18, 1e18, proof), vitalik);
}
}

function test_PTokenPause() 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);

PToken pToken = pointTokenVault.pTokens(eigenPointsId);

// Pause the pToken
vm.prank(operator);
pointTokenVault.pausePToken(eigenPointsId);

// Cannot transfer pTokens
vm.prank(vitalik);
vm.expectRevert(Pausable.EnforcedPause.selector);
pToken.transfer(vitalik, 1e18);

// Unpause the pToken
vm.prank(operator);
pointTokenVault.unpausePToken(eigenPointsId);

// Can transfer pTokens
vm.prank(vitalik);
pToken.transfer(vitalik, 1e18);
}

// Internal
function _deployAdditionalVault() internal returns (PointTokenVault mockVault) {
Expand Down

0 comments on commit f29027c

Please sign in to comment.