Skip to content

Commit

Permalink
wip: set claimer and optimise
Browse files Browse the repository at this point in the history
  • Loading branch information
ksatyarth2 committed Jul 19, 2024
1 parent 58c2f2e commit 2724ba4
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 163 deletions.
12 changes: 2 additions & 10 deletions mainnet-contracts/script/DeployL2RewardManager.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,19 @@ import {L2RewardManager} from "../src/l2-contracts/L2RewardManager.sol";
contract DeployL2RewardManager is BaseScript {

address _CONNEXT = 0x8247ed6d0a344eeae4edBC7e44572F1B70ECA82A; //@todo change for mainnet
address L1_PUFFER_VAULT = 0x9196830bB4c05504E0A8475A0aD566AceEB6BeC9; //@todo change for mainnet

function run() public broadcast {
AccessManager accessManager = new AccessManager(_broadcaster);

console.log("AccessManager", address(accessManager));

L2RewardManager newImplementation = new L2RewardManager(address(_CONNEXT));
L2RewardManager newImplementation = new L2RewardManager(address(_CONNEXT), address(L1_PUFFER_VAULT));
console.log("L2RewardManager Implementation", address(newImplementation));

ERC1967Proxy proxy = new ERC1967Proxy(address(newImplementation), abi.encodeCall(L2RewardManager.initialize, (address(accessManager))));
console.log("L2RewardManager Proxy", address(proxy));

bytes4[] memory bridgeContractSelector = new bytes4[](1);
bridgeContractSelector[0] = L2RewardManager.xReceive.selector;

// TODO - create new role for bridge contract
bytes memory cd = abi.encodeWithSelector(AccessManager.setTargetFunctionRole.selector, address(proxy), bridgeContractSelector, PUBLIC_ROLE);

console.logBytes(cd);
accessManager.execute(address(accessManager), cd);

accessManager.grantRole(PUBLIC_ROLE, _CONNEXT, 0);
}
}
43 changes: 21 additions & 22 deletions mainnet-contracts/src/interface/IL2RewardManager.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {ClaimOrder} from "../struct/RewardManagerInfo.sol";
import {ClaimOrder} from "../struct/L2RewardManagerInfo.sol";

interface IL2RewardManager {
/**
Expand Down Expand Up @@ -37,26 +37,6 @@ interface IL2RewardManager {
bytes memory _callData
) external returns (bytes memory);

/**
* @notice Sets the claimer for a specific account
* @param account The account to set the claimer for
* @param claimer The address of the claimer
*/

function setClaimer(address account, address claimer) external;

// /**
// * @notice Posts the updated rewards root for a specific epoch range
// * @param startEpoch The start epoch of the interval
// * @param endEpoch The end epoch of the interval
// * @param root The merkle root of the rewards
// */
// function postRewardsRoot(
// uint64 startEpoch,
// uint64 endEpoch,
// bytes32 root
// ) external;

/**
* @notice Claims the rewards for a specific epoch range
* @param claimOrders The list of orders for claiming.
Expand All @@ -71,7 +51,20 @@ interface IL2RewardManager {
* @param endEpoch The end epoch of the interval
* @param root The merkle root of the rewards
*/
event RewardRootAndRatePosted( uint128 rewardsAmount, uint128 ethToPufETHRate, uint64 startEpoch, uint64 endEpoch, bytes32 root);
event RewardRootAndRatePosted(
uint128 rewardsAmount,
uint128 ethToPufETHRate,
uint64 startEpoch,
uint64 endEpoch,
bytes32 root
);

/**
* @notice Event emitted when a claimer is set
* @param account The account to set the claimer for
* @param claimer The address of the claimer
*/
event ClaimerSet(address indexed account, address claimer);

/**
* @notice Event emitted when rewards are claimed
Expand All @@ -87,6 +80,12 @@ interface IL2RewardManager {
uint256 amount
);

/**
* @notice Custom error when called function is not by PufferVault
*/

error CallerNotPufferVault();

/**
* @notice Custom error for invalid asset
*/
Expand Down
111 changes: 64 additions & 47 deletions mainnet-contracts/src/l2-contracts/L2RewardManager.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {AccessManagedUpgradeable} from "@openzeppelin-contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {BridgingParams, BridgingType, ClaimOrder, MintAndBridgeParams, SetClaimerParams} from "../struct/L2RewardManagerInfo.sol";
import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IL2RewardManager} from "../interface/IL2RewardManager.sol";
import {IXReceiver} from "interfaces/core/IXReceiver.sol";
import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {L2RewardManagerStorage} from "./L2RewardManagerStorage.sol";
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import {BridgingParams, BridgingType, MintAndBridgeParams, SetClaimerParams, ClaimOrder} from "../struct/RewardManagerInfo.sol";
import {AccessManagedUpgradeable} from "@openzeppelin-contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {RewardManagerStorage} from "../struct/RewardManagerStorage.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

/**
* @title L2RewardManager
Expand All @@ -17,28 +18,39 @@ import {RewardManagerStorage} from "../struct/RewardManagerStorage.sol";
*/
contract L2RewardManager is
IL2RewardManager,
L2RewardManagerStorage,
IXReceiver,
AccessManagedUpgradeable,
UUPSUpgradeable
{
using SafeERC20 for IERC20;
using Math for uint256;

// The ERC20 token being distributed
IERC20 public immutable XTOKEN;
IERC20 public immutable xPufETH;

// keccak256(abi.encode(uint256(keccak256("L2RewardManager.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant _REWARD_MANAGER_STORAGE_LOCATION =
0x7f1aa0bc41c09fbe61ccc14f95edc9998b7136087969b5ccb26131ec2cbbc800;
address public immutable L1_PUFFER_VAULT;

constructor(address xToken) {
XTOKEN = IERC20(xToken);
constructor(address _xPufETH, address l1PufferVault) {
xPufETH = IERC20(_xPufETH);
L1_PUFFER_VAULT = l1PufferVault;
_disableInitializers();
}

modifier onlyPufferVault(address _originSender) {
if (_originSender != address(L1_PUFFER_VAULT)) {
revert CallerNotPufferVault();
}
_;
}

function initialize(address accessManager) external initializer {
__AccessManaged_init(accessManager);
}

/// @inheritdoc IL2RewardManager
/**
* @inheritdoc IL2RewardManager
*/
function isClaimed(
uint64 startEpoch,
uint64 endEpoch,
Expand All @@ -48,18 +60,20 @@ contract L2RewardManager is
return $.claimedRewards[startEpoch][endEpoch][account];
}

/// @inheritdoc IL2RewardManager
/**
* @inheritdoc IL2RewardManager
*/
function xReceive(
bytes32,
uint256 _amount,
address _asset,
address,
address _originSender,
uint32,
bytes memory _callData
)
external
override(IL2RewardManager, IXReceiver)
restricted
onlyPufferVault(_originSender)
returns (bytes memory)
{
// Decode the _callData to get the BridgingParams
Expand All @@ -75,18 +89,19 @@ contract L2RewardManager is
(MintAndBridgeParams)
);
// Check for the right token
if (_asset != address(XTOKEN)) {
if (_asset != address(xPufETH)) {
revert InvalidAsset();
}

if (_amount < params.rewardsAmount) revert InvalidAmount();

RewardManagerStorage storage $ = _getRewardManagerStorage();

$.rewardRoots[params.startEpoch][params.endEpoch] = params
.rewardsRoot;
$.ethToPufETHRates[params.startEpoch][params.endEpoch] = params
.ethToPufETHRate;
// Store the rate and root
$.rateAndRoots[params.startEpoch][params.endEpoch] = RateAndRoot({
ethToPufETHRate: params.ethToPufETHRate,
rewardRoot: params.rewardsRoot
});

emit RewardRootAndRatePosted(
params.rewardsAmount,
Expand All @@ -101,7 +116,10 @@ contract L2RewardManager is
bridgingParams.data,
(SetClaimerParams)
);
setClaimer(claimerParams.account, claimerParams.claimer);
RewardManagerStorage storage $ = _getRewardManagerStorage();
$.customClaimers[claimerParams.account] = claimerParams.claimer;

emit ClaimerSet(claimerParams.account, claimerParams.claimer);
} else {
revert InvalidBridgingType();
}
Expand All @@ -110,11 +128,9 @@ contract L2RewardManager is
return abi.encode(true);
}

function setClaimer(address account, address claimer) public restricted {
// TODO: implement
}

/// @inheritdoc IL2RewardManager
/**
* @inheritdoc IL2RewardManager
*/
function claimRewards(ClaimOrder[] calldata claimOrders) external {
uint256 length = claimOrders.length;

Expand All @@ -135,12 +151,9 @@ contract L2RewardManager is
}
RewardManagerStorage storage $ = _getRewardManagerStorage();

bytes32 rewardRoot = $.rewardRoots[claimOrder.startEpoch][
claimOrder.endEpoch
];
uint128 ethToPufETHRate = $.ethToPufETHRates[claimOrder.startEpoch][
claimOrder.endEpoch
];
RateAndRoot storage rateAndRoot = $.rateAndRoots[
claimOrder.startEpoch
][claimOrder.endEpoch];

// Node calculated using: keccak256(abi.encode(alice, startEpoch, endEpoch, total))
bytes32 leaf = keccak256(
Expand All @@ -155,16 +168,31 @@ contract L2RewardManager is
)
)
);
if (!MerkleProof.verify(claimOrder.merkleProof, rewardRoot, leaf))
revert InvalidProof();
if (
!MerkleProof.verify(
claimOrder.merkleProof,
rateAndRoot.rewardRoot,
leaf
)
) revert InvalidProof();

// Mark it claimed and transfer the tokens
$.claimedRewards[claimOrder.startEpoch][claimOrder.endEpoch][
claimOrder.account
] = true;
uint256 amountToTransfer = claimOrder.amount * ethToPufETHRate;

XTOKEN.safeTransfer(claimOrder.account, amountToTransfer);
uint256 amountToTransfer = claimOrder.amount.mulDiv(
rateAndRoot.ethToPufETHRate,
10 ** 18,
Math.Rounding.Ceil
); //TODO: check if this is correct

// if the custom claimer is set, then transfer the tokens to the set claimer
xPufETH.safeTransfer(
($.customClaimers[claimOrder.account] == address(0))
? claimOrder.account
: $.customClaimers[claimOrder.account],
amountToTransfer
);

emit Claimed(
claimOrder.account,
Expand All @@ -175,17 +203,6 @@ contract L2RewardManager is
}
}

function _getRewardManagerStorage()
internal
pure
returns (RewardManagerStorage storage $)
{
// solhint-disable-next-line
assembly {
$.slot := _REWARD_MANAGER_STORAGE_LOCATION
}
}

/**
* @dev Authorizes an upgrade to a new implementation
* Restricted access
Expand Down
53 changes: 53 additions & 0 deletions mainnet-contracts/src/l2-contracts/L2RewardManagerStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

/**
* @title L2RewardManagerStorage
* @author Puffer Finance
* @custom:security-contact security@puffer.fi
*/
abstract contract L2RewardManagerStorage {
/**
* @custom:storage-location erc7201:L2RewardManager.storage
* @dev +-----------------------------------------------------------+
* | |
* | DO NOT CHANGE, REORDER, REMOVE EXISTING STORAGE VARIABLES |
* | |
* +-----------------------------------------------------------+
*/

struct RateAndRoot {
uint128 ethToPufETHRate;
bytes32 rewardRoot;
}

struct RewardManagerStorage {
/**
* @notice Mapping to track the exchange rate from ETH to pufETH and reward root for each unique epoch range
*/
mapping(uint64 startEpoch => mapping(uint64 endEpoch => RateAndRoot)) rateAndRoots;
/**
* @notice Mapping to track claimed tokens for users for each unique epoch range
*/
mapping(uint64 startEpoch => mapping(uint64 endEpoch => mapping(address account => bool claimed))) claimedRewards;
/**
* @notice Mapping to track the custom claimer set by specific accounts
*/
mapping(address account => address claimer) customClaimers;
}

// keccak256(abi.encode(uint256(keccak256("L2RewardManager.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 internal constant _REWARD_MANAGER_STORAGE_LOCATION =
0x7f1aa0bc41c09fbe61ccc14f95edc9998b7136087969b5ccb26131ec2cbbc800;

function _getRewardManagerStorage()
internal
pure
returns (RewardManagerStorage storage $)
{
// solhint-disable-next-line
assembly {
$.slot := _REWARD_MANAGER_STORAGE_LOCATION
}
}
}
Loading

0 comments on commit 2724ba4

Please sign in to comment.