Merge pull request #690 from cosmos/sunny/keeper-based-modules
Keeper based modules
This commit is contained in:
commit
d0eb05b162
|
@ -19,7 +19,6 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/sketchy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -58,15 +57,14 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||||
|
|
||||||
// add handlers
|
// add handlers
|
||||||
coinKeeper := bank.NewCoinKeeper(app.accountMapper)
|
coinKeeper := bank.NewCoinKeeper(app.accountMapper)
|
||||||
coolMapper := cool.NewMapper(app.capKeyMainStore)
|
coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper)
|
||||||
ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore)
|
ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore)
|
||||||
stakingMapper := staking.NewMapper(app.capKeyStakingStore)
|
stakeKeeper := staking.NewKeeper(app.capKeyStakingStore, coinKeeper)
|
||||||
app.Router().
|
app.Router().
|
||||||
AddRoute("bank", bank.NewHandler(coinKeeper)).
|
AddRoute("bank", bank.NewHandler(coinKeeper)).
|
||||||
AddRoute("cool", cool.NewHandler(coinKeeper, coolMapper)).
|
AddRoute("cool", cool.NewHandler(coolKeeper)).
|
||||||
AddRoute("sketchy", sketchy.NewHandler()).
|
|
||||||
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)).
|
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)).
|
||||||
AddRoute("staking", staking.NewHandler(stakingMapper, coinKeeper))
|
AddRoute("staking", staking.NewHandler(stakeKeeper))
|
||||||
|
|
||||||
// initialize BaseApp
|
// initialize BaseApp
|
||||||
app.SetTxDecoder(app.txDecoder)
|
app.SetTxDecoder(app.txDecoder)
|
||||||
|
|
|
@ -259,12 +259,12 @@ func TestQuizMsg(t *testing.T) {
|
||||||
SignCheckDeliver(t, bapp, setTrendMsg1, 0, true)
|
SignCheckDeliver(t, bapp, setTrendMsg1, 0, true)
|
||||||
SignCheckDeliver(t, bapp, quizMsg1, 1, true)
|
SignCheckDeliver(t, bapp, quizMsg1, 1, true)
|
||||||
CheckBalance(t, bapp, "69icecold")
|
CheckBalance(t, bapp, "69icecold")
|
||||||
SignCheckDeliver(t, bapp, quizMsg2, 2, true) // result without reward
|
SignCheckDeliver(t, bapp, quizMsg2, 2, false) // result without reward
|
||||||
CheckBalance(t, bapp, "69icecold")
|
CheckBalance(t, bapp, "69icecold")
|
||||||
SignCheckDeliver(t, bapp, quizMsg1, 3, true)
|
SignCheckDeliver(t, bapp, quizMsg1, 3, true)
|
||||||
CheckBalance(t, bapp, "138icecold")
|
CheckBalance(t, bapp, "138icecold")
|
||||||
SignCheckDeliver(t, bapp, setTrendMsg2, 4, true) // reset the trend
|
SignCheckDeliver(t, bapp, setTrendMsg2, 4, true) // reset the trend
|
||||||
SignCheckDeliver(t, bapp, quizMsg1, 5, true) // the same answer will nolonger do!
|
SignCheckDeliver(t, bapp, quizMsg1, 5, false) // the same answer will nolonger do!
|
||||||
CheckBalance(t, bapp, "138icecold")
|
CheckBalance(t, bapp, "138icecold")
|
||||||
SignCheckDeliver(t, bapp, quizMsg2, 6, true) // earlier answer now relavent again
|
SignCheckDeliver(t, bapp, quizMsg2, 6, true) // earlier answer now relavent again
|
||||||
CheckBalance(t, bapp, "69badvibesonly,138icecold")
|
CheckBalance(t, bapp, "69badvibesonly,138icecold")
|
||||||
|
@ -325,6 +325,7 @@ func TestHandler(t *testing.T) {
|
||||||
SignCheckDeliver(t, bapp, receiveMsg, 3, false)
|
SignCheckDeliver(t, bapp, receiveMsg, 3, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO describe the use of this function
|
||||||
func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq int64, expPass bool) {
|
func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq int64, expPass bool) {
|
||||||
|
|
||||||
// Sign the tx
|
// Sign the tx
|
||||||
|
@ -350,6 +351,8 @@ func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq int64, e
|
||||||
} else {
|
} else {
|
||||||
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
|
require.NotEqual(t, sdk.CodeOK, res.Code, res.Log)
|
||||||
}
|
}
|
||||||
|
bapp.EndBlock(abci.RequestEndBlock{})
|
||||||
|
//bapp.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckBalance(t *testing.T, bapp *BasecoinApp, balExpected string) {
|
func CheckBalance(t *testing.T, bapp *BasecoinApp, balExpected string) {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package cool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Cool module reserves error 400-499 lawl
|
||||||
|
CodeIncorrectCoolAnswer sdk.CodeType = 400
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrIncorrectCoolAnswer - Error returned upon an incorrect guess
|
||||||
|
func ErrIncorrectCoolAnswer(answer string) sdk.Error {
|
||||||
|
return sdk.NewError(CodeIncorrectCoolAnswer, fmt.Sprintf("Incorrect cool answer: %v", answer))
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is just an example to demonstrate a functional custom module
|
// This is just an example to demonstrate a functional custom module
|
||||||
|
@ -18,14 +17,14 @@ import (
|
||||||
//| $$$$$$$| $$$$$$/| $$$$$$/| $$$$$$$
|
//| $$$$$$$| $$$$$$/| $$$$$$/| $$$$$$$
|
||||||
// \_______/ \______/ \______/ |______/
|
// \_______/ \______/ \______/ |______/
|
||||||
|
|
||||||
// Handle all "coolmodule" type objects
|
// NewHandler returns a handler for "cool" type messages.
|
||||||
func NewHandler(ck bank.CoinKeeper, cm Mapper) sdk.Handler {
|
func NewHandler(k Keeper) sdk.Handler {
|
||||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case SetTrendMsg:
|
case SetTrendMsg:
|
||||||
return handleSetTrendMsg(ctx, cm, msg)
|
return handleSetTrendMsg(ctx, k, msg)
|
||||||
case QuizMsg:
|
case QuizMsg:
|
||||||
return handleQuizMsg(ctx, ck, cm, msg)
|
return handleQuizMsg(ctx, k, msg)
|
||||||
default:
|
default:
|
||||||
errMsg := fmt.Sprintf("Unrecognized cool Msg type: %v", reflect.TypeOf(msg).Name())
|
errMsg := fmt.Sprintf("Unrecognized cool Msg type: %v", reflect.TypeOf(msg).Name())
|
||||||
return sdk.ErrUnknownRequest(errMsg).Result()
|
return sdk.ErrUnknownRequest(errMsg).Result()
|
||||||
|
@ -34,22 +33,29 @@ func NewHandler(ck bank.CoinKeeper, cm Mapper) sdk.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle QuizMsg This is the engine of your module
|
// Handle QuizMsg This is the engine of your module
|
||||||
func handleSetTrendMsg(ctx sdk.Context, cm Mapper, msg SetTrendMsg) sdk.Result {
|
func handleSetTrendMsg(ctx sdk.Context, k Keeper, msg SetTrendMsg) sdk.Result {
|
||||||
cm.SetTrend(ctx, msg.Cool)
|
k.setTrend(ctx, msg.Cool)
|
||||||
return sdk.Result{}
|
return sdk.Result{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle QuizMsg This is the engine of your module
|
// Handle QuizMsg This is the engine of your module
|
||||||
func handleQuizMsg(ctx sdk.Context, ck bank.CoinKeeper, cm Mapper, msg QuizMsg) sdk.Result {
|
func handleQuizMsg(ctx sdk.Context, k Keeper, msg QuizMsg) sdk.Result {
|
||||||
|
|
||||||
currentTrend := cm.GetTrend(ctx)
|
correct := k.CheckTrend(ctx, msg.CoolAnswer)
|
||||||
|
|
||||||
if msg.CoolAnswer == currentTrend {
|
if !correct {
|
||||||
bonusCoins := sdk.Coins{{currentTrend, 69}}
|
return ErrIncorrectCoolAnswer(msg.CoolAnswer).Result()
|
||||||
_, err := ck.AddCoins(ctx, msg.Sender, bonusCoins)
|
}
|
||||||
if err != nil {
|
|
||||||
return err.Result()
|
if ctx.IsCheckTx() {
|
||||||
}
|
return sdk.Result{} // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
bonusCoins := sdk.Coins{{msg.CoolAnswer, 69}}
|
||||||
|
|
||||||
|
_, err := k.ck.AddCoins(ctx, msg.Sender, bonusCoins)
|
||||||
|
if err != nil {
|
||||||
|
return err.Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
return sdk.Result{}
|
return sdk.Result{}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package cool
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keeper - handlers sets/gets of custom variables for your module
|
||||||
|
type Keeper struct {
|
||||||
|
ck bank.CoinKeeper
|
||||||
|
|
||||||
|
storeKey sdk.StoreKey // The (unexposed) key used to access the store from the Context.
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewKeeper - Returns the Keeper
|
||||||
|
func NewKeeper(key sdk.StoreKey, bankKeeper bank.CoinKeeper) Keeper {
|
||||||
|
return Keeper{bankKeeper, key}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key to knowing the trend on the streets!
|
||||||
|
var trendKey = []byte("TrendKey")
|
||||||
|
|
||||||
|
// GetTrend - returns the current cool trend
|
||||||
|
func (k Keeper) GetTrend(ctx sdk.Context) string {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
bz := store.Get(trendKey)
|
||||||
|
return string(bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements sdk.AccountMapper.
|
||||||
|
func (k Keeper) setTrend(ctx sdk.Context, newTrend string) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
store.Set(trendKey, []byte(newTrend))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckTrend - Returns true or false based on whether guessedTrend is currently cool or not
|
||||||
|
func (k Keeper) CheckTrend(ctx sdk.Context, guessedTrend string) bool {
|
||||||
|
if guessedTrend == k.GetTrend(ctx) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -1,30 +0,0 @@
|
||||||
package cool
|
|
||||||
|
|
||||||
import (
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This Cool Mapper handlers sets/gets of custom variables for your module
|
|
||||||
type Mapper struct {
|
|
||||||
key sdk.StoreKey // The (unexposed) key used to access the store from the Context.
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMapper(key sdk.StoreKey) Mapper {
|
|
||||||
return Mapper{key}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key to knowing the trend on the streets!
|
|
||||||
var trendKey = []byte("TrendKey")
|
|
||||||
|
|
||||||
// Implements sdk.AccountMapper.
|
|
||||||
func (am Mapper) GetTrend(ctx sdk.Context) string {
|
|
||||||
store := ctx.KVStore(am.key)
|
|
||||||
bz := store.Get(trendKey)
|
|
||||||
return string(bz)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements sdk.AccountMapper.
|
|
||||||
func (am Mapper) SetTrend(ctx sdk.Context, newTrend string) {
|
|
||||||
store := ctx.KVStore(am.key)
|
|
||||||
store.Set(trendKey, []byte(newTrend))
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handle all "bank" type messages.
|
// NewHandler returns a handler for "bank" type messages.
|
||||||
func NewHandler(ck CoinKeeper) sdk.Handler {
|
func NewHandler(ck CoinKeeper) sdk.Handler {
|
||||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
|
@ -25,18 +25,9 @@ func NewHandler(ck CoinKeeper) sdk.Handler {
|
||||||
func handleSendMsg(ctx sdk.Context, ck CoinKeeper, msg SendMsg) sdk.Result {
|
func handleSendMsg(ctx sdk.Context, ck CoinKeeper, msg SendMsg) sdk.Result {
|
||||||
// NOTE: totalIn == totalOut should already have been checked
|
// NOTE: totalIn == totalOut should already have been checked
|
||||||
|
|
||||||
for _, in := range msg.Inputs {
|
err := ck.InputOutputCoins(ctx, msg.Inputs, msg.Outputs)
|
||||||
_, err := ck.SubtractCoins(ctx, in.Address, in.Coins)
|
if err != nil {
|
||||||
if err != nil {
|
return err.Result()
|
||||||
return err.Result()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, out := range msg.Outputs {
|
|
||||||
_, err := ck.AddCoins(ctx, out.Address, out.Coins)
|
|
||||||
if err != nil {
|
|
||||||
return err.Result()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add some tags so we can search it!
|
// TODO: add some tags so we can search it!
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const moduleName = "bank"
|
||||||
|
|
||||||
// CoinKeeper manages transfers between accounts
|
// CoinKeeper manages transfers between accounts
|
||||||
type CoinKeeper struct {
|
type CoinKeeper struct {
|
||||||
am sdk.AccountMapper
|
am sdk.AccountMapper
|
||||||
|
@ -16,6 +18,12 @@ func NewCoinKeeper(am sdk.AccountMapper) CoinKeeper {
|
||||||
return CoinKeeper{am: am}
|
return CoinKeeper{am: am}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCoins returns the coins at the addr.
|
||||||
|
func (ck CoinKeeper) GetCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coins) sdk.Coins {
|
||||||
|
acc := ck.am.GetAccount(ctx, addr)
|
||||||
|
return acc.GetCoins()
|
||||||
|
}
|
||||||
|
|
||||||
// SubtractCoins subtracts amt from the coins at the addr.
|
// SubtractCoins subtracts amt from the coins at the addr.
|
||||||
func (ck CoinKeeper) SubtractCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Error) {
|
func (ck CoinKeeper) SubtractCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Error) {
|
||||||
acc := ck.am.GetAccount(ctx, addr)
|
acc := ck.am.GetAccount(ctx, addr)
|
||||||
|
@ -48,3 +56,37 @@ func (ck CoinKeeper) AddCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coins)
|
||||||
ck.am.SetAccount(ctx, acc)
|
ck.am.SetAccount(ctx, acc)
|
||||||
return newCoins, nil
|
return newCoins, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendCoins moves coins from one account to another
|
||||||
|
func (ck CoinKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.Address, toAddr sdk.Address, amt sdk.Coins) sdk.Error {
|
||||||
|
_, err := ck.SubtractCoins(ctx, fromAddr, amt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = ck.AddCoins(ctx, toAddr, amt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InputOutputCoins handles a list of inputs and outputs
|
||||||
|
func (ck CoinKeeper) InputOutputCoins(ctx sdk.Context, inputs []Input, outputs []Output) sdk.Error {
|
||||||
|
for _, in := range inputs {
|
||||||
|
_, err := ck.SubtractCoins(ctx, in.Address, in.Coins)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, out := range outputs {
|
||||||
|
_, err := ck.AddCoins(ctx, out.Address, out.Coins)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -6,11 +6,16 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Staking errors reserve 300 - 399.
|
// Staking errors reserve 300 - 399.
|
||||||
CodeEmptyValidator sdk.CodeType = 300
|
CodeEmptyValidator sdk.CodeType = 300
|
||||||
CodeInvalidUnbond sdk.CodeType = 301
|
CodeInvalidUnbond sdk.CodeType = 301
|
||||||
CodeEmptyStake sdk.CodeType = 302
|
CodeEmptyStake sdk.CodeType = 302
|
||||||
|
CodeIncorrectStakingToken sdk.CodeType = 303
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ErrIncorrectStakingToken() sdk.Error {
|
||||||
|
return newError(CodeIncorrectStakingToken, "")
|
||||||
|
}
|
||||||
|
|
||||||
func ErrEmptyValidator() sdk.Error {
|
func ErrEmptyValidator() sdk.Error {
|
||||||
return newError(CodeEmptyValidator, "")
|
return newError(CodeEmptyValidator, "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,29 +4,24 @@ import (
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewHandler(sm StakingMapper, ck bank.CoinKeeper) sdk.Handler {
|
// NewHandler returns a handler for "bank" type messages.
|
||||||
|
func NewHandler(k Keeper) sdk.Handler {
|
||||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case BondMsg:
|
case BondMsg:
|
||||||
return handleBondMsg(ctx, sm, ck, msg)
|
return handleBondMsg(ctx, k, msg)
|
||||||
case UnbondMsg:
|
case UnbondMsg:
|
||||||
return handleUnbondMsg(ctx, sm, ck, msg)
|
return handleUnbondMsg(ctx, k, msg)
|
||||||
default:
|
default:
|
||||||
return sdk.ErrUnknownRequest("No match for message type.").Result()
|
return sdk.ErrUnknownRequest("No match for message type.").Result()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleBondMsg(ctx sdk.Context, sm StakingMapper, ck bank.CoinKeeper, msg BondMsg) sdk.Result {
|
func handleBondMsg(ctx sdk.Context, k Keeper, msg BondMsg) sdk.Result {
|
||||||
_, err := ck.SubtractCoins(ctx, msg.Address, []sdk.Coin{msg.Stake})
|
power, err := k.Bond(ctx, msg.Address, msg.PubKey, msg.Stake)
|
||||||
if err != nil {
|
|
||||||
return err.Result()
|
|
||||||
}
|
|
||||||
|
|
||||||
power, err := sm.Bond(ctx, msg.Address, msg.PubKey, msg.Stake.Amount)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.Result()
|
return err.Result()
|
||||||
}
|
}
|
||||||
|
@ -42,17 +37,8 @@ func handleBondMsg(ctx sdk.Context, sm StakingMapper, ck bank.CoinKeeper, msg Bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUnbondMsg(ctx sdk.Context, sm StakingMapper, ck bank.CoinKeeper, msg UnbondMsg) sdk.Result {
|
func handleUnbondMsg(ctx sdk.Context, k Keeper, msg UnbondMsg) sdk.Result {
|
||||||
pubKey, power, err := sm.Unbond(ctx, msg.Address)
|
pubKey, _, err := k.Unbond(ctx, msg.Address)
|
||||||
if err != nil {
|
|
||||||
return err.Result()
|
|
||||||
}
|
|
||||||
|
|
||||||
stake := sdk.Coin{
|
|
||||||
Denom: "mycoin",
|
|
||||||
Amount: power,
|
|
||||||
}
|
|
||||||
_, err = ck.AddCoins(ctx, msg.Address, sdk.Coins{stake})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.Result()
|
return err.Result()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
package staking
|
||||||
|
|
||||||
|
import (
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
)
|
||||||
|
|
||||||
|
const stakingToken = "steak"
|
||||||
|
|
||||||
|
type Keeper struct {
|
||||||
|
ck bank.CoinKeeper
|
||||||
|
|
||||||
|
key sdk.StoreKey
|
||||||
|
cdc *wire.Codec
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKeeper(key sdk.StoreKey, coinKeeper bank.CoinKeeper) Keeper {
|
||||||
|
cdc := wire.NewCodec()
|
||||||
|
return Keeper{
|
||||||
|
key: key,
|
||||||
|
cdc: cdc,
|
||||||
|
ck: coinKeeper,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Keeper) getBondInfo(ctx sdk.Context, addr sdk.Address) bondInfo {
|
||||||
|
store := ctx.KVStore(k.key)
|
||||||
|
bz := store.Get(addr)
|
||||||
|
if bz == nil {
|
||||||
|
return bondInfo{}
|
||||||
|
}
|
||||||
|
var bi bondInfo
|
||||||
|
err := k.cdc.UnmarshalBinary(bz, &bi)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return bi
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Keeper) setBondInfo(ctx sdk.Context, addr sdk.Address, bi bondInfo) {
|
||||||
|
store := ctx.KVStore(k.key)
|
||||||
|
bz, err := k.cdc.MarshalBinary(bi)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
store.Set(addr, bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Keeper) deleteBondInfo(ctx sdk.Context, addr sdk.Address) {
|
||||||
|
store := ctx.KVStore(k.key)
|
||||||
|
store.Delete(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Keeper) Bond(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, stake sdk.Coin) (int64, sdk.Error) {
|
||||||
|
if stake.Denom != stakingToken {
|
||||||
|
return 0, ErrIncorrectStakingToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := k.ck.SubtractCoins(ctx, addr, []sdk.Coin{stake})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bi := k.getBondInfo(ctx, addr)
|
||||||
|
if bi.isEmpty() {
|
||||||
|
bi = bondInfo{
|
||||||
|
PubKey: pubKey,
|
||||||
|
Power: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bi.Power = bi.Power + stake.Amount
|
||||||
|
|
||||||
|
k.setBondInfo(ctx, addr, bi)
|
||||||
|
return bi.Power, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Keeper) Unbond(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, sdk.Error) {
|
||||||
|
bi := k.getBondInfo(ctx, addr)
|
||||||
|
if bi.isEmpty() {
|
||||||
|
return crypto.PubKey{}, 0, ErrInvalidUnbond()
|
||||||
|
}
|
||||||
|
k.deleteBondInfo(ctx, addr)
|
||||||
|
|
||||||
|
returnedBond := sdk.Coin{stakingToken, bi.Power}
|
||||||
|
|
||||||
|
_, err := k.ck.AddCoins(ctx, addr, []sdk.Coin{returnedBond})
|
||||||
|
if err != nil {
|
||||||
|
return bi.PubKey, bi.Power, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bi.PubKey, bi.Power, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR TESTING PURPOSES -------------------------------------------------
|
||||||
|
|
||||||
|
func (k Keeper) bondWithoutCoins(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, stake sdk.Coin) (int64, sdk.Error) {
|
||||||
|
if stake.Denom != stakingToken {
|
||||||
|
return 0, ErrIncorrectStakingToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
bi := k.getBondInfo(ctx, addr)
|
||||||
|
if bi.isEmpty() {
|
||||||
|
bi = bondInfo{
|
||||||
|
PubKey: pubKey,
|
||||||
|
Power: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bi.Power = bi.Power + stake.Amount
|
||||||
|
|
||||||
|
k.setBondInfo(ctx, addr, bi)
|
||||||
|
return bi.Power, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Keeper) unbondWithoutCoins(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, sdk.Error) {
|
||||||
|
bi := k.getBondInfo(ctx, addr)
|
||||||
|
if bi.isEmpty() {
|
||||||
|
return crypto.PubKey{}, 0, ErrInvalidUnbond()
|
||||||
|
}
|
||||||
|
k.deleteBondInfo(ctx, addr)
|
||||||
|
|
||||||
|
return bi.PubKey, bi.Power, nil
|
||||||
|
}
|
|
@ -13,25 +13,29 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/store"
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) {
|
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
|
authKey := sdk.NewKVStoreKey("authkey")
|
||||||
capKey := sdk.NewKVStoreKey("capkey")
|
capKey := sdk.NewKVStoreKey("capkey")
|
||||||
ms := store.NewCommitMultiStore(db)
|
ms := store.NewCommitMultiStore(db)
|
||||||
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
|
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
|
||||||
|
ms.MountStoreWithDB(authKey, sdk.StoreTypeIAVL, db)
|
||||||
ms.LoadLatestVersion()
|
ms.LoadLatestVersion()
|
||||||
return ms, capKey
|
return ms, authKey, capKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStakingMapperGetSet(t *testing.T) {
|
func TestKeeperGetSet(t *testing.T) {
|
||||||
ms, capKey := setupMultiStore()
|
ms, _, capKey := setupMultiStore()
|
||||||
|
|
||||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
||||||
stakingMapper := NewMapper(capKey)
|
stakeKeeper := NewKeeper(capKey, bank.NewCoinKeeper(nil))
|
||||||
addr := sdk.Address([]byte("some-address"))
|
addr := sdk.Address([]byte("some-address"))
|
||||||
|
|
||||||
bi := stakingMapper.getBondInfo(ctx, addr)
|
bi := stakeKeeper.getBondInfo(ctx, addr)
|
||||||
assert.Equal(t, bi, bondInfo{})
|
assert.Equal(t, bi, bondInfo{})
|
||||||
|
|
||||||
privKey := crypto.GenPrivKeyEd25519()
|
privKey := crypto.GenPrivKeyEd25519()
|
||||||
|
@ -41,36 +45,39 @@ func TestStakingMapperGetSet(t *testing.T) {
|
||||||
Power: int64(10),
|
Power: int64(10),
|
||||||
}
|
}
|
||||||
fmt.Printf("Pubkey: %v\n", privKey.PubKey())
|
fmt.Printf("Pubkey: %v\n", privKey.PubKey())
|
||||||
stakingMapper.setBondInfo(ctx, addr, bi)
|
stakeKeeper.setBondInfo(ctx, addr, bi)
|
||||||
|
|
||||||
savedBi := stakingMapper.getBondInfo(ctx, addr)
|
savedBi := stakeKeeper.getBondInfo(ctx, addr)
|
||||||
assert.NotNil(t, savedBi)
|
assert.NotNil(t, savedBi)
|
||||||
fmt.Printf("Bond Info: %v\n", savedBi)
|
fmt.Printf("Bond Info: %v\n", savedBi)
|
||||||
assert.Equal(t, int64(10), savedBi.Power)
|
assert.Equal(t, int64(10), savedBi.Power)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBonding(t *testing.T) {
|
func TestBonding(t *testing.T) {
|
||||||
ms, capKey := setupMultiStore()
|
ms, authKey, capKey := setupMultiStore()
|
||||||
|
|
||||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
||||||
stakingMapper := NewMapper(capKey)
|
|
||||||
|
accountMapper := auth.NewAccountMapper(authKey, &auth.BaseAccount{})
|
||||||
|
coinKeeper := bank.NewCoinKeeper(accountMapper)
|
||||||
|
stakeKeeper := NewKeeper(capKey, coinKeeper)
|
||||||
addr := sdk.Address([]byte("some-address"))
|
addr := sdk.Address([]byte("some-address"))
|
||||||
privKey := crypto.GenPrivKeyEd25519()
|
privKey := crypto.GenPrivKeyEd25519()
|
||||||
pubKey := privKey.PubKey()
|
pubKey := privKey.PubKey()
|
||||||
|
|
||||||
_, _, err := stakingMapper.Unbond(ctx, addr)
|
_, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr)
|
||||||
assert.Equal(t, err, ErrInvalidUnbond())
|
assert.Equal(t, err, ErrInvalidUnbond())
|
||||||
|
|
||||||
_, err = stakingMapper.Bond(ctx, addr, pubKey, 10)
|
_, err = stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.Coin{"steak", 10})
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
power, err := stakingMapper.Bond(ctx, addr, pubKey, 10)
|
power, err := stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.Coin{"steak", 10})
|
||||||
assert.Equal(t, int64(20), power)
|
assert.Equal(t, int64(20), power)
|
||||||
|
|
||||||
pk, _, err := stakingMapper.Unbond(ctx, addr)
|
pk, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, pubKey, pk)
|
assert.Equal(t, pubKey, pk)
|
||||||
|
|
||||||
_, _, err = stakingMapper.Unbond(ctx, addr)
|
_, _, err = stakeKeeper.unbondWithoutCoins(ctx, addr)
|
||||||
assert.Equal(t, err, ErrInvalidUnbond())
|
assert.Equal(t, err, ErrInvalidUnbond())
|
||||||
}
|
}
|
|
@ -1,92 +0,0 @@
|
||||||
package staking
|
|
||||||
|
|
||||||
import (
|
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StakingMapper struct {
|
|
||||||
key sdk.StoreKey
|
|
||||||
cdc *wire.Codec
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMapper(key sdk.StoreKey) StakingMapper {
|
|
||||||
cdc := wire.NewCodec()
|
|
||||||
return StakingMapper{
|
|
||||||
key: key,
|
|
||||||
cdc: cdc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm StakingMapper) getBondInfo(ctx sdk.Context, addr sdk.Address) bondInfo {
|
|
||||||
store := ctx.KVStore(sm.key)
|
|
||||||
bz := store.Get(addr)
|
|
||||||
if bz == nil {
|
|
||||||
return bondInfo{}
|
|
||||||
}
|
|
||||||
var bi bondInfo
|
|
||||||
err := sm.cdc.UnmarshalBinary(bz, &bi)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return bi
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm StakingMapper) setBondInfo(ctx sdk.Context, addr sdk.Address, bi bondInfo) {
|
|
||||||
store := ctx.KVStore(sm.key)
|
|
||||||
bz, err := sm.cdc.MarshalBinary(bi)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
store.Set(addr, bz)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm StakingMapper) deleteBondInfo(ctx sdk.Context, addr sdk.Address) {
|
|
||||||
store := ctx.KVStore(sm.key)
|
|
||||||
store.Delete(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm StakingMapper) Bond(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, power int64) (int64, sdk.Error) {
|
|
||||||
|
|
||||||
bi := sm.getBondInfo(ctx, addr)
|
|
||||||
if bi.isEmpty() {
|
|
||||||
bi = bondInfo{
|
|
||||||
PubKey: pubKey,
|
|
||||||
Power: power,
|
|
||||||
}
|
|
||||||
sm.setBondInfo(ctx, addr, bi)
|
|
||||||
return bi.Power, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
newPower := bi.Power + power
|
|
||||||
newBi := bondInfo{
|
|
||||||
PubKey: bi.PubKey,
|
|
||||||
Power: newPower,
|
|
||||||
}
|
|
||||||
sm.setBondInfo(ctx, addr, newBi)
|
|
||||||
|
|
||||||
return newBi.Power, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm StakingMapper) Unbond(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, sdk.Error) {
|
|
||||||
bi := sm.getBondInfo(ctx, addr)
|
|
||||||
if bi.isEmpty() {
|
|
||||||
return crypto.PubKey{}, 0, ErrInvalidUnbond()
|
|
||||||
}
|
|
||||||
sm.deleteBondInfo(ctx, addr)
|
|
||||||
return bi.PubKey, bi.Power, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type bondInfo struct {
|
|
||||||
PubKey crypto.PubKey
|
|
||||||
Power int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bi bondInfo) isEmpty() bool {
|
|
||||||
if bi == (bondInfo{}) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package staking
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// BondMsg
|
||||||
|
|
||||||
|
type BondMsg struct {
|
||||||
|
Address sdk.Address `json:"address"`
|
||||||
|
Stake sdk.Coin `json:"coins"`
|
||||||
|
PubKey crypto.PubKey `json:"pub_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBondMsg(addr sdk.Address, stake sdk.Coin, pubKey crypto.PubKey) BondMsg {
|
||||||
|
return BondMsg{
|
||||||
|
Address: addr,
|
||||||
|
Stake: stake,
|
||||||
|
PubKey: pubKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg BondMsg) Type() string {
|
||||||
|
return "staking"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg BondMsg) ValidateBasic() sdk.Error {
|
||||||
|
if msg.Stake.IsZero() {
|
||||||
|
return ErrEmptyStake()
|
||||||
|
}
|
||||||
|
|
||||||
|
if msg.PubKey.Empty() {
|
||||||
|
return sdk.ErrInvalidPubKey("BondMsg.PubKey must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg BondMsg) Get(key interface{}) interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg BondMsg) GetSignBytes() []byte {
|
||||||
|
bz, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return bz
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg BondMsg) GetSigners() []sdk.Address {
|
||||||
|
return []sdk.Address{msg.Address}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// UnbondMsg
|
||||||
|
|
||||||
|
type UnbondMsg struct {
|
||||||
|
Address sdk.Address `json:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnbondMsg(addr sdk.Address) UnbondMsg {
|
||||||
|
return UnbondMsg{
|
||||||
|
Address: addr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg UnbondMsg) Type() string {
|
||||||
|
return "staking"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg UnbondMsg) ValidateBasic() sdk.Error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg UnbondMsg) Get(key interface{}) interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg UnbondMsg) GetSignBytes() []byte {
|
||||||
|
bz, err := json.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return bz
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg UnbondMsg) GetSigners() []sdk.Address {
|
||||||
|
return []sdk.Address{msg.Address}
|
||||||
|
}
|
|
@ -1,95 +1,15 @@
|
||||||
package staking
|
package staking
|
||||||
|
|
||||||
import (
|
import crypto "github.com/tendermint/go-crypto"
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
crypto "github.com/tendermint/go-crypto"
|
type bondInfo struct {
|
||||||
|
PubKey crypto.PubKey
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
Power int64
|
||||||
)
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// BondMsg
|
|
||||||
|
|
||||||
type BondMsg struct {
|
|
||||||
Address sdk.Address `json:"address"`
|
|
||||||
Stake sdk.Coin `json:"coins"`
|
|
||||||
PubKey crypto.PubKey `json:"pub_key"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBondMsg(addr sdk.Address, stake sdk.Coin, pubKey crypto.PubKey) BondMsg {
|
func (bi bondInfo) isEmpty() bool {
|
||||||
return BondMsg{
|
if bi == (bondInfo{}) {
|
||||||
Address: addr,
|
return true
|
||||||
Stake: stake,
|
|
||||||
PubKey: pubKey,
|
|
||||||
}
|
}
|
||||||
}
|
return false
|
||||||
|
|
||||||
func (msg BondMsg) Type() string {
|
|
||||||
return "staking"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg BondMsg) ValidateBasic() sdk.Error {
|
|
||||||
if msg.Stake.IsZero() {
|
|
||||||
return ErrEmptyStake()
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.PubKey.Empty() {
|
|
||||||
return sdk.ErrInvalidPubKey("BondMsg.PubKey must not be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg BondMsg) Get(key interface{}) interface{} {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg BondMsg) GetSignBytes() []byte {
|
|
||||||
bz, err := json.Marshal(msg)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return bz
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg BondMsg) GetSigners() []sdk.Address {
|
|
||||||
return []sdk.Address{msg.Address}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// UnbondMsg
|
|
||||||
|
|
||||||
type UnbondMsg struct {
|
|
||||||
Address sdk.Address `json:"address"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUnbondMsg(addr sdk.Address) UnbondMsg {
|
|
||||||
return UnbondMsg{
|
|
||||||
Address: addr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg UnbondMsg) Type() string {
|
|
||||||
return "staking"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg UnbondMsg) ValidateBasic() sdk.Error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg UnbondMsg) Get(key interface{}) interface{} {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg UnbondMsg) GetSignBytes() []byte {
|
|
||||||
bz, err := json.Marshal(msg)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return bz
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg UnbondMsg) GetSigners() []sdk.Address {
|
|
||||||
return []sdk.Address{msg.Address}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue