Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SD utility pool #212

Merged
merged 122 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
b3e9567
basic utility pool structure
Nov 6, 2023
d8664c1
sdCollateral intergration with utilityPool
Nov 6, 2023
f47f2e1
Rename SDx.sol to SDX.sol
sanjay-staderlabs Nov 6, 2023
b7aee57
terminology change
Nov 7, 2023
0b2b4c0
SD Incentive Controller (#210)
dulguun-staderlabs Nov 7, 2023
eb88282
utilize flow
Nov 14, 2023
82cc1c8
origin pull
Nov 14, 2023
12bab11
dwlwgator withdraw flow
Nov 14, 2023
7d706b7
seperate function in node registry to utilze SD
Nov 16, 2023
ac24c13
view function to get latest data
Nov 17, 2023
28e52c7
Liquidation (#211)
dulguun-staderlabs Nov 17, 2023
cb26fe2
Add back comments
dulguun-staderlabs Nov 17, 2023
efcfa04
include pause functionality
Nov 17, 2023
d771bfb
origin pull
Nov 17, 2023
5ea300a
repay flow changes and comments
Nov 20, 2023
1dd59d2
Operator reward integration (#213)
dulguun-staderlabs Nov 23, 2023
28a5a64
Add PoolUtils
dulguun-staderlabs Nov 23, 2023
4fbc7ba
claimLiquidation
dulguun-staderlabs Nov 23, 2023
51d3796
Fix compile
dulguun-staderlabs Nov 28, 2023
26c1f4d
Fix claimFor
dulguun-staderlabs Nov 28, 2023
f614c56
Add liquidator data
dulguun-staderlabs Nov 30, 2023
dcb8182
review fixes
Dec 2, 2023
c6ecd53
merge origin feat/SD_Utility_Pool
Dec 2, 2023
adae26e
deposit SD reward as collateral changes
Dec 2, 2023
2850ec0
Fix compilation
dulguun-staderlabs Dec 3, 2023
70ccf89
Change function orders
dulguun-staderlabs Dec 3, 2023
d3008fc
Fix review
dulguun-staderlabs Dec 3, 2023
b8f4db4
Add exit operator
dulguun-staderlabs Dec 3, 2023
db1f400
deposit SD reward as collateral flow changes
Dec 4, 2023
9f03ab3
Fix review
dulguun-staderlabs Dec 4, 2023
cca972e
Use operatorUtilizedSDBalance
dulguun-staderlabs Dec 4, 2023
77aef08
custom error message
Dec 5, 2023
351df68
deploy script for utility pool
Dec 5, 2023
62d839b
Updates on incentiveController
dulguun-staderlabs Dec 6, 2023
df0a793
Add docs and checkers
dulguun-staderlabs Dec 6, 2023
bf4a1e8
fix claim function time cool down logic
Dec 7, 2023
38a95a9
Add withdrawable
dulguun-staderlabs Dec 7, 2023
55205d0
Merge branch 'feat/SD_Utility_Pool' of https://github.com/stader-labs…
dulguun-staderlabs Dec 7, 2023
4234681
rename function and variables
Dec 8, 2023
2427c9f
Add non-existent liquidation check
dulguun-staderlabs Dec 8, 2023
004b7d1
fix sdCollateral withdraw function
Dec 8, 2023
d0ceaac
Merge branch 'feat/SD_Utility_Pool' of https://github.com/stader-labs…
Dec 8, 2023
8360869
Fix claim logic
dulguun-staderlabs Dec 8, 2023
cf935da
refactor slash SD
Dec 9, 2023
d78e882
Merge branch 'feat/SD_Utility_Pool' of https://github.com/stader-labs…
Dec 9, 2023
450a8e6
whenNotPaused modifier
Dec 9, 2023
c6bfcc8
Claim rewards during requestWithdraw
dulguun-staderlabs Dec 9, 2023
c3ab55a
review fixes
Dec 10, 2023
4fc456c
Merge branch 'feat/SD_Utility_Pool' of https://github.com/stader-labs…
Dec 10, 2023
673663d
change in request withdraw logic
Dec 10, 2023
5b9be86
Review fix
dulguun-staderlabs Dec 10, 2023
713d962
Introduce weth
dulguun-staderlabs Dec 10, 2023
8cd59c6
introducing withdrawOnBehalf in SDCollateral
Dec 11, 2023
432f6ca
Merge branch 'feat/SD_Utility_Pool' of https://github.com/stader-labs…
Dec 11, 2023
7f7dfa6
Transfer back utilized SD
dulguun-staderlabs Dec 11, 2023
4b74a72
add getter in interface
Dec 11, 2023
d7c3381
Merge branch 'feat/SD_Utility_Pool' of https://github.com/stader-labs…
Dec 11, 2023
90e0b9d
incentiveController and addValidatorKey fix
Dec 14, 2023
5788efb
test case for utilze and delegate flow
Dec 22, 2023
79c2a86
referral Id for adding validator keys
Dec 24, 2023
7d38257
sdCollateral test cases
Jan 2, 2024
42bd2f7
SD token decimal adjust
dulguun-staderlabs Jan 3, 2024
e9cdab0
Multiply by DECIMAL
dulguun-staderlabs Jan 3, 2024
45200fa
Liquidation test
dulguun-staderlabs Jan 4, 2024
4abd088
Only manager role for certain functions
dulguun-staderlabs Jan 5, 2024
7421670
test fix
Jan 5, 2024
c93e196
Fix weth issue
dulguun-staderlabs Jan 5, 2024
e9251e7
Small fix and unit test
dulguun-staderlabs Jan 7, 2024
fe32591
Minimum reward amount
dulguun-staderlabs Jan 7, 2024
f79c803
Claim available amount
dulguun-staderlabs Jan 7, 2024
914d4bb
Lint test
dulguun-staderlabs Jan 7, 2024
0996dc2
Add start incentive later test
dulguun-staderlabs Jan 7, 2024
39339f7
SDP-06 fix
Jan 8, 2024
8dcc156
Merge branch 'feat/SD_Utility_Pool' of https://github.com/stader-labs…
Jan 8, 2024
a79ba4e
SDP-11 fix
Jan 8, 2024
e4a2bfe
Fix SDP-03
dulguun-staderlabs Jan 8, 2024
d66e714
SDP-02 fix
Jan 8, 2024
b69ad87
push back SDP-03 fix
Jan 8, 2024
b8ae94b
SDP-07 fix
sanjay-staderlabs Jan 9, 2024
773f584
SDP-17 fix
sanjay-staderlabs Jan 9, 2024
2a31470
Take initial _delegate into consideration
dulguun-staderlabs Jan 10, 2024
4d981f3
whenNotPaused test cases
sanjay-staderlabs Jan 10, 2024
d1a230a
Merge branch 'feat/SD_Utility_Pool' of https://github.com/stader-labs…
sanjay-staderlabs Jan 10, 2024
bed5ffb
comment fix
sanjay-staderlabs Jan 11, 2024
5e38f9b
Expand liquidation call tests
dulguun-staderlabs Jan 11, 2024
8fdcb9a
Update SDIncentiveController.t.sol
dulguun-staderlabs Jan 11, 2024
5a9504f
Separate claim and claimLiquidation
dulguun-staderlabs Jan 11, 2024
87c80cf
Add test
dulguun-staderlabs Jan 11, 2024
e8ed9b1
Quick fix
dulguun-staderlabs Jan 11, 2024
ced164f
Remove claimFor
dulguun-staderlabs Jan 11, 2024
45358bb
Fix test
dulguun-staderlabs Jan 12, 2024
6d75aa2
Lint and add tests
dulguun-staderlabs Jan 14, 2024
6b4870c
small change claim
dulguun-staderlabs Jan 14, 2024
834adc4
Add emit tests
dulguun-staderlabs Jan 14, 2024
b8cf0c1
Refactor test
dulguun-staderlabs Jan 14, 2024
f8fe3f8
add emit test
dulguun-staderlabs Jan 14, 2024
a0962b6
claim after liquidation
dulguun-staderlabs Jan 14, 2024
a0b411f
change initial delegate amount to 1 SD
sanjay-staderlabs Jan 15, 2024
e9bc3a9
Initialise risk config at initialize
dulguun-staderlabs Jan 15, 2024
85164c6
Internal function prefix with _
dulguun-staderlabs Jan 15, 2024
21ba418
renaming change
sanjay-staderlabs Jan 15, 2024
a876de8
Collateral in ETH and expose liquidationIndexByOperator
dulguun-staderlabs Jan 17, 2024
73514c3
rounding up interest in ETH
sanjay-staderlabs Jan 17, 2024
7efcb29
reward collector test fixed
sanjay-staderlabs Jan 17, 2024
5a5797f
foundry deploy script
sanjay-staderlabs Jan 17, 2024
9176358
minimum withdraw and delegate limits
sanjay-staderlabs Jan 18, 2024
10b4341
rounding up cTokenShare in requestWithdrawWithSD call
sanjay-staderlabs Jan 18, 2024
492073d
fix utilityPool with min delegate amount
sanjay-staderlabs Jan 18, 2024
559d4bc
add clearUtilizedPosition function
sanjay-staderlabs Jan 29, 2024
238519a
add totalUtilizedSD getter in interface
sanjay-staderlabs Jan 30, 2024
b59025c
clearing utilized position using withdrawOnBehalf
sanjay-staderlabs Jan 31, 2024
d652be5
optimize _transferBackUtilizedSD
sanjay-staderlabs Jan 31, 2024
7d90edb
handling of edge cases when nonTerminalKeys are 0
sanjay-staderlabs Feb 1, 2024
1469477
update interface
sanjay-staderlabs Feb 1, 2024
e8b4afc
add utilityPool deploy script
sanjay-staderlabs Feb 6, 2024
cfb81ce
introduce claimWithAmount function in rewardCollector
sanjay-staderlabs Feb 7, 2024
c0b3f9a
fix: only call withdraw if balance of nodeELVault greater than 0
sanjay-staderlabs Feb 7, 2024
5bb7c2d
updating operatorRewardsCollector Interface
sanjay-staderlabs Feb 20, 2024
b2ca94c
adding third party license file
sanjay-staderlabs Feb 28, 2024
a76a8e8
fix formatting of README
sanjay-staderlabs Feb 28, 2024
ffe585a
add title in License file
sanjay-staderlabs Feb 28, 2024
46462f4
formatting the title of License file
sanjay-staderlabs Feb 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions contracts/OperatorRewardsCollector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ contract OperatorRewardsCollector is IOperatorRewardsCollector, AccessControlUpg

mapping(address => uint256) public balances;

mapping(address => uint256)[] public owedAmounts;
mapping(address => uint256)[] public claimableAmounts;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
Expand Down Expand Up @@ -46,6 +49,30 @@ contract OperatorRewardsCollector is IOperatorRewardsCollector, AccessControlUpg
emit Claimed(operatorRewardsAddr, amount);
dulguun-staderlabs marked this conversation as resolved.
Show resolved Hide resolved
}

function claimFor(address operator) external {
uint256 toSendAmount;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this variable? No usages right?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add documentation? This logic is not very clear.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add documentation? This logic is not very clear.

for (uint256 i = 0; i < owedAmounts[operator].length; i++) {
if (balances[operator] >= owedAmounts[operator][i]) {
toSendAmount = owedAmounts[operator][i];
balances[operator] -= owedAmounts[operator][i];
claimableAmounts[operator][i] = owedAmounts[operator][i];
owedAmounts[operator][i] = 0;
} else {
toSendAmount = balances[operator];
owedAmounts[operator][i] -= balances[operator];
claimableAmounts[operator][i] = balances[operator];
balances[operator] = 0;
break;
}
}

if (balances[operator] > 0) {
address operatorRewardsAddr = UtilLib.getOperatorRewardAddress(operator, staderConfig);
UtilLib.sendValue(operatorRewardsAddr, balances[operator]);
emit Claimed(operatorRewardsAddr, balances[operator]);
}
}

function updateStaderConfig(address _staderConfig) external onlyRole(DEFAULT_ADMIN_ROLE) {
UtilLib.checkNonZeroAddress(_staderConfig);
staderConfig = IStaderConfig(_staderConfig);
Expand Down
49 changes: 34 additions & 15 deletions contracts/PermissionlessNodeRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import './interfaces/IStaderConfig.sol';
import './interfaces/IVaultFactory.sol';
import './interfaces/IPoolUtils.sol';
import './interfaces/INodeRegistry.sol';
import './interfaces/ISDUtilityPool.sol';
import './interfaces/IPermissionlessPool.sol';
import './interfaces/INodeELRewardVault.sol';
import './interfaces/IStaderInsuranceFund.sol';
Expand Down Expand Up @@ -128,13 +129,29 @@ contract PermissionlessNodeRegistry is
bytes[] calldata _preDepositSignature,
bytes[] calldata _depositSignature
) external payable override nonReentrant whenNotPaused {
addValidatorKeysWithUtilizeSD(0, _pubkey, _preDepositSignature, _depositSignature);
}

/**
* @notice add validator keys
* @dev only accepts if bond of 4 ETH per key is provided along with sufficient SD lockup after utilize
* @param _amountOfSDToUtilize amount of SD to utilize from Utility Pool
* @param _pubkey pubkey of validators
* @param _preDepositSignature signature of a validators for 1ETH deposit
* @param _depositSignature signature of a validator for 31ETH deposit
*/
function addValidatorKeysWithUtilizeSD(
uint256 _amountOfSDToUtilize,
bytes[] calldata _pubkey,
bytes[] calldata _preDepositSignature,
bytes[] calldata _depositSignature
) public payable override nonReentrant whenNotPaused {
uint256 operatorId = onlyActiveOperator(msg.sender);
(uint256 keyCount, uint256 operatorTotalKeys) = checkInputKeysCountAndCollateral(
_pubkey.length,
_preDepositSignature.length,
_depositSignature.length,
operatorId
);
uint256 keyCount = _pubkey.length;
if (keyCount != _preDepositSignature.length || keyCount != _depositSignature.length) {
revert MisMatchingInputKeysSize();
}
uint256 operatorTotalKeys = checkInputKeysCountAndCollateral(keyCount, operatorId, _amountOfSDToUtilize);

address vaultFactory = staderConfig.getVaultFactory();
address poolUtils = staderConfig.getPoolUtils();
Expand Down Expand Up @@ -662,15 +679,10 @@ contract PermissionlessNodeRegistry is

// validate the input of `addValidatorKeys` function
function checkInputKeysCountAndCollateral(
uint256 _pubkeyLength,
uint256 _preDepositSignatureLength,
uint256 _depositSignatureLength,
uint256 _operatorId
) internal view returns (uint256 keyCount, uint256 totalKeys) {
if (_pubkeyLength != _preDepositSignatureLength || _pubkeyLength != _depositSignatureLength) {
revert MisMatchingInputKeysSize();
}
keyCount = _pubkeyLength;
uint256 keyCount,
uint256 _operatorId,
uint256 _amountOfSDToUtilize
) internal returns (uint256 totalKeys) {
if (keyCount == 0 || keyCount > inputKeyCountLimit) {
revert InvalidKeyCount();
}
Expand All @@ -685,6 +697,13 @@ contract PermissionlessNodeRegistry is
if (msg.value != keyCount * COLLATERAL_ETH) {
revert InvalidBondEthValue();
}
if (_amountOfSDToUtilize > 0) {
ISDUtilityPool(staderConfig.getSDUtilityPool()).utilizeWhileAddingKeys(
msg.sender,
_amountOfSDToUtilize,
totalNonTerminalKeys + keyCount
);
}
//checks if operator has enough SD collateral for adding `keyCount` keys
if (
!ISDCollateral(staderConfig.getSDCollateral()).hasEnoughSDCollateral(
Expand Down
82 changes: 70 additions & 12 deletions contracts/SDCollateral.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '../contracts/interfaces/IPoolUtils.sol';
import '../contracts/interfaces/SDCollateral/ISDCollateral.sol';
import '../contracts/interfaces/SDCollateral/IAuction.sol';
import '../contracts/interfaces/IStaderOracle.sol';
import './interfaces/ISDUtilityPool.sol';

import '@openzeppelin/contracts/utils/math/Math.sol';
import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol';
Expand All @@ -17,6 +18,8 @@ contract SDCollateral is ISDCollateral, AccessControlUpgradeable, ReentrancyGuar
IStaderConfig public override staderConfig;
mapping(uint8 => PoolThresholdInfo) public poolThresholdbyPoolId;
mapping(address => uint256) public override operatorSDBalance;
//amount of SD added as collateral via utility pool
mapping(address => uint256) public override operatorUtilizedSDBalance;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
Expand Down Expand Up @@ -51,21 +54,67 @@ contract SDCollateral is ISDCollateral, AccessControlUpgradeable, ReentrancyGuar
emit SDDeposited(operator, _sdAmount);
}

function depositUtilizedSD(address _operator, uint256 _sdAmount) external override {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

depositSDFromUtilityPool*

UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.SD_UTILITY_POOL());

operatorUtilizedSDBalance[_operator] += _sdAmount;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would prefer this addn to occur after the if

if (!IERC20(staderConfig.getStaderToken()).transferFrom(msg.sender, address(this), _sdAmount)) {
revert SDTransferFailed();
}

emit UtilizedSDDeposited(_operator, _sdAmount);
}

function reduceUtilizedSDPosition(address operator, uint256 sdAmount) external override {
UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.SD_UTILITY_POOL());

operatorUtilizedSDBalance[operator] -= sdAmount;
operatorSDBalance[operator] += sdAmount;

emit ReducedUtilizedPosition(operator, sdAmount);
}

/// @notice for operator to withdraw their sd collateral, which is over and above withdraw threshold
function withdraw(uint256 _requestedSD) external override {
address operator = msg.sender;
uint256 opSDBalance = operatorSDBalance[operator];
uint256 operatorUtilizedSD = operatorUtilizedSDBalance[operator];
uint256 opSDBalance = operatorSDBalance[operator] + operatorUtilizedSD;

if (opSDBalance < getOperatorWithdrawThreshold(operator) + _requestedSD) {
revert InsufficientSDToWithdraw(opSDBalance);
}
operatorSDBalance[operator] -= _requestedSD;
uint256 operatorCurrentUtilizeSD = ISDUtilityPool(staderConfig.getSDUtilityPool()).utilizerBalanceCurrent(
Copy link

@galacticminter galacticminter Nov 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fn can called .currentBalance()

operator
);

// cannot use safeERC20 as this contract is an upgradeable contract, and using safeERC20 is not upgrade-safe
if (!IERC20(staderConfig.getStaderToken()).transfer(payable(operator), _requestedSD)) {
revert SDTransferFailed();
uint256 utilizePositionChange = operatorUtilizedSD >= _requestedSD ? _requestedSD : operatorUtilizedSD;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No easier way to do Math.min()?

operatorUtilizedSDBalance[operator] -= utilizePositionChange;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SDRequestedLeft = SDRequested;
interestAccrued = operatorTotalUtilizedSD - operatorRecordedUtilizedSD // difference between the two is interest

interestPaid = Math.min(SDRequestedLeft, interestAccrued);
sdRequestedLeft -= interestPaid;
//Update repay amount in SDUtilityPool by transferring interestPaid tokens. Might have to update both utilized and bonded positions.

if (sdRequestedLeft == 0) { // You are done.}

utilizedPositionRepayAmount = Math.min(sdRequestedLeft, operatorRecordedUtilizedSD)
sdRequestedLeft -= utilizedPositionRepayAmount;
//definitely decrease the RecordedUtilizedSD & increment the Self Bonded SD & transfer utilizedPositionRepayAmount tokens to SD utilization pool.


if (sdRequestedLeft == 0) { // You are done}

// At this stage all interest + utilized amount has been repaid. The rest can to operator wallet & only self bonded position will be decremented

Will optimize this further.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SDRequestedLeft = SDRequested;
operatorTotalUtilizedSD = utilityPool.currentUtilizedAmount(operator);

repayAmount = Math.min(SDRequestedLeft, operatorTotalUtilizedSD);
sdRequestedLeft -= repayAmount;
// transfer repayAmount tokens to SD utility pool. Decrement total utilized balance on pool & operator current utilized balance on pool.
interestPaid = Math.min(repayAmount, operatorTotalUtilizedSD - operatorRecordedUtilizedSD); // How do we make sure this math works for incentivized lending when the 2nd term might be negative?
utilizedAmountPaid = repayAmount - interestPaid;
operatorRecordedUtilizedSD -= utilizedAmountPaid;
SDBalances[operator] += utilizedAmountPaid;

if (sdRequestedLeft > 0) {
// Send sdRequestedLeft tokens to operator wallet.
}

return (interestPaid, utilizedAmountPaid, sdRequestedLeft);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the above simpler?

Copy link
Contributor Author

@sanjay-staderlabs sanjay-staderlabs Nov 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will push another implementation of this, mostly the same as above, with a change that the repay function will return the actual repayment amount.

uint256 remainingUtilizePosition = operatorCurrentUtilizeSD - utilizePositionChange;
uint256 selfBondedPositionChange = _requestedSD - utilizePositionChange;
uint256 repayFromSelfBond = remainingUtilizePosition >= selfBondedPositionChange
? selfBondedPositionChange
: remainingUtilizePosition;
operatorSDBalance[operator] -= selfBondedPositionChange;

if (utilizePositionChange + repayFromSelfBond > 0) {
ISDUtilityPool(staderConfig.getSDUtilityPool()).repayViaSDCollateral(
operator,
utilizePositionChange + repayFromSelfBond
);
}

if (selfBondedPositionChange - repayFromSelfBond > 0) {
address operatorRewardAddr = UtilLib.getOperatorRewardAddress(operator, staderConfig);
// cannot use safeERC20 as this contract is an upgradeable contract, and using safeERC20 is not upgrade-safe
if (
!IERC20(staderConfig.getStaderToken()).transfer(
operatorRewardAddr,
selfBondedPositionChange - repayFromSelfBond
)
) {
revert SDTransferFailed();
}
}
emit SDRepaid(operator, utilizePositionChange + repayFromSelfBond);
emit SDWithdrawn(operator, _requestedSD);
}

Expand All @@ -85,22 +134,31 @@ contract SDCollateral is ISDCollateral, AccessControlUpgradeable, ReentrancyGuar
/// @param _operator which operator SD collateral to slash
/// @param _sdToSlash amount of SD to slash
function slashSD(address _operator, uint256 _sdToSlash) internal {
uint256 sdBalance = operatorSDBalance[_operator];
uint256 operatorSelfBondedSD = operatorSDBalance[_operator];
uint256 sdBalance = operatorSelfBondedSD + operatorUtilizedSDBalance[_operator];
uint256 sdSlashed = Math.min(_sdToSlash, sdBalance);
if (sdSlashed == 0) {
return;
}
operatorSDBalance[_operator] -= sdSlashed;
uint256 sdSlashFromUtilized = operatorSelfBondedSD >= sdSlashed ? 0 : sdSlashed - operatorSelfBondedSD;
operatorSDBalance[_operator] -= (sdSlashed - sdSlashFromUtilized);
if (sdSlashFromUtilized > 0) {
operatorUtilizedSDBalance[_operator] -= sdSlashFromUtilized;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this the right place to inform the utility pool of the slashed SD?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think there is any use case of informing the utility pool

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please simplify this logic.

sdToSlashFromSelfBonded = math.min(operatorSelfBondedSD, sdSlashed)
operatorSDBalance[_operator] -= sdToSlashFromSelfBonded

operatorUtilizedSDBalance[operator] -= (sdSlashed - sdToSlashFromSelfBonded)

This avoids the if stmt.

}
IAuction(staderConfig.getAuctionContract()).createLot(sdSlashed);
emit SDSLashedFromUtilize(_operator, sdSlashFromUtilized);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get casing right please.

emit SDSlashed(_operator, staderConfig.getAuctionContract(), sdSlashed);
}

/// @notice for max approval to auction contract for spending SD tokens
/// @notice for max approval to auction/SD utility pool contract for spending SD tokens

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and

function maxApproveSD() external override {
UtilLib.onlyManagerRole(msg.sender, staderConfig);
address auctionContract = staderConfig.getAuctionContract();
address sdUtilityPool = staderConfig.getSDUtilityPool();
UtilLib.checkNonZeroAddress(auctionContract);
UtilLib.checkNonZeroAddress(sdUtilityPool);
IERC20(staderConfig.getStaderToken()).approve(auctionContract, type(uint256).max);
IERC20(staderConfig.getStaderToken()).approve(sdUtilityPool, type(uint256).max);
}

// SETTERS
Expand Down Expand Up @@ -182,7 +240,7 @@ contract SDCollateral is ISDCollateral, AccessControlUpgradeable, ReentrancyGuar
uint8 _poolId,
uint256 _numValidator
) public view override returns (uint256) {
uint256 sdBalance = operatorSDBalance[_operator];
uint256 sdBalance = operatorSDBalance[_operator] + operatorUtilizedSDBalance[_operator];
uint256 minSDToBond = getMinimumSDToBond(_poolId, _numValidator);
return (sdBalance >= minSDToBond ? 0 : minSDToBond - sdBalance);
}
Expand All @@ -195,7 +253,7 @@ contract SDCollateral is ISDCollateral, AccessControlUpgradeable, ReentrancyGuar

uint256 totalMinThreshold = validatorCount * convertETHToSD(poolThreshold.minThreshold);
uint256 totalMaxThreshold = validatorCount * convertETHToSD(poolThreshold.maxThreshold);
uint256 sdBalance = operatorSDBalance[_operator];
uint256 sdBalance = operatorSDBalance[_operator] + operatorUtilizedSDBalance[_operator];
return (sdBalance < totalMinThreshold ? 0 : Math.min(sdBalance, totalMaxThreshold));
}

Expand All @@ -212,7 +270,7 @@ contract SDCollateral is ISDCollateral, AccessControlUpgradeable, ReentrancyGuar
// HELPER

function getOperatorInfo(address _operator)
internal
public
view
returns (
uint8 _poolId,
Expand Down
108 changes: 108 additions & 0 deletions contracts/SDIncentiveController.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.16;

import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

import './library/UtilLib.sol';
import './interfaces/IStaderConfig.sol';
import './interfaces/ISDUtilityPool.sol';
import './interfaces/ISDIncentiveController.sol';

/// @title SDIncentiveController
/// @notice This contract handles the distribution of reward tokens for a lending pool.
dulguun-staderlabs marked this conversation as resolved.
Show resolved Hide resolved
contract SDIncentiveController is ISDIncentiveController, AccessControlUpgradeable {
// The emission rate of the reward tokens per block.
uint256 public emissionPerBlock;

// The block number of the last reward calculation.
uint256 public lastUpdateBlockNumber;

// The stored value of the reward per token, used to calculate rewards.
uint256 public rewardPerTokenStored;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be a mapping? The name is confusing.


// Reference to the Stader configuration contract.
IStaderConfig public staderConfig;

// A mapping of accounts to their pending reward amounts.
mapping(address => uint256) public rewards;

// A mapping of accounts to the reward per token value at their last update.
mapping(address => uint256) public userRewardPerTokenPaid;

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

/// @notice Initializes the contract with necessary addresses.
/// @param _staderConfig The address of the Stader configuration contract.
function initialize(address _staderConfig) external initializer {
dulguun-staderlabs marked this conversation as resolved.
Show resolved Hide resolved
UtilLib.checkNonZeroAddress(_staderConfig);

staderConfig = IStaderConfig(_staderConfig);

__AccessControl_init();
}

/// @notice Claims the accrued rewards for an account.
/// @param account The address of the account claiming rewards.
function claim(address account) external {
UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.SD_UTILITY_POOL());

updateReward(account);

uint256 reward = rewards[account];
require(reward > 0, 'No rewards to claim.');
rewards[account] = 0;
IERC20(staderConfig.getStaderToken()).transfer(account, reward);

emit RewardClaimed(account, reward);
}

/// @notice Updates the reward on deposit in the lending pool.
/// @param account The account that made a deposit.
function onDelegate(address account) external override {
UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.SD_UTILITY_POOL());

updateReward(account);
}

/// @notice Calculates the current reward per token.
/// @return The calculated reward per token.
function rewardPerToken() public view returns (uint256) {
uint256 totalSupply = ISDUtilityPool(staderConfig.getSDUtilityPool()).cTokenTotalSupply();
if (totalSupply == 0) {
return rewardPerTokenStored;
}
return
rewardPerTokenStored + (((block.number - lastUpdateBlockNumber) * emissionPerBlock * 1e18) / totalSupply);
}

/// @notice Calculates the total accrued reward for an account.
/// @param account The account to calculate rewards for.
/// @return The total accrued reward for the account.
function earned(address account) public view returns (uint256) {
uint256 currentBalance = ISDUtilityPool(staderConfig.getSDUtilityPool()).delegatorCTokenBalance(account);
uint256 currentRewardPerToken = rewardPerToken();

return ((currentBalance * (currentRewardPerToken - userRewardPerTokenPaid[account])) / 1e18) + rewards[account];
}

/// @dev Internal function to update the reward state for an account.
/// @param account The account to update the reward for.
function updateReward(address account) internal {
rewardPerTokenStored = rewardPerToken();
lastUpdateBlockNumber = block.number;

if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
}

/// @dev Emitted when a reward is claimed.
/// @param user The user who claimed the reward.
/// @param reward The amount of reward claimed.
event RewardClaimed(address indexed user, uint256 reward);
}
Loading
Loading