github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/apps/27-interchain-accounts/controller/keeper/account.go (about)

     1  package keeper
     2  
     3  import (
     4  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     5  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
     6  	icatypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/apps/27-interchain-accounts/types"
     7  	channeltypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types"
     8  	host "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/24-host"
     9  )
    10  
    11  // RegisterInterchainAccount is the entry point to registering an interchain account:
    12  // - It generates a new port identifier using the provided owner string, binds to the port identifier and claims the associated capability.
    13  // - Callers are expected to provide the appropriate application version string.
    14  // - For example, this could be an ICS27 encoded metadata type or an ICS29 encoded metadata type with a nested application version.
    15  // - A new MsgChannelOpenInit is routed through the MsgServiceRouter, executing the OnOpenChanInit callback stack as configured.
    16  // - An error is returned if the port identifier is already in use. Gaining access to interchain accounts whose channels
    17  // have closed cannot be done with this function. A regular MsgChannelOpenInit must be used.
    18  func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner, version string) error {
    19  	portID, err := icatypes.NewControllerPortID(owner)
    20  	if err != nil {
    21  		return err
    22  	}
    23  
    24  	// if there is an active channel for this portID / connectionID return an error
    25  	activeChannelID, found := k.GetOpenActiveChannel(ctx, connectionID, portID)
    26  	if found {
    27  		return sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s on connection %s for owner %s", activeChannelID, portID, connectionID, owner)
    28  	}
    29  
    30  	switch {
    31  	case k.portKeeper.IsBound(ctx, portID) && !k.IsBound(ctx, portID):
    32  		return sdkerrors.Wrapf(icatypes.ErrPortAlreadyBound, "another module has claimed capability for and bound port with portID: %s", portID)
    33  	case !k.portKeeper.IsBound(ctx, portID):
    34  		cap := k.BindPort(ctx, portID)
    35  		if err := k.ClaimCapability(ctx, cap, host.PortPath(portID)); err != nil {
    36  			return sdkerrors.Wrapf(err, "unable to bind to newly generated portID: %s", portID)
    37  		}
    38  	}
    39  
    40  	msg := channeltypes.NewMsgChannelOpenInitV4(portID, version, channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName)
    41  	handler := k.msgRouter.HandlerWithMsg(msg)
    42  
    43  	res, err := handler(ctx, msg)
    44  	if err != nil {
    45  		return err
    46  	}
    47  
    48  	// NOTE: The sdk msg handler creates a new EventManager, so events must be correctly propagated back to the current context
    49  	ctx.EventManager().EmitEvents(res.Events)
    50  
    51  	return nil
    52  }