Skip to content

Commit

Permalink
[Stablestake]: Dynamic Redemption Rate Implementation (#832)
Browse files Browse the repository at this point in the history
* add redemption rate

* add tests

* fix

* update

* fix
  • Loading branch information
amityadav0 authored Oct 1, 2024
1 parent 95feaae commit cc69188
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 5 deletions.
2 changes: 2 additions & 0 deletions x/stablestake/keeper/begin_blocker.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ func (k Keeper) BeginBlocker(ctx sdk.Context) {
if epochPosition == 0 { // if epoch has passed
rate := k.InterestRateComputation(ctx)
params.InterestRate = rate

params.RedemptionRate = k.GetRedemptionRate(ctx)
k.SetParams(ctx, params)
}
k.SetInterest(ctx, uint64(ctx.BlockHeight()), types.InterestBlock{InterestRate: params.InterestRate, BlockTime: ctx.BlockTime().Unix(), BlockHeight: uint64(ctx.BlockHeight())})
Expand Down
8 changes: 5 additions & 3 deletions x/stablestake/keeper/msg_server_bond.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func (k msgServer) Bond(goCtx context.Context, msg *types.MsgBond) (*types.MsgBo

params := k.GetParams(ctx)
creator := sdk.MustAccAddressFromBech32(msg.Creator)
redemptionRate := k.GetRedemptionRate(ctx)

depositDenom := k.GetDepositDenom(ctx)
depositCoin := sdk.NewCoin(depositDenom, msg.Amount)
Expand All @@ -24,10 +25,11 @@ func (k msgServer) Bond(goCtx context.Context, msg *types.MsgBond) (*types.MsgBo
}

shareDenom := types.GetShareDenom()
if params.RedemptionRate.IsZero() {
return nil, types.ErrRedemptionRateIsZero
// Initial case
if redemptionRate.IsZero() {
redemptionRate = sdk.OneDec()
}
shareAmount := sdk.NewDecFromInt(depositCoin.Amount).Quo(params.RedemptionRate).RoundInt()
shareAmount := sdk.NewDecFromInt(depositCoin.Amount).Quo(redemptionRate).RoundInt()
shareCoins := sdk.NewCoins(sdk.NewCoin(shareDenom, shareAmount))

err = k.bk.MintCoins(ctx, types.ModuleName, shareCoins)
Expand Down
3 changes: 2 additions & 1 deletion x/stablestake/keeper/msg_server_unbond.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ func (k msgServer) Unbond(goCtx context.Context, msg *types.MsgUnbond) (*types.M

params := k.GetParams(ctx)
creator := sdk.MustAccAddressFromBech32(msg.Creator)
redemptionRate := k.GetRedemptionRate(ctx)

shareDenom := types.GetShareDenom()

Expand All @@ -33,7 +34,7 @@ func (k msgServer) Unbond(goCtx context.Context, msg *types.MsgUnbond) (*types.M
return nil, err
}

redemptionAmount := sdk.NewDecFromInt(shareCoin.Amount).Mul(params.RedemptionRate).RoundInt()
redemptionAmount := sdk.NewDecFromInt(shareCoin.Amount).Mul(redemptionRate).RoundInt()

depositDenom := k.GetDepositDenom(ctx)
redemptionCoin := sdk.NewCoin(depositDenom, redemptionAmount)
Expand Down
3 changes: 2 additions & 1 deletion x/stablestake/keeper/msg_server_unbond_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ func (suite *KeeperTestSuite) TestUnbond() {
suite.Require().NoError(err)

params := suite.app.StablestakeKeeper.GetParams(suite.ctx)
params.TotalValue = sdk.NewInt(1000_000_000)
params.TotalValue = sdk.NewInt(1000_000)
params.RedemptionRate = sdk.NewDec(1)
suite.app.StablestakeKeeper.SetParams(suite.ctx, params)

msgServer := keeper.NewMsgServerImpl(suite.app.StablestakeKeeper)
Expand Down
11 changes: 11 additions & 0 deletions x/stablestake/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,14 @@ func (k Keeper) GetDepositDenom(ctx sdk.Context) string {
}
return entry.Denom
}

func (k Keeper) GetRedemptionRate(ctx sdk.Context) sdk.Dec {
params := k.GetParams(ctx)
totalShares := k.bk.GetSupply(ctx, types.GetShareDenom())

if totalShares.Amount.IsZero() {
return sdk.ZeroDec()
}

return params.TotalValue.ToLegacyDec().Quo(totalShares.Amount.ToLegacyDec())
}
68 changes: 68 additions & 0 deletions x/stablestake/keeper/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ package keeper_test
import (
"testing"

"cosmossdk.io/math"
"github.com/cometbft/cometbft/crypto/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
testkeeper "github.com/elys-network/elys/testutil/keeper"
ptypes "github.com/elys-network/elys/x/parameter/types"
"github.com/elys-network/elys/x/stablestake/keeper"
"github.com/elys-network/elys/x/stablestake/types"
"github.com/stretchr/testify/require"
)
Expand All @@ -16,3 +22,65 @@ func TestGetParams(t *testing.T) {

require.EqualValues(t, params, k.GetParams(ctx))
}

func (suite *KeeperTestSuite) TestGetRedemptionRate() {
for _, tc := range []struct {
desc string
senderInitBalance sdk.Coins
bondAmount math.Int
expSenderBalance sdk.Coins
expSenderCommit sdk.Coin
expPass bool
}{
{
desc: "successful bonding process, redemption should be set",
senderInitBalance: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
bondAmount: sdk.NewInt(10000),
expSenderBalance: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 990000)}.Sort(),
expSenderCommit: sdk.NewInt64Coin(types.GetShareDenom(), 10000),
expPass: true,
},
{
desc: "lack of balance, redemption should not be set",
senderInitBalance: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
bondAmount: sdk.NewInt(10000000000000),
expSenderBalance: sdk.Coins{sdk.NewInt64Coin(ptypes.BaseCurrency, 1000000)},
expSenderCommit: sdk.Coin{},
expPass: false,
},
} {
suite.Run(tc.desc, func() {
suite.SetupTest()

// bootstrap accounts
sender := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())

// bootstrap balances
err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, tc.senderInitBalance)
suite.Require().NoError(err)
err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, minttypes.ModuleName, sender, tc.senderInitBalance)
suite.Require().NoError(err)

msgServer := keeper.NewMsgServerImpl(suite.app.StablestakeKeeper)
_, err = msgServer.Bond(
sdk.WrapSDKContext(suite.ctx),
&types.MsgBond{
Creator: sender.String(),
Amount: tc.bondAmount,
})
if !tc.expPass {
suite.Require().Error(err)

// Check redemption rate
rate := suite.app.StablestakeKeeper.GetRedemptionRate(suite.ctx)
suite.Require().Equal(sdk.ZeroDec(), rate)
} else {
suite.Require().NoError(err)

// Check redemption rate
rate := suite.app.StablestakeKeeper.GetRedemptionRate(suite.ctx)
suite.Require().Equal(sdk.NewDec(1), rate)
}
})
}
}
1 change: 1 addition & 0 deletions x/stablestake/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type AccountKeeper interface {
// BankKeeper defines the expected interface needed to retrieve account balances.
type BankKeeper interface {
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
GetSupply(ctx sdk.Context, denom string) sdk.Coin
MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
Expand Down

0 comments on commit cc69188

Please sign in to comment.