diff --git a/README.md b/README.md new file mode 100644 index 00000000..3b62e6cb --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Kava + +## Installation + + go install ./kava/cmd/kavad + go install ./kava/cmd/kavacli \ No newline at end of file diff --git a/kava/app/app.go b/kava/app/app.go new file mode 100644 index 00000000..393cd7e3 --- /dev/null +++ b/kava/app/app.go @@ -0,0 +1,145 @@ +package app + +import ( + "encoding/json" + + abci "github.com/tendermint/abci/types" + cmn "github.com/tendermint/tmlibs/common" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" + + bam "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/stake" + + "github.com/kava-labs/kava/kava/types" +) + +const ( + appName = "BasecoinApp" +) + +// Extended ABCI application +type BasecoinApp struct { + *bam.BaseApp + cdc *wire.Codec + + // keys to access the substores + keyMain *sdk.KVStoreKey + keyAccount *sdk.KVStoreKey + keyIBC *sdk.KVStoreKey + keyStake *sdk.KVStoreKey + + // Manage getting and setting accounts + accountMapper sdk.AccountMapper + coinKeeper bank.Keeper + ibcMapper ibc.Mapper + stakeKeeper stake.Keeper +} + +func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { + + // Create app-level codec for txs and accounts. + var cdc = MakeCodec() + + // Create your application object. + var app = &BasecoinApp{ + BaseApp: bam.NewBaseApp(appName, cdc, logger, db), + cdc: cdc, + keyMain: sdk.NewKVStoreKey("main"), + keyAccount: sdk.NewKVStoreKey("acc"), + keyIBC: sdk.NewKVStoreKey("ibc"), + keyStake: sdk.NewKVStoreKey("stake"), + } + + // Define the accountMapper. + app.accountMapper = auth.NewAccountMapper( + cdc, + app.keyAccount, // target store + &types.AppAccount{}, // prototype + ) + + // add accountMapper/handlers + app.coinKeeper = bank.NewKeeper(app.accountMapper) + app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) + app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace)) + + // register message routes + app.Router(). + AddRoute("bank", bank.NewHandler(app.coinKeeper)). + AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)). + AddRoute("stake", stake.NewHandler(app.stakeKeeper)) + + // Initialize BaseApp. + app.SetInitChainer(app.initChainer) + app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake) + app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.BurnFeeHandler)) + err := app.LoadLatestVersion(app.keyMain) + if err != nil { + cmn.Exit(err.Error()) + } + return app +} + +// Custom tx codec +func MakeCodec() *wire.Codec { + var cdc = wire.NewCodec() + wire.RegisterCrypto(cdc) // Register crypto. + sdk.RegisterWire(cdc) // Register Msgs + bank.RegisterWire(cdc) + stake.RegisterWire(cdc) + ibc.RegisterWire(cdc) + + // register custom AppAccount + cdc.RegisterInterface((*sdk.Account)(nil), nil) + cdc.RegisterConcrete(&types.AppAccount{}, "basecoin/Account", nil) + return cdc +} + +// Custom logic for basecoin initialization +func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + stateJSON := req.AppStateBytes + + genesisState := new(types.GenesisState) + err := app.cdc.UnmarshalJSON(stateJSON, genesisState) + if err != nil { + panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 + // return sdk.ErrGenesisParse("").TraceCause(err, "") + } + + for _, gacc := range genesisState.Accounts { + acc, err := gacc.ToAppAccount() + if err != nil { + panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 + // return sdk.ErrGenesisParse("").TraceCause(err, "") + } + app.accountMapper.SetAccount(ctx, acc) + } + return abci.ResponseInitChain{} +} + +// Custom logic for state export +func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) { + ctx := app.NewContext(true, abci.Header{}) + + // iterate to get the accounts + accounts := []*types.GenesisAccount{} + appendAccount := func(acc sdk.Account) (stop bool) { + account := &types.GenesisAccount{ + Address: acc.GetAddress(), + Coins: acc.GetCoins(), + } + accounts = append(accounts, account) + return false + } + app.accountMapper.IterateAccounts(ctx, appendAccount) + + genState := types.GenesisState{ + Accounts: accounts, + } + return wire.MarshalJSONIndent(app.cdc, genState) +} diff --git a/kava/app/app_test.go b/kava/app/app_test.go new file mode 100644 index 00000000..b502aae4 --- /dev/null +++ b/kava/app/app_test.go @@ -0,0 +1,461 @@ +package app + +import ( + "encoding/json" + "fmt" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/examples/basecoin/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/ibc" + + abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" +) + +// Construct some global addrs and txs for tests. +var ( + chainID = "" // TODO + + accName = "foobart" + + priv1 = crypto.GenPrivKeyEd25519() + addr1 = priv1.PubKey().Address() + priv2 = crypto.GenPrivKeyEd25519() + addr2 = priv2.PubKey().Address() + addr3 = crypto.GenPrivKeyEd25519().PubKey().Address() + priv4 = crypto.GenPrivKeyEd25519() + addr4 = priv4.PubKey().Address() + coins = sdk.Coins{{"foocoin", 10}} + halfCoins = sdk.Coins{{"foocoin", 5}} + manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}} + fee = sdk.StdFee{ + sdk.Coins{{"foocoin", 0}}, + 0, + } + + sendMsg1 = bank.MsgSend{ + Inputs: []bank.Input{bank.NewInput(addr1, coins)}, + Outputs: []bank.Output{bank.NewOutput(addr2, coins)}, + } + + sendMsg2 = bank.MsgSend{ + Inputs: []bank.Input{bank.NewInput(addr1, coins)}, + Outputs: []bank.Output{ + bank.NewOutput(addr2, halfCoins), + bank.NewOutput(addr3, halfCoins), + }, + } + + sendMsg3 = bank.MsgSend{ + Inputs: []bank.Input{ + bank.NewInput(addr1, coins), + bank.NewInput(addr4, coins), + }, + Outputs: []bank.Output{ + bank.NewOutput(addr2, coins), + bank.NewOutput(addr3, coins), + }, + } + + sendMsg4 = bank.MsgSend{ + Inputs: []bank.Input{ + bank.NewInput(addr2, coins), + }, + Outputs: []bank.Output{ + bank.NewOutput(addr1, coins), + }, + } + + sendMsg5 = bank.MsgSend{ + Inputs: []bank.Input{ + bank.NewInput(addr1, manyCoins), + }, + Outputs: []bank.Output{ + bank.NewOutput(addr2, manyCoins), + }, + } +) + +func loggerAndDB() (log.Logger, dbm.DB) { + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") + db := dbm.NewMemDB() + return logger, db +} + +func newBasecoinApp() *BasecoinApp { + logger, db := loggerAndDB() + return NewBasecoinApp(logger, db) +} + +func setGenesisAccounts(bapp *BasecoinApp, accs ...auth.BaseAccount) error { + genaccs := make([]*types.GenesisAccount, len(accs)) + for i, acc := range accs { + genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, accName}) + } + + genesisState := types.GenesisState{ + Accounts: genaccs, + } + + stateBytes, err := json.MarshalIndent(genesisState, "", "\t") + if err != nil { + return err + } + + // Initialize the chain + vals := []abci.Validator{} + bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.Commit() + + return nil +} + +//_______________________________________________________________________ + +func TestMsgs(t *testing.T) { + bapp := newBasecoinApp() + + msgs := []struct { + msg sdk.Msg + }{ + {sendMsg1}, + } + + for i, m := range msgs { + // Run a CheckDeliver + SignCheckDeliver(t, bapp, m.msg, []int64{int64(i)}, false, priv1) + } +} + +func TestSortGenesis(t *testing.T) { + logger, db := loggerAndDB() + bapp := NewBasecoinApp(logger, db) + + // Note the order: the coins are unsorted! + coinDenom1, coinDenom2 := "foocoin", "barcoin" + + genState := fmt.Sprintf(`{ + "accounts": [{ + "address": "%s", + "coins": [ + { + "denom": "%s", + "amount": 10 + }, + { + "denom": "%s", + "amount": 20 + } + ] + }] + }`, addr1.String(), coinDenom1, coinDenom2) + + // Initialize the chain + vals := []abci.Validator{} + bapp.InitChain(abci.RequestInitChain{vals, []byte(genState)}) + bapp.Commit() + + // Unsorted coins means invalid + err := sendMsg5.ValidateBasic() + require.Equal(t, sdk.CodeInvalidCoins, err.Code(), err.ABCILog()) + + // Sort coins, should be valid + sendMsg5.Inputs[0].Coins.Sort() + sendMsg5.Outputs[0].Coins.Sort() + err = sendMsg5.ValidateBasic() + require.Nil(t, err) + + // Ensure we can send + SignCheckDeliver(t, bapp, sendMsg5, []int64{0}, true, priv1) +} + +func TestGenesis(t *testing.T) { + logger, db := loggerAndDB() + bapp := NewBasecoinApp(logger, db) + + // Construct some genesis bytes to reflect basecoin/types/AppAccount + pk := crypto.GenPrivKeyEd25519().PubKey() + addr := pk.Address() + coins, err := sdk.ParseCoins("77foocoin,99barcoin") + require.Nil(t, err) + baseAcc := auth.BaseAccount{ + Address: addr, + Coins: coins, + } + acc := &types.AppAccount{baseAcc, "foobart"} + + err = setGenesisAccounts(bapp, baseAcc) + assert.Nil(t, err) + + // A checkTx context + ctx := bapp.BaseApp.NewContext(true, abci.Header{}) + res1 := bapp.accountMapper.GetAccount(ctx, baseAcc.Address) + assert.Equal(t, acc, res1) + + // reload app and ensure the account is still there + bapp = NewBasecoinApp(logger, db) + ctx = bapp.BaseApp.NewContext(true, abci.Header{}) + res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address) + assert.Equal(t, acc, res1) +} + +func TestMsgSendWithAccounts(t *testing.T) { + bapp := newBasecoinApp() + + // Construct some genesis bytes to reflect basecoin/types/AppAccount + // Give 77 foocoin to the first key + coins, err := sdk.ParseCoins("77foocoin") + require.Nil(t, err) + baseAcc := auth.BaseAccount{ + Address: addr1, + Coins: coins, + } + + // Construct genesis state + err = setGenesisAccounts(bapp, baseAcc) + assert.Nil(t, err) + // A checkTx context (true) + ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{}) + res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1) + assert.Equal(t, baseAcc, res1.(*types.AppAccount).BaseAccount) + + // Run a CheckDeliver + SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1) + + // Check balances + CheckBalance(t, bapp, addr1, "67foocoin") + CheckBalance(t, bapp, addr2, "10foocoin") + + // Delivering again should cause replay error + SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, false, priv1) + + // bumping the txnonce number without resigning should be an auth error + tx := genTx(sendMsg1, []int64{0}, priv1) + tx.Signatures[0].Sequence = 1 + res := bapp.Deliver(tx) + + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) + + // resigning the tx with the bumped sequence should work + SignCheckDeliver(t, bapp, sendMsg1, []int64{1}, true, priv1) +} + +func TestMsgSendMultipleOut(t *testing.T) { + bapp := newBasecoinApp() + + genCoins, err := sdk.ParseCoins("42foocoin") + require.Nil(t, err) + + acc1 := auth.BaseAccount{ + Address: addr1, + Coins: genCoins, + } + + acc2 := auth.BaseAccount{ + Address: addr2, + Coins: genCoins, + } + + err = setGenesisAccounts(bapp, acc1, acc2) + assert.Nil(t, err) + + // Simulate a Block + SignCheckDeliver(t, bapp, sendMsg2, []int64{0}, true, priv1) + + // Check balances + CheckBalance(t, bapp, addr1, "32foocoin") + CheckBalance(t, bapp, addr2, "47foocoin") + CheckBalance(t, bapp, addr3, "5foocoin") +} + +func TestSengMsgMultipleInOut(t *testing.T) { + bapp := newBasecoinApp() + + genCoins, err := sdk.ParseCoins("42foocoin") + require.Nil(t, err) + + acc1 := auth.BaseAccount{ + Address: addr1, + Coins: genCoins, + } + + acc2 := auth.BaseAccount{ + Address: addr2, + Coins: genCoins, + } + + acc4 := auth.BaseAccount{ + Address: addr4, + Coins: genCoins, + } + + err = setGenesisAccounts(bapp, acc1, acc2, acc4) + assert.Nil(t, err) + + // CheckDeliver + SignCheckDeliver(t, bapp, sendMsg3, []int64{0, 0}, true, priv1, priv4) + + // Check balances + CheckBalance(t, bapp, addr1, "32foocoin") + CheckBalance(t, bapp, addr4, "32foocoin") + CheckBalance(t, bapp, addr2, "52foocoin") + CheckBalance(t, bapp, addr3, "10foocoin") +} + +func TestMsgSendDependent(t *testing.T) { + bapp := newBasecoinApp() + + genCoins, err := sdk.ParseCoins("42foocoin") + require.Nil(t, err) + + acc1 := auth.BaseAccount{ + Address: addr1, + Coins: genCoins, + } + + err = setGenesisAccounts(bapp, acc1) + assert.Nil(t, err) + + // CheckDeliver + SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1) + + // Check balances + CheckBalance(t, bapp, addr1, "32foocoin") + CheckBalance(t, bapp, addr2, "10foocoin") + + // Simulate a Block + SignCheckDeliver(t, bapp, sendMsg4, []int64{0}, true, priv2) + + // Check balances + CheckBalance(t, bapp, addr1, "42foocoin") +} + +func TestMsgQuiz(t *testing.T) { + bapp := newBasecoinApp() + + // Construct genesis state + // Construct some genesis bytes to reflect basecoin/types/AppAccount + baseAcc := auth.BaseAccount{ + Address: addr1, + Coins: nil, + } + acc1 := &types.AppAccount{baseAcc, "foobart"} + + // Construct genesis state + genesisState := map[string]interface{}{ + "accounts": []*types.GenesisAccount{ + types.NewGenesisAccount(acc1), + }, + } + stateBytes, err := json.MarshalIndent(genesisState, "", "\t") + require.Nil(t, err) + + // Initialize the chain (nil) + vals := []abci.Validator{} + bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.Commit() + + // A checkTx context (true) + ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{}) + res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1) + assert.Equal(t, acc1, res1) + +} + +func TestIBCMsgs(t *testing.T) { + bapp := newBasecoinApp() + + sourceChain := "source-chain" + destChain := "dest-chain" + + baseAcc := auth.BaseAccount{ + Address: addr1, + Coins: coins, + } + acc1 := &types.AppAccount{baseAcc, "foobart"} + + err := setGenesisAccounts(bapp, baseAcc) + assert.Nil(t, err) + // A checkTx context (true) + ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{}) + res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1) + assert.Equal(t, acc1, res1) + + packet := ibc.IBCPacket{ + SrcAddr: addr1, + DestAddr: addr1, + Coins: coins, + SrcChain: sourceChain, + DestChain: destChain, + } + + transferMsg := ibc.IBCTransferMsg{ + IBCPacket: packet, + } + + receiveMsg := ibc.IBCReceiveMsg{ + IBCPacket: packet, + Relayer: addr1, + Sequence: 0, + } + + SignCheckDeliver(t, bapp, transferMsg, []int64{0}, true, priv1) + CheckBalance(t, bapp, addr1, "") + SignCheckDeliver(t, bapp, transferMsg, []int64{1}, false, priv1) + SignCheckDeliver(t, bapp, receiveMsg, []int64{2}, true, priv1) + CheckBalance(t, bapp, addr1, "10foocoin") + SignCheckDeliver(t, bapp, receiveMsg, []int64{3}, false, priv1) +} + +func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.StdTx { + sigs := make([]sdk.StdSignature, len(priv)) + for i, p := range priv { + sigs[i] = sdk.StdSignature{ + PubKey: p.PubKey(), + Signature: p.Sign(sdk.StdSignBytes(chainID, seq, fee, msg)), + Sequence: seq[i], + } + } + + return sdk.NewStdTx(msg, fee, sigs) + +} + +func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) { + + // Sign the tx + tx := genTx(msg, seq, priv...) + // Run a Check + res := bapp.Check(tx) + if expPass { + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) + } else { + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) + } + + // Simulate a Block + bapp.BeginBlock(abci.RequestBeginBlock{}) + res = bapp.Deliver(tx) + if expPass { + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) + } else { + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) + } + bapp.EndBlock(abci.RequestEndBlock{}) + //bapp.Commit() +} + +func CheckBalance(t *testing.T, bapp *BasecoinApp, addr sdk.Address, balExpected string) { + ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{}) + res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr) + assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins())) +} diff --git a/kava/cmd/kavacli/main.go b/kava/cmd/kavacli/main.go new file mode 100644 index 00000000..67c8b168 --- /dev/null +++ b/kava/cmd/kavacli/main.go @@ -0,0 +1,80 @@ +package main + +import ( + "os" + + "github.com/spf13/cobra" + + "github.com/tendermint/tmlibs/cli" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client/lcd" + "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/client/tx" + + "github.com/cosmos/cosmos-sdk/version" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" + ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli" + stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli" + + "github.com/kava-labs/kava/kava/app" + "github.com/kava-labs/kava/kava/types" +) + +// rootCmd is the entry point for this binary +var ( + rootCmd = &cobra.Command{ + Use: "basecli", + Short: "Basecoin light-client", + } +) + +func main() { + // disable sorting + cobra.EnableCommandSorting = false + + // get the codec + cdc := app.MakeCodec() + + // TODO: setup keybase, viper object, etc. to be passed into + // the below functions and eliminate global vars, like we do + // with the cdc + + // add standard rpc, and tx commands + rpc.AddCommands(rootCmd) + rootCmd.AddCommand(client.LineBreak) + tx.AddCommands(rootCmd, cdc) + rootCmd.AddCommand(client.LineBreak) + + // add query/post commands (custom to binary) + rootCmd.AddCommand( + client.GetCommands( + authcmd.GetAccountCmd("acc", cdc, types.GetAccountDecoder(cdc)), + )...) + + rootCmd.AddCommand( + client.PostCommands( + bankcmd.SendTxCmd(cdc), + ibccmd.IBCTransferCmd(cdc), + ibccmd.IBCRelayCmd(cdc), + stakecmd.GetCmdDeclareCandidacy(cdc), + stakecmd.GetCmdEditCandidacy(cdc), + stakecmd.GetCmdDelegate(cdc), + stakecmd.GetCmdUnbond(cdc), + )...) + + // add proxy, version and key info + rootCmd.AddCommand( + client.LineBreak, + lcd.ServeCommand(cdc), + keys.Commands(), + client.LineBreak, + version.VersionCmd, + ) + + // prepare and add flags + executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.basecli")) + executor.Execute() +} diff --git a/kava/cmd/kavad/main.go b/kava/cmd/kavad/main.go new file mode 100644 index 00000000..ef3b1f50 --- /dev/null +++ b/kava/cmd/kavad/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "encoding/json" + "os" + + "github.com/spf13/cobra" + + abci "github.com/tendermint/abci/types" + "github.com/tendermint/tmlibs/cli" + dbm "github.com/tendermint/tmlibs/db" + "github.com/tendermint/tmlibs/log" + + "github.com/cosmos/cosmos-sdk/server" + "github.com/kava-labs/kava/kava/app" +) + +func main() { + cdc := app.MakeCodec() + ctx := server.NewDefaultContext() + + rootCmd := &cobra.Command{ + Use: "basecoind", + Short: "Basecoin Daemon (server)", + PersistentPreRunE: server.PersistentPreRunEFn(ctx), + } + + server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, + server.ConstructAppCreator(newApp, "basecoin"), + server.ConstructAppExporter(exportAppState, "basecoin")) + + // prepare and add flags + rootDir := os.ExpandEnv("$HOME/.basecoind") + executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) + executor.Execute() +} + +func newApp(logger log.Logger, db dbm.DB) abci.Application { + return app.NewBasecoinApp(logger, db) +} + +func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) { + bapp := app.NewBasecoinApp(logger, db) + return bapp.ExportAppStateJSON() +} diff --git a/kava/types/account.go b/kava/types/account.go new file mode 100644 index 00000000..e6eb5d7b --- /dev/null +++ b/kava/types/account.go @@ -0,0 +1,72 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" +) + +var _ sdk.Account = (*AppAccount)(nil) + +// Custom extensions for this application. This is just an example of +// extending auth.BaseAccount with custom fields. +// +// This is compatible with the stock auth.AccountStore, since +// auth.AccountStore uses the flexible go-amino library. +type AppAccount struct { + auth.BaseAccount + Name string `json:"name"` +} + +// nolint +func (acc AppAccount) GetName() string { return acc.Name } +func (acc *AppAccount) SetName(name string) { acc.Name = name } + +// Get the AccountDecoder function for the custom AppAccount +func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { + return func(accBytes []byte) (res sdk.Account, err error) { + if len(accBytes) == 0 { + return nil, sdk.ErrTxDecode("accBytes are empty") + } + acct := new(AppAccount) + err = cdc.UnmarshalBinaryBare(accBytes, &acct) + if err != nil { + panic(err) + } + return acct, err + } +} + +//___________________________________________________________________________________ + +// State to Unmarshal +type GenesisState struct { + Accounts []*GenesisAccount `json:"accounts"` +} + +// GenesisAccount doesn't need pubkey or sequence +type GenesisAccount struct { + Name string `json:"name"` + Address sdk.Address `json:"address"` + Coins sdk.Coins `json:"coins"` +} + +func NewGenesisAccount(aa *AppAccount) *GenesisAccount { + return &GenesisAccount{ + Name: aa.Name, + Address: aa.Address, + Coins: aa.Coins.Sort(), + } +} + +// convert GenesisAccount to AppAccount +func (ga *GenesisAccount) ToAppAccount() (acc *AppAccount, err error) { + baseAcc := auth.BaseAccount{ + Address: ga.Address, + Coins: ga.Coins.Sort(), + } + return &AppAccount{ + BaseAccount: baseAcc, + Name: ga.Name, + }, nil +}