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 inner bounds #938

Merged
merged 14 commits into from
Sep 18, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/Stride-Labs/stride/v14/x/stakeibc/types"
Expand All @@ -27,13 +28,15 @@ func (k msgServer) UpdateInnerRedemptionRateBounds(goCtx context.Context, msg *t

// Confirm the inner bounds are within the outer bounds
if innerMinSafetyThreshold.LT(outerMinSafetyThreshold) {
k.Logger(ctx).Error(fmt.Sprintf("Inner min safety threshold (%s) is less than outer min safety threshold (%s)", innerMinSafetyThreshold, outerMinSafetyThreshold))
return nil, types.ErrInvalidBounds
errMsg := fmt.Sprintf("inner min safety threshold (%s) is less than outer min safety threshold (%s)", innerMinSafetyThreshold, outerMinSafetyThreshold)
k.Logger(ctx).Error(errMsg)
return nil, errorsmod.Wrapf(types.ErrInvalidBounds, errMsg)
}

if innerMaxSafetyThreshold.GT(outerMaxSafetyThreshold) {
k.Logger(ctx).Error(fmt.Sprintf("Inner max safety threshold (%s) is greater than outer max safety threshold (%s)", innerMaxSafetyThreshold, outerMaxSafetyThreshold))
return nil, types.ErrInvalidBounds
errMsg := fmt.Sprintf("inner max safety threshold (%s) is greater than outer max safety threshold (%s)", innerMaxSafetyThreshold, outerMaxSafetyThreshold)
k.Logger(ctx).Error(errMsg)
return nil, errorsmod.Wrapf(types.ErrInvalidBounds, errMsg)
}

// Set the inner bounds on the host zone
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,111 @@
package keeper
package keeper_test

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
_ "github.com/stretchr/testify/suite"

stakeibctypes "github.com/Stride-Labs/stride/v14/x/stakeibc/types"
)

type UpdateInnerRedemptionRateBoundsTestCase struct {
validMsg stakeibctypes.MsgUpdateInnerRedemptionRateBounds
zone stakeibctypes.HostZone
}

func (s *KeeperTestSuite) SetupUpdateInnerRedemptionRateBounds() UpdateInnerRedemptionRateBoundsTestCase {
// Register a host zone
hostZone := stakeibctypes.HostZone{
ChainId: HostChainId,
HostDenom: Atom,
IbcDenom: IbcAtom,
RedemptionRate: sdk.NewDec(1.0),
MinRedemptionRate: sdk.NewDec(9).Quo(sdk.NewDec(10)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: it's a bit easier to read if you create these with MustNewDecFromStr

MaxRedemptionRate: sdk.NewDec(15).Quo(sdk.NewDec(10)),
}

s.App.StakeibcKeeper.SetHostZone(s.Ctx, hostZone)

defaultMsg := stakeibctypes.MsgUpdateInnerRedemptionRateBounds{
// TODO: does this need to be the admin address?
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think so cause I don't think validate basic is run when you call the msg server function directly

Creator: s.TestAccs[0].String(),
ChainId: HostChainId,
MinInnerRedemptionRate: sdk.NewDec(1),
MaxInnerRedemptionRate: sdk.NewDec(11).Quo(sdk.NewDec(10)),
}

return UpdateInnerRedemptionRateBoundsTestCase{
validMsg: defaultMsg,
zone: hostZone,
}
}

// Verify that bounds can be set successfully
func (s *KeeperTestSuite) TestUpdateInnerRedemptionRateBounds_Success() {
tc := s.SetupUpdateInnerRedemptionRateBounds()

// Set the inner bounds on the host zone
_, err := s.GetMsgServer().UpdateInnerRedemptionRateBounds(s.Ctx, &tc.validMsg)
s.Require().NoError(err, "should not throw an error")

// Confirm the inner bounds were set
zone, found := s.App.StakeibcKeeper.GetHostZone(s.Ctx, HostChainId)
s.Require().True(found, "host zone should be in the store")
s.Require().Equal(tc.validMsg.MinInnerRedemptionRate, zone.MinInnerRedemptionRate, "min inner redemption rate should be set")
s.Require().Equal(tc.validMsg.MaxInnerRedemptionRate, zone.MaxInnerRedemptionRate, "max inner redemption rate should be set")
}

// Setting inner bounds outside of outer bounds should throw an error
func (s *KeeperTestSuite) TestUpdateInnerRedemptionRateBounds_OutOfBounds() {
tc := s.SetupUpdateInnerRedemptionRateBounds()

// Set the min inner bound to be less than the min outer bound
tc.validMsg.MinInnerRedemptionRate = sdk.NewDec(0)

// Set the inner bounds on the host zone
_, err := s.GetMsgServer().UpdateInnerRedemptionRateBounds(s.Ctx, &tc.validMsg)
// verify it throws an error
errMsg := fmt.Sprintf("inner min safety threshold (%s) is less than outer min safety threshold (%s)", tc.validMsg.MinInnerRedemptionRate, sdk.NewDec(9).Quo(sdk.NewDec(10)))
s.Require().ErrorContains(err, errMsg)

// Set the min inner bound to be valid, but the max inner bound to be greater than the max outer bound
tc.validMsg.MinInnerRedemptionRate = sdk.NewDec(1)
tc.validMsg.MaxInnerRedemptionRate = sdk.NewDec(3)
// Set the inner bounds on the host zone
_, err = s.GetMsgServer().UpdateInnerRedemptionRateBounds(s.Ctx, &tc.validMsg)
// verify it throws an error
errMsg = fmt.Sprintf("inner max safety threshold (%s) is greater than outer max safety threshold (%s)", tc.validMsg.MaxInnerRedemptionRate, sdk.NewDec(15).Quo(sdk.NewDec(10)))
s.Require().ErrorContains(err, errMsg)
}

// Validate basic tests
func (s *KeeperTestSuite) TestUpdateInnerRedemptionRateBounds_InvalidMsg() {
tc := s.SetupUpdateInnerRedemptionRateBounds()

// Set the min inner bound to be greater than than the max inner bound
invalidMsg := tc.validMsg
invalidMsg.MinInnerRedemptionRate = sdk.NewDec(2)

err := invalidMsg.ValidateBasic()

// Verify the error
errMsg := fmt.Sprintf("Inner max safety threshold (%s) is less than inner min safety threshold (%s)", invalidMsg.MaxInnerRedemptionRate, invalidMsg.MinInnerRedemptionRate)
s.Require().ErrorContains(err, errMsg)
}

// Verify that if inner bounds end up outside of outer bounds (somehow), the outer bounds are returned
func (s *KeeperTestSuite) TestGetInnerSafetyBounds() {
tc := s.SetupUpdateInnerRedemptionRateBounds()

// Set the inner bounds outside the outer bounds on the host zone directly
tc.zone.MinInnerRedemptionRate = sdk.NewDec(0)
tc.zone.MaxInnerRedemptionRate = sdk.NewDec(3)
// Set the host zone
s.App.StakeibcKeeper.SetHostZone(s.Ctx, tc.zone)

// Get the inner bounds and verify the outer bounds are used
innerMinSafetyThreshold, innerMaxSafetyThreshold := s.App.StakeibcKeeper.GetInnerSafetyBounds(s.Ctx, tc.zone)
s.Require().Equal(tc.zone.MinRedemptionRate, innerMinSafetyThreshold, "min inner redemption rate should be set")
s.Require().Equal(tc.zone.MaxRedemptionRate, innerMaxSafetyThreshold, "max inner redemption rate should be set")
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (msg *MsgUpdateInnerRedemptionRateBounds) ValidateBasic() error {
return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err)
}
// Confirm the max is greater than the min
if msg.MaxInnerRedemptionRate.LTE(msg.MaxInnerRedemptionRate) {
if msg.MaxInnerRedemptionRate.LTE(msg.MinInnerRedemptionRate) {
return errorsmod.Wrapf(ErrInvalidBounds, "Inner max safety threshold (%s) is less than inner min safety threshold (%s)", msg.MaxInnerRedemptionRate, msg.MinInnerRedemptionRate)
}
if err := utils.ValidateAdminAddress(msg.Creator); err != nil {
Expand Down