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

chore(staking): api and error codes #445

Merged
merged 5 commits into from
Dec 19, 2024
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
2,023 changes: 1,111 additions & 912 deletions client/server/README.md

Large diffs are not rendered by default.

1,381 changes: 992 additions & 389 deletions client/server/api.swagger.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion client/server/bank.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//nolint:wrapcheck // The api server is our server, so we don't need to wrap it
//nolint:wrapcheck,dupl // The api server is our server, so we don't need to wrap it
package server

import (
Expand Down
46 changes: 1 addition & 45 deletions client/server/distribution.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
//nolint:wrapcheck // The api server is our server, so we don't need to wrap it.
//nolint:wrapcheck,dupl // The api server is our server, so we don't need to wrap it.
package server

import (
"errors"
"net/http"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/distribution/keeper"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
Expand All @@ -21,7 +19,6 @@ func (s *Server) initDistributionRoute() {
s.httpMux.HandleFunc("/distribution/validators/{validator_address}/commission", utils.SimpleWrap(s.aminoCodec, s.GetValidatorCommissionByValidatorAddress))
s.httpMux.HandleFunc("/distribution/validators/{validator_address}/outstanding_rewards", utils.SimpleWrap(s.aminoCodec, s.GetValidatorOutstandingRewardsByValidatorAddress))
s.httpMux.HandleFunc("/distribution/validators/{validator_address}/slashes", utils.AutoWrap(s.aminoCodec, s.GetValidatorSlashesByValidatorAddress))
s.httpMux.HandleFunc("/distribution/all_validators/outstanding_rewards", utils.AutoWrap(s.aminoCodec, s.GetAllValidatorOutstandingRewards))

ezreal1997 marked this conversation as resolved.
Show resolved Hide resolved
s.httpMux.HandleFunc("/distribution/delegators/{delegator_address}/validators", utils.SimpleWrap(s.aminoCodec, s.GetDistributionValidatorsByDelegatorAddress))
s.httpMux.HandleFunc("/distribution/delegators/{delegator_address}/rewards", utils.SimpleWrap(s.aminoCodec, s.GetDelegatorRewardsByDelegatorAddress))
Expand Down Expand Up @@ -97,47 +94,6 @@ func (s *Server) GetValidatorOutstandingRewardsByValidatorAddress(r *http.Reques
return queryResp, nil
}

// GetAllValidatorOutstandingRewards queries rewards of all validators.
func (s *Server) GetAllValidatorOutstandingRewards(req *getAllValidatorOutstandingRewardsRequest, r *http.Request) (resp any, err error) {
if req.To-req.From > 100 {
return nil, errors.New("search max 100 blocks")
}

curBlock, err := s.cl.Block(r.Context(), nil)
if err != nil {
return nil, errors.Join(errors.New("curbock fetch fail"), err)
}

querier := keeper.NewQuerier(s.store.GetDistrKeeper())
result := make([]*getAllValidatorOutstandingRewardsRequestBlockResults, 0)

for i := req.From; i < min(req.To, curBlock.Block.Height); i++ {
queryContext, err := s.store.CreateQueryContext(i, false)
if err != nil {
return nil, errors.Join(errors.New("create query context fail"), err)
}

blockResult := &getAllValidatorOutstandingRewardsRequestBlockResults{
Height: i,
Validators: make(map[string]sdk.DecCoins),
}
//nolint: contextcheck // false positive
querier.IterateValidatorOutstandingRewards(queryContext, func(val sdk.ValAddress, rewards distributiontypes.ValidatorOutstandingRewards) (stop bool) {
if len(rewards.Rewards) > 0 {
blockResult.Validators[val.String()] = rewards.Rewards
}

return false
})

if len(blockResult.Validators) > 0 {
result = append(result, blockResult)
}
}

return result, nil
}

// GetValidatorSlashesByValidatorAddress queries slash events of a validator.
func (s *Server) GetValidatorSlashesByValidatorAddress(req *getValidatorSlashesByValidatorAddressRequest, r *http.Request) (resp any, err error) {
queryContext, err := s.createQueryContextByHeader(r)
Expand Down
14 changes: 0 additions & 14 deletions client/server/payload.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package server

import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

type pagination struct {
Key string `mapstructure:"key"`
Offset uint64 `mapstructure:"offset"`
Expand Down Expand Up @@ -50,16 +46,6 @@ type getDenomOwnersByQueryRequest struct {
Pagination pagination `mapstructure:"pagination"`
}

type getAllValidatorOutstandingRewardsRequest struct {
From int64 `mapstructure:"from"`
To int64 `mapstructure:"to"`
}

type getAllValidatorOutstandingRewardsRequestBlockResults struct {
Height int64 `json:"height"`
Validators map[string]sdk.DecCoins `json:"validators"`
}

type getValidatorSlashesByValidatorAddressRequest struct {
StartingHeight uint64 `mapstructure:"starting_height"`
EndingHeight uint64 `mapstructure:"ending_height"`
Expand Down
18 changes: 15 additions & 3 deletions client/x/evmstaking/keeper/redelegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,24 @@ func (k Keeper) ProcessRedelegate(ctx context.Context, ev *bindings.IPTokenStaki
depositorAddr.String(), validatorSrcAddr.String(), validatorDstAddr.String(),
ev.DelegationId.String(), amountCoin,
)

_, err = skeeper.NewMsgServerImpl(k.stakingKeeper.(*skeeper.Keeper)).BeginRedelegate(cachedCtx, msg)
if err != nil {
switch {
case errors.Is(err, stypes.ErrSelfRedelegation):
return errors.WrapErrWithCode(errors.SelfRedelegation, err)
case errors.Is(err, stypes.ErrNoValidatorFound):
return errors.WrapErrWithCode(errors.ValidatorNotFound, err)
case errors.Is(err, stypes.ErrTokenTypeMismatch):
return errors.WrapErrWithCode(errors.TokenTypeMismatch, err)
case errors.Is(err, stypes.ErrNoDelegation):
return errors.WrapErrWithCode(errors.DelegationNotFound, err)
case errors.Is(err, stypes.ErrNoPeriodDelegation):
return errors.WrapErrWithCode(errors.PeriodDelegationNotFound, err)
case err != nil:
return errors.Wrap(err, "failed to begin redelegation")
default:
return nil
}

return nil
}

func (k Keeper) ParseRedelegateLog(ethLog ethtypes.Log) (*bindings.IPTokenStakingRedelegate, error) {
Expand Down
12 changes: 10 additions & 2 deletions client/x/evmstaking/keeper/unjail.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"cosmossdk.io/collections"

sdk "github.com/cosmos/cosmos-sdk/types"
slashtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
ethtypes "github.com/ethereum/go-ethereum/core/types"

"github.com/piplabs/story/client/x/evmstaking/types"
Expand Down Expand Up @@ -78,8 +79,15 @@ func (k Keeper) ProcessUnjail(ctx context.Context, ev *bindings.IPTokenStakingUn
}
}

err = k.slashingKeeper.Unjail(cachedCtx, valAddr)
if err != nil {
if err = k.slashingKeeper.Unjail(cachedCtx, valAddr); errors.Is(err, slashtypes.ErrNoValidatorForAddress) {
return errors.WrapErrWithCode(errors.ValidatorNotFound, err)
} else if errors.Is(err, slashtypes.ErrMissingSelfDelegation) {
return errors.WrapErrWithCode(errors.MissingSelfDelegation, err)
} else if errors.Is(err, slashtypes.ErrValidatorNotJailed) {
return errors.WrapErrWithCode(errors.ValidatorNotJailed, err)
} else if errors.Is(err, slashtypes.ErrValidatorJailed) {
return errors.WrapErrWithCode(errors.ValidatorStillJailed, err)
} else if err != nil {
return errors.Wrap(err, "unjail")
}

Expand Down
4 changes: 3 additions & 1 deletion client/x/evmstaking/keeper/update_commission.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ func (k Keeper) ProcessUpdateValidatorCommission(ctx context.Context, ev *bindin

validatorAddr := sdk.ValAddress(validatorPubkey.Address().Bytes())
validator, err := k.stakingKeeper.GetValidator(cachedCtx, validatorAddr)
if err != nil {
if errors.Is(err, stypes.ErrNoValidatorFound) {
return errors.WrapErrWithCode(errors.ValidatorNotFound, err)
} else if err != nil {
return errors.Wrap(err, "get validator")
}

Expand Down
11 changes: 3 additions & 8 deletions client/x/evmstaking/keeper/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,6 @@ func (k Keeper) ProcessCreateValidator(ctx context.Context, ev *bindings.IPToken
}
skeeperMsgServer := skeeper.NewMsgServerImpl(evmstakingSKeeper)

if _, err = k.stakingKeeper.GetValidator(cachedCtx, validatorAddr); err == nil {
ezreal1997 marked this conversation as resolved.
Show resolved Hide resolved
return errors.WrapErrWithCode(errors.ValidatorAlreadyExists, errors.New("validator already exists"))
} else if !errors.Is(err, stypes.ErrNoValidatorFound) {
// Either the validator does not exist, or unknown error.
return errors.Wrap(err, "get validator")
}

moniker := ev.Moniker
if moniker == "" {
moniker = validatorAddr.String() // use validator address as moniker if not provided
Expand Down Expand Up @@ -158,7 +151,9 @@ func (k Keeper) ProcessCreateValidator(ctx context.Context, ev *bindings.IPToken
return errors.Wrap(err, "create stake coin for depositor: send coins")
}

if _, err = skeeperMsgServer.CreateValidator(cachedCtx, msg); errors.Is(err, stypes.ErrCommissionLTMinRate) {
if _, err := skeeperMsgServer.CreateValidator(cachedCtx, msg); errors.Is(err, stypes.ErrValidatorOwnerExists) {
return errors.WrapErrWithCode(errors.ValidatorAlreadyExists, err)
} else if errors.Is(err, stypes.ErrCommissionLTMinRate) {
return errors.WrapErrWithCode(errors.InvalidCommissionRate, err)
} else if errors.Is(err, stypes.ErrMinSelfDelegationBelowMinDelegation) {
return errors.WrapErrWithCode(errors.InvalidMinSelfDelegation, err)
Expand Down
6 changes: 5 additions & 1 deletion client/x/evmstaking/keeper/withdraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,11 @@ func (k Keeper) ProcessWithdraw(ctx context.Context, ev *bindings.IPTokenStaking

// Undelegate from the validator (validator existence is checked in ValidateUnbondAmount)
resp, err := skeeper.NewMsgServerImpl(k.stakingKeeper.(*skeeper.Keeper)).Undelegate(cachedCtx, msg)
if errors.Is(err, stypes.ErrNoPeriodDelegation) {
if errors.Is(err, stypes.ErrNoValidatorFound) {
return errors.WrapErrWithCode(errors.ValidatorNotFound, err)
} else if errors.Is(err, stypes.ErrNoDelegation) {
return errors.WrapErrWithCode(errors.DelegationNotFound, err)
} else if errors.Is(err, stypes.ErrNoPeriodDelegation) {
return errors.WrapErrWithCode(errors.PeriodDelegationNotFound, err)
} else if err != nil {
return errors.Wrap(err, "undelegate")
Expand Down
10 changes: 2 additions & 8 deletions contracts/script/GenerateAlloc.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,10 @@ contract GenerateAlloc is Script {
vm.stopPrank();
bytes32 cancellerRole = TimelockController(payable(timelock)).CANCELLER_ROLE();
vm.prank(protocolAdmin);
TimelockController(payable(timelock)).grantRole(
cancellerRole,
canceller
);
TimelockController(payable(timelock)).grantRole(cancellerRole, canceller);
if (!KEEP_TIMELOCK_ADMIN_ROLE) {
bytes32 adminRole = TimelockController(payable(timelock)).DEFAULT_ADMIN_ROLE();
TimelockController(payable(timelock)).renounceRole(
adminRole,
protocolAdmin
);
TimelockController(payable(timelock)).renounceRole(adminRole, protocolAdmin);
}
vm.stopPrank();
vm.startPrank(deployer);
Expand Down
64 changes: 47 additions & 17 deletions lib/errors/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,50 +8,68 @@ type ErrCode uint32

const (
Unspecified ErrCode = 0
InvalidUncmpPubKey ErrCode = 1
ValidatorNotFound ErrCode = 2
ValidatorAlreadyExists ErrCode = 3
InvalidTokenType ErrCode = 4
InvalidPeriodType ErrCode = 5
UnexpectedCondition ErrCode = 1
ezreal1997 marked this conversation as resolved.
Show resolved Hide resolved
InvalidUncmpPubKey ErrCode = 2
ValidatorNotFound ErrCode = 3
ValidatorAlreadyExists ErrCode = 4
InvalidTokenType ErrCode = 5
InvalidOperator ErrCode = 6
InvalidCommissionRate ErrCode = 7
InvalidMinSelfDelegation ErrCode = 8
InvalidDelegationAmount ErrCode = 9
PeriodDelegationNotFound ErrCode = 10
InvalidRequest ErrCode = 11
UnexpectedCondition ErrCode = 12
InvalidPeriodType ErrCode = 9
InvalidDelegationAmount ErrCode = 10
DelegationNotFound ErrCode = 11
PeriodDelegationNotFound ErrCode = 12
InvalidRequest ErrCode = 13
SelfRedelegation ErrCode = 14
TokenTypeMismatch ErrCode = 15
MissingSelfDelegation ErrCode = 16
ValidatorNotJailed ErrCode = 17
ValidatorStillJailed ErrCode = 18
)

var (
ErrUnspecified = stderrors.New("unspecified")
ErrUnexpectedCondition = stderrors.New("unexpected_condition")
ErrInvalidUncmpPubKey = stderrors.New("invalid_uncompressed_pubkey")
ErrValidatorNotFound = stderrors.New("validator_not_found")
ErrValidatorAlreadyExists = stderrors.New("validator_already_exists")
ErrInvalidTokenType = stderrors.New("invalid_token_type")
ErrInvalidPeriodType = stderrors.New("invalid_period_type")
ErrInvalidOperator = stderrors.New("invalid_operator")
ErrInvalidCommissionRate = stderrors.New("invalid_commission_rate")
ErrInvalidMinSelfDelegation = stderrors.New("invalid_min_self_delegation")
ErrInvalidPeriodType = stderrors.New("invalid_period_type")
ErrInvalidDelegationAmount = stderrors.New("invalid_delegation_amount")
ErrDelegationNotFound = stderrors.New("delegation_not_found")
ErrPeriodDelegationNotFound = stderrors.New("period_delegation_not_found")
ErrInvalidRequest = stderrors.New("invalid_request")
ErrUnexpectedCondition = stderrors.New("unexpected_condition")
ErrSelfRedelegation = stderrors.New("self_redelegation")
ErrTokenTypeMismatch = stderrors.New("token_type_mismatch")
ErrMissingSelfDelegation = stderrors.New("missing_self_delegation")
ErrValidatorNotJailed = stderrors.New("validator_not_jailed")
ErrValidatorStillJailed = stderrors.New("validator_still_jailed")
)

var codeToErr = map[ErrCode]error{
Unspecified: ErrUnspecified,
UnexpectedCondition: ErrUnexpectedCondition,
InvalidUncmpPubKey: ErrInvalidUncmpPubKey,
ValidatorNotFound: ErrValidatorNotFound,
ValidatorAlreadyExists: ErrValidatorAlreadyExists,
InvalidTokenType: ErrInvalidTokenType,
InvalidPeriodType: ErrInvalidPeriodType,
InvalidOperator: ErrInvalidOperator,
InvalidCommissionRate: ErrInvalidCommissionRate,
InvalidMinSelfDelegation: ErrInvalidMinSelfDelegation,
InvalidPeriodType: ErrInvalidPeriodType,
InvalidDelegationAmount: ErrInvalidDelegationAmount,
DelegationNotFound: ErrDelegationNotFound,
PeriodDelegationNotFound: ErrPeriodDelegationNotFound,
InvalidRequest: ErrInvalidRequest,
UnexpectedCondition: ErrUnexpectedCondition,
SelfRedelegation: ErrSelfRedelegation,
TokenTypeMismatch: ErrTokenTypeMismatch,
MissingSelfDelegation: ErrMissingSelfDelegation,
ValidatorNotJailed: ErrValidatorNotJailed,
ValidatorStillJailed: ErrValidatorStillJailed,
}

func (c ErrCode) String() string {
Expand All @@ -75,6 +93,8 @@ func UnwrapErrCode(err error) ErrCode {
switch {
case stderrors.Is(err, ErrUnspecified):
return Unspecified
case stderrors.Is(err, ErrUnexpectedCondition):
return UnexpectedCondition
case stderrors.Is(err, ErrInvalidUncmpPubKey):
return InvalidUncmpPubKey
case stderrors.Is(err, ErrValidatorNotFound):
Expand All @@ -83,22 +103,32 @@ func UnwrapErrCode(err error) ErrCode {
return ValidatorAlreadyExists
case stderrors.Is(err, ErrInvalidTokenType):
return InvalidTokenType
case stderrors.Is(err, ErrInvalidPeriodType):
return InvalidPeriodType
case stderrors.Is(err, ErrInvalidOperator):
return InvalidOperator
case stderrors.Is(err, ErrInvalidCommissionRate):
return InvalidCommissionRate
case stderrors.Is(err, ErrInvalidMinSelfDelegation):
return InvalidMinSelfDelegation
case stderrors.Is(err, ErrInvalidPeriodType):
return InvalidPeriodType
case stderrors.Is(err, ErrInvalidDelegationAmount):
return InvalidDelegationAmount
case stderrors.Is(err, ErrDelegationNotFound):
return DelegationNotFound
case stderrors.Is(err, ErrPeriodDelegationNotFound):
return PeriodDelegationNotFound
case stderrors.Is(err, ErrInvalidRequest):
return InvalidRequest
case stderrors.Is(err, ErrUnexpectedCondition):
return UnexpectedCondition
case stderrors.Is(err, ErrSelfRedelegation):
return SelfRedelegation
case stderrors.Is(err, ErrTokenTypeMismatch):
return TokenTypeMismatch
case stderrors.Is(err, ErrMissingSelfDelegation):
return MissingSelfDelegation
case stderrors.Is(err, ErrValidatorNotJailed):
return ValidatorNotJailed
case stderrors.Is(err, ErrValidatorStillJailed):
return ValidatorStillJailed
default:
return Unspecified
}
Expand Down
Loading