Merge pull request #1434 from cosmos/bucky-aditya/docs-core

Bucky aditya/docs core
This commit is contained in:
Ethan Buchman 2018-06-28 15:35:15 -04:00 committed by GitHub
commit 3a96f8ffd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 249 additions and 239 deletions

View File

@ -2,7 +2,6 @@ package app
import (
"encoding/json"
"reflect"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
@ -35,7 +34,7 @@ func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Register message routes.
// Note the handler gets access to the account store.
app.Router().
AddRoute("bank", NewApp1Handler(keyAccount))
AddRoute("send", handleMsgSend(keyAccount))
// Mount stores and load the latest state.
app.MountStoresIAVL(keyAccount)
@ -65,7 +64,7 @@ func NewMsgSend(from, to sdk.Address, amt sdk.Coins) MsgSend {
}
// Implements Msg.
func (msg MsgSend) Type() string { return "bank" }
func (msg MsgSend) Type() string { return "send" }
// Implements Msg. Ensure the addresses are good and the
// amount is positive.
@ -105,41 +104,40 @@ func (msg MsgSend) Tags() sdk.Tags {
//------------------------------------------------------------------
// Handler for the message
func NewApp1Handler(keyAcc *sdk.KVStoreKey) sdk.Handler {
// Handle MsgSend.
// NOTE: msg.From, msg.To, and msg.Amount were already validated
func handleMsgSend(key *sdk.KVStoreKey) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MsgSend:
return handleMsgSend(ctx, keyAcc, msg)
default:
errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name()
return sdk.ErrUnknownRequest(errMsg).Result()
sendMsg, ok := msg.(MsgSend)
if !ok {
// Create custom error message and return result
// Note: Using unreserved error codespace
return sdk.NewError(2, 1, "Send Message is malformed").Result()
}
// Load the store.
store := ctx.KVStore(key)
// Debit from the sender.
if res := handleFrom(store, sendMsg.From, sendMsg.Amount); !res.IsOK() {
return res
}
// Credit the receiver.
if res := handleTo(store, sendMsg.To, sendMsg.Amount); !res.IsOK() {
return res
}
// Return a success (Code 0).
// Add list of key-value pair descriptors ("tags").
return sdk.Result{
Tags: sendMsg.Tags(),
}
}
}
// Handle MsgSend.
// NOTE: msg.From, msg.To, and msg.Amount were already validated
func handleMsgSend(ctx sdk.Context, key *sdk.KVStoreKey, msg MsgSend) sdk.Result {
// Load the store.
store := ctx.KVStore(key)
// Debit from the sender.
if res := handleFrom(store, msg.From, msg.Amount); !res.IsOK() {
return res
}
// Credit the receiver.
if res := handleTo(store, msg.To, msg.Amount); !res.IsOK() {
return res
}
// Return a success (Code 0).
// Add list of key-value pair descriptors ("tags").
return sdk.Result{
Tags: msg.Tags(),
}
}
// Convenience Handlers
func handleFrom(store sdk.KVStore, from sdk.Address, amt sdk.Coins) sdk.Result {
// Get sender account from the store.
accBytes := store.Get(from)
@ -210,6 +208,7 @@ func handleTo(store sdk.KVStore, to sdk.Address, amt sdk.Coins) sdk.Result {
return sdk.Result{}
}
// Simple account struct
type appAccount struct {
Coins sdk.Coins `json:"coins"`
}

View File

@ -49,7 +49,8 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Register message routes.
// Note the handler gets access to the account store.
app.Router().
AddRoute("bank", NewApp2Handler(keyAccount, keyMain))
AddRoute("send", handleMsgSend(keyAccount)).
AddRoute("issue", handleMsgIssue(keyAccount, keyMain))
// Mount stores and load the latest state.
app.MountStoresIAVL(keyAccount, keyMain)
@ -71,39 +72,37 @@ type CoinMetadata struct {
//------------------------------------------------------------------
// Msgs
// Create Output struct to allow single message to issue arbitrary coins to multiple users
type Output struct {
Address sdk.Address
Coins sdk.Coins
}
// Single permissioned issuer can issue multiple outputs
// Single permissioned issuer can issue Coin to Receiver
// if he is the issuer in Coin Metadata
// Implements sdk.Msg Interface
type MsgIssue struct {
Issuer sdk.Address
Outputs []Output
Receiver sdk.Address
Coin sdk.Coin
}
// nolint
func (msg MsgIssue) Type() string { return "bank" }
// Implements Msg.
func (msg MsgIssue) Type() string { return "issue" }
// Implements Msg. Ensures addresses are valid and Coin is positive
func (msg MsgIssue) ValidateBasic() sdk.Error {
if len(msg.Issuer) == 0 {
return sdk.ErrInvalidAddress("Issuer address cannot be empty")
}
for _, o := range msg.Outputs {
if len(o.Address) == 0 {
return sdk.ErrInvalidAddress("Output address cannot be empty")
}
// Cannot issue zero or negative coins
if !o.Coins.IsPositive() {
return sdk.ErrInvalidCoins("Cannot issue 0 or negative coin amounts")
}
if len(msg.Receiver) == 0 {
return sdk.ErrInvalidAddress("Receiver address cannot be empty")
}
// Cannot issue zero or negative coins
if !msg.Coin.IsPositive() {
return sdk.ErrInvalidCoins("Cannot issue 0 or negative coin amounts")
}
return nil
}
// Implements Msg. Get canonical sign bytes for MsgIssue
func (msg MsgIssue) GetSignBytes() []byte {
bz, err := json.Marshal(msg)
if err != nil {
@ -117,112 +116,93 @@ func (msg MsgIssue) GetSigners() []sdk.Address {
return []sdk.Address{msg.Issuer}
}
// Returns the sdk.Tags for the message
func (msg MsgIssue) Tags() sdk.Tags {
return sdk.NewTags("issuer", []byte(msg.Issuer.String())).
AppendTag("receiver", []byte(msg.Receiver.String()))
}
//------------------------------------------------------------------
// Handler for the message
func NewApp2Handler(keyAcc *sdk.KVStoreKey, keyMain *sdk.KVStoreKey) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MsgSend:
return handleMsgSend(ctx, keyAcc, msg)
case MsgIssue:
return handleMsgIssue(ctx, keyMain, keyAcc, msg)
default:
errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name()
return sdk.ErrUnknownRequest(errMsg).Result()
}
}
}
// Handle Msg Issue
func handleMsgIssue(ctx sdk.Context, keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey, msg MsgIssue) sdk.Result {
store := ctx.KVStore(keyMain)
accStore := ctx.KVStore(keyAcc)
for _, o := range msg.Outputs {
for _, coin := range o.Coins {
bz := store.Get([]byte(coin.Denom))
var metadata CoinMetadata
if bz == nil {
// Coin not set yet, initialize with issuer and default values
// Coin amount can't be above default value
if coin.Amount.GT(sdk.NewInt(1000000)) {
return sdk.ErrInvalidCoins("Cannot issue that many new coins").Result()
}
metadata = CoinMetadata{
TotalSupply: sdk.NewInt(1000000),
CurrentSupply: sdk.NewInt(0),
Issuer: msg.Issuer,
Decimal: 10,
}
} else {
// Decode coin metadata
err := json.Unmarshal(bz, &metadata)
if err != nil {
return sdk.ErrInternal("Decoding coin metadata failed").Result()
}
}
// Return error result if msg Issuer is not equal to coin issuer
if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) {
return sdk.ErrUnauthorized(fmt.Sprintf("Msg issuer cannot issue these coins: %s", coin.Denom)).Result()
}
// Issuer cannot issue more than remaining supply
issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply)
if coin.Amount.GT(issuerSupply) {
return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result()
}
// Update coin metadata
metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount)
val, err := json.Marshal(metadata)
if err != nil {
return sdk.ErrInternal("Encoding coin metadata failed").Result()
}
// Update coin metadata in store
store.Set([]byte(coin.Denom), val)
func handleMsgIssue(keyMain *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
issueMsg, ok := msg.(MsgIssue)
if !ok {
return sdk.NewError(2, 1, "IssueMsg is malformed").Result()
}
// Add coins to receiver account
bz := accStore.Get(o.Address)
var acc appAccount
if bz == nil {
// Receiver account does not already exist, create a new one.
acc = appAccount{}
} else {
// Receiver account already exists. Retrieve and decode it.
err := json.Unmarshal(bz, &acc)
if err != nil {
return sdk.ErrInternal("Account decoding error").Result()
}
// Retrieve stores
store := ctx.KVStore(keyMain)
accStore := ctx.KVStore(keyAcc)
// Handle updating metadata
if res := handleMetaData(store, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() {
return res
}
// Add amount to receiver's old coins
receiverCoins := acc.Coins.Plus(o.Coins)
// Update receiver account
acc.Coins = receiverCoins
// Encode receiver account
val, err := json.Marshal(acc)
if err != nil {
return sdk.ErrInternal("Account encoding error").Result()
// Issue coins to receiver using previously defined handleTo function
if res := handleTo(accStore, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin}); !res.IsOK() {
return res
}
// set account with new issued coins in store
store.Set(o.Address, val)
return sdk.Result{
// Return result with Issue msg tags
Tags: issueMsg.Tags(),
}
}
return sdk.Result{
// TODO: Tags
}
}
func handleMetaData(store sdk.KVStore, issuer sdk.Address, coin sdk.Coin) sdk.Result {
bz := store.Get([]byte(coin.Denom))
var metadata CoinMetadata
if bz == nil {
// Coin not set yet, initialize with issuer and default values
// Coin amount can't be above default value
if coin.Amount.GT(sdk.NewInt(1000000)) {
return sdk.ErrInvalidCoins("Cannot issue that many new coins").Result()
}
metadata = CoinMetadata{
TotalSupply: sdk.NewInt(1000000),
CurrentSupply: sdk.NewInt(0),
Issuer: issuer,
Decimal: 10,
}
} else {
// Decode coin metadata
err := json.Unmarshal(bz, &metadata)
if err != nil {
return sdk.ErrInternal("Decoding coin metadata failed").Result()
}
}
// Msg Issuer is not authorized to issue these coins
if !reflect.DeepEqual(metadata.Issuer, issuer) {
return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result()
}
// Update coin current circulating supply
metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount)
// Current supply cannot exceed total supply
if metadata.TotalSupply.LT(metadata.CurrentSupply) {
return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result()
}
val, err := json.Marshal(metadata)
if err != nil {
return sdk.ErrInternal(fmt.Sprintf("Error encoding metadata: %s", err.Error())).Result()
}
// Update store with new metadata
store.Set([]byte(coin.Denom), val)
return sdk.Result{}
}
//------------------------------------------------------------------
// Tx

View File

@ -2,8 +2,8 @@ package app
import (
"encoding/json"
"fmt"
"reflect"
"fmt"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
@ -44,7 +44,8 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Register message routes.
// Note the handler gets access to the account store.
app.Router().
AddRoute("bank", NewApp3Handler(accountKeeper, metadataMapper))
AddRoute("send", betterHandleMsgSend(accountKeeper)).
AddRoute("issue", betterHandleMsgIssue(metadataMapper, accountKeeper))
// Mount stores and load the latest state.
app.MountStoresIAVL(keyAccount, keyMain, keyFees)
@ -55,91 +56,105 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
return app
}
func NewApp3Handler(accountKeeper bank.Keeper, metadataMapper MetaDataMapper) sdk.Handler {
func betterHandleMsgSend(accountKeeper bank.Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MsgSend:
return betterHandleMsgSend(ctx, accountKeeper, msg)
case MsgIssue:
return betterHandleMsgIssue(ctx, metadataMapper, accountKeeper, msg)
default:
errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name()
return sdk.ErrUnknownRequest(errMsg).Result()
sendMsg, ok := msg.(MsgSend)
if !ok {
return sdk.NewError(2, 1, "Send Message Malformed").Result()
}
// Subtract coins from sender account
_, _, err := accountKeeper.SubtractCoins(ctx, sendMsg.From, sendMsg.Amount)
if err != nil {
// if error, return its result
return err.Result()
}
// Add coins to receiver account
_, _, err = accountKeeper.AddCoins(ctx, sendMsg.To, sendMsg.Amount)
if err != nil {
// if error, return its result
return err.Result()
}
return sdk.Result{
Tags: sendMsg.Tags(),
}
}
}
func betterHandleMsgSend(ctx sdk.Context, accountKeeper bank.Keeper, msg MsgSend) sdk.Result {
// Subtract coins from sender account
_, _, err := accountKeeper.SubtractCoins(ctx, msg.From, msg.Amount)
if err != nil {
// if error, return its result
return err.Result()
}
// Add coins to receiver account
_, _, err = accountKeeper.AddCoins(ctx, msg.To, msg.Amount)
if err != nil {
// if error, return its result
return err.Result()
}
return sdk.Result{}
}
func betterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, accountKeeper bank.Keeper, msg MsgIssue) sdk.Result {
for _, o := range msg.Outputs {
for _, coin := range o.Coins {
metadata := metadataMapper.GetMetaData(ctx, coin.Denom)
if len(metadata.Issuer) == 0 {
// coin doesn't have issuer yet, set issuer to msg issuer
metadata.Issuer = msg.Issuer
}
// Check that msg Issuer is authorized to issue these coins
if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) {
return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue these coins: %s", coin.Denom)).Result()
}
// Issuer cannot issue more than remaining supply
issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply)
if coin.Amount.GT(issuerSupply) {
return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result()
}
// update metadata current circulating supply
metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount)
metadataMapper.SetMetaData(ctx, coin.Denom, metadata)
func betterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
issueMsg, ok := msg.(MsgIssue)
if !ok {
return sdk.NewError(2, 1, "Issue Message Malformed").Result()
}
// Handle updating metadata
if res := betterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() {
return res
}
// Add newly issued coins to output address
_, _, err := accountKeeper.AddCoins(ctx, o.Address, o.Coins)
_, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin})
if err != nil {
return err.Result()
}
return sdk.Result{
// Return result with Issue msg tags
Tags: issueMsg.Tags(),
}
}
}
func betterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result {
metadata := metadataMapper.GetMetaData(ctx, coin.Denom)
// Metadata was created fresh, should set issuer to msg issuer
if len(metadata.Issuer) == 0 {
metadata.Issuer = issuer
}
// Msg Issuer is not authorized to issue these coins
if !reflect.DeepEqual(metadata.Issuer, issuer) {
return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result()
}
// Update current circulating supply
metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount)
// Current supply cannot exceed total supply
if metadata.TotalSupply.LT(metadata.CurrentSupply) {
return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result()
}
metadataMapper.SetMetaData(ctx, coin.Denom, metadata)
return sdk.Result{}
}
//------------------------------------------------------------------
// Mapper for Coin Metadata
// Example of a very simple user-defined mapper
// Example of a very simple user-defined mapper interface
type MetaDataMapper interface {
GetMetaData(sdk.Context, string) CoinMetadata
SetMetaData(sdk.Context, string, CoinMetadata)
}
// Implements MetaDataMapper
type App3MetaDataMapper struct {
mainKey *sdk.KVStoreKey
}
// Construct new App3MetaDataMapper
func NewApp3MetaDataMapper(key *sdk.KVStoreKey) App3MetaDataMapper {
return App3MetaDataMapper{mainKey: key}
}
// Implements MetaDataMpper. Returns metadata for coin
// If metadata does not exist in store, function creates default metadata and returns it
// without adding it to the store.
func (mdm App3MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata {
store := ctx.KVStore(mdm.mainKey)
@ -160,6 +175,7 @@ func (mdm App3MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMet
return metadata
}
// Implements MetaDataMapper. Sets metadata in store with key equal to denom.
func (mdm App3MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) {
store := ctx.KVStore(mdm.mainKey)

View File

@ -47,7 +47,8 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp {
// Register message routes.
// Note the handler gets access to the account store.
app.Router().
AddRoute("bank", NewApp4Handler(accountKeeper, metadataMapper))
AddRoute("send", betterHandleMsgSend(accountKeeper)).
AddRoute("issue", evenBetterHandleMsgIssue(metadataMapper, accountKeeper))
// Mount stores and load the latest state.
app.MountStoresIAVL(keyAccount, keyMain, keyFees)
@ -58,6 +59,7 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp {
return app
}
// Application state at Genesis has accounts with starting balances and coins with starting metadata
type GenesisState struct {
Accounts []*GenesisAccount `json:"accounts"`
Coins []*GenesisCoin `json:"coins"`
@ -69,6 +71,7 @@ type GenesisAccount struct {
Coins sdk.Coins `json:"coins"`
}
// Converts GenesisAccount to auth.BaseAccount for storage in account store
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount, err error) {
baseAcc := auth.BaseAccount{
Address: ga.Address,
@ -85,6 +88,7 @@ type GenesisCoin struct {
Decimal uint64 `json:"decimals"`
}
// Converts GenesisCoin to its denom and metadata for storage in main store
func (gc *GenesisCoin) ToMetaData() (string, CoinMetadata) {
return gc.Denom, CoinMetadata{
Issuer: gc.Issuer,
@ -128,66 +132,76 @@ func NewInitChainer(cdc *wire.Codec, accountMapper auth.AccountMapper, metadataM
}
//---------------------------------------------------------------------------------------------
// Now that initializing coin metadata is done in InitChainer we can simplifiy handleMsgIssue
// Now that initializing coin metadata is done in InitChainer we can simplify handleMsgIssue
func NewApp4Handler(accountKeeper bank.Keeper, metadataMapper MetaDataMapper) sdk.Handler {
// New MsgIssue handler will no longer generate coin metadata on the fly.
// Allows issuers (permissioned at genesis) to issue coin to receiver.
func evenBetterHandleMsgIssue(metadataMapper MetaDataMapper, accountKeeper bank.Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MsgSend:
return betterHandleMsgSend(ctx, accountKeeper, msg)
case MsgIssue:
// use new MsgIssue handler
return evenBetterHandleMsgIssue(ctx, metadataMapper, accountKeeper, msg)
default:
errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name()
return sdk.ErrUnknownRequest(errMsg).Result()
issueMsg, ok := msg.(MsgIssue)
if !ok {
return sdk.NewError(2, 1, "Issue Message Malformed").Result()
}
// Handle updating metadata
if res := evenBetterHandleMetaData(ctx, metadataMapper, issueMsg.Issuer, issueMsg.Coin); !res.IsOK() {
return res
}
// Add newly issued coins to output address
_, _, err := accountKeeper.AddCoins(ctx, issueMsg.Receiver, []sdk.Coin{issueMsg.Coin})
if err != nil {
return err.Result()
}
return sdk.Result{
// Return result with Issue msg tags
Tags: issueMsg.Tags(),
}
}
}
func evenBetterHandleMsgIssue(ctx sdk.Context, metadataMapper MetaDataMapper, accountKeeper bank.Keeper, msg MsgIssue) sdk.Result {
for _, o := range msg.Outputs {
for _, coin := range o.Coins {
// Metadata is no longer created on the fly since it is initalized at genesis with InitChain
metadata := metadataMapper.GetMetaData(ctx, coin.Denom)
// Check that msg Issuer is authorized to issue these coins
if !reflect.DeepEqual(metadata.Issuer, msg.Issuer) {
return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue these coins: %s", coin.Denom)).Result()
}
// No longer generates metadata on the fly.
// Returns error result when it cannot find coin metadata
func evenBetterHandleMetaData(ctx sdk.Context, metadataMapper MetaDataMapper, issuer sdk.Address, coin sdk.Coin) sdk.Result {
metadata := metadataMapper.GetMetaData(ctx, coin.Denom)
// Issuer cannot issue more than remaining supply
issuerSupply := metadata.TotalSupply.Sub(metadata.CurrentSupply)
if coin.Amount.GT(issuerSupply) {
return sdk.ErrInsufficientCoins(fmt.Sprintf("Issuer cannot issue that many coins. Current issuer supply: %d", issuerSupply.Int64())).Result()
}
// update metadata current circulating supply
metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount)
metadataMapper.SetMetaData(ctx, coin.Denom, metadata)
}
// Add newly issued coins to output address
_, _, err := accountKeeper.AddCoins(ctx, o.Address, o.Coins)
if err != nil {
return err.Result()
}
// Coin metadata does not exist in store
if reflect.DeepEqual(metadata, CoinMetadata{}) {
return sdk.ErrInvalidCoins(fmt.Sprintf("Cannot find metadata for coin: %s", coin.Denom)).Result()
}
// Msg Issuer not authorized to issue these coins
if !reflect.DeepEqual(metadata.Issuer, issuer) {
return sdk.ErrUnauthorized(fmt.Sprintf("Msg Issuer cannot issue tokens: %s", coin.Denom)).Result()
}
// Update current circulating supply
metadata.CurrentSupply = metadata.CurrentSupply.Add(coin.Amount)
// Current supply cannot exceed total supply
if metadata.TotalSupply.LT(metadata.CurrentSupply) {
return sdk.ErrInsufficientCoins("Issuer cannot issue more than total supply of coin").Result()
}
metadataMapper.SetMetaData(ctx, coin.Denom, metadata)
return sdk.Result{}
}
//---------------------------------------------------------------------------------------------
// Simpler MetaDataMapper no longer able to initalize default CoinMetaData
// Simpler MetaDataMapper no longer able to initialize default CoinMetaData
// Implements MetaDataMapper
type App4MetaDataMapper struct {
mainKey *sdk.KVStoreKey
}
// Constructs new App4MetaDataMapper
func NewApp4MetaDataMapper(key *sdk.KVStoreKey) App4MetaDataMapper {
return App4MetaDataMapper{mainKey: key}
}
// Returns coin Metadata. If metadata not found in store, function returns empty struct.
func (mdm App4MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMetadata {
store := ctx.KVStore(mdm.mainKey)
@ -206,6 +220,7 @@ func (mdm App4MetaDataMapper) GetMetaData(ctx sdk.Context, denom string) CoinMet
return metadata
}
// Sets metadata in store with key equal to coin denom. Same behavior as App3 implementation.
func (mdm App4MetaDataMapper) SetMetaData(ctx sdk.Context, denom string, metadata CoinMetadata) {
store := ctx.KVStore(mdm.mainKey)