-
Notifications
You must be signed in to change notification settings - Fork 568
/
pool.go
260 lines (212 loc) · 7 KB
/
pool.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
package keeper
import (
"fmt"
gogotypes "github.com/gogo/protobuf/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/osmosis-labs/osmosis/v12/osmoutils"
"github.com/osmosis-labs/osmosis/v12/x/gamm/pool-models/balancer"
"github.com/osmosis-labs/osmosis/v12/x/gamm/types"
)
func (k Keeper) MarshalPool(pool types.PoolI) ([]byte, error) {
return k.cdc.MarshalInterface(pool)
}
func (k Keeper) UnmarshalPool(bz []byte) (types.PoolI, error) {
var acc types.PoolI
return acc, k.cdc.UnmarshalInterface(bz, &acc)
}
// GetPoolAndPoke returns a PoolI based on it's identifier if one exists. Prior
// to returning the pool, the weights of the pool are updated via PokePool.
// TODO: Consider rename to GetPool due to downstream API confusion.
func (k Keeper) GetPoolAndPoke(ctx sdk.Context, poolId uint64) (types.PoolI, error) {
store := ctx.KVStore(k.storeKey)
poolKey := types.GetKeyPrefixPools(poolId)
if !store.Has(poolKey) {
return nil, types.PoolDoesNotExistError{PoolId: poolId}
}
bz := store.Get(poolKey)
pool, err := k.UnmarshalPool(bz)
if err != nil {
return nil, err
}
pool.PokePool(ctx.BlockTime())
return pool, nil
}
// Get pool and check if the pool is active, i.e. allowed to be swapped against.
func (k Keeper) getPoolForSwap(ctx sdk.Context, poolId uint64) (types.PoolI, error) {
pool, err := k.GetPoolAndPoke(ctx, poolId)
if err != nil {
return &balancer.Pool{}, err
}
if !pool.IsActive(ctx) {
return &balancer.Pool{}, sdkerrors.Wrapf(types.ErrPoolLocked, "swap on inactive pool")
}
return pool, nil
}
func (k Keeper) iterator(ctx sdk.Context, prefix []byte) sdk.Iterator {
store := ctx.KVStore(k.storeKey)
return sdk.KVStorePrefixIterator(store, prefix)
}
func (k Keeper) GetPoolsAndPoke(ctx sdk.Context) (res []types.PoolI, err error) {
iter := k.iterator(ctx, types.KeyPrefixPools)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
bz := iter.Value()
pool, err := k.UnmarshalPool(bz)
if err != nil {
return nil, err
}
pool.PokePool(ctx.BlockTime())
res = append(res, pool)
}
return res, nil
}
func (k Keeper) setPool(ctx sdk.Context, pool types.PoolI) error {
bz, err := k.MarshalPool(pool)
if err != nil {
return err
}
store := ctx.KVStore(k.storeKey)
poolKey := types.GetKeyPrefixPools(pool.GetId())
store.Set(poolKey, bz)
return nil
}
func (k Keeper) DeletePool(ctx sdk.Context, poolId uint64) error {
store := ctx.KVStore(k.storeKey)
poolKey := types.GetKeyPrefixPools(poolId)
if !store.Has(poolKey) {
return fmt.Errorf("pool with ID %d does not exist", poolId)
}
store.Delete(poolKey)
return nil
}
// CleanupBalancerPool destructs a pool and refund all the assets according to
// the shares held by the accounts. CleanupBalancerPool should not be called during
// the chain execution time, as it iterates the entire account balances.
// TODO: once SDK v0.46.0, use https://github.com/cosmos/cosmos-sdk/pull/9611
//
// All locks on this pool share must be unlocked prior to execution. Use LockupKeeper.ForceUnlock
// on remaining locks before calling this function.
// func (k Keeper) CleanupBalancerPool(ctx sdk.Context, poolIds []uint64, excludedModules []string) (err error) {
// pools := make(map[string]types.PoolI)
// totalShares := make(map[string]sdk.Int)
// for _, poolId := range poolIds {
// pool, err := k.GetPool(ctx, poolId)
// if err != nil {
// return err
// }
// shareDenom := pool.GetTotalShares().Denom
// pools[shareDenom] = pool
// totalShares[shareDenom] = pool.GetTotalShares().Amount
// }
// moduleAccounts := make(map[string]string)
// for _, module := range excludedModules {
// moduleAccounts[string(authtypes.NewModuleAddress(module))] = module
// }
// // first iterate through the share holders and burn them
// k.bankKeeper.IterateAllBalances(ctx, func(addr sdk.AccAddress, coin sdk.Coin) (stop bool) {
// if coin.Amount.IsZero() {
// return
// }
// pool, ok := pools[coin.Denom]
// if !ok {
// return
// }
// // track the iterated shares
// pool.SubTotalShares(coin.Amount)
// pools[coin.Denom] = pool
// // check if the shareholder is a module
// if _, ok = moduleAccounts[coin.Denom]; ok {
// return
// }
// // Burn the share tokens
// err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.Coins{coin})
// if err != nil {
// return true
// }
// err = k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.Coins{coin})
// if err != nil {
// return true
// }
// // Refund assets
// for _, asset := range pool.GetAllPoolAssets() {
// // lpShareEquivalentTokens = (amount in pool) * (your shares) / (total shares)
// lpShareEquivalentTokens := asset.Token.Amount.Mul(coin.Amount).Quo(totalShares[coin.Denom])
// if lpShareEquivalentTokens.IsZero() {
// continue
// }
// err = k.bankKeeper.SendCoins(
// ctx, pool.GetAddress(), addr, sdk.Coins{{asset.Token.Denom, lpShareEquivalentTokens}})
// if err != nil {
// return true
// }
// }
// return false
// })
// if err != nil {
// return err
// }
// for _, pool := range pools {
// // sanity check
// if !pool.GetTotalShares().IsZero() {
// panic("pool total share should be zero after cleanup")
// }
// err = k.DeletePool(ctx, pool.GetId())
// if err != nil {
// return err
// }
// }
// return nil
// }
// GetPoolDenom retrieves the pool based on PoolId and
// returns the coin denoms that it holds.
func (k Keeper) GetPoolDenoms(ctx sdk.Context, poolId uint64) ([]string, error) {
pool, err := k.GetPoolAndPoke(ctx, poolId)
if err != nil {
return nil, err
}
denoms := osmoutils.CoinsDenoms(pool.GetTotalPoolLiquidity(ctx))
return denoms, err
}
// setNextPoolId sets next pool Id.
func (k Keeper) setNextPoolId(ctx sdk.Context, poolId uint64) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&gogotypes.UInt64Value{Value: poolId})
store.Set(types.KeyNextGlobalPoolId, bz)
}
// GetNextPoolId returns the next pool Id.
func (k Keeper) GetNextPoolId(ctx sdk.Context) uint64 {
var nextPoolId uint64
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyNextGlobalPoolId)
if bz == nil {
panic(fmt.Errorf("pool has not been initialized -- Should have been done in InitGenesis"))
} else {
val := gogotypes.UInt64Value{}
err := k.cdc.Unmarshal(bz, &val)
if err != nil {
panic(err)
}
nextPoolId = val.GetValue()
}
return nextPoolId
}
func (k Keeper) GetPoolType(ctx sdk.Context, poolId uint64) (string, error) {
pool, err := k.GetPoolAndPoke(ctx, poolId)
if err != nil {
return "", err
}
switch pool := pool.(type) {
case *balancer.Pool:
return "Balancer", nil
default:
errMsg := fmt.Sprintf("unrecognized %s pool type: %T", types.ModuleName, pool)
return "", sdkerrors.Wrap(sdkerrors.ErrUnpackAny, errMsg)
}
}
// getNextPoolIdAndIncrement returns the next pool Id, and increments the corresponding state entry.
func (k Keeper) getNextPoolIdAndIncrement(ctx sdk.Context) uint64 {
nextPoolId := k.GetNextPoolId(ctx)
k.setNextPoolId(ctx, nextPoolId+1)
return nextPoolId
}