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

feat: implement claimKghReward function #348

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
111 changes: 109 additions & 2 deletions packages/contracts/contracts/L1/AssetManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,26 @@ contract AssetManager is ISemver, IERC721Receiver, IAssetManager {
return kghAssets + kroAssets;
}

/**
* @inheritdoc IAssetManager
*/
function getKghReward(
address validator,
address delegator,
uint256[] calldata tokenIds
) external view returns (uint128) {
Vault storage vault = _vaults[validator];
KghDelegator storage kghDelegator = vault.kghDelegators[delegator];

uint128 rewardPerKghStored = vault.asset.rewardPerKghStored;
uint128 totalBoostedReward = kghDelegator.kghNum *
(rewardPerKghStored - kghDelegator.rewardPerKghPaid);

(, uint128 kghBaseReward) = _calculateBaseRewardForKgh(validator, kghDelegator, tokenIds);

return totalBoostedReward + kghBaseReward;
}

/**
* @inheritdoc IAssetManager
*/
Expand Down Expand Up @@ -343,7 +363,9 @@ contract AssetManager is ISemver, IERC721Receiver, IAssetManager {
uint128 assets
) external isRegistered(validator) returns (uint128) {
if (assets == 0) revert NotAllowedZeroInput();
ASSET_TOKEN.safeTransferFrom(msg.sender, address(this), assets);
uint128 shares = _delegate(validator, msg.sender, assets);

emit KroDelegated(validator, msg.sender, assets, shares);
seolaoh marked this conversation as resolved.
Show resolved Hide resolved
return shares;
}
Expand Down Expand Up @@ -669,6 +691,37 @@ contract AssetManager is ISemver, IERC721Receiver, IAssetManager {
emit RewardClaimFinalized(msg.sender, rewardsToClaim);
}

/**
* @inheritdoc IAssetManager
*/
function claimKghReward(address validator, uint256[] calldata tokenIds) external {
if (validator == address(0)) revert ZeroAddress();
if (tokenIds.length == 0) revert NotAllowedZeroInput();

Vault storage vault = _vaults[validator];
KghDelegator storage kghDelegator = vault.kghDelegators[msg.sender];
if (kghDelegator.kghNum != uint128(tokenIds.length)) revert InvalidTokenIdsInput();

uint128 claimedRewards = _claimBoostedReward(validator, msg.sender);
if (claimedRewards == 0) revert InsufficientAsset();

(uint128 kroSharesToBurn, uint128 kghBaseReward) = _calculateBaseRewardForKgh(
validator,
kghDelegator,
tokenIds
);

unchecked {
claimedRewards += kghBaseReward;
vault.asset.totalKroShares -= kroSharesToBurn;
vault.asset.totalKro -= kghBaseReward;
}

ASSET_TOKEN.safeTransfer(msg.sender, claimedRewards);

emit KghRewardClaimed(validator, msg.sender, claimedRewards, kroSharesToBurn);
}

/**
* @notice Bond KRO from validator KRO during output submission or challenge creation. This
* function is only called by the ValidatorManager contract.
Expand Down Expand Up @@ -873,6 +926,38 @@ contract AssetManager is ISemver, IERC721Receiver, IAssetManager {
vault.kghDelegators[msg.sender].undelegateRequestTimes.push(block.timestamp);
}

/**
* @notice Internal function to calculate base rewards from the given validator address,
* delegator struct, and token ids of KGHs.
*
* @param validator Address of the validator.
* @param delegator KghDelegator struct of the delegator.
* @param tokenIds Array of token ids of the KGH to calculate base rewards.
*
* @return The amount of shares corresponding to the reward.
* @return The amount of base rewards.
*/
function _calculateBaseRewardForKgh(
address validator,
KghDelegator storage delegator,
uint256[] calldata tokenIds
) internal view returns (uint128, uint128) {
uint128 kroSharesToBurn;
for (uint256 i = 0; i < tokenIds.length; ) {
if (kghDelegator.delegatedAt[tokenIds[i]] == 0) revert InvalidTokenIdsInput();
uint128 kroShares = kghDelegator.kroShares[tokenIds[i]] -
_convertToKroShares(validator, KGH_MANAGER.totalKroInKgh(tokenIds[i]));

unchecked {
kroSharesToBurn += kroShares;
++i;
}
}

uint128 kghBaseReward = _convertToKroAssets(validator, kroSharesToBurn);
return (kroSharesToBurn, kghBaseReward);
}

/**
* @notice Internal conversion function for KRO (from assets to shares).
*
Expand Down Expand Up @@ -976,8 +1061,6 @@ contract AssetManager is ISemver, IERC721Receiver, IAssetManager {
uint128 shares = _convertToKroShares(validator, assets);
Vault storage vault = _vaults[validator];

ASSET_TOKEN.safeTransferFrom(owner, address(this), assets);

unchecked {
vault.asset.totalKro += assets;
vault.asset.totalKroShares += shares;
Expand Down Expand Up @@ -1197,6 +1280,30 @@ contract AssetManager is ISemver, IERC721Receiver, IAssetManager {
}
}

/**
* @notice Internal function to claim the boosted reward of the delegator.
*
* @param validator Address of the validator.
* @param delegator Address of the delegator.
*
* @return The amount of the claimed boosted reward.
*/
function _claimBoostedReward(
address validator,
address delegator,
) internal returns (uint128) {
Vault storage vault = _vaults[validator];
KghDelegator storage kghDelegator = vault.kghDelegators[delegator];

uint128 rewardPerKghStored = vault.asset.rewardPerKghStored;
uint128 totalBoostedReward = kghDelegator.kghNum *
(rewardPerKghStored - kghDelegator.rewardPerKghPaid);

kghDelegator.rewardPerKghPaid = rewardPerKghStored;

return totalBoostedReward;
}

/**
* @inheritdoc IERC721Receiver
*/
Expand Down
19 changes: 15 additions & 4 deletions packages/contracts/contracts/L1/interfaces/IAssetManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ interface IAssetManager {
*/
struct KghDelegator {
uint128 rewardPerKghPaid;
uint256 kghNum;
uint128 kghNum;
mapping(uint256 => uint128) delegatedAt;
mapping(uint256 => uint128) kroShares;
}
Expand Down Expand Up @@ -260,6 +260,11 @@ interface IAssetManager {
*/
error ShareNotExists();

/**
* @notice Reverts when the given token ids are invalid.
*/
error InvalidTokenIdsInput();

/**
* @notice Returns the address of withdraw account of given validator.
*
Expand Down Expand Up @@ -423,10 +428,15 @@ interface IAssetManager {
*
* @param validator The address of the validator.
* @param delegator The address of the delegator.
* @param tokenIds The token id array of KGH to check the base reward.
*
* @return The amount of claimable reward of KGH delegation.
*/
function getKghReward(address validator, address delegator) external view returns (uint128);
function getKghReward(
address validator,
address delegator,
uint256[] calldata tokenIds
) external view returns (uint128);

/**
* @notice Deposit KRO. To deposit KRO, the validator should be initiated.
Expand Down Expand Up @@ -503,9 +513,10 @@ interface IAssetManager {
function undelegateKghBatch(address validator, uint256[] calldata tokenIds) external;

/**
* @notice Claim the reward of the KGH delegator from the given validator vault.
* @notice Claim the reward of the KGH delegator from the given validator vault and token ids.
*
* @param validator Address of the validator.
* @param tokenIds Array of token ids of KGHs to claim base reward.
*/
function claimKghReward(address validator) external;
function claimKghReward(address validator, uint256[] calldata tokenIds) external;
}
Loading