github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/apps/transfer/ibc_module.go (about)

     1  package transfer
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	types2 "github.com/fibonacci-chain/fbc/libs/tendermint/types"
     9  
    10  	porttypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/05-port/types"
    11  
    12  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    13  
    14  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    15  	capabilitytypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/capability/types"
    16  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/apps/transfer/keeper"
    17  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/apps/transfer/types"
    18  	channeltypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types"
    19  	host "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/24-host"
    20  	ibcexported "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/exported"
    21  )
    22  
    23  var (
    24  	_                  porttypes.Middleware = IBCModule{}
    25  	errNotSupportICS20                      = errors.New("not support by ics-20")
    26  )
    27  
    28  // NewIBCModule creates a new IBCModule given the keeper
    29  func NewIBCModule(k keeper.Keeper, v2module AppModule) porttypes.Middleware {
    30  	return IBCModule{
    31  		keeper:   k,
    32  		v2Module: v2module,
    33  	}
    34  }
    35  
    36  // OnChanOpenInit implements the IBCModule interface
    37  func (im IBCModule) OnChanOpenInit(
    38  	ctx sdk.Context,
    39  	order channeltypes.Order,
    40  	connectionHops []string,
    41  	portID string,
    42  	channelID string,
    43  	chanCap *capabilitytypes.Capability,
    44  	counterparty channeltypes.Counterparty,
    45  	version string,
    46  ) (string, error) {
    47  	if !types2.HigherThanVenus4(ctx.BlockHeight()) {
    48  		return im.v2Module.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version)
    49  	}
    50  
    51  	if err := ValidateTransferChannelParamsV4(ctx, im.keeper, order, portID, channelID); err != nil {
    52  		return "", err
    53  	}
    54  
    55  	if strings.TrimSpace(version) == "" {
    56  		version = types.Version
    57  	}
    58  
    59  	if version != types.Version {
    60  		return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version)
    61  	}
    62  
    63  	// Claim channel capability passed back by IBC module
    64  	if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
    65  		return "", err
    66  	}
    67  
    68  	return version, nil
    69  }
    70  
    71  // OnChanOpenTry implements the IBCModule interface.
    72  func (im IBCModule) OnChanOpenTry(
    73  	ctx sdk.Context,
    74  	order channeltypes.Order,
    75  	connectionHops []string,
    76  	portID,
    77  	channelID string,
    78  	chanCap *capabilitytypes.Capability,
    79  	counterparty channeltypes.Counterparty,
    80  	version string,
    81  	counterpartyVersion string,
    82  ) (string, error) {
    83  	if !types2.HigherThanVenus4(ctx.BlockHeight()) {
    84  		return im.v2Module.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version, counterpartyVersion)
    85  	}
    86  
    87  	if err := ValidateTransferChannelParamsV4(ctx, im.keeper, order, portID, channelID); err != nil {
    88  		return "", err
    89  	}
    90  
    91  	if counterpartyVersion != types.Version {
    92  		return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", counterpartyVersion, types.Version)
    93  	}
    94  
    95  	// OpenTry must claim the channelCapability that IBC passes into the callback
    96  	if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
    97  		return "", err
    98  	}
    99  
   100  	return types.Version, nil
   101  }
   102  
   103  // OnChanOpenAck implements the IBCModule interface
   104  func (im IBCModule) OnChanOpenAck(
   105  	ctx sdk.Context,
   106  	portID,
   107  	channelID string,
   108  	_ string,
   109  	counterpartyVersion string,
   110  ) error {
   111  	if counterpartyVersion != types.Version {
   112  		return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version)
   113  	}
   114  	return nil
   115  }
   116  
   117  // OnChanOpenConfirm implements the IBCModule interface
   118  func (im IBCModule) OnChanOpenConfirm(
   119  	ctx sdk.Context,
   120  	portID,
   121  	channelID string,
   122  ) error {
   123  	return nil
   124  }
   125  
   126  // OnChanCloseInit implements the IBCModule interface
   127  func (im IBCModule) OnChanCloseInit(
   128  	ctx sdk.Context,
   129  	portID,
   130  	channelID string,
   131  ) error {
   132  	// Disallow user-initiated channel closing for transfer channels
   133  	return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel")
   134  }
   135  
   136  // OnChanCloseConfirm implements the IBCModule interface
   137  func (im IBCModule) OnChanCloseConfirm(
   138  	ctx sdk.Context,
   139  	portID,
   140  	channelID string,
   141  ) error {
   142  	return nil
   143  }
   144  
   145  // OnRecvPacket implements the IBCModule interface. A successful acknowledgement
   146  // is returned if the packet data is successfully decoded and the receive application
   147  // logic returns without error.
   148  func (im IBCModule) OnRecvPacket(
   149  	ctx sdk.Context,
   150  	packet channeltypes.Packet,
   151  	relayer sdk.AccAddress,
   152  ) ibcexported.Acknowledgement {
   153  	if !types2.HigherThanVenus4(ctx.BlockHeight()) {
   154  		return im.v2Module.OnRecvPacket(ctx, packet, relayer)
   155  	}
   156  
   157  	ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
   158  
   159  	var data types.FungibleTokenPacketData
   160  	var ackErr error
   161  	if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
   162  		ackErr = sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data")
   163  		ack = channeltypes.NewErrorAcknowledgementV4(ackErr)
   164  	}
   165  
   166  	// only attempt the application logic if the packet data
   167  	// was successfully decoded
   168  	if ack.Success() {
   169  		err := im.keeper.OnRecvPacket(ctx, packet, data)
   170  		if err != nil {
   171  			ack = channeltypes.NewErrorAcknowledgementV4(err)
   172  			ackErr = err
   173  		}
   174  	}
   175  
   176  	eventAttributes := []sdk.Attribute{
   177  		sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
   178  		sdk.NewAttribute(sdk.AttributeKeySender, data.Sender),
   179  		sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
   180  		sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
   181  		sdk.NewAttribute(types.AttributeKeyAmount, data.Amount),
   182  		sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())),
   183  	}
   184  
   185  	if ackErr != nil {
   186  		eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error()))
   187  	}
   188  
   189  	ctx.EventManager().EmitEvent(
   190  		sdk.NewEvent(
   191  			types.EventTypePacket,
   192  			eventAttributes...,
   193  		),
   194  	)
   195  
   196  	// NOTE: acknowledgement will be written synchronously during IBC handler execution.
   197  	return ack
   198  }
   199  
   200  // OnAcknowledgementPacket implements the IBCModule interface
   201  func (im IBCModule) OnAcknowledgementPacket(
   202  	ctx sdk.Context,
   203  	packet channeltypes.Packet,
   204  	acknowledgement []byte,
   205  	relayer sdk.AccAddress,
   206  ) error {
   207  	if !types2.HigherThanVenus4(ctx.BlockHeight()) {
   208  		return im.v2Module.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
   209  	}
   210  	var ack channeltypes.Acknowledgement
   211  	if err := types.Marshal.GetProtocMarshal().UnmarshalJSON(acknowledgement, &ack); err != nil {
   212  		return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err)
   213  	}
   214  	var data types.FungibleTokenPacketData
   215  	if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
   216  		return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
   217  	}
   218  
   219  	if err := im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil {
   220  		return err
   221  	}
   222  
   223  	ctx.EventManager().EmitEvent(
   224  		sdk.NewEvent(
   225  			types.EventTypePacket,
   226  			sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
   227  			sdk.NewAttribute(sdk.AttributeKeySender, data.Sender),
   228  			sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
   229  			sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
   230  			sdk.NewAttribute(types.AttributeKeyAmount, data.Amount),
   231  			sdk.NewAttribute(types.AttributeKeyAck, ack.String()),
   232  		),
   233  	)
   234  
   235  	switch resp := ack.Response.(type) {
   236  	case *channeltypes.Acknowledgement_Result:
   237  		ctx.EventManager().EmitEvent(
   238  			sdk.NewEvent(
   239  				types.EventTypePacket,
   240  				sdk.NewAttribute(types.AttributeKeyAckSuccess, string(resp.Result)),
   241  			),
   242  		)
   243  	case *channeltypes.Acknowledgement_Error:
   244  		ctx.EventManager().EmitEvent(
   245  			sdk.NewEvent(
   246  				types.EventTypePacket,
   247  				sdk.NewAttribute(types.AttributeKeyAckError, resp.Error),
   248  			),
   249  		)
   250  	}
   251  
   252  	return nil
   253  }
   254  
   255  // OnTimeoutPacket implements the IBCModule interface
   256  func (im IBCModule) OnTimeoutPacket(
   257  	ctx sdk.Context,
   258  	packet channeltypes.Packet,
   259  	relayer sdk.AccAddress,
   260  ) error {
   261  	if !types2.HigherThanVenus4(ctx.BlockHeight()) {
   262  		return im.v2Module.OnTimeoutPacket(ctx, packet, relayer)
   263  	}
   264  	var data types.FungibleTokenPacketData
   265  	if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
   266  		return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
   267  	}
   268  	// refund tokens
   269  	if err := im.keeper.OnTimeoutPacket(ctx, packet, data); err != nil {
   270  		return err
   271  	}
   272  
   273  	ctx.EventManager().EmitEvent(
   274  		sdk.NewEvent(
   275  			types.EventTypeTimeout,
   276  			sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
   277  			sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender),
   278  			sdk.NewAttribute(types.AttributeKeyRefundDenom, data.Denom),
   279  			sdk.NewAttribute(types.AttributeKeyRefundAmount, data.Amount),
   280  		),
   281  	)
   282  
   283  	return nil
   284  }
   285  
   286  // IBCModule implements the ICS26 interface for transfer given the transfer keeper.
   287  type IBCModule struct {
   288  	keeper   keeper.Keeper
   289  	v2Module AppModule
   290  }
   291  
   292  func (im IBCModule) SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI) error {
   293  	return errNotSupportICS20
   294  }
   295  
   296  func (im IBCModule) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ack ibcexported.Acknowledgement) error {
   297  	return errNotSupportICS20
   298  }
   299  
   300  func (im IBCModule) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) {
   301  	panic(errNotSupportICS20)
   302  }
   303  
   304  func (im IBCModule) NegotiateAppVersion(ctx sdk.Context, order channeltypes.Order, connectionID string, portID string, counterparty channeltypes.Counterparty, proposedVersion string) (version string, err error) {
   305  	return "", errNotSupportICS20
   306  }