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, ¶ms) 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, ¶ms) 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 }