package keeper
import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
globalerrors "github.com/cybercongress/go-cyber/v7/app/helpers"
"github.com/cybercongress/go-cyber/v7/x/clock/types"
)
var (
StoreKeyContracts = []byte("contracts")
)
func (k Keeper) getContractsStore(ctx sdk.Context) prefix.Store {
return prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts)
}
func (k Keeper) SetClockContract(ctx sdk.Context, contract types.ClockContract) error {
store := k.getContractsStore(ctx)
bz, err := k.cdc.Marshal(&contract)
if err != nil {
return err
}
store.Set([]byte(contract.ContractAddress), bz)
return nil
}
func (k Keeper) IsClockContract(ctx sdk.Context, contractAddress string) bool {
store := k.getContractsStore(ctx)
return store.Has([]byte(contractAddress))
}
func (k Keeper) GetClockContract(ctx sdk.Context, contractAddress string) (*types.ClockContract, error) {
if !k.IsClockContract(ctx, contractAddress) {
return nil, globalerrors.ErrContractNotRegistered
}
store := k.getContractsStore(ctx)
bz := store.Get([]byte(contractAddress))
var contract types.ClockContract
err := k.cdc.Unmarshal(bz, &contract)
if err != nil {
return nil, err
}
return &contract, nil
}
func (k Keeper) GetAllContracts(ctx sdk.Context) ([]types.ClockContract, error) {
store := k.getContractsStore(ctx)
iterator := sdk.KVStorePrefixIterator(store, []byte(nil))
defer iterator.Close()
contracts := []types.ClockContract{}
for ; iterator.Valid(); iterator.Next() {
var contract types.ClockContract
err := k.cdc.Unmarshal(iterator.Value(), &contract)
if err != nil {
return nil, err
}
contracts = append(contracts, contract)
}
return contracts, nil
}
func (k Keeper) GetPaginatedContracts(ctx sdk.Context, pag *query.PageRequest) (*types.QueryClockContractsResponse, error) {
store := k.getContractsStore(ctx)
results, pageRes, err := query.GenericFilteredPaginate(
k.cdc,
store,
pag,
func(_ []byte, value *types.ClockContract) (*types.ClockContract, error) {
return value, nil
},
func() *types.ClockContract {
return &types.ClockContract{}
},
)
if err != nil {
return nil, err
}
var contracts []types.ClockContract
for _, contract := range results {
contracts = append(contracts, *contract)
}
return &types.QueryClockContractsResponse{
ClockContracts: contracts,
Pagination: pageRes,
}, nil
}
func (k Keeper) RemoveContract(ctx sdk.Context, contractAddress string) {
store := k.getContractsStore(ctx)
key := []byte(contractAddress)
if store.Has(key) {
store.Delete(key)
}
}
func (k Keeper) RegisterContract(ctx sdk.Context, senderAddress string, contractAddress string) error {
if k.IsClockContract(ctx, contractAddress) {
return globalerrors.ErrContractAlreadyRegistered
}
if ok, err := k.IsContractManager(ctx, senderAddress, contractAddress); !ok {
return err
}
return k.SetClockContract(ctx, types.ClockContract{
ContractAddress: contractAddress,
IsJailed: false,
})
}
func (k Keeper) UnregisterContract(ctx sdk.Context, senderAddress string, contractAddress string) error {
if !k.IsClockContract(ctx, contractAddress) {
return globalerrors.ErrContractNotRegistered
}
if ok, err := k.IsContractManager(ctx, senderAddress, contractAddress); !ok {
return err
}
k.RemoveContract(ctx, contractAddress)
return nil
}
func (k Keeper) SetJailStatus(ctx sdk.Context, contractAddress string, isJailed bool) error {
contract, err := k.GetClockContract(ctx, contractAddress)
if err != nil {
return err
}
if contract.IsJailed == isJailed {
if isJailed {
return types.ErrContractAlreadyJailed
}
return types.ErrContractNotJailed
}
contract.IsJailed = isJailed
return k.SetClockContract(ctx, *contract)
}
func (k Keeper) SetJailStatusBySender(ctx sdk.Context, senderAddress string, contractAddress string, jailStatus bool) error {
if ok, err := k.IsContractManager(ctx, senderAddress, contractAddress); !ok {
return err
}
return k.SetJailStatus(ctx, contractAddress, jailStatus)
}
func (k Keeper) IsContractManager(ctx sdk.Context, senderAddress string, contractAddress string) (bool, error) {
contractAddr := sdk.MustAccAddressFromBech32(contractAddress)
if ok := k.wasmKeeper.HasContractInfo(ctx, contractAddr); !ok {
return false, globalerrors.ErrInvalidCWContract
}
contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr)
adminExists := len(contractInfo.Admin) > 0
isSenderAdmin := contractInfo.Admin == senderAddress
isSenderCreator := contractInfo.Creator == senderAddress
if adminExists && !isSenderAdmin {
return false, globalerrors.ErrContractNotAdmin
} else if !adminExists && !isSenderCreator {
return false, globalerrors.ErrContractNotCreator
}
return true, nil
}