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

add validation for supported nstID #223

Merged
merged 7 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
81 changes: 56 additions & 25 deletions x/oracle/keeper/native_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,32 @@ import (
// undelegate: update operator's price, operator's totalAmount, operator's totalShare, staker's share
// msg(refund or slash on beaconChain): update staker's price, operator's price

type NSTETHAssetID string

const (
NSTETHASSETID = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_0x65"
// TODO: we currently support NSTETH only which has capped effective balance for one validator
// TODO: this is a bad practice, and for Lz, they have different version of endpoint with different chainID
// Do the validation before invoke oracle ralted functions instead of check these hard code ids here.
MaxMustermann2 marked this conversation as resolved.
Show resolved Hide resolved
NSTETHAssetIDMainnet NSTETHAssetID = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_0x7595"
NSTETHAssetIDLocalnet NSTETHAssetID = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_0x65"
NSTETHAssetIDHolesky NSTETHAssetID = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_0x9d19"
NSTETHAssetIDSepolia NSTETHAssetID = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_0x9ce1"
)

var (
limitedChangeNST = map[NSTETHAssetID]bool{
NSTETHAssetIDMainnet: true,
NSTETHAssetIDLocalnet: true,
NSTETHAssetIDHolesky: true,
NSTETHAssetIDSepolia: true,
}

maxEffectiveBalances = map[NSTETHAssetID]int{
NSTETHAssetIDMainnet: 32,
NSTETHAssetIDLocalnet: 32,
NSTETHAssetIDHolesky: 32,
NSTETHAssetIDSepolia: 32,
}
)

// SetStakerInfos set stakerInfos for the specific assetID
Expand All @@ -33,10 +57,6 @@ func (k Keeper) SetStakerInfos(ctx sdk.Context, assetID string, stakerInfos []*t
}
}

var maxEffectiveBalance = map[string]int{
NSTETHASSETID: 32,
}

// GetStakerInfo returns details about staker for native-restaking under asset of assetID
func (k Keeper) GetStakerInfo(ctx sdk.Context, assetID, stakerAddr string) types.StakerInfo {
store := ctx.KVStore(k.storeKey)
Expand Down Expand Up @@ -133,6 +153,14 @@ func (k Keeper) GetAllStakerListAssets(ctx sdk.Context) (ret []types.StakerListA
}

func (k Keeper) UpdateNSTValidatorListForStaker(ctx sdk.Context, assetID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error {
if !IsLimitedChangeNST(assetID) {
return types.ErrNSTAssetNotSupported
}
_, decimalInt, err := k.getDecimal(ctx, assetID)
if err != nil {
return err
}
amountInt64 := amount.Quo(decimalInt).Int64()
// emit an event to tell that a staker's validator list has changed
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeCreatePrice,
Expand All @@ -146,8 +174,9 @@ func (k Keeper) UpdateNSTValidatorListForStaker(ctx sdk.Context, assetID, staker
stakerInfo = types.NewStakerInfo(stakerAddr, validatorPubkey)
} else {
k.cdc.MustUnmarshal(value, stakerInfo)
if amount.IsPositive() {
if amountInt64 > 0 {
leonz789 marked this conversation as resolved.
Show resolved Hide resolved
// deopsit add a new validator into staker's validatorList
// one validator can only deposit once before it completed withdraw which remove its pubkey form this list. So there's no need to check duplication
stakerInfo.ValidatorPubkeyList = append(stakerInfo.ValidatorPubkeyList, validatorPubkey)
}
}
Expand All @@ -159,7 +188,7 @@ func (k Keeper) UpdateNSTValidatorListForStaker(ctx sdk.Context, assetID, staker
newBalance.Index++
}
newBalance.Block = uint64(ctx.BlockHeight())
if amount.IsPositive() {
if amountInt64 > 0 {
newBalance.Change = types.Action_ACTION_DEPOSIT
} else {
// TODO: check if this validator has withdraw all its asset and then we can move it out from the staker's validatorList
Expand All @@ -174,19 +203,7 @@ func (k Keeper) UpdateNSTValidatorListForStaker(ctx sdk.Context, assetID, staker
}
}

decimal, decimalInt, err := k.getDecimal(ctx, assetID)
if err != nil {
return err
}

// the amount should be checked by caller
// in case of nstETH, deposit should be equal to 32e18 as the maxeffectivebalance
efbUnit := sdkmath.NewIntWithDecimal(int64(maxEffectiveBalance[assetID]), decimal)
if amount.GTE(efbUnit) {
newBalance.Balance += int64(maxEffectiveBalance[assetID])
} else {
newBalance.Balance += amount.Quo(decimalInt).Int64()
}
newBalance.Balance += amountInt64

keyStakerList := types.NativeTokenStakerListKey(assetID)
valueStakerList := store.Get(keyStakerList)
Expand All @@ -210,7 +227,7 @@ func (k Keeper) UpdateNSTValidatorListForStaker(ctx sdk.Context, assetID, staker
}
}
if !exists {
if !amount.IsPositive() {
if amountInt64 <= 0 {
return errors.New("remove unexist validator")
Comment on lines +230 to 231
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the error message for clarity

The error message at line 231 reads "remove unexist validator." Consider changing it to "remove nonexistent validator" for better readability.

Apply this diff to correct the error message:

-return errors.New("remove unexist validator")
+return errors.New("remove nonexistent validator")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if amountInt64 <= 0 {
return errors.New("remove unexist validator")
if amountInt64 <= 0 {
return errors.New("remove nonexistent validator")

}
stakerList.StakerAddrs = append(stakerList.StakerAddrs, stakerAddr)
Expand Down Expand Up @@ -244,6 +261,9 @@ func (k Keeper) UpdateNSTValidatorListForStaker(ctx sdk.Context, assetID, staker

// UpdateNSTByBalanceChange updates balance info for staker under native-restaking asset of assetID when its balance changed by slash/refund on the source chain (beacon chain for eth)
func (k Keeper) UpdateNSTByBalanceChange(ctx sdk.Context, assetID string, rawData []byte, roundID uint64) error {
if !IsLimitedChangeNST(assetID) {
return types.ErrNSTAssetNotSupported
}
_, chainID, _ := assetstypes.ParseID(assetID)
if len(rawData) < 32 {
return errors.New("length of indicate maps for stakers shoule be exactly 32 bytes")
Expand All @@ -252,9 +272,9 @@ func (k Keeper) UpdateNSTByBalanceChange(ctx sdk.Context, assetID string, rawDat
if len(sl.StakerAddrs) == 0 {
return errors.New("staker list is empty")
}
stakerChanges, err := parseBalanceChange(rawData, sl)
stakerChanges, err := parseBalanceChangeCapped(rawData, sl)
if err != nil {
return err
return fmt.Errorf("failed to parse balance changes: %w", err)
}
store := ctx.KVStore(k.storeKey)
for _, stakerAddr := range sl.StakerAddrs {
Expand All @@ -280,7 +300,7 @@ func (k Keeper) UpdateNSTByBalanceChange(ctx sdk.Context, assetID string, rawDat
}
newBalance.Change = types.Action_ACTION_SLASH_REFUND
// balance update are based on initial/max effective balance: 32
maxBalance := maxEffectiveBalance[assetID] * (len(stakerInfo.ValidatorPubkeyList))
maxBalance := maxEffectiveBalance(assetID) * (len(stakerInfo.ValidatorPubkeyList))
balance := maxBalance + change
// there's one case that this delta might be more than previous Balance
// staker's validatorlist: {v1, v2, v3, v5}
Expand Down Expand Up @@ -319,8 +339,10 @@ func (k Keeper) getDecimal(ctx sdk.Context, assetID string) (int, sdkmath.Int, e
return int(decimal), sdkmath.NewIntWithDecimal(1, int(decimal)), nil
}

// TODO: This conversion has limited length for balance change, it suites for beaconchain currently, If we extend to other changes, this method need to be upgrade
// for value that might be too big leading too long length of the change value, many related changes need to be done since the message size might be too big then
// parseBalanceChange parses rawData to details of amount change for all stakers relative to native restaking
func parseBalanceChange(rawData []byte, sl types.StakerList) (map[string]int, error) {
func parseBalanceChangeCapped(rawData []byte, sl types.StakerList) (map[string]int, error) {
// eg. 0100-000011
// first part 0100 tells that the effective-balance of staker corresponding to index 2 in StakerList
// the lenft part 000011. we use the first 4 bits to tell the length of this number, and it shows as 1 here, the 5th bit is used to tell symbol of the number, 1 means negative, then we can get the abs number indicate by the length. It's -1 here, means effective-balane is 32-1 on beacon chain for now
Expand Down Expand Up @@ -392,3 +414,12 @@ func parseBalanceChange(rawData []byte, sl types.StakerList) (map[string]int, er
func getStakerID(stakerAddr string, chainID uint64) string {
return strings.Join([]string{strings.ToLower(stakerAddr), hexutil.EncodeUint64(chainID)}, utils.DelimiterForID)
}

// IsLimitChangesNST returns that is input assetID corresponding to asset which balance change has a cap limit
func IsLimitedChangeNST(assetID string) bool {
return limitedChangeNST[NSTETHAssetID(assetID)]
}

func maxEffectiveBalance(assetID string) int {
return maxEffectiveBalances[NSTETHAssetID(assetID)]
}
leonz789 marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion x/oracle/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ var (
ErrGetPriceAssetNotFound = sdkerrors.Register(ModuleName, getPriceFailedAssetNotFound, "get price failed for asset not found")
ErrGetPriceRoundNotFound = sdkerrors.Register(ModuleName, getPriceFailedRoundNotFound, "get price failed for round not found")
ErrUpdateNativeTokenVirtualPriceFail = sdkerrors.Register(ModuleName, updateNativeTokenVirtualPriceFail, "update native token balance change failed")
ErrNSTAssetNotSurpported = sdkerrors.Register(ModuleName, nstAssetNotSurpported, "nstAsset not supported")
ErrNSTAssetNotSupported = sdkerrors.Register(ModuleName, nstAssetNotSurpported, "nstAsset not supported")
)
Loading