github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/token/keeper.go (about)

     1  package token
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  
     9  	ethcrypto "github.com/ethereum/go-ethereum/crypto"
    10  	app "github.com/fibonacci-chain/fbc/app/types"
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    12  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    13  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/bank"
    14  	types2 "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    15  	"github.com/fibonacci-chain/fbc/x/params"
    16  	"github.com/fibonacci-chain/fbc/x/token/types"
    17  )
    18  
    19  // Keeper maintains the link to data storage and exposes getter/setter methods for the various parts of the state machine
    20  type Keeper struct {
    21  	bankKeeper       bank.Keeper
    22  	supplyKeeper     SupplyKeeper
    23  	accountKeeper    types.AccountKeeper
    24  	feeCollectorName string // name of the FeeCollector ModuleAccount
    25  
    26  	// The reference to the Paramstore to get and set gov specific params
    27  	paramSpace    params.Subspace
    28  	tokenStoreKey sdk.StoreKey // Unexposed key to access name store from sdk.Context
    29  	lockStoreKey  sdk.StoreKey
    30  	//TokenPairNewSignalChan chan types.TokenPair
    31  
    32  	cdc *codec.Codec // The wire codec for binary encoding/decoding.
    33  
    34  	enableBackend bool // whether open backend plugin
    35  
    36  	// cache data in memory to avoid marshal/unmarshal too frequently
    37  	// reset cache data in BeginBlock
    38  	cache *Cache
    39  }
    40  
    41  // NewKeeper creates a new token keeper
    42  func NewKeeper(bankKeeper bank.Keeper, paramSpace params.Subspace,
    43  	feeCollectorName string, supplyKeeper SupplyKeeper, tokenStoreKey, lockStoreKey sdk.StoreKey,
    44  	cdc *codec.Codec, enableBackend bool, ak types.AccountKeeper) Keeper {
    45  
    46  	k := Keeper{
    47  		bankKeeper:       bankKeeper,
    48  		paramSpace:       paramSpace.WithKeyTable(types.ParamKeyTable()),
    49  		feeCollectorName: feeCollectorName,
    50  		supplyKeeper:     supplyKeeper,
    51  		accountKeeper:    ak,
    52  		tokenStoreKey:    tokenStoreKey,
    53  		lockStoreKey:     lockStoreKey,
    54  		cdc:              cdc,
    55  		enableBackend:    enableBackend,
    56  		cache:            NewCache(),
    57  	}
    58  	return k
    59  }
    60  
    61  // nolint
    62  func (k Keeper) ResetCache(ctx sdk.Context) {
    63  	k.cache.reset()
    64  }
    65  
    66  // nolint
    67  func (k Keeper) GetTokenInfo(ctx sdk.Context, symbol string) types.Token {
    68  	var token types.Token
    69  	store := ctx.KVStore(k.tokenStoreKey)
    70  	bz := store.Get(types.GetTokenAddress(symbol))
    71  	if bz == nil {
    72  		return token
    73  	}
    74  	k.cdc.MustUnmarshalBinaryBare(bz, &token)
    75  	return token
    76  }
    77  
    78  // nolint
    79  func (k Keeper) GetTokenTotalSupply(ctx sdk.Context, symbol string) sdk.Dec {
    80  	return k.supplyKeeper.GetSupplyByDenom(ctx, symbol)
    81  }
    82  
    83  // TokenExist checks whether the token with symbol exist or not
    84  func (k Keeper) TokenExist(ctx sdk.Context, symbol string) bool {
    85  	store := ctx.KVStore(k.tokenStoreKey)
    86  	return store.Has(types.GetTokenAddress(symbol))
    87  }
    88  
    89  // nolint
    90  func (k Keeper) GetTokensInfo(ctx sdk.Context) (tokens []types.Token) {
    91  	store := ctx.KVStore(k.tokenStoreKey)
    92  	iter := sdk.KVStorePrefixIterator(store, types.TokenKey)
    93  	defer iter.Close()
    94  	for iter.Valid() {
    95  		var token types.Token
    96  		tokenBytes := iter.Value()
    97  		k.cdc.MustUnmarshalBinaryBare(tokenBytes, &token)
    98  		tokens = append(tokens, token)
    99  		iter.Next()
   100  	}
   101  	return tokens
   102  }
   103  
   104  // GetUserTokensInfo gets tokens info by owner address
   105  func (k Keeper) GetUserTokensInfo(ctx sdk.Context, owner sdk.AccAddress) (tokens []types.Token) {
   106  	userTokenPrefix := types.GetUserTokenPrefix(owner)
   107  	userTokenPrefixLen := len(userTokenPrefix)
   108  	store := ctx.KVStore(k.tokenStoreKey)
   109  	iter := sdk.KVStorePrefixIterator(store, userTokenPrefix)
   110  	defer iter.Close()
   111  	for iter.Valid() {
   112  		userTokenKey := iter.Key()
   113  		symbol := string(userTokenKey[userTokenPrefixLen:])
   114  		tokens = append(tokens, k.GetTokenInfo(ctx, symbol))
   115  
   116  		iter.Next()
   117  	}
   118  
   119  	return tokens
   120  }
   121  
   122  // GetCurrenciesInfo returns all of the currencies info
   123  func (k Keeper) GetCurrenciesInfo(ctx sdk.Context) (currencies []types.Currency) {
   124  	store := ctx.KVStore(k.tokenStoreKey)
   125  	iter := sdk.KVStorePrefixIterator(store, types.TokenKey)
   126  	defer iter.Close()
   127  	//iter := store.Iterator(nil, nil)
   128  	for iter.Valid() {
   129  		var token types.Token
   130  		tokenBytes := iter.Value()
   131  		k.cdc.MustUnmarshalBinaryBare(tokenBytes, &token)
   132  
   133  		supply := k.supplyKeeper.GetSupplyByDenom(ctx, token.Symbol)
   134  		currencies = append(currencies,
   135  			types.Currency{
   136  				Description: token.Description,
   137  				Symbol:      token.Symbol,
   138  				TotalSupply: supply,
   139  			})
   140  		iter.Next()
   141  	}
   142  	return currencies
   143  }
   144  
   145  // DeleteUserToken deletes token by user address and symbol
   146  func (k Keeper) DeleteUserToken(ctx sdk.Context, owner sdk.AccAddress, symbol string) {
   147  	store := ctx.KVStore(k.tokenStoreKey)
   148  	store.Delete(types.GetUserTokenKey(owner, symbol))
   149  }
   150  
   151  // nolint
   152  func (k Keeper) NewToken(ctx sdk.Context, token types.Token) {
   153  	// save token info
   154  	store := ctx.KVStore(k.tokenStoreKey)
   155  	store.Set(types.GetTokenAddress(token.Symbol), k.cdc.MustMarshalBinaryBare(token))
   156  	store.Set(types.GetUserTokenKey(token.Owner, token.Symbol), []byte{})
   157  
   158  	// update token number
   159  	tokenNumber := k.getTokenNum(ctx)
   160  	b := k.cdc.MustMarshalBinaryBare(tokenNumber + 1)
   161  	store.Set(types.TokenNumberKey, b)
   162  }
   163  
   164  func (k Keeper) UpdateToken(ctx sdk.Context, token types.Token) {
   165  	store := ctx.KVStore(k.tokenStoreKey)
   166  	store.Set(types.GetTokenAddress(token.Symbol), k.cdc.MustMarshalBinaryBare(token))
   167  }
   168  
   169  func (k Keeper) IsContractAddress(ctx sdk.Context, addr sdk.AccAddress) bool {
   170  	acc := k.accountKeeper.GetAccount(ctx, addr)
   171  	if acc != nil {
   172  		ethAcc, ok := acc.(*app.EthAccount)
   173  		if ok {
   174  			return bytes.Compare(ethAcc.CodeHash, ethcrypto.Keccak256(nil)) != 0
   175  		}
   176  	}
   177  	return false
   178  }
   179  
   180  // SendCoinsFromAccountToAccount - send token from one account to another account
   181  func (k Keeper) SendCoinsFromAccountToAccount(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.SysCoins) error {
   182  	if k.bankKeeper.BlacklistedAddr(to) {
   183  		return types.ErrBlockedRecipient(to.String())
   184  	}
   185  
   186  	if k.IsContractAddress(ctx, to) {
   187  		return types.ErrBlockedContractRecipient(to.String())
   188  	}
   189  
   190  	return k.bankKeeper.SendCoins(ctx, from, to, amt)
   191  }
   192  
   193  // nolint
   194  func (k Keeper) LockCoins(ctx sdk.Context, addr sdk.AccAddress, coins sdk.SysCoins, lockCoinsType int) error {
   195  	if err := k.supplyKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, coins); err != nil {
   196  		return types.ErrSendCoinsFromAccountToModuleFailed(err.Error())
   197  	}
   198  	// update lock coins
   199  	return k.updateLockedCoins(ctx, addr, coins, true, lockCoinsType)
   200  }
   201  
   202  // nolint
   203  func (k Keeper) updateLockedCoins(ctx sdk.Context, addr sdk.AccAddress, coins sdk.SysCoins, doAdd bool, lockCoinsType int) error {
   204  	var key []byte
   205  	switch lockCoinsType {
   206  	case types.LockCoinsTypeQuantity:
   207  		key = types.GetLockAddress(addr.Bytes())
   208  	case types.LockCoinsTypeFee:
   209  		key = types.GetLockFeeAddress(addr.Bytes())
   210  	default:
   211  		return types.ErrUnrecognizedLockCoinsType(lockCoinsType)
   212  	}
   213  
   214  	var newCoins sdk.SysCoins
   215  	var oldCoins sdk.SysCoins
   216  
   217  	store := ctx.KVStore(k.lockStoreKey)
   218  	coinsBytes := store.Get(key)
   219  
   220  	if doAdd {
   221  		// lock coins
   222  		if coinsBytes == nil {
   223  			newCoins = coins
   224  		} else {
   225  			k.cdc.MustUnmarshalBinaryBare(coinsBytes, &oldCoins)
   226  			newCoins = oldCoins.Add2(coins)
   227  		}
   228  	} else {
   229  		// unlock coins
   230  		if coinsBytes == nil {
   231  			return types.ErrFailedToUnlockAddress(coins.String(), addr.String())
   232  		}
   233  		k.cdc.MustUnmarshalBinaryBare(coinsBytes, &oldCoins)
   234  		var isNegative bool
   235  		newCoins, isNegative = oldCoins.SafeSub(coins)
   236  		if isNegative {
   237  			return types.ErrFailedToUnlockAddress(coins.String(), addr.String())
   238  		}
   239  	}
   240  
   241  	sort.Sort(newCoins)
   242  	if len(newCoins) > 0 {
   243  		store.Set(key, k.cdc.MustMarshalBinaryBare(newCoins))
   244  	} else {
   245  		store.Delete(key)
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  // nolint
   252  func (k Keeper) UnlockCoins(ctx sdk.Context, addr sdk.AccAddress, coins sdk.SysCoins, lockCoinsType int) error {
   253  	// update lock coins
   254  	if err := k.updateLockedCoins(ctx, addr, coins, false, lockCoinsType); err != nil {
   255  		return err
   256  	}
   257  
   258  	// update account
   259  	if err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, coins); err != nil {
   260  		return types.ErrSendCoinsFromModuleToAccountFailed(err.Error())
   261  	}
   262  
   263  	return nil
   264  }
   265  
   266  // GetLockCoins gets locked coins by address
   267  func (k Keeper) GetLockedCoins(ctx sdk.Context, addr sdk.AccAddress) (coins sdk.SysCoins) {
   268  	store := ctx.KVStore(k.lockStoreKey)
   269  	coinsBytes := store.Get(types.GetLockAddress(addr.Bytes()))
   270  	if coinsBytes == nil {
   271  		return coins
   272  	}
   273  	k.cdc.MustUnmarshalBinaryBare(coinsBytes, &coins)
   274  	return coins
   275  }
   276  
   277  // GetAllLockCoins iterates KVStore and gets all of the locked coins
   278  func (k Keeper) GetAllLockedCoins(ctx sdk.Context) (locks []types.AccCoins) {
   279  	store := ctx.KVStore(k.lockStoreKey)
   280  	iter := sdk.KVStorePrefixIterator(store, types.LockKey)
   281  	defer iter.Close()
   282  	for iter.Valid() {
   283  		var accCoins types.AccCoins
   284  		accCoins.Acc = iter.Key()[len(types.LockKey):]
   285  		coinsBytes := iter.Value()
   286  		var coins sdk.SysCoins
   287  		k.cdc.MustUnmarshalBinaryBare(coinsBytes, &coins)
   288  		accCoins.Coins = coins
   289  		locks = append(locks, accCoins)
   290  		iter.Next()
   291  	}
   292  	return locks
   293  }
   294  
   295  // IterateAllDeposits iterates over the all the stored lock fee and performs a callback function
   296  func (k Keeper) IterateLockedFees(ctx sdk.Context, cb func(acc sdk.AccAddress, coins sdk.SysCoins) (stop bool)) {
   297  	store := ctx.KVStore(k.lockStoreKey)
   298  	iter := sdk.KVStorePrefixIterator(store, types.LockedFeeKey)
   299  	defer iter.Close()
   300  	for ; iter.Valid(); iter.Next() {
   301  		acc := iter.Key()[len(types.LockKey):]
   302  
   303  		var coins sdk.SysCoins
   304  		k.cdc.MustUnmarshalBinaryBare(iter.Value(), &coins)
   305  
   306  		if cb(acc, coins) {
   307  			break
   308  		}
   309  	}
   310  }
   311  
   312  // BalanceAccount is ONLY expected by the order module to settle an order where outputCoins
   313  // is used to exchange inputCoins
   314  func (k Keeper) BalanceAccount(ctx sdk.Context, addr sdk.AccAddress, outputCoins sdk.SysCoins,
   315  	inputCoins sdk.SysCoins) (err error) {
   316  
   317  	if !outputCoins.IsZero() {
   318  		if err = k.updateLockedCoins(ctx, addr, outputCoins, false, types.LockCoinsTypeQuantity); err != nil {
   319  			return types.ErrUpdateLockedCoins()
   320  		}
   321  	}
   322  
   323  	if !inputCoins.IsZero() {
   324  		return k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, inputCoins)
   325  	}
   326  
   327  	return nil
   328  }
   329  
   330  // nolint
   331  func (k Keeper) GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.SysCoins {
   332  	return k.bankKeeper.GetCoins(ctx, addr)
   333  }
   334  
   335  // GetParams gets inflation params from the global param store
   336  func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
   337  	k.paramSpace.GetParamSet(ctx, &params)
   338  	return params
   339  }
   340  
   341  // SetParams set inflation params from the global param store
   342  func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
   343  	k.paramSpace.SetParamSet(ctx, &params)
   344  }
   345  
   346  // GetCoinsInfo gets all of the coin info by addr
   347  func (k Keeper) GetCoinsInfo(ctx sdk.Context, addr sdk.AccAddress) (coinsInfo types.CoinsInfo) {
   348  	availableCoins := k.GetCoins(ctx, addr)
   349  	lockedCoins := k.GetLockedCoins(ctx, addr)
   350  
   351  	// merge coins
   352  	coinsInfo = types.MergeCoinInfo(availableCoins, lockedCoins)
   353  	return coinsInfo
   354  }
   355  
   356  // GetFeeDetailList gets fee detail list from cache
   357  func (k Keeper) GetFeeDetailList() []*FeeDetail {
   358  	return k.cache.getFeeDetailList()
   359  }
   360  
   361  // nolint
   362  func (k Keeper) AddFeeDetail(ctx sdk.Context, from string, fee sdk.SysCoins, feeType string, receiver string) {
   363  	if k.enableBackend {
   364  		feeDetail := &FeeDetail{
   365  			Address:   from,
   366  			Fee:       fee.String(),
   367  			FeeType:   feeType,
   368  			Timestamp: ctx.BlockTime().Unix(),
   369  			Receiver:  receiver,
   370  		}
   371  		k.cache.addFeeDetail(feeDetail)
   372  	}
   373  }
   374  
   375  func (k Keeper) getNumKeys(ctx sdk.Context) (tokenStoreKeyNum, lockStoreKeyNum int64) {
   376  	{
   377  		store := ctx.KVStore(k.tokenStoreKey)
   378  		iter := store.Iterator(nil, nil)
   379  		defer iter.Close()
   380  		for ; iter.Valid(); iter.Next() {
   381  			tokenStoreKeyNum++
   382  		}
   383  	}
   384  	{
   385  		store := ctx.KVStore(k.lockStoreKey)
   386  		iter := store.Iterator(nil, nil)
   387  		defer iter.Close()
   388  		for ; iter.Valid(); iter.Next() {
   389  			lockStoreKeyNum++
   390  		}
   391  	}
   392  
   393  	return
   394  }
   395  
   396  func (k Keeper) getTokenNum(ctx sdk.Context) (tokenNumber uint64) {
   397  	store := ctx.KVStore(k.tokenStoreKey)
   398  	b := store.Get(types.TokenNumberKey)
   399  	if b != nil {
   400  		k.cdc.MustUnmarshalBinaryBare(b, &tokenNumber)
   401  	}
   402  	return
   403  }
   404  
   405  // addTokenSuffix add token suffix
   406  func addTokenSuffix(ctx sdk.Context, keeper Keeper, originalSymbol string) (name string, valid bool) {
   407  	hash := fmt.Sprintf("%x", types2.Tx(ctx.TxBytes()).Hash(ctx.BlockHeight()))
   408  	var i int
   409  	for i = len(hash)/3 - 1; i >= 0; i-- {
   410  		name = originalSymbol + "-" + strings.ToLower(hash[3*i:3*i+3])
   411  		// check token name valid
   412  		if sdk.ValidateDenom(name) != nil {
   413  			return "", false
   414  		}
   415  		if !keeper.TokenExist(ctx, name) {
   416  			break
   417  		}
   418  	}
   419  	if i == -1 {
   420  		return "", false
   421  	}
   422  	return name, true
   423  }
   424  
   425  // GetConfirmOwnership returns ownership confirming information
   426  func (k Keeper) GetConfirmOwnership(ctx sdk.Context, symbol string) (confirmOwnership *types.ConfirmOwnership, exist bool) {
   427  	store := ctx.KVStore(k.tokenStoreKey)
   428  	bytes := store.Get(types.GetConfirmOwnershipKey(symbol))
   429  	if bytes == nil {
   430  		return nil, false
   431  	}
   432  
   433  	k.cdc.MustUnmarshalBinaryBare(bytes, &confirmOwnership)
   434  	return confirmOwnership, true
   435  }
   436  
   437  // SetConfirmOwnership sets ownership confirming information to db
   438  func (k Keeper) SetConfirmOwnership(ctx sdk.Context, confirmOwnership *types.ConfirmOwnership) {
   439  	store := ctx.KVStore(k.tokenStoreKey)
   440  	key := types.GetConfirmOwnershipKey(confirmOwnership.Symbol)
   441  	store.Set(key, k.cdc.MustMarshalBinaryBare(confirmOwnership))
   442  }
   443  
   444  // DeleteConfirmOwnership deletes ownership confirming information from db
   445  func (k Keeper) DeleteConfirmOwnership(ctx sdk.Context, symbol string) {
   446  	store := ctx.KVStore(k.tokenStoreKey)
   447  	key := types.GetConfirmOwnershipKey(symbol)
   448  	store.Delete(key)
   449  }