0g-chain/x/earn/keeper/vault.go
Derrick Lee ed9991d44a
Add Init/ExportGenesis for Earn module (#1280)
* Add vault and vault shares to genesis

* Fix error and denoms

* Update init and export genesis with correct data

* Fix total supply genesis check, remove legacy test for enum errors

* Add vault slice validate tests

* Update denom validation, add additional test
2022-07-28 10:01:30 -07:00

256 lines
7.5 KiB
Go

package keeper
import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/earn/types"
)
// GetVaultTotalSupplied returns the total balance supplied to the vault. This
// may not necessarily be the current value of the vault, as it is the sum
// of the supplied denom and the value may be higher due to accumulated APYs.
func (k *Keeper) GetVaultTotalSupplied(
ctx sdk.Context,
denom string,
) (sdk.Coin, error) {
vault, found := k.GetVaultRecord(ctx, denom)
if !found {
return sdk.Coin{}, types.ErrVaultRecordNotFound
}
return vault.TotalSupply, nil
}
// GetTotalValue returns the total **value** of all coins in this vault,
// i.e. the realizable total value denominated by GetDenom() if the vault
// were to liquidate its entire strategies.
//
// **Note:** This does not include the tokens held in bank by the module
// account. If it were to be included, also note that the module account is
// unblocked and can receive funds from bank sends.
func (k *Keeper) GetVaultTotalValue(
ctx sdk.Context,
denom string,
) (sdk.Coin, error) {
enabledVault, found := k.GetAllowedVault(ctx, denom)
if !found {
return sdk.Coin{}, types.ErrVaultRecordNotFound
}
strategy, err := k.GetStrategy(enabledVault.VaultStrategy)
if err != nil {
return sdk.Coin{}, types.ErrInvalidVaultStrategy
}
return strategy.GetEstimatedTotalAssets(ctx, enabledVault.Denom)
}
// GetVaultAccountSupplied returns the supplied amount for a single address
// within a vault.
func (k *Keeper) GetVaultAccountSupplied(
ctx sdk.Context,
acc sdk.AccAddress,
) (sdk.Coins, error) {
vaultShareRecord, found := k.GetVaultShareRecord(ctx, acc)
if !found {
return sdk.Coins{}, types.ErrVaultShareRecordNotFound
}
return vaultShareRecord.AmountSupplied, nil
}
// GetVaultAccountValue returns the value of a single address within a vault
// if the account were to withdraw their entire balance.
func (k *Keeper) GetVaultAccountValue(
ctx sdk.Context,
denom string,
acc sdk.AccAddress,
) (sdk.Coin, error) {
totalSupplied, err := k.GetVaultTotalSupplied(ctx, denom)
if err != nil {
return sdk.Coin{}, err
}
accSupplied, err := k.GetVaultAccountSupplied(ctx, acc)
if err != nil {
return sdk.Coin{}, err
}
vaultTotalValue, err := k.GetVaultTotalValue(ctx, denom)
if err != nil {
return sdk.Coin{}, err
}
// Percent of vault account ownership = accountSupply / totalSupply
// Value of vault account ownership = percentOwned * totalValue
vaultShare := accSupplied.AmountOf(denom).ToDec().Quo(totalSupplied.Amount.ToDec())
shareValueDec := vaultTotalValue.Amount.ToDec().Mul(vaultShare)
return sdk.NewCoin(denom, shareValueDec.TruncateInt()), nil
}
// ----------------------------------------------------------------------------
// VaultRecord -- vault total supplies
// GetVaultRecord returns the vault record for a given denom.
func (k *Keeper) GetVaultRecord(
ctx sdk.Context,
vaultDenom string,
) (types.VaultRecord, bool) {
store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix)
bz := store.Get(types.VaultKey(vaultDenom))
if bz == nil {
return types.VaultRecord{}, false
}
var record types.VaultRecord
k.cdc.MustUnmarshal(bz, &record)
return record, true
}
// UpdateVaultRecord updates the vault record in state for a given denom. This
// deletes it if the supply is zero and updates the state if supply is non-zero.
func (k *Keeper) UpdateVaultRecord(
ctx sdk.Context,
vaultRecord types.VaultRecord,
) {
if vaultRecord.TotalSupply.IsZero() {
k.DeleteVaultRecord(ctx, vaultRecord.Denom)
} else {
k.SetVaultRecord(ctx, vaultRecord)
}
}
// DeleteVaultRecord deletes the vault record for a given denom.
func (k *Keeper) DeleteVaultRecord(ctx sdk.Context, vaultDenom string) {
store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix)
store.Delete(types.VaultKey(vaultDenom))
}
// SetVaultRecord sets the vault record for a given denom.
func (k *Keeper) SetVaultRecord(ctx sdk.Context, record types.VaultRecord) {
store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix)
bz := k.cdc.MustMarshal(&record)
store.Set(types.VaultKey(record.Denom), bz)
}
// IterateVaultRecords iterates over all vault objects in the store and performs
// a callback function.
func (k Keeper) IterateVaultRecords(
ctx sdk.Context,
cb func(record types.VaultRecord) (stop bool),
) {
store := prefix.NewStore(ctx.KVStore(k.key), types.VaultRecordKeyPrefix)
iterator := sdk.KVStorePrefixIterator(store, []byte{})
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var record types.VaultRecord
k.cdc.MustUnmarshal(iterator.Value(), &record)
if cb(record) {
break
}
}
}
// GetAllVaultRecords returns all vault records from the store.
func (k Keeper) GetAllVaultRecords(ctx sdk.Context) types.VaultRecords {
var records types.VaultRecords
k.IterateVaultRecords(ctx, func(record types.VaultRecord) bool {
records = append(records, record)
return false
})
return records
}
// ----------------------------------------------------------------------------
// VaultShare -- user shares per vault
// GetVaultShareRecord returns the vault share record for a given denom and
// account.
func (k *Keeper) GetVaultShareRecord(
ctx sdk.Context,
acc sdk.AccAddress,
) (types.VaultShareRecord, bool) {
store := prefix.NewStore(ctx.KVStore(k.key), types.VaultShareRecordKeyPrefix)
bz := store.Get(types.DepositorVaultSharesKey(acc))
if bz == nil {
return types.VaultShareRecord{}, false
}
var record types.VaultShareRecord
k.cdc.MustUnmarshal(bz, &record)
return record, true
}
// UpdateVaultShareRecord updates the vault share record in state for a given
// denom and account. This deletes it if the supply is zero and updates the
// state if supply is non-zero.
func (k *Keeper) UpdateVaultShareRecord(
ctx sdk.Context,
record types.VaultShareRecord,
) {
if record.AmountSupplied.IsZero() {
k.DeleteVaultShareRecord(ctx, record.Depositor)
} else {
k.SetVaultShareRecord(ctx, record)
}
}
// DeleteVaultShareRecord deletes the vault share record for a given denom and
// account.
func (k *Keeper) DeleteVaultShareRecord(
ctx sdk.Context,
acc sdk.AccAddress,
) {
store := prefix.NewStore(ctx.KVStore(k.key), types.VaultShareRecordKeyPrefix)
store.Delete(types.DepositorVaultSharesKey(acc))
}
// SetVaultShareRecord sets the vault share record for a given denom and account.
func (k *Keeper) SetVaultShareRecord(
ctx sdk.Context,
record types.VaultShareRecord,
) {
store := prefix.NewStore(ctx.KVStore(k.key), types.VaultShareRecordKeyPrefix)
bz := k.cdc.MustMarshal(&record)
store.Set(types.DepositorVaultSharesKey(record.Depositor), bz)
}
// IterateVaultShareRecords iterates over all vault share objects in the store
// and performs a callback function.
func (k Keeper) IterateVaultShareRecords(
ctx sdk.Context,
cb func(record types.VaultShareRecord) (stop bool),
) {
store := prefix.NewStore(ctx.KVStore(k.key), types.VaultShareRecordKeyPrefix)
iterator := sdk.KVStorePrefixIterator(store, []byte{})
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var record types.VaultShareRecord
k.cdc.MustUnmarshal(iterator.Value(), &record)
if cb(record) {
break
}
}
}
// GetAllVaultShareRecords returns all vault share records from the store.
func (k Keeper) GetAllVaultShareRecords(ctx sdk.Context) types.VaultShareRecords {
var records types.VaultShareRecords
k.IterateVaultShareRecords(ctx, func(record types.VaultShareRecord) bool {
records = append(records, record)
return false
})
return records
}