Skip to content

Commit

Permalink
add axelar IBCMiddleware
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreamer committed Mar 8, 2024
1 parent bbefb02 commit 531761c
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 2 deletions.
10 changes: 8 additions & 2 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ import (
tokentypes "github.com/irisnet/irismod/modules/token/types"
tokenv1 "github.com/irisnet/irismod/modules/token/types/v1"

"github.com/irisnet/irishub/v2/modules/axelar"
guardiankeeper "github.com/irisnet/irishub/v2/modules/guardian/keeper"
guardiantypes "github.com/irisnet/irishub/v2/modules/guardian/types"
"github.com/irisnet/irishub/v2/modules/internft"
Expand Down Expand Up @@ -395,7 +396,6 @@ func New(
appKeepers.scopedTransferKeeper,
)
appKeepers.TransferModule = transfer.NewAppModule(appKeepers.IBCTransferKeeper)
transferIBCModule := transfer.NewIBCModule(appKeepers.IBCTransferKeeper)

appKeepers.IBCNFTTransferKeeper = ibcnfttransferkeeper.NewKeeper(
appCodec,
Expand All @@ -411,10 +411,16 @@ func New(
appKeepers.IBCNftTransferModule = nfttransfer.NewAppModule(appKeepers.IBCNFTTransferKeeper)
nfttransferIBCModule := nfttransfer.NewIBCModule(appKeepers.IBCNFTTransferKeeper)


// create IBC module from bottom to top of stack
var transferStack porttypes.IBCModule
transferStack = transfer.NewIBCModule(appKeepers.IBCTransferKeeper)
transferStack = axelar.NewIBCMiddleware(transferStack,nil)

// routerModule := router.NewAppModule(app.RouterKeeper, transferIBCModule)
// create static IBC router, add transfer route, then set and seal it
ibcRouter := porttypes.NewRouter().
AddRoute(ibctransfertypes.ModuleName, transferIBCModule).
AddRoute(ibctransfertypes.ModuleName, transferStack).
AddRoute(ibcnfttransfertypes.ModuleName, nfttransferIBCModule).
AddRoute(icahosttypes.SubModuleName, icaHostIBCModule)
appKeepers.IBCKeeper.SetRouter(ibcRouter)
Expand Down
174 changes: 174 additions & 0 deletions modules/axelar/ibc_middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package axelar

import (
"encoding/json"
"fmt"

errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"

sdk "github.com/cosmos/cosmos-sdk/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"

transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types"
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"

"github.com/irisnet/irishub/v2/modules/axelar/types"
)

// IBCMiddleware implements the IBCMiddleware interface
type IBCMiddleware struct {
app porttypes.IBCModule
handler types.GeneralMessageHandler
}

// NewIBCMiddleware creates a new IBCMiddleware
func NewIBCMiddleware(app porttypes.IBCModule, handler types.GeneralMessageHandler) IBCMiddleware {
if handler == nil {
handler = types.EmptyHandler{}
}
return IBCMiddleware{
app: app,
handler: handler,
}
}

// OnChanOpenInit implements the IBCModule interface
func (im IBCMiddleware) OnChanOpenInit(
ctx sdk.Context,
order channeltypes.Order,
connectionHops []string,
portID string,
channelID string,
chanCap *capabilitytypes.Capability,
counterparty channeltypes.Counterparty,
version string,
) (string, error) {
// call underlying callback
return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version)
}

// OnChanOpenTry implements the IBCMiddleware interface
func (im IBCMiddleware) OnChanOpenTry(
ctx sdk.Context,
order channeltypes.Order,
connectionHops []string,
portID,
channelID string,
channelCap *capabilitytypes.Capability,
counterparty channeltypes.Counterparty,
counterpartyVersion string,
) (string, error) {
return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion)
}

// OnChanOpenAck implements the IBCMiddleware interface
func (im IBCMiddleware) OnChanOpenAck(
ctx sdk.Context,
portID,
channelID string,
counterpartyChannelID string,
counterpartyVersion string,
) error {
return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion)
}

// OnChanOpenConfirm implements the IBCMiddleware interface
func (im IBCMiddleware) OnChanOpenConfirm(
ctx sdk.Context,
portID,
channelID string,
) error {
return im.app.OnChanOpenConfirm(ctx, portID, channelID)
}

// OnChanCloseInit implements the IBCMiddleware interface
func (im IBCMiddleware) OnChanCloseInit(
ctx sdk.Context,
portID,
channelID string,
) error {
return im.app.OnChanCloseInit(ctx, portID, channelID)
}

// OnChanCloseConfirm implements the IBCMiddleware interface
func (im IBCMiddleware) OnChanCloseConfirm(
ctx sdk.Context,
portID,
channelID string,
) error {
return im.app.OnChanCloseConfirm(ctx, portID, channelID)
}

// OnRecvPacket implements the IBCMiddleware interface
func (im IBCMiddleware) OnRecvPacket(
ctx sdk.Context,
packet channeltypes.Packet,
relayer sdk.AccAddress,
) ibcexported.Acknowledgement {
ack := im.app.OnRecvPacket(ctx, packet, relayer)
if !ack.Success() {
return ack
}

var data transfertypes.FungibleTokenPacketData
if err := transfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
return channeltypes.NewErrorAcknowledgement(fmt.Errorf("cannot unmarshal ICS-20 transfer packet data"))
}

// authenticate the message with packet sender + channel-id
// TODO: authenticate the message with channel-id
if data.Sender != types.AxelarGMPAcc {
return ack
}

var (
msg types.Message
err error
)

if err = json.Unmarshal([]byte(data.GetMemo()), &msg); err != nil {
return channeltypes.NewErrorAcknowledgement(fmt.Errorf("cannot unmarshal memo"))
}

switch msg.Type {
case types.TypePureMessage:
err = im.handler.HandleGeneralMessage(ctx, msg.SourceChain, msg.SourceAddress, data.Receiver, msg.Payload)
case types.TypeMessageWithToken:
amt, ok := sdkmath.NewIntFromString(data.Amount)
if !ok {
return channeltypes.NewErrorAcknowledgement(errorsmod.Wrapf(transfertypes.ErrInvalidAmount, "unable to parse transfer amount (%s) into sdk.Int", data.Amount))
}

denom := types.ParseDenom(packet, data.Denom)
err = im.handler.HandleGeneralMessageWithToken(ctx, msg.SourceChain, msg.SourceAddress, data.Receiver, msg.Payload, sdk.NewCoin(denom, amt))
default:
err = fmt.Errorf("unrecognized mesasge type: %d", msg.Type)
}

if err != nil {
return channeltypes.NewErrorAcknowledgement(err)
}
return ack
}

// OnAcknowledgementPacket implements the IBCMiddleware interface
func (im IBCMiddleware) OnAcknowledgementPacket(
ctx sdk.Context,
packet channeltypes.Packet,
acknowledgement []byte,
relayer sdk.AccAddress,
) error {
return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
}

// OnTimeoutPacket implements the IBCMiddleware interface
func (im IBCMiddleware) OnTimeoutPacket(
ctx sdk.Context,
packet channeltypes.Packet,
relayer sdk.AccAddress,
) error {
return im.app.OnTimeoutPacket(ctx, packet, relayer)
}
39 changes: 39 additions & 0 deletions modules/axelar/types/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// GeneralMessageHandler handles messages from axelar
type GeneralMessageHandler interface {
HandleGeneralMessage(ctx sdk.Context, srcChain, srcAddress string, destAddress string, payload []byte) error
HandleGeneralMessageWithToken(ctx sdk.Context, srcChain, srcAddress string, destAddress string, payload []byte, coin sdk.Coin) error
}

// EmptyHandler implements the GeneralMessageHandler
type EmptyHandler struct{}

// HandleGeneralMessage implements the GeneralMessageHandler
func (h EmptyHandler) HandleGeneralMessage(ctx sdk.Context, srcChain, srcAddress string, destAddress string, payload []byte) error {
ctx.Logger().Info("HandleGeneralMessage called",
"srcChain", srcChain,
"srcAddress", srcAddress,
"destAddress", destAddress,
"payload", payload,
"module", "axelar",
)
return nil
}

// HandleGeneralMessageWithToken implements the GeneralMessageHandler
func (h EmptyHandler) HandleGeneralMessageWithToken(ctx sdk.Context, srcChain, srcAddress string, destAddress string, payload []byte, coin sdk.Coin) error {
ctx.Logger().Info("HandleGeneralMessageWithToken called",
"srcChain", srcChain,
"srcAddress", srcAddress,
"destAddress", destAddress,
"payload", payload,
"coin", coin,
"module", "axelar",
)
return nil
}
54 changes: 54 additions & 0 deletions modules/axelar/types/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package types

import (
transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
)

// TODO: AxelarGMPAcc should be moved to config
const AxelarGMPAcc = "axelar1dv4u5k73pzqrxlzujxg3qp8kvc3pje7jtdvu72npnt5zhq05ejcsn5qme5"

// Message is attached in ICS20 packet memo field
type Message struct {
SourceChain string `json:"source_chain"`
SourceAddress string `json:"source_address"`
Payload []byte `json:"payload"`
Type int64 `json:"type"`
}

// MessageType is the type of message
type MessageType int

const (
// TypeUnrecognized means coin type is unrecognized
TypeUnrecognized = iota
// TypePureMessage is a general message
TypePureMessage
// TypeMessageWithToken is a general message with token
TypeMessageWithToken
)

// ParseDenom convert denom to receiver chain representation
func ParseDenom(packet channeltypes.Packet, denom string) string {
if transfertypes.ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), denom) {
// remove prefix added by sender chain
voucherPrefix := transfertypes.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel())
unprefixedDenom := denom[len(voucherPrefix):]

// coin denomination used in sending from the escrow address
denom = unprefixedDenom

// The denomination used to send the coins is either the native denom or the hash of the path
// if the denomination is not native.
denomTrace := transfertypes.ParseDenomTrace(unprefixedDenom)
if denomTrace.Path != "" {
denom = denomTrace.IBCDenom()
}
return denom
}

prefixedDenom := transfertypes.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel()) + denom
denom = transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom()

return denom
}

0 comments on commit 531761c

Please sign in to comment.