Skip to content

Commit

Permalink
feat: add sd reward manager contract
Browse files Browse the repository at this point in the history
  • Loading branch information
blockgroot committed Sep 20, 2024
1 parent c2b620a commit 60ebe72
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
93 changes: 93 additions & 0 deletions contracts/SDRewardManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
pragma solidity 0.8.16;

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { IStaderConfig } from "./interfaces/IStaderConfig.sol";
import { INodeRegistry } from "./interfaces/INodeRegistry.sol";

Check warning on line 7 in contracts/SDRewardManager.sol

View workflow job for this annotation

GitHub Actions / Run linters

imported name INodeRegistry is not used
import { UtilLib } from "./library/UtilLib.sol";

contract SDRewardManager is Initializable {
using SafeERC20Upgradeable for IERC20Upgradeable;

struct SDRewardEntry {
uint256 cycleNumber;
uint256 amount; // in exact SD value, not in gwei or wei
bool approved;
}

IStaderConfig public staderConfig;

uint256 public latestCycleNumber;

// Mapping of cycle numbers to reward entries
mapping(uint256 => SDRewardEntry) public rewardEntries;

// Event emitted when a new reward entry is created
event NewRewardEntry(uint256 indexed cycleNumber, uint256 amount);

// Event emitted when a reward entry is approved
event RewardEntryApproved(uint256 indexed cycleNumber, uint256 amount);

error AccessDenied(address account);
error EntryNotFound(uint256 cycleNumber);
error EntryAlreadyRegistered(uint256 cycleNumber);
error EntryAlreadApproved(uint256 cycleNumber);

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();

Check warning on line 39 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L39

Added line #L39 was not covered by tests
}

function initialize(address _staderConfig) external initializer {
UtilLib.checkNonZeroAddress(_staderConfig);
staderConfig = IStaderConfig(_staderConfig);

Check warning on line 44 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L43-L44

Added lines #L43 - L44 were not covered by tests
}

function addRewardEntry(uint256 _cycleNumber, uint256 _amount) external {
if (!staderConfig.isAllowedToCall(msg.sender, "addRewardEntry(uint256,uint256)")) {
revert AccessDenied(msg.sender);

Check warning on line 49 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L49

Added line #L49 was not covered by tests
}

if (_cycleNumber <= latestCycleNumber) {
revert EntryAlreadyRegistered(_cycleNumber);

Check warning on line 53 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L53

Added line #L53 was not covered by tests
}

SDRewardEntry storage rewardEntry = rewardEntries[_cycleNumber];
rewardEntry.cycleNumber = _cycleNumber;
rewardEntry.amount = _amount;
latestCycleNumber = _cycleNumber;

Check warning on line 59 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L56-L59

Added lines #L56 - L59 were not covered by tests

emit NewRewardEntry(_cycleNumber, _amount);

Check warning on line 61 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L61

Added line #L61 was not covered by tests
}

function approveEntry(uint256 _cycleNumber, uint256 _amount) external {
if (!staderConfig.isAllowedToCall(msg.sender, "approveEntry(uint256,uint256)")) {
revert AccessDenied(msg.sender);

Check warning on line 66 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L66

Added line #L66 was not covered by tests
}

SDRewardEntry storage rewardEntry = rewardEntries[_cycleNumber];

Check warning on line 69 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L69

Added line #L69 was not covered by tests

if (rewardEntry.cycleNumber == 0) {
revert EntryNotFound(_cycleNumber);

Check warning on line 72 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L72

Added line #L72 was not covered by tests
}

if (rewardEntry.approved) {
revert EntryAlreadApproved(_cycleNumber);

Check warning on line 76 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L76

Added line #L76 was not covered by tests
}

rewardEntry.approved = true;

Check warning on line 79 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L79

Added line #L79 was not covered by tests
if (rewardEntry.amount > 0) {
IERC20Upgradeable(staderConfig.getStaderToken()).safeTransferFrom(

Check warning on line 81 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L81

Added line #L81 was not covered by tests
msg.sender,
staderConfig.getPermissionlessSocializingPool(),
_amount
);
emit RewardEntryApproved(_cycleNumber, _amount);

Check warning on line 86 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L86

Added line #L86 was not covered by tests
}
}

function viewLatestEntry() external view returns (SDRewardEntry memory) {
return rewardEntries[latestCycleNumber];

Check warning on line 91 in contracts/SDRewardManager.sol

View check run for this annotation

Codecov / codecov/patch

contracts/SDRewardManager.sol#L91

Added line #L91 was not covered by tests
}
}
26 changes: 26 additions & 0 deletions contracts/StaderConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,27 @@ contract StaderConfig is IStaderConfig, AccessControlUpgradeable {
setContract(SD_INCENTIVE_CONTROLLER, _sdIncentiveController);
}

// Access Control
function giveCallPermission(
address contractAddress,
string calldata functionSig,
address accountToPermit
) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));
grantRole(role, accountToPermit);
emit PermissionGranted(accountToPermit, contractAddress, functionSig);

Check warning on line 308 in contracts/StaderConfig.sol

View check run for this annotation

Codecov / codecov/patch

contracts/StaderConfig.sol#L306-L308

Added lines #L306 - L308 were not covered by tests
}

function revokeCallPermission(
address contractAddress,
string calldata functionSig,
address accountToRevoke
) external onlyRole(DEFAULT_ADMIN_ROLE) {
bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));
revokeRole(role, accountToRevoke);
emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);

Check warning on line 318 in contracts/StaderConfig.sol

View check run for this annotation

Codecov / codecov/patch

contracts/StaderConfig.sol#L316-L318

Added lines #L316 - L318 were not covered by tests
}

//Constants Getters

function getStakedEthPerNode() external view override returns (uint256) {
Expand Down Expand Up @@ -537,6 +558,11 @@ contract StaderConfig is IStaderConfig, AccessControlUpgradeable {
return hasRole(OPERATOR, account);
}

function isAllowedToCall(address account, string calldata functionSig) external view returns (bool) {
bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));
return hasRole(role, account);

Check warning on line 563 in contracts/StaderConfig.sol

View check run for this annotation

Codecov / codecov/patch

contracts/StaderConfig.sol#L562-L563

Added lines #L562 - L563 were not covered by tests
}

function verifyDepositAndWithdrawLimits() internal view {
if (
!(variablesMap[MIN_DEPOSIT_AMOUNT] != 0 &&
Expand Down
12 changes: 12 additions & 0 deletions contracts/interfaces/IStaderConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ interface IStaderConfig {
event SetAccount(bytes32 key, address newAddress);
event SetContract(bytes32 key, address newAddress);
event SetToken(bytes32 key, address newAddress);
event PermissionGranted(address indexed accountToPermit, address indexed contractAddress, string functionSig);
event PermissionRevoked(address indexed accountToRevoke, address indexed contractAddress, string functionSig);

//Contracts
function POOL_UTILS() external view returns (bytes32);
Expand Down Expand Up @@ -171,4 +173,14 @@ interface IStaderConfig {
function onlyManagerRole(address account) external view returns (bool);

function onlyOperatorRole(address account) external view returns (bool);

function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);

function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;

function revokeCallPermission(
address contractAddress,
string calldata functionSig,
address accountToRevoke
) external;
}

0 comments on commit 60ebe72

Please sign in to comment.