Skip to content

Commit

Permalink
feat(uibc): adding ICS 20 memo handler (#2349)
Browse files Browse the repository at this point in the history
* feat(uibc): adding ICS 20 memo handler

* update codec

* adding dispatcher test

* add tests

* add leverage keeper to uics20 module

* update module initializer

* lint
  • Loading branch information
robert-zaremba authored Dec 18, 2023
1 parent 6239857 commit 5dbe282
Show file tree
Hide file tree
Showing 10 changed files with 493 additions and 37 deletions.
4 changes: 3 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,9 @@ func New(
var transferStack ibcporttypes.IBCModule
transferStack = ibctransfer.NewIBCModule(app.IBCTransferKeeper)
// transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper)
transferStack = uics20.NewICS20Module(transferStack, app.UIbcQuotaKeeperB, appCodec)
transferStack = uics20.NewICS20Module(transferStack, appCodec,
app.UIbcQuotaKeeperB,
leveragekeeper.NewMsgServerImpl(app.LeverageKeeper))

// Create Interchain Accounts Controller Stack
// SendPacket, since it is originating from the application to core IBC:
Expand Down
16 changes: 16 additions & 0 deletions proto/umee/uibc/v1/uibc.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
syntax = "proto3";
package umee.uibc.v1;

import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";

option go_package = "github.com/umee-network/umee/v6/x/uibc";

option (gogoproto.goproto_getters_all) = false;
option (gogoproto.messagename_all) = true;

message ICS20Memo {
// messages is a list of `sdk.Msg`s that will be executed when handling ICS20 transfer.
repeated google.protobuf.Any messages = 1;
}
2 changes: 1 addition & 1 deletion tests/tsdk/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
// typically a RegisterInterfaces function in Cosmos SDK modules)
func NewCodec(registrars ...func(types.InterfaceRegistry)) codec.Codec {
interfaceRegistry := types.NewInterfaceRegistry()
std.RegisterInterfaces(interfaceRegistry)
std.RegisterInterfaces(interfaceRegistry) // register SDK interfaces
for _, f := range registrars {
f(interfaceRegistry)
}
Expand Down
11 changes: 11 additions & 0 deletions x/uibc/ics20.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package uibc

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

// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (m ICS20Memo) UnpackInterfaces(unpacker types.AnyUnpacker) error {
return tx.UnpackInterfaces(unpacker, m.Messages)
}
13 changes: 3 additions & 10 deletions x/uibc/quota/ibc_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (

func (k Keeper) IBCOnSendPacket(packet []byte) error {
params := k.GetParams()

if !params.IbcStatus.IBCTransferEnabled() {
return ics20types.ErrSendDisabled
}
Expand All @@ -34,21 +33,15 @@ func (k Keeper) IBCOnSendPacket(packet []byte) error {
return nil
}

func (k Keeper) IBCOnRecvPacket(packet channeltypes.Packet) exported.Acknowledgement {
func (k Keeper) IBCOnRecvPacket(ft ics20types.FungibleTokenPacketData, packet channeltypes.Packet,
) exported.Acknowledgement {
params := k.GetParams()
if !params.IbcStatus.IBCTransferEnabled() {
return channeltypes.NewErrorAcknowledgement(ics20types.ErrReceiveDisabled)
}

if params.IbcStatus.OutflowQuotaEnabled() {
var data ics20types.FungibleTokenPacketData
if err := ics20types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
ackErr := sdkerrors.ErrInvalidType.Wrap("cannot unmarshal ICS-20 transfer packet data")
return channeltypes.NewErrorAcknowledgement(ackErr)
}

isSourceChain := ics20types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom)
ackErr := k.RecordIBCInflow(packet, data.Denom, data.Amount, isSourceChain)
ackErr := k.RecordIBCInflow(packet, ft.Denom, ft.Amount)
if ackErr != nil {
return ackErr
}
Expand Down
21 changes: 11 additions & 10 deletions x/uibc/quota/quota.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
ics20types "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
"github.com/cosmos/ibc-go/v7/modules/core/exported"

Expand Down Expand Up @@ -229,24 +229,25 @@ func (k Keeper) UndoUpdateQuota(denom string, amount sdkmath.Int) error {
}

// RecordIBCInflow will save the inflow amount if token is registered otherwise it will skip
func (k Keeper) RecordIBCInflow(
packet channeltypes.Packet, dataDenom, dataAmount string, isSourceChain bool,
func (k Keeper) RecordIBCInflow(packet channeltypes.Packet, denom, amount string,
) exported.Acknowledgement {

// if chain is recevier and sender chain is source then we need create ibc_denom (ibc/hash(channel,denom)) to
// check ibc_denom is exists in leverage token registry
if isSourceChain {
if !ics20types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), denom) {
// since SendPacket did not prefix the denomination, we must prefix denomination here
sourcePrefix := transfertypes.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel())
sourcePrefix := ics20types.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel())
// NOTE: sourcePrefix contains the trailing "/"
prefixedDenom := sourcePrefix + dataDenom
prefixedDenom := sourcePrefix + denom
// construct the denomination trace from the full raw denomination and get the ibc_denom
ibcDenom := transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom()
ibcDenom := ics20types.ParseDenomTrace(prefixedDenom).IBCDenom()
ts, err := k.leverage.GetTokenSettings(*k.ctx, ibcDenom)
if err != nil {
// skip if token is not a registered token on leverage
if ltypes.ErrNotRegisteredToken.Is(err) {
return nil
return nil // skip recording inflow if the token is not registered
}
k.ctx.Logger().Error("can't get x/leverage token settings", "error", err)
return channeltypes.NewErrorAcknowledgement(err)
}

// get the exchange price (eg: UMEE) in USD from oracle using SYMBOL Denom eg: `UMEE`
Expand All @@ -256,7 +257,7 @@ func (k Keeper) RecordIBCInflow(
}
// calculate total exchange rate
powerReduction := ten.Power(uint64(ts.Exponent))
inflowInUSD := sdk.MustNewDecFromStr(dataAmount).Quo(powerReduction).Mul(exchangeRate)
inflowInUSD := sdk.MustNewDecFromStr(amount).Quo(powerReduction).Mul(exchangeRate)

tokenInflow := sdk.NewDecCoinFromDec(ibcDenom, inflowInUSD)
k.SetTokenInflow(tokenInflow)
Expand Down
Loading

0 comments on commit 5dbe282

Please sign in to comment.