2024-07-01 06:05:28 +00:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
2024-07-03 11:38:48 +00:00
|
|
|
"encoding/json"
|
2024-07-29 10:28:30 +00:00
|
|
|
"errors"
|
2024-07-01 06:05:28 +00:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"cosmossdk.io/collections"
|
|
|
|
"cosmossdk.io/core/address"
|
|
|
|
storetypes "cosmossdk.io/core/store"
|
2024-07-03 11:38:48 +00:00
|
|
|
errorsmod "cosmossdk.io/errors"
|
|
|
|
"cosmossdk.io/log"
|
|
|
|
|
2024-07-01 06:05:28 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
2024-07-03 11:38:48 +00:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
2024-07-01 06:05:28 +00:00
|
|
|
|
2024-07-03 11:38:48 +00:00
|
|
|
"git.vdb.to/cerc-io/laconicd/utils"
|
2024-07-04 05:23:26 +00:00
|
|
|
onboardingTypes "git.vdb.to/cerc-io/laconicd/x/onboarding"
|
2024-07-01 06:05:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Keeper struct {
|
|
|
|
cdc codec.BinaryCodec
|
|
|
|
addressCodec address.Codec
|
|
|
|
|
|
|
|
// authority is the address capable of executing a MsgUpdateParams and other authority-gated message.
|
|
|
|
// typically, this should be the x/gov module account.
|
|
|
|
authority string
|
|
|
|
|
|
|
|
// state management
|
2024-07-03 11:38:48 +00:00
|
|
|
Schema collections.Schema
|
2024-07-04 05:23:26 +00:00
|
|
|
Params collections.Item[onboardingTypes.Params]
|
|
|
|
Participants collections.Map[string, onboardingTypes.Participant]
|
2024-07-01 06:05:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewKeeper creates a new Keeper instance
|
|
|
|
func NewKeeper(cdc codec.BinaryCodec, addressCodec address.Codec, storeService storetypes.KVStoreService, authority string) *Keeper {
|
|
|
|
if _, err := addressCodec.StringToBytes(authority); err != nil {
|
|
|
|
panic(fmt.Errorf("invalid authority address: %w", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
sb := collections.NewSchemaBuilder(storeService)
|
|
|
|
k := Keeper{
|
|
|
|
cdc: cdc,
|
|
|
|
addressCodec: addressCodec,
|
|
|
|
authority: authority,
|
2024-07-04 05:23:26 +00:00
|
|
|
Params: collections.NewItem(sb, onboardingTypes.ParamsPrefix, "params", codec.CollValue[onboardingTypes.Params](cdc)),
|
2024-07-11 05:16:31 +00:00
|
|
|
Participants: collections.NewMap(
|
|
|
|
sb, onboardingTypes.ParticipantsPrefix, "participants", collections.StringKey, codec.CollValue[onboardingTypes.Participant](cdc),
|
|
|
|
),
|
2024-07-01 06:05:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
schema, err := sb.Build()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
k.Schema = schema
|
|
|
|
|
|
|
|
return &k
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetAuthority returns the module's authority.
|
|
|
|
func (k Keeper) GetAuthority() string {
|
|
|
|
return k.authority
|
|
|
|
}
|
2024-07-03 11:38:48 +00:00
|
|
|
|
|
|
|
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
|
2024-07-04 05:23:26 +00:00
|
|
|
return ctx.Logger().With("module", onboardingTypes.ModuleName)
|
2024-07-03 11:38:48 +00:00
|
|
|
}
|
|
|
|
|
2024-07-11 05:16:31 +00:00
|
|
|
func (k Keeper) OnboardParticipant(
|
|
|
|
ctx sdk.Context,
|
|
|
|
msg *onboardingTypes.MsgOnboardParticipant,
|
|
|
|
signerAddress sdk.AccAddress,
|
|
|
|
) (*onboardingTypes.MsgOnboardParticipantResponse, error) {
|
2024-07-04 13:40:10 +00:00
|
|
|
params, err := k.Params.Get(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !params.OnboardingEnabled {
|
|
|
|
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Validator onboarding is disabled")
|
|
|
|
}
|
|
|
|
|
2024-07-03 11:38:48 +00:00
|
|
|
message, err := json.Marshal(msg.EthPayload)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Invalid format for payload")
|
|
|
|
}
|
|
|
|
|
2024-07-15 09:33:44 +00:00
|
|
|
// Decode eth address from signature which should be the nitro address of the participant
|
|
|
|
nitroAddress, err := utils.DecodeEthereumAddress(message, msg.EthSignature)
|
2024-07-11 05:16:31 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Failed to decode Ethereum address")
|
|
|
|
}
|
|
|
|
|
2024-07-15 09:33:44 +00:00
|
|
|
if nitroAddress != msg.EthPayload.Address {
|
2024-07-03 11:38:48 +00:00
|
|
|
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Recovered ethereum address does not match the address set in payload")
|
|
|
|
}
|
|
|
|
|
2024-07-04 05:23:26 +00:00
|
|
|
participant := &onboardingTypes.Participant{
|
2024-07-15 09:33:44 +00:00
|
|
|
CosmosAddress: signerAddress.String(),
|
|
|
|
NitroAddress: nitroAddress,
|
2024-07-26 14:42:40 +00:00
|
|
|
Role: msg.Role,
|
|
|
|
KycId: msg.KycId,
|
2024-07-03 11:38:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := k.StoreParticipant(ctx, participant); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-07-04 13:40:10 +00:00
|
|
|
return &onboardingTypes.MsgOnboardParticipantResponse{}, nil
|
2024-07-03 11:38:48 +00:00
|
|
|
}
|
|
|
|
|
2024-07-04 05:23:26 +00:00
|
|
|
func (k Keeper) StoreParticipant(ctx sdk.Context, participant *onboardingTypes.Participant) error {
|
2024-07-03 11:38:48 +00:00
|
|
|
key := participant.CosmosAddress
|
2024-07-11 05:16:31 +00:00
|
|
|
return k.Participants.Set(ctx, key, *participant)
|
2024-07-03 11:38:48 +00:00
|
|
|
}
|
2024-07-04 05:23:26 +00:00
|
|
|
|
|
|
|
// ListParticipants - get all participants.
|
|
|
|
func (k Keeper) ListParticipants(ctx sdk.Context) ([]*onboardingTypes.Participant, error) {
|
|
|
|
var participants []*onboardingTypes.Participant
|
|
|
|
|
|
|
|
iter, err := k.Participants.Iterate(ctx, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for ; iter.Valid(); iter.Next() {
|
|
|
|
participant, err := iter.Value()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
participants = append(participants, &participant)
|
|
|
|
}
|
|
|
|
|
|
|
|
return participants, nil
|
|
|
|
}
|
2024-07-29 10:28:30 +00:00
|
|
|
|
|
|
|
// GetParticipantByAddress - get participant by cosmos (laconic) address.
|
|
|
|
func (k Keeper) GetParticipantByAddress(ctx sdk.Context, address string) (onboardingTypes.Participant, error) {
|
|
|
|
participant, err := k.Participants.Get(ctx, address)
|
|
|
|
if err != nil {
|
|
|
|
if errors.Is(err, collections.ErrNotFound) {
|
|
|
|
return onboardingTypes.Participant{}, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "participant with given address not found.")
|
|
|
|
}
|
|
|
|
return onboardingTypes.Participant{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return participant, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetParticipantByNitroAddress - get participant by nitro address.
|
|
|
|
func (k Keeper) GetParticipantByNitroAddress(ctx sdk.Context, nitroAddress string) (onboardingTypes.Participant, error) {
|
|
|
|
var participant onboardingTypes.Participant
|
|
|
|
|
|
|
|
err := k.Participants.Walk(ctx, nil, func(key string, value onboardingTypes.Participant) (bool, error) {
|
|
|
|
if value.NitroAddress == nitroAddress {
|
|
|
|
participant = value
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return onboardingTypes.Participant{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return participant, nil
|
|
|
|
}
|