github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/supply/internal/keeper/bank.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     7  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/supply/internal/types"
     9  )
    10  
    11  // SendCoinsFromModuleToAccount transfers coins from a ModuleAccount to an AccAddress.
    12  // It will panic if the module account does not exist.
    13  func (k Keeper) SendCoinsFromModuleToAccount(
    14  	ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins,
    15  ) error {
    16  	if k.bk.BlacklistedAddr(recipientAddr) {
    17  		return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "Address <%s> in blacklist is not allowed", recipientAddr)
    18  	}
    19  	senderAddr := k.GetModuleAddress(senderModule)
    20  	if senderAddr == nil {
    21  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule))
    22  	}
    23  
    24  	return k.bk.SendCoins(ctx, senderAddr, recipientAddr, amt)
    25  }
    26  
    27  // SendCoinsFromModuleToModule transfers coins from a ModuleAccount to another.
    28  // It will panic if either module account does not exist.
    29  func (k Keeper) SendCoinsFromModuleToModule(
    30  	ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins,
    31  ) error {
    32  
    33  	senderAddr := k.GetModuleAddress(senderModule)
    34  	if senderAddr == nil {
    35  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule))
    36  	}
    37  
    38  	recipientAcc := k.GetModuleAccount(ctx, recipientModule)
    39  	if recipientAcc == nil {
    40  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule))
    41  	}
    42  
    43  	return k.bk.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt)
    44  }
    45  
    46  // SendCoinsFromAccountToModule transfers coins from an AccAddress to a ModuleAccount.
    47  // It will panic if the module account does not exist.
    48  func (k Keeper) SendCoinsFromAccountToModule(
    49  	ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins,
    50  ) error {
    51  	recipientAcc := k.GetModuleAccount(ctx, recipientModule)
    52  	if recipientAcc == nil {
    53  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule))
    54  	}
    55  
    56  	// GetModuleAccount may create a new module account, we don't know does the gas consumed contains the gas of new account creation
    57  	ctx.UpdateToAccountCache(recipientAcc, 0)
    58  
    59  	return k.bk.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt)
    60  }
    61  
    62  // DelegateCoinsFromAccountToModule delegates coins and transfers them from a
    63  // delegator account to a module account. It will panic if the module account
    64  // does not exist or is unauthorized.
    65  func (k Keeper) DelegateCoinsFromAccountToModule(
    66  	ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins,
    67  ) error {
    68  
    69  	recipientAcc := k.GetModuleAccount(ctx, recipientModule)
    70  	if recipientAcc == nil {
    71  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule))
    72  	}
    73  
    74  	if !recipientAcc.HasPermission(types.Staking) {
    75  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to receive delegated coins", recipientModule))
    76  	}
    77  
    78  	return k.bk.DelegateCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt)
    79  }
    80  
    81  // UndelegateCoinsFromModuleToAccount undelegates the unbonding coins and transfers
    82  // them from a module account to the delegator account. It will panic if the
    83  // module account does not exist or is unauthorized.
    84  func (k Keeper) UndelegateCoinsFromModuleToAccount(
    85  	ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins,
    86  ) error {
    87  
    88  	acc := k.GetModuleAccount(ctx, senderModule)
    89  	if acc == nil {
    90  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule))
    91  	}
    92  
    93  	if !acc.HasPermission(types.Staking) {
    94  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to undelegate coins", senderModule))
    95  	}
    96  
    97  	return k.bk.UndelegateCoins(ctx, acc.GetAddress(), recipientAddr, amt)
    98  }
    99  
   100  // MintCoins creates new coins from thin air and adds it to the module account.
   101  // It will panic if the module account does not exist or is unauthorized.
   102  func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error {
   103  	acc := k.GetModuleAccount(ctx, moduleName)
   104  	if acc == nil {
   105  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName))
   106  	}
   107  
   108  	if !acc.HasPermission(types.Minter) {
   109  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to mint tokens", moduleName))
   110  	}
   111  
   112  	_, err := k.bk.AddCoins(ctx, acc.GetAddress(), amt)
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	// update supply
   118  	for i := 0; i < len(amt); i++ {
   119  		k.inflate(ctx, amt[i].Denom, amt[i].Amount)
   120  	}
   121  
   122  	logger := k.Logger(ctx)
   123  	logger.Info(fmt.Sprintf("minted %s from %s module account", amt.String(), moduleName))
   124  
   125  	return nil
   126  }
   127  
   128  // BurnCoins burns coins deletes coins from the balance of the module account.
   129  // It will panic if the module account does not exist or is unauthorized.
   130  func (k Keeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error {
   131  	acc := k.GetModuleAccount(ctx, moduleName)
   132  	if acc == nil {
   133  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName))
   134  	}
   135  
   136  	if !acc.HasPermission(types.Burner) {
   137  		panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to burn tokens", moduleName))
   138  	}
   139  
   140  	_, err := k.bk.SubtractCoins(ctx, acc.GetAddress(), amt)
   141  	if err != nil {
   142  		return err
   143  	}
   144  
   145  	// update supply
   146  	for i := 0; i < len(amt); i++ {
   147  		if err = k.deflate(ctx, amt[i].Denom, amt[i].Amount); err != nil {
   148  			return err
   149  		}
   150  	}
   151  
   152  	logger := k.Logger(ctx)
   153  	logger.Info(fmt.Sprintf("burned %s from %s module account", amt.String(), moduleName))
   154  
   155  	return nil
   156  }
   157  
   158  // GetSupplyByDenom gets the amount of a token supply from the store
   159  func (k Keeper) GetSupplyByDenom(ctx sdk.Context, denom string) sdk.Dec {
   160  	tokenSupplyAmount := sdk.ZeroDec()
   161  	bytes := ctx.KVStore(k.storeKey).Get(getTokenSupplyKey(denom))
   162  	if bytes == nil {
   163  		return tokenSupplyAmount
   164  	}
   165  
   166  	k.cdc.MustUnmarshalBinaryLengthPrefixed(bytes, &tokenSupplyAmount)
   167  	return tokenSupplyAmount
   168  }
   169  
   170  // inflate adds the amount of a token in the store
   171  func (k Keeper) inflate(ctx sdk.Context, tokenSymbol string, amount sdk.Dec) {
   172  	if amount.Equal(sdk.ZeroDec()) {
   173  		return
   174  	}
   175  
   176  	originalSupplyAmount := k.GetSupplyByDenom(ctx, tokenSymbol)
   177  	k.setTokenSupplyAmount(ctx, tokenSymbol, originalSupplyAmount.Add(amount))
   178  }
   179  
   180  // deflate subtracts the amount of a token from the original in the store
   181  func (k Keeper) deflate(ctx sdk.Context, tokenSymbol string, deflationAmount sdk.Dec) error {
   182  	currentSupplyAmount := k.GetSupplyByDenom(ctx, tokenSymbol)
   183  	supplyAmount := currentSupplyAmount.Sub(deflationAmount)
   184  	if supplyAmount.IsNegative() {
   185  		return types.ErrInvalidDeflation
   186  	}
   187  
   188  	k.setTokenSupplyAmount(ctx, tokenSymbol, supplyAmount)
   189  	return nil
   190  }