2024-02-01 04:48:40 +00:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
2024-02-02 09:39:10 +00:00
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"cosmossdk.io/collections"
|
|
|
|
"cosmossdk.io/core/store"
|
|
|
|
errorsmod "cosmossdk.io/errors"
|
|
|
|
|
2024-02-01 04:48:40 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
2024-02-01 10:58:34 +00:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2024-02-02 09:39:10 +00:00
|
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
|
|
auth "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
|
|
|
bank "github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
2024-02-01 04:48:40 +00:00
|
|
|
|
2024-02-02 09:39:10 +00:00
|
|
|
bondtypes "git.vdb.to/cerc-io/laconic2d/x/bond"
|
|
|
|
)
|
2024-02-01 04:48:40 +00:00
|
|
|
|
|
|
|
type Keeper struct {
|
2024-02-01 10:58:34 +00:00
|
|
|
// Codecs
|
|
|
|
cdc codec.BinaryCodec
|
2024-02-01 04:48:40 +00:00
|
|
|
|
2024-02-01 10:58:34 +00:00
|
|
|
// External keepers
|
2024-02-02 09:39:10 +00:00
|
|
|
accountKeeper auth.AccountKeeper
|
|
|
|
bankKeeper bank.Keeper
|
2024-02-01 10:58:34 +00:00
|
|
|
|
|
|
|
// Track bond usage in other cosmos-sdk modules (more like a usage tracker).
|
|
|
|
// usageKeepers []types.BondUsageKeeper
|
|
|
|
|
|
|
|
// paramSubspace paramtypes.Subspace
|
2024-02-02 09:39:10 +00:00
|
|
|
|
|
|
|
// State management
|
|
|
|
Schema collections.Schema
|
|
|
|
Bonds collections.Map[string, bondtypes.Bond]
|
2024-02-01 10:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewKeeper creates new instances of the bond Keeper
|
|
|
|
func NewKeeper(
|
|
|
|
cdc codec.BinaryCodec,
|
2024-02-02 09:39:10 +00:00
|
|
|
storeService store.KVStoreService,
|
|
|
|
accountKeeper auth.AccountKeeper,
|
|
|
|
bankKeeper bank.Keeper,
|
2024-02-01 10:58:34 +00:00
|
|
|
// usageKeepers []types.BondUsageKeeper,
|
|
|
|
// ps paramtypes.Subspace,
|
|
|
|
) Keeper {
|
|
|
|
// set KeyTable if it has not already been set
|
|
|
|
// if !ps.HasKeyTable() {
|
|
|
|
// ps = ps.WithKeyTable(types.ParamKeyTable())
|
|
|
|
// }
|
|
|
|
|
2024-02-02 09:39:10 +00:00
|
|
|
sb := collections.NewSchemaBuilder(storeService)
|
|
|
|
k := Keeper{
|
|
|
|
cdc: cdc,
|
|
|
|
accountKeeper: accountKeeper,
|
|
|
|
bankKeeper: bankKeeper,
|
|
|
|
Bonds: collections.NewMap(sb, bondtypes.BondsKey, "bonds", collections.StringKey, codec.CollValue[bondtypes.Bond](cdc)),
|
2024-02-01 10:58:34 +00:00
|
|
|
// usageKeepers: usageKeepers,
|
|
|
|
// paramSubspace: ps,
|
|
|
|
}
|
2024-02-02 09:39:10 +00:00
|
|
|
|
|
|
|
schema, err := sb.Build()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
k.Schema = schema
|
|
|
|
|
|
|
|
return k
|
2024-02-01 10:58:34 +00:00
|
|
|
}
|
|
|
|
|
2024-02-02 09:39:10 +00:00
|
|
|
// BondID simplifies generation of bond IDs.
|
|
|
|
type BondID struct {
|
|
|
|
Address sdk.Address
|
|
|
|
AccNum uint64
|
|
|
|
Sequence uint64
|
|
|
|
}
|
2024-02-01 10:58:34 +00:00
|
|
|
|
2024-02-02 09:39:10 +00:00
|
|
|
// Generate creates the bond ID.
|
|
|
|
func (bondID BondID) Generate() string {
|
|
|
|
hasher := sha256.New()
|
|
|
|
str := fmt.Sprintf("%s:%d:%d", bondID.Address.String(), bondID.AccNum, bondID.Sequence)
|
|
|
|
hasher.Write([]byte(str))
|
|
|
|
return hex.EncodeToString(hasher.Sum(nil))
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateBond creates a new bond.
|
|
|
|
func (k Keeper) CreateBond(ctx sdk.Context, ownerAddress sdk.AccAddress, coins sdk.Coins) (*bondtypes.Bond, error) {
|
|
|
|
// Check if account has funds.
|
|
|
|
for _, coin := range coins {
|
|
|
|
balance := k.bankKeeper.HasBalance(ctx, ownerAddress, coin)
|
|
|
|
if !balance {
|
|
|
|
return nil, errorsmod.Wrap(sdkerrors.ErrInsufficientFunds, "failed to create bond; Insufficient funds")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate bond ID.
|
|
|
|
account := k.accountKeeper.GetAccount(ctx, ownerAddress)
|
|
|
|
bondID := BondID{
|
|
|
|
Address: ownerAddress,
|
|
|
|
AccNum: account.GetAccountNumber(),
|
|
|
|
Sequence: account.GetSequence(),
|
|
|
|
}.Generate()
|
|
|
|
|
|
|
|
maxBondAmount := k.getMaxBondAmount(ctx)
|
|
|
|
|
|
|
|
bond := bondtypes.Bond{Id: bondID, Owner: ownerAddress.String(), Balance: coins}
|
|
|
|
if bond.Balance.IsAnyGT(maxBondAmount) {
|
|
|
|
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Max bond amount exceeded.")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move funds into the bond account module.
|
|
|
|
err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, ownerAddress, bondtypes.ModuleName, bond.Balance)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save bond in store.
|
|
|
|
if err := k.Bonds.Set(ctx, bond.Id, bond); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &bond, nil
|
2024-02-01 04:48:40 +00:00
|
|
|
}
|
|
|
|
|
2024-02-01 10:58:34 +00:00
|
|
|
// ListBonds - get all bonds.
|
2024-02-02 09:39:10 +00:00
|
|
|
func (k Keeper) ListBonds(ctx sdk.Context) ([]*bondtypes.Bond, error) {
|
|
|
|
var bonds []*bondtypes.Bond
|
|
|
|
|
|
|
|
iter, err := k.Bonds.Iterate(ctx, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for ; iter.Valid(); iter.Next() {
|
|
|
|
bond, err := iter.Value()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
bonds = append(bonds, &bond)
|
|
|
|
}
|
|
|
|
|
|
|
|
return bonds, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k Keeper) getMaxBondAmount(ctx sdk.Context) sdk.Coins {
|
|
|
|
params := k.GetParams(ctx)
|
|
|
|
maxBondAmount := params.MaxBondAmount
|
|
|
|
return sdk.NewCoins(maxBondAmount)
|
2024-02-01 04:48:40 +00:00
|
|
|
}
|