github.com/Finschia/finschia-sdk@v0.49.1/x/fswap/keeper/keeper.go (about) 1 package keeper 2 3 import ( 4 "fmt" 5 6 "github.com/Finschia/ostracon/libs/log" 7 8 "github.com/Finschia/finschia-sdk/codec" 9 "github.com/Finschia/finschia-sdk/store/prefix" 10 storetypes "github.com/Finschia/finschia-sdk/store/types" 11 sdk "github.com/Finschia/finschia-sdk/types" 12 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 13 bank "github.com/Finschia/finschia-sdk/x/bank/types" 14 "github.com/Finschia/finschia-sdk/x/fswap/types" 15 ) 16 17 type Keeper struct { 18 cdc codec.BinaryCodec 19 storeKey storetypes.StoreKey 20 config types.Config 21 authority string 22 BankKeeper 23 } 24 25 func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, config types.Config, authority string, ak AccountKeeper, bk BankKeeper) Keeper { 26 if _, err := sdk.AccAddressFromBech32(authority); err != nil { 27 panic("authority is not a valid acc address") 28 } 29 30 if addr := ak.GetModuleAddress(types.ModuleName); addr == nil { 31 panic("fswap module account has not been set") 32 } 33 34 found := false 35 for _, addr := range types.AuthorityCandidates() { 36 if authority == addr.String() { 37 found = true 38 break 39 } 40 } 41 42 if !found { 43 panic("x/fswap authority must be ether gov or foundation module account") 44 } 45 46 return Keeper{ 47 cdc, 48 storeKey, 49 config, 50 authority, 51 bk, 52 } 53 } 54 55 func (k Keeper) Logger(ctx sdk.Context) log.Logger { 56 return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) 57 } 58 59 func (k Keeper) Swap(ctx sdk.Context, addr sdk.AccAddress, fromCoinAmount sdk.Coin, toDenom string) error { 60 swap, err := k.getSwap(ctx, fromCoinAmount.Denom, toDenom) 61 if err != nil { 62 return err 63 } 64 65 newCoinAmountInt := CalcSwap(swap.SwapRate, fromCoinAmount.Amount) 66 newCoinAmount := sdk.NewCoin(toDenom, newCoinAmountInt) 67 swapped, err := k.getSwapped(ctx, swap.GetFromDenom(), swap.GetToDenom()) 68 if err != nil { 69 return err 70 } 71 72 updateSwapped, err := k.updateSwapped(ctx, swapped, fromCoinAmount, newCoinAmount) 73 if err != nil { 74 return err 75 } 76 77 if err := k.checkSwapCap(swap, updateSwapped); err != nil { 78 return err 79 } 80 81 if err := k.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.NewCoins(fromCoinAmount)); err != nil { 82 return err 83 } 84 85 if err := k.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(fromCoinAmount)); err != nil { 86 return err 87 } 88 89 if err := k.MintCoins(ctx, types.ModuleName, sdk.NewCoins(newCoinAmount)); err != nil { 90 return err 91 } 92 93 if err := k.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, sdk.NewCoins(newCoinAmount)); err != nil { 94 return err 95 } 96 97 if err := ctx.EventManager().EmitTypedEvent(&types.EventSwapCoins{ 98 Address: addr.String(), 99 FromCoinAmount: fromCoinAmount, 100 ToCoinAmount: newCoinAmount, 101 }); err != nil { 102 return err 103 } 104 return nil 105 } 106 107 func (k Keeper) SetSwap(ctx sdk.Context, swap types.Swap, toDenomMetadata bank.Metadata) error { 108 isNewSwap := true 109 if _, err := k.getSwap(ctx, swap.FromDenom, swap.ToDenom); err == nil { 110 isNewSwap = false 111 } 112 113 if !isNewSwap && !k.config.UpdateAllowed { 114 return sdkerrors.ErrInvalidRequest.Wrap("update existing swap not allowed") 115 } 116 117 if isNewSwap { 118 if err := k.increaseSwapCount(ctx); err != nil { 119 return err 120 } 121 } 122 123 stats, err := k.getSwapStats(ctx) 124 if err != nil { 125 return err 126 } 127 128 if int(stats.SwapCount) > k.config.MaxSwaps && !k.isUnlimited() { 129 return types.ErrCanNotHaveMoreSwap.Wrapf("cannot make more swaps, max swaps is %d", k.config.MaxSwaps) 130 } 131 132 if _, ok := k.GetDenomMetaData(ctx, swap.FromDenom); !ok { 133 return sdkerrors.ErrInvalidRequest.Wrap("fromDenom should be existed in chain") 134 } 135 136 if isNewSwap { 137 swapped := types.Swapped{ 138 FromCoinAmount: sdk.Coin{ 139 Denom: swap.GetFromDenom(), 140 Amount: sdk.ZeroInt(), 141 }, 142 ToCoinAmount: sdk.Coin{ 143 Denom: swap.GetToDenom(), 144 Amount: sdk.ZeroInt(), 145 }, 146 } 147 if err := k.setSwapped(ctx, swapped); err != nil { 148 return err 149 } 150 } 151 152 if err := k.setSwap(ctx, swap); err != nil { 153 return err 154 } 155 156 eventManager := ctx.EventManager() 157 if err := eventManager.EmitTypedEvent(&types.EventSetSwap{Swap: swap}); err != nil { 158 panic(err) 159 } 160 161 existingMetadata, ok := k.GetDenomMetaData(ctx, swap.ToDenom) 162 if !ok { 163 k.SetDenomMetaData(ctx, toDenomMetadata) 164 if err := eventManager.EmitTypedEvent(&(types.EventAddDenomMetadata{Metadata: toDenomMetadata})); err != nil { 165 panic(err) 166 } 167 return nil 168 } 169 if !denomMetadataEqual(existingMetadata, toDenomMetadata) { 170 return sdkerrors.ErrInvalidRequest.Wrap("changing existing metadata not allowed") 171 } 172 173 return nil 174 } 175 176 func (k Keeper) getAllSwapped(ctx sdk.Context) []types.Swapped { 177 swappedSlice := []types.Swapped{} 178 k.iterateAllSwapped(ctx, func(swapped types.Swapped) bool { 179 swappedSlice = append(swappedSlice, swapped) 180 return false 181 }) 182 return swappedSlice 183 } 184 185 func (k Keeper) iterateAllSwapped(ctx sdk.Context, cb func(swapped types.Swapped) (stop bool)) { 186 store := ctx.KVStore(k.storeKey) 187 swappedDataStore := prefix.NewStore(store, swappedKeyPrefix) 188 189 iterator := swappedDataStore.Iterator(nil, nil) 190 defer iterator.Close() 191 192 for ; iterator.Valid(); iterator.Next() { 193 swapped := types.Swapped{} 194 k.cdc.MustUnmarshal(iterator.Value(), &swapped) 195 if cb(swapped) { 196 break 197 } 198 } 199 } 200 201 func (k Keeper) getSwapped(ctx sdk.Context, fromDenom, toDenom string) (types.Swapped, error) { 202 store := ctx.KVStore(k.storeKey) 203 key := swappedKey(fromDenom, toDenom) 204 bz := store.Get(key) 205 if bz == nil { 206 return types.Swapped{}, types.ErrSwappedNotFound 207 } 208 209 swapped := types.Swapped{} 210 if err := k.cdc.Unmarshal(bz, &swapped); err != nil { 211 return types.Swapped{}, err 212 } 213 return swapped, nil 214 } 215 216 func (k Keeper) setSwapped(ctx sdk.Context, swapped types.Swapped) error { 217 key := swappedKey(swapped.FromCoinAmount.Denom, swapped.ToCoinAmount.Denom) 218 bz, err := k.cdc.Marshal(&swapped) 219 if err != nil { 220 return err 221 } 222 223 store := ctx.KVStore(k.storeKey) 224 store.Set(key, bz) 225 return nil 226 } 227 228 func (k Keeper) getSwappableNewCoinAmount(ctx sdk.Context, fromDenom, toDenom string) (sdk.Coin, error) { 229 swap, err := k.getSwap(ctx, fromDenom, toDenom) 230 if err != nil { 231 return sdk.Coin{}, err 232 } 233 234 swapped, err := k.getSwapped(ctx, fromDenom, toDenom) 235 if err != nil { 236 return sdk.Coin{}, err 237 } 238 239 swapCap := swap.AmountCapForToDenom 240 remainingAmount := swapCap.Sub(swapped.GetToCoinAmount().Amount) 241 242 return sdk.NewCoin(toDenom, remainingAmount), nil 243 } 244 245 func (k Keeper) updateSwapped(ctx sdk.Context, curSwapped types.Swapped, fromAmount, toAmount sdk.Coin) (types.Swapped, error) { 246 updatedSwapped := types.Swapped{ 247 FromCoinAmount: fromAmount.Add(curSwapped.FromCoinAmount), 248 ToCoinAmount: toAmount.Add(curSwapped.ToCoinAmount), 249 } 250 251 key := swappedKey(fromAmount.Denom, toAmount.Denom) 252 bz, err := k.cdc.Marshal(&updatedSwapped) 253 if err != nil { 254 return types.Swapped{}, err 255 } 256 257 store := ctx.KVStore(k.storeKey) 258 store.Set(key, bz) 259 return updatedSwapped, nil 260 } 261 262 func (k Keeper) checkSwapCap(swap types.Swap, swapped types.Swapped) error { 263 swapCap := swap.AmountCapForToDenom 264 if swapCap.LT(swapped.ToCoinAmount.Amount) { 265 return types.ErrExceedSwappableToCoinAmount 266 } 267 return nil 268 } 269 270 func (k Keeper) getSwapStats(ctx sdk.Context) (types.SwapStats, error) { 271 store := ctx.KVStore(k.storeKey) 272 bz := store.Get(swapStatsKey) 273 if bz == nil { 274 return types.SwapStats{}, nil 275 } 276 277 stats := types.SwapStats{} 278 err := k.cdc.Unmarshal(bz, &stats) 279 if err != nil { 280 return types.SwapStats{}, err 281 } 282 return stats, nil 283 } 284 285 func (k Keeper) setSwapStats(ctx sdk.Context, stats types.SwapStats) error { 286 bz, err := k.cdc.Marshal(&stats) 287 if err != nil { 288 return err 289 } 290 291 store := ctx.KVStore(k.storeKey) 292 store.Set(swapStatsKey, bz) 293 return nil 294 } 295 296 func (k Keeper) validateAuthority(authority string) error { 297 if authority != k.authority { 298 return sdkerrors.ErrUnauthorized.Wrapf("invalid authority; expected %s, got %s", k.authority, authority) 299 } 300 301 return nil 302 } 303 304 func denomMetadataEqual(metadata, otherMetadata bank.Metadata) bool { 305 if metadata.Description != otherMetadata.Description { 306 return false 307 } 308 if len(metadata.DenomUnits) != len(otherMetadata.DenomUnits) { 309 return false 310 } 311 for i, unit := range metadata.DenomUnits { 312 if unit.Denom != otherMetadata.DenomUnits[i].Denom { 313 return false 314 } 315 } 316 if metadata.Base != otherMetadata.Base { 317 return false 318 } 319 if metadata.Display != otherMetadata.Display { 320 return false 321 } 322 if metadata.Name != otherMetadata.Name { 323 return false 324 } 325 if metadata.Symbol != otherMetadata.Symbol { 326 return false 327 } 328 return true 329 } 330 331 func (k Keeper) increaseSwapCount(ctx sdk.Context) error { 332 stats, err := k.getSwapStats(ctx) 333 if err != nil { 334 return err 335 } 336 337 prev := stats.SwapCount 338 stats.SwapCount++ 339 if stats.SwapCount < prev { 340 return types.ErrInvalidState.Wrap("overflow detected") 341 } 342 343 if err := k.setSwapStats(ctx, stats); err != nil { 344 return err 345 } 346 return nil 347 } 348 349 func (k Keeper) setSwap(ctx sdk.Context, swap types.Swap) error { 350 key := swapKey(swap.FromDenom, swap.ToDenom) 351 bz, err := k.cdc.Marshal(&swap) 352 if err != nil { 353 return err 354 } 355 356 store := ctx.KVStore(k.storeKey) 357 store.Set(key, bz) 358 return nil 359 } 360 361 func (k Keeper) getSwap(ctx sdk.Context, fromDenom, toDenom string) (types.Swap, error) { 362 store := ctx.KVStore(k.storeKey) 363 key := swapKey(fromDenom, toDenom) 364 bz := store.Get(key) 365 if bz == nil { 366 return types.Swap{}, sdkerrors.ErrNotFound.Wrap("swap not found") 367 } 368 369 swap := types.Swap{} 370 if err := k.cdc.Unmarshal(bz, &swap); err != nil { 371 return types.Swap{}, err 372 } 373 374 return swap, nil 375 } 376 377 func (k Keeper) getAllSwaps(ctx sdk.Context) []types.Swap { 378 swaps := []types.Swap{} 379 k.iterateAllSwaps(ctx, func(swap types.Swap) bool { 380 swaps = append(swaps, swap) 381 return false 382 }) 383 return swaps 384 } 385 386 func (k Keeper) iterateAllSwaps(ctx sdk.Context, cb func(swapped types.Swap) (stop bool)) { 387 store := ctx.KVStore(k.storeKey) 388 swapDataStore := prefix.NewStore(store, swapPrefix) 389 390 iterator := swapDataStore.Iterator(nil, nil) 391 defer iterator.Close() 392 for ; iterator.Valid(); iterator.Next() { 393 swap := types.Swap{} 394 k.cdc.MustUnmarshal(iterator.Value(), &swap) 395 if cb(swap) { 396 break 397 } 398 } 399 }