diff --git a/Makefile b/Makefile index 9c8a00e2d..a2a54ab7c 100644 --- a/Makefile +++ b/Makefile @@ -178,7 +178,7 @@ test: test-unit test-all: check test-race test-cover test-unit: - @VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock' ./... + @VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock' `go list ./... | grep -v dex` test-race: @VERSION=$(VERSION) go test -mod=readonly -race -tags='ledger test_ledger_mock' ./... diff --git a/app/app.go b/app/app.go index d25bc5583..af04a7b11 100644 --- a/app/app.go +++ b/app/app.go @@ -193,10 +193,6 @@ import ( dexkeeper "github.com/neutron-org/neutron/v4/x/dex/keeper" dextypes "github.com/neutron-org/neutron/v4/x/dex/types" - "github.com/neutron-org/neutron/v4/x/ibcswap" - ibcswapkeeper "github.com/neutron-org/neutron/v4/x/ibcswap/keeper" - ibcswaptypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" - globalfeekeeper "github.com/neutron-org/neutron/v4/x/globalfee/keeper" gmpmiddleware "github.com/neutron-org/neutron/v4/x/gmp" @@ -276,7 +272,6 @@ var ( globalfee.AppModule{}, feemarket.AppModuleBasic{}, dex.AppModuleBasic{}, - ibcswap.AppModuleBasic{}, oracle.AppModuleBasic{}, marketmap.AppModuleBasic{}, dynamicfees.AppModuleBasic{}, @@ -298,7 +293,6 @@ var ( tokenfactorytypes.ModuleName: {authtypes.Minter, authtypes.Burner}, crontypes.ModuleName: nil, dextypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - ibcswaptypes.ModuleName: {authtypes.Burner}, oracletypes.ModuleName: nil, marketmaptypes.ModuleName: nil, feemarkettypes.FeeCollectorName: nil, @@ -370,7 +364,6 @@ type App struct { CronKeeper cronkeeper.Keeper PFMKeeper *pfmkeeper.Keeper DexKeeper dexkeeper.Keeper - SwapKeeper ibcswapkeeper.Keeper GlobalFeeKeeper globalfeekeeper.Keeper PFMModule packetforward.AppModule @@ -748,15 +741,6 @@ func New( dexModule := dex.NewAppModule(appCodec, app.DexKeeper, app.BankKeeper) - app.SwapKeeper = ibcswapkeeper.NewKeeper( - appCodec, - app.MsgServiceRouter(), - app.IBCKeeper.ChannelKeeper, - app.BankKeeper, - ) - - swapModule := ibcswap.NewAppModule(app.SwapKeeper) - wasmDir := filepath.Join(homePath, "wasm") wasmConfig, err := wasm.ReadWasmConfig(appOpts) if err != nil { @@ -921,7 +905,6 @@ func New( pfmkeeper.DefaultRefundTransferPacketTimeoutTimestamp, ) - ibcStack = ibcswap.NewIBCMiddleware(ibcStack, app.SwapKeeper) ibcStack = gmpmiddleware.NewIBCMiddleware(ibcStack) ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). @@ -972,7 +955,6 @@ func New( globalfee.NewAppModule(app.GlobalFeeKeeper, app.GetSubspace(globalfee.ModuleName), app.AppCodec(), app.keys[globalfee.ModuleName]), feemarket.NewAppModule(appCodec, *app.FeeMarkerKeeper), dynamicfees.NewAppModule(appCodec, *app.DynamicFeesKeeper), - swapModule, dexModule, marketmapModule, oracleModule, @@ -1022,7 +1004,6 @@ func New( oracletypes.ModuleName, globalfee.ModuleName, feemarkettypes.ModuleName, - ibcswaptypes.ModuleName, dextypes.ModuleName, consensusparamtypes.ModuleName, ) @@ -1059,7 +1040,6 @@ func New( oracletypes.ModuleName, globalfee.ModuleName, feemarkettypes.ModuleName, - ibcswaptypes.ModuleName, dextypes.ModuleName, consensusparamtypes.ModuleName, ) @@ -1101,7 +1081,6 @@ func New( feemarkettypes.ModuleName, oracletypes.ModuleName, marketmaptypes.ModuleName, - ibcswaptypes.ModuleName, dextypes.ModuleName, dynamicfeestypes.ModuleName, consensusparamtypes.ModuleName, diff --git a/contracts/neutron_chain_manager.wasm b/contracts/neutron_chain_manager.wasm index 912789846..83945edcf 100644 Binary files a/contracts/neutron_chain_manager.wasm and b/contracts/neutron_chain_manager.wasm differ diff --git a/tests/feemarket/go.sum b/tests/feemarket/go.sum index e47067c01..e2c9ef1fc 100644 --- a/tests/feemarket/go.sum +++ b/tests/feemarket/go.sum @@ -1050,6 +1050,7 @@ github.com/skip-mev/chaintestutil v0.0.0-20240514161515-056d7ba45610 h1:4JlsiRVt github.com/skip-mev/chaintestutil v0.0.0-20240514161515-056d7ba45610/go.mod h1:kB8gFZX07CyJnw8q9iEZijI3qJTIe1K/Y++P5VGkrcg= github.com/skip-mev/feemarket v1.1.0 h1:3z/3Mplmk4t1C/IjghC+OE361L9n8dR3Xr7bXIcS7ec= github.com/skip-mev/feemarket v1.1.0/go.mod h1:CVsCaHxJDK4y271c1Dan6Z8G2QaOyWJLoSBnDEPon40= +github.com/skip-mev/feemarket v1.1.1/go.mod h1:DUa6djUsTeMOrbrcIZqWSVxU9IZNCXp96ruaojyBNpc= github.com/skip-mev/feemarket/tests/e2e v1.10.0 h1:oKAZSo+rynd2b7+T8/U+4C+h//rrTdjLICG2Awjk8YA= github.com/skip-mev/feemarket/tests/e2e v1.10.0/go.mod h1:57BURopGhr+L0zDkhj1E9jzP9W8rMzRb3b+MT+trlB4= github.com/skip-mev/interchaintest/v8 v8.0.1-0.20240611183342-72ec508eb966 h1:X5BD7m4QieHlORqGho1Af8r0O1GSWBRYO330xyu2kzQ= diff --git a/tests/ibc/gmp_swap_forward_test.go b/tests/ibc/gmp_swap_forward_test.go deleted file mode 100644 index c337c953c..000000000 --- a/tests/ibc/gmp_swap_forward_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package ibc_test - -import ( - "encoding/json" - - "cosmossdk.io/math" - - "github.com/neutron-org/neutron/v4/x/dex/types" - "github.com/neutron-org/neutron/v4/x/gmp" - swaptypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -// TestGMPSwapAndForward_Success asserts that the swap middleware works as intended when the original message is sent via GMP -func (s *IBCTestSuite) TestGMPSwapAndForward_Success() { - // Send an IBC transfer from provider to Neutron, so we can initialize a pool with the IBC denom token + native Neutron token - s.IBCTransferProviderToNeutron(s.providerAddr, s.neutronAddr, nativeDenom, ibcTransferAmount, "") - - // Assert that the funds are gone from the acc on provider and present in the acc on Neutron - newProviderBalNative := genesisWalletAmount.Sub(ibcTransferAmount) - s.assertProviderBalance(s.providerAddr, nativeDenom, newProviderBalNative) - - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, ibcTransferAmount) - - // deposit stake<>ibcTransferToken to initialize the pool on Neutron - depositAmount := math.NewInt(100_000) - postDepositNeutronBalNative := genesisWalletAmount.Sub(depositAmount) - s.neutronDeposit( - nativeDenom, - s.providerToNeutronDenom, - depositAmount, - depositAmount, - 0, - 1, - s.neutronAddr) - - // Compose the IBC transfer memo metadata to be used in the swap and forward - swapAmount := math.NewInt(100000) - expectedOut := math.NewInt(99990) - - swapMetadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 2, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - }, - } - swapMetadataBz, err := json.Marshal(swapMetadata) - - s.Require().NoError(err) - - gmpMetadata := gmp.Message{ - SourceChain: "axelar", - SourceAddress: "alice", - Payload: swapMetadataBz, - Type: gmp.TypeGeneralMessageWithToken, - } - - gmpMetadataBz, err := json.Marshal(gmpMetadata) - s.Require().NoError(err) - - // Send an IBC transfer from chainA to chainB with GMP payload containing the swap metadata - - s.IBCTransferProviderToNeutron(s.providerAddr, s.neutronAddr, nativeDenom, ibcTransferAmount, string(gmpMetadataBz)) - - // Check that the funds are moved out of the acc on providerChain - s.assertProviderBalance( - s.providerAddr, - nativeDenom, - newProviderBalNative.Sub(ibcTransferAmount), - ) - - // Check that the swap funds are now present in the acc on Neutron - s.assertNeutronBalance(s.neutronAddr, nativeDenom, postDepositNeutronBalNative.Add(expectedOut)) - - // Check that the overrideReceiver did not keep anything - overrideAddr := s.ReceiverOverrideAddr(s.neutronTransferPath.EndpointA.ChannelID, s.providerAddr.String()) - s.assertNeutronBalance(overrideAddr, s.providerToNeutronDenom, math.ZeroInt()) - s.assertNeutronBalance(overrideAddr, s.providerToNeutronDenom, math.ZeroInt()) - - // Check that nothing is credited to the original creator - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) -} diff --git a/tests/ibc/ibc_setup_test.go b/tests/ibc/ibc_setup_test.go index 54264e685..51477e833 100644 --- a/tests/ibc/ibc_setup_test.go +++ b/tests/ibc/ibc_setup_test.go @@ -5,7 +5,6 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -20,12 +19,10 @@ import ( appparams "github.com/neutron-org/neutron/v4/app/params" "github.com/neutron-org/neutron/v4/testutil" - dextypes "github.com/neutron-org/neutron/v4/x/dex/types" ) var ( nativeDenom = appparams.DefaultDenom - ibcTransferAmount = math.NewInt(100_000) genesisWalletAmount, _ = math.NewIntFromString("10000000000000000000") ) @@ -338,38 +335,3 @@ func (s *IBCTestSuite) assertChainBBalance(addr sdk.AccAddress, denom string, ex func (s *IBCTestSuite) assertChainCBalance(addr sdk.AccAddress, denom string, expectedAmt math.Int) { s.assertBalance(s.bundleC.App.GetTestBankKeeper(), s.bundleC.Chain, addr, denom, expectedAmt) } - -func (s *IBCTestSuite) ReceiverOverrideAddr(channel, sender string) sdk.AccAddress { - addr, err := packetforward.GetReceiver(channel, sender) - if err != nil { - panic("Cannot calc receiver override: " + err.Error()) - } - return sdk.MustAccAddressFromBech32(addr) -} - -func (s *IBCTestSuite) neutronDeposit( - token0 string, - token1 string, - depositAmount0 math.Int, - depositAmount1 math.Int, - tickIndex int64, - fee uint64, - creator sdk.AccAddress, -) { - // create deposit msg - msgDeposit := dextypes.NewMsgDeposit( - creator.String(), - creator.String(), - token0, - token1, - []math.Int{depositAmount0}, - []math.Int{depositAmount1}, - []int64{tickIndex}, - []uint64{fee}, - []*dextypes.DepositOptions{{DisableAutoswap: false}}, - ) - - // execute deposit msg - _, err := s.neutronChain.SendMsgs(msgDeposit) - s.Assert().NoError(err, "Deposit Failed") -} diff --git a/tests/ibc/swap_forward_test.go b/tests/ibc/swap_forward_test.go deleted file mode 100644 index 2385da68d..000000000 --- a/tests/ibc/swap_forward_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package ibc_test - -import ( - "encoding/json" - "time" - - "cosmossdk.io/math" - pfmtypes "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward/types" - - "github.com/neutron-org/neutron/v4/x/dex/types" - swaptypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -// TestSwapAndForward_Fails asserts that the IBC swap middleware fails gracefully when provided with a package-forward memo -func (s *IBCTestSuite) TestSwapAndForward_Fails() { - // Send an IBC transfer from provider chain to neutron, so we can initialize a pool with the IBC denom token + native Neutron token - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - "", - ) - newProviderBalNative := genesisWalletAmount.Sub(ibcTransferAmount) - - // deposit stake<>ibcTransferToken to initialize the pool on Neutron - depositAmount := math.NewInt(100_000) - s.neutronDeposit( - nativeDenom, - s.providerToNeutronDenom, - depositAmount, - depositAmount, - 0, - 1, - s.neutronAddr) - - postDepositNeutronBalNative := genesisWalletAmount.Sub(depositAmount) - - // Compose the IBC transfer memo metadata to be used in the swap and forward - swapAmount := math.NewInt(100000) - chainBAddr := s.bundleB.Chain.SenderAccount.GetAddress() - - retries := uint8(0) - - forwardMetadata := pfmtypes.PacketMetadata{ - Forward: &pfmtypes.ForwardMetadata{ - Receiver: chainBAddr.String(), - Port: s.neutronChainBPath.EndpointA.ChannelConfig.PortID, - Channel: s.neutronChainBPath.EndpointA.ChannelID, - Timeout: pfmtypes.Duration(5 * time.Minute), - Retries: &retries, - Next: nil, - }, - } - - bz, err := json.Marshal(forwardMetadata) - s.Assert().NoError(err) - - nextJSON := new(swaptypes.JSONObject) - err = json.Unmarshal(bz, nextJSON) - s.Assert().NoError(err) - - metadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 2, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nextJSON, - }, - } - - metadataBz, err := json.Marshal(metadata) - s.Require().NoError(err) - - // Send (failing) IBC transfer with PFM data - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - string(metadataBz), - ) - - // Check that the funds are not present in the account on Neutron - s.assertNeutronBalance(s.neutronAddr, nativeDenom, postDepositNeutronBalNative) - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) - - // Check that the refund takes place and the funds are moved back to the account on Gaia - s.assertProviderBalance(s.providerAddr, nativeDenom, newProviderBalNative) -} diff --git a/tests/ibc/swap_test.go b/tests/ibc/swap_test.go deleted file mode 100644 index bd8f47ca7..000000000 --- a/tests/ibc/swap_test.go +++ /dev/null @@ -1,173 +0,0 @@ -package ibc_test - -import ( - "encoding/json" - - "cosmossdk.io/math" - - dextypes "github.com/neutron-org/neutron/v4/x/dex/types" - swaptypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -// TestIBCSwapMiddleware_Success asserts that the IBC swap middleware works as intended with Neutron running as a -// consumer chain connected to the Cosmos Hub. -func (s *IBCTestSuite) TestIBCSwapMiddleware_Success() { - // Send an IBC transfer from provider to Neutron, so we can initialize a pool with the IBC denom token + native Neutron token - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - "", - ) - - // Assert that the funds are gone from the acc on provider and present in the acc on Neutron - newProviderBalNative := genesisWalletAmount.Sub(ibcTransferAmount) - s.assertProviderBalance(s.providerAddr, nativeDenom, newProviderBalNative) - - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, ibcTransferAmount) - - // deposit stake<>ibcTransferToken to initialize the pool on Neutron - depositAmount := math.NewInt(100_000) - s.neutronDeposit( - nativeDenom, - s.providerToNeutronDenom, - depositAmount, - depositAmount, - 0, - 1, - s.neutronAddr) - - // Assert that the deposit was successful and the funds are moved out of the Neutron user acc - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) - postDepositNeutronBalNative := genesisWalletAmount.Sub(depositAmount) - s.assertNeutronBalance(s.neutronAddr, nativeDenom, postDepositNeutronBalNative) - - // Send an IBC transfer from providerChain to Neutron with packet memo containing the swap metadata - swapAmount := math.NewInt(100000) - expectedOut := math.NewInt(99_990) - - metadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &dextypes.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 2, - OrderType: dextypes.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - - metadataBz, err := json.Marshal(metadata) - s.Require().NoError(err) - - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - string(metadataBz), - ) - - // Check that the funds are moved out of the acc on providerChain - s.assertProviderBalance( - s.providerAddr, - nativeDenom, - newProviderBalNative.Sub(ibcTransferAmount), - ) - - // Check that the swap funds are now present in the acc on Neutron - s.assertNeutronBalance(s.neutronAddr, nativeDenom, postDepositNeutronBalNative.Add(expectedOut)) - - // Check that the overrideReceiver did not keep anything - overrideAddr := s.ReceiverOverrideAddr(s.neutronTransferPath.EndpointA.ChannelID, s.providerAddr.String()) - s.assertNeutronBalance(overrideAddr, s.providerToNeutronDenom, math.ZeroInt()) - s.assertNeutronBalance(overrideAddr, s.providerToNeutronDenom, math.ZeroInt()) - - // Check that nothing credited to the original creator - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) -} - -// TestIBCSwapMiddleware_FailRefund asserts that the IBC swap middleware works as intended with Neutron running as a -// consumer chain connected to the Cosmos Hub. The swap should fail and a refund to the src chain should take place. -func (s *IBCTestSuite) TestIBCSwapMiddleware_FailRefund() { - // Compose the swap metadata, this swap will fail because there is no pool initialized for this pair - swapAmount := math.NewInt(100000) - metadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &dextypes.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 1, - OrderType: dextypes.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - - metadataBz, err := json.Marshal(metadata) - s.Require().NoError(err) - - // Send (failing) IBC transfer with swap metadata - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - string(metadataBz), - ) - - // Check that the funds are not present in the account on Neutron - s.assertNeutronBalance(s.neutronAddr, nativeDenom, genesisWalletAmount) - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) - - // Check that the refund takes place and the funds are moved back to the account on Gaia - s.assertProviderBalance(s.providerAddr, nativeDenom, genesisWalletAmount) -} - -func (s *IBCTestSuite) TestIBCSwapMiddleware_FailWithRefundAddr() { - // Compose the swap metadata, this swap will fail because there is no pool initialized for this pair - refundAddr := s.neutronChain.SenderAccounts[1].SenderAccount.GetAddress() - swapAmount := math.NewInt(100000) - metadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &dextypes.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 1, - OrderType: dextypes.LimitOrderType_FILL_OR_KILL, - }, - NeutronRefundAddress: refundAddr.String(), - Next: nil, - }, - } - - metadataBz, err := json.Marshal(metadata) - s.Require().NoError(err) - - // Send (failing) IBC transfer with swap metadata - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - string(metadataBz), - ) - - // Check that the funds have been moved to the refund address - s.assertNeutronBalance(refundAddr, nativeDenom, genesisWalletAmount) - s.assertNeutronBalance(refundAddr, s.providerToNeutronDenom, ibcTransferAmount) - - // Check that no refund takes place and the funds are not in the account on provider - s.assertProviderBalance(s.providerAddr, nativeDenom, genesisWalletAmount.Sub(ibcTransferAmount)) -} diff --git a/x/dex/keeper/msg_server.go b/x/dex/keeper/msg_server.go index 1211cc57b..2b3bca666 100644 --- a/x/dex/keeper/msg_server.go +++ b/x/dex/keeper/msg_server.go @@ -259,12 +259,6 @@ func (k MsgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParam return &types.MsgUpdateParamsResponse{}, nil } -func (k MsgServer) AssertNotPaused(goCtx context.Context) error { - ctx := sdk.UnwrapSDKContext(goCtx) - paused := k.GetParams(ctx).Paused - - if paused { - return types.ErrDexPaused - } - return nil +func (k MsgServer) AssertNotPaused(_ context.Context) error { + return types.ErrDexPaused } diff --git a/x/ibcswap/ibc_middleware.go b/x/ibcswap/ibc_middleware.go deleted file mode 100644 index 9f5b5edab..000000000 --- a/x/ibcswap/ibc_middleware.go +++ /dev/null @@ -1,428 +0,0 @@ -package ibcswap - -import ( - "encoding/json" - "errors" - "strings" - - sdkerrors "cosmossdk.io/errors" - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" - - "github.com/neutron-org/neutron/v4/x/ibcswap/keeper" - "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -var _ porttypes.Middleware = &IBCMiddleware{} - -// IBCMiddleware implements the ICS26 callbacks for the swap middleware given the -// swap keeper and the underlying application. -type IBCMiddleware struct { - app porttypes.IBCModule - keeper keeper.Keeper -} - -// NewIBCMiddleware creates a new IBCMiddleware given the keeper and underlying application. -func NewIBCMiddleware(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware { - return IBCMiddleware{ - app: app, - keeper: k, - } -} - -// 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) { - return im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - chanCap, - counterparty, - version, - ) -} - -// OnChanOpenTry implements the IBCModule interface. -func (im IBCMiddleware) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (version string, err error) { - return im.app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - chanCap, - counterparty, - counterpartyVersion, - ) -} - -// OnChanOpenAck implements the IBCModule 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 IBCModule interface. -func (im IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanOpenConfirm(ctx, portID, channelID) -} - -// OnChanCloseInit implements the IBCModule interface. -func (im IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanCloseInit(ctx, portID, channelID) -} - -// OnChanCloseConfirm implements the IBCModule interface. -func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanCloseConfirm(ctx, portID, channelID) -} - -// OnRecvPacket checks the memo field on this packet and if the metadata inside's root key indicates this packet -// should be handled by the swap middleware it attempts to perform a swap. If the swap is successful -// the underlying application's OnRecvPacket callback is invoked. - -// For clarity, here is a breakdown of the steps -// 1. Check if this is a swap packet; if not pass it to next middleware -// 2. validate swapMetadata; ErrAck if invalid -// 3. Pass through the middleware stack to ibc-go/transfer#OnRecvPacket; transfer coins are sent to receiver -// 4. Do swap; handle failures - -func (im IBCMiddleware) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - var data transfertypes.FungibleTokenPacketData - if err := transfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - return channeltypes.NewErrorAcknowledgement(err) - } - - m := &types.PacketMetadata{} - err := json.Unmarshal([]byte(data.Memo), m) - if err != nil || m.Swap == nil { - // Not a packet that should be handled by the swap middleware - return im.app.OnRecvPacket(ctx, packet, relayer) - } - - metadata := m.Swap - - if err := metadata.Validate(); err != nil { - return channeltypes.NewErrorAcknowledgement(err) - } - - if err := validateSwapPacket(packet, data, *metadata); err != nil { - return channeltypes.NewErrorAcknowledgement(err) - } - - // Use overrideReceiver so that users cannot ibcswap through arbitrary addresses. - // Instead generate a unique address for each user based on their channel and origin-address - originalCreator := m.Swap.Creator - overrideReceiver, err := packetforward.GetReceiver(packet.DestinationChannel, data.Sender) - if err != nil { - return channeltypes.NewErrorAcknowledgement(err) - } - metadata.Creator = overrideReceiver - // Update packet data to match the new receiver so that transfer middleware adds tokens to the expected address - packet = newPacketWithOverrideReceiver(packet, data, overrideReceiver) - - ack := im.app.OnRecvPacket(ctx, packet, relayer) - if ack == nil || !ack.Success() { - return ack - } - - // Attempt to perform a swap using a cacheCtx - cacheCtx, writeCache := ctx.CacheContext() - res, err := im.keeper.Swap(cacheCtx, originalCreator, metadata.MsgPlaceLimitOrder) - if err != nil { - return im.handleFailedSwap(ctx, packet, data, metadata, err) - } - - // If there is no next field set in the metadata return ack - if metadata.Next == nil { - writeCache() - return ack - } - - // We need to reset the packets memo field so that the root key in the metadata is the - // next field from the current metadata. - memoBz, err := json.Marshal(metadata.Next) - if err != nil { - return ack - } - - postSwapData := data - postSwapData.Memo = string(memoBz) - - // Override the packet data to include the token denom and amount that was received from the swap. - postSwapData.Denom = res.TakerCoinOut.Denom - postSwapData.Amount = res.TakerCoinOut.Amount.String() - - // After a successful swap funds are now in the receiver account from the MsgPlaceLimitOrder so, - // we need to override the packets receiver field before invoking the forward middlewares OnRecvPacket. - postSwapData.Receiver = m.Swap.Receiver - - dataBz, err := transfertypes.ModuleCdc.MarshalJSON(&postSwapData) - if err != nil { - return ack - } - - packet.Data = dataBz - - // The forward middleware should return a nil ack if the forward is initiated properly. - // If not an error occurred, and we return the original ack. - newAck := im.app.OnRecvPacket(cacheCtx, packet, relayer) - if newAck != nil { - return im.handleFailedSwap(ctx, packet, data, metadata, errors.New(string(newAck.Acknowledgement()))) - } - - writeCache() - return nil -} - -// OnAcknowledgementPacket implements the IBCModule 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 IBCModule interface. -func (im IBCMiddleware) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - return im.app.OnTimeoutPacket(ctx, packet, relayer) -} - -func (im IBCMiddleware) SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (sequence uint64, err error) { - return im.keeper.SendPacket( - ctx, - chanCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, - ) -} - -// WriteAcknowledgement implements the ICS4 Wrapper interface. -func (im IBCMiddleware) WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, -) error { - return im.keeper.WriteAcknowledgement(ctx, chanCap, packet, ack) -} - -func (im IBCMiddleware) GetAppVersion( - ctx sdk.Context, - portID string, - channelID string, -) (string, bool) { - return im.keeper.GetAppVersion(ctx, portID, channelID) -} - -// handleFailedSwap will invoke the appropriate failover logic depending on if this swap was marked refundable -// or non-refundable in the SwapMetadata. -func (im IBCMiddleware) handleFailedSwap( - ctx sdk.Context, - packet channeltypes.Packet, - data transfertypes.FungibleTokenPacketData, - metadata *types.SwapMetadata, - err error, -) ibcexported.Acknowledgement { - swapErr := sdkerrors.Wrap(types.ErrSwapFailed, err.Error()) - im.keeper.Logger(ctx).Error( - "ibc swap failed", - "err", swapErr, - "creator", metadata.Creator, - "receiver", metadata.Receiver, - "tokenIn", metadata.TokenIn, - "tokenOut", metadata.TokenOut, - "AmountIn", metadata.AmountIn, - "TickIndexInToOut", metadata.TickIndexInToOut, - "OrderType", metadata.OrderType, - "refund address", metadata.NeutronRefundAddress, - ) - - // The current denom is from the sender chains perspective, we need to compose the appropriate denom for this side - denomOnThisChain := getDenomForThisChain(packet, data.Denom) - - if len(metadata.NeutronRefundAddress) != 0 { - return im.handleOnChainRefund(ctx, data, metadata, denomOnThisChain, err) - } - - return im.handleIBCRefund(ctx, packet, data, metadata, denomOnThisChain, err) -} - -// handleOnChainRefund will compose a successful ack to send back to the counterparty chain containing any error messages. -// Returning a successful ack ensures that a refund is not issued on the counterparty chain. -// See: https://github.com/cosmos/ibc-go/blob/3ecc7dd3aef5790ec5d906936a297b34adf1ee41/modules/apps/transfer/keeper/relay.go#L320 -func (im IBCMiddleware) handleOnChainRefund( - ctx sdk.Context, - data transfertypes.FungibleTokenPacketData, - metadata *types.SwapMetadata, - newDenom string, - swapErr error, -) ibcexported.Acknowledgement { - amount, ok := math.NewIntFromString(data.Amount) - if !ok { - wrappedErr := sdkerrors.Wrapf( - transfertypes.ErrInvalidAmount, - "unable to parse transfer amount (%s) into math.Int", - data.Amount, - ) - wrappedErr = sdkerrors.Wrap(swapErr, wrappedErr.Error()) - return channeltypes.NewResultAcknowledgement([]byte(wrappedErr.Error())) - } - - token := sdk.NewCoin(newDenom, amount) - err := im.keeper.SendCoins(ctx, metadata.Creator, metadata.NeutronRefundAddress, sdk.NewCoins(token)) - if err != nil { - wrappedErr := sdkerrors.Wrap(err, "failed to move funds to refund address") - wrappedErr = sdkerrors.Wrap(swapErr, wrappedErr.Error()) - return channeltypes.NewResultAcknowledgement([]byte(wrappedErr.Error())) - } - - return channeltypes.NewResultAcknowledgement([]byte(swapErr.Error())) -} - -// handleIBCRefund will either burn or transfer the funds back to the appropriate escrow account. -// When a packet comes in the transfer module's OnRecvPacket callback is invoked which either -// mints or unescrows funds on this side so if the swap fails an explicit refund is required. -func (im IBCMiddleware) handleIBCRefund( - ctx sdk.Context, - packet channeltypes.Packet, - data transfertypes.FungibleTokenPacketData, - metadata *types.SwapMetadata, - newDenom string, - swapErr error, -) ibcexported.Acknowledgement { - data.Denom = newDenom - - err := im.keeper.RefundPacketToken(ctx, packet, data, metadata) - if err != nil { - wrappedErr := sdkerrors.Wrap(swapErr, err.Error()) - - // If the refund fails on this side we want to make sure that the refund does not happen on the counterparty, - // so we return a successful ack containing the error - return channeltypes.NewResultAcknowledgement([]byte(wrappedErr.Error())) - } - - return channeltypes.NewErrorAcknowledgement(swapErr) -} - -// getDenomForThisChain composes a new token denom by either unwinding or prefixing the specified token denom appropriately. -// This is necessary because the token denom in the packet data is from the perspective of the counterparty chain. -func getDenomForThisChain(packet channeltypes.Packet, denom string) string { - counterpartyPrefix := transfertypes.GetDenomPrefix(packet.SourcePort, packet.SourceChannel) - if strings.HasPrefix(denom, counterpartyPrefix) { - // unwind denom - unwoundDenom := denom[len(counterpartyPrefix):] - denomTrace := transfertypes.ParseDenomTrace(unwoundDenom) - if denomTrace.Path == "" { - // denom is now unwound back to native denom - return unwoundDenom - } - // denom is still IBC denom - return denomTrace.IBCDenom() - } - - // append port and channel from this chain to denom - prefixedDenom := transfertypes.GetDenomPrefix(packet.DestinationPort, packet.DestinationChannel) + denom - return transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom() -} - -// Update the packet data to reflect the new receiver address that is used by the PFM -func newPacketWithOverrideReceiver(oldPacket channeltypes.Packet, data transfertypes.FungibleTokenPacketData, overrideReceiver string) channeltypes.Packet { - overrideData := transfertypes.FungibleTokenPacketData{ - Denom: data.Denom, - Amount: data.Amount, - Sender: data.Sender, - Receiver: overrideReceiver, // override receiver - } - overrideDataBz := transfertypes.ModuleCdc.MustMarshalJSON(&overrideData) - - return channeltypes.Packet{ - Sequence: oldPacket.Sequence, - SourcePort: oldPacket.SourcePort, - SourceChannel: oldPacket.SourceChannel, - DestinationPort: oldPacket.DestinationPort, - DestinationChannel: oldPacket.DestinationChannel, - Data: overrideDataBz, // override data - TimeoutHeight: oldPacket.TimeoutHeight, - TimeoutTimestamp: oldPacket.TimeoutTimestamp, - } -} - -func validateSwapPacket(packet channeltypes.Packet, transferData transfertypes.FungibleTokenPacketData, sm types.SwapMetadata) error { - denomOnNeutron := getDenomForThisChain(packet, transferData.Denom) - if denomOnNeutron != sm.TokenIn { - return sdkerrors.Wrap(types.ErrInvalidSwapMetadata, "Transfer Denom must match TokenIn") - } - - transferAmount, ok := math.NewIntFromString(transferData.Amount) - if !ok { - return sdkerrors.Wrapf( - transfertypes.ErrInvalidAmount, - "unable to parse transfer amount (%s) into math.Int", - transferData.Amount, - ) - } - - if transferAmount.LT(sm.AmountIn) { - return sdkerrors.Wrap(types.ErrInvalidSwapMetadata, "Transfer amount must be >= AmountIn") - } - - if sm.ContainsPFM() { - return sdkerrors.Wrap( - types.ErrInvalidSwapMetadata, - "ibcswap middleware cannot be used in conjunction with packet-forward-middleware", - ) - } - return nil -} diff --git a/x/ibcswap/keeper/keeper.go b/x/ibcswap/keeper/keeper.go deleted file mode 100644 index 33d5f1493..000000000 --- a/x/ibcswap/keeper/keeper.go +++ /dev/null @@ -1,207 +0,0 @@ -package keeper - -import ( - "fmt" - - sdkerrors "cosmossdk.io/errors" - "cosmossdk.io/log" - "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/gogoproto/proto" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" - - dextypes "github.com/neutron-org/neutron/v4/x/dex/types" - "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -// Keeper defines the swap middleware keeper. -type Keeper struct { - cdc codec.BinaryCodec - msgServiceRouter *baseapp.MsgServiceRouter - - ics4Wrapper porttypes.ICS4Wrapper - bankKeeper types.BankKeeper -} - -// NewKeeper creates a new swap Keeper instance. -func NewKeeper( - cdc codec.BinaryCodec, - msgServiceRouter *baseapp.MsgServiceRouter, - ics4Wrapper porttypes.ICS4Wrapper, - bankKeeper types.BankKeeper, -) Keeper { - return Keeper{ - cdc: cdc, - msgServiceRouter: msgServiceRouter, - - ics4Wrapper: ics4Wrapper, - bankKeeper: bankKeeper, - } -} - -// Logger returns a module-specific logger. -func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", "x/"+ibcexported.ModuleName+"-"+types.ModuleName) -} - -// Swap calls into the base app's msg service router so that the appropriate handler is called when sending the swap msg. -func (k Keeper) Swap( - ctx sdk.Context, - originalCreator string, - msg *dextypes.MsgPlaceLimitOrder, -) (*dextypes.MsgPlaceLimitOrderResponse, error) { - swapHandler := k.msgServiceRouter.Handler(msg) - if swapHandler == nil { - return nil, sdkerrors.Wrap( - types.ErrMsgHandlerInvalid, - fmt.Sprintf("could not find the handler for %T", msg), - ) - } - - res, err := swapHandler(ctx, msg) - if err != nil { - return nil, err - } - - msgSwapRes := &dextypes.MsgPlaceLimitOrderResponse{} - // TODO: replace the Data field with MsgResponses? - if err := proto.Unmarshal(res.Data, msgSwapRes); err != nil { - return nil, err - } - - amountUnused := msg.AmountIn.Sub(msgSwapRes.CoinIn.Amount) - // If not all tokenIn is swapped and a temporary creator address has been used - // return the unused portion to the original creator address - if amountUnused.IsPositive() && originalCreator != msg.Creator { - overrrideCreatorAddr := sdk.MustAccAddressFromBech32(msg.Creator) - originalCreatorAddr := sdk.MustAccAddressFromBech32(originalCreator) - unusedCoin := sdk.NewCoin(msg.TokenIn, amountUnused) - - err := k.bankKeeper.SendCoins(ctx, overrrideCreatorAddr, originalCreatorAddr, sdk.Coins{unusedCoin}) - if err != nil { - return nil, err - } - } - - return msgSwapRes, nil -} - -// SendPacket wraps IBC ChannelKeeper's SendPacket function. -func (k Keeper) SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (sequence uint64, err error) { - return k.ics4Wrapper.SendPacket( - ctx, - chanCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, - ) -} - -// WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function. -func (k Keeper) WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet ibcexported.PacketI, - acknowledgement ibcexported.Acknowledgement, -) error { - return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, acknowledgement) -} - -// RefundPacketToken handles the burning or escrow lock up of vouchers when an asset should be refunded. -// This is only used in the case where we call into the transfer modules OnRecvPacket callback but then the swap fails. -func (k Keeper) RefundPacketToken( - ctx sdk.Context, - packet channeltypes.Packet, - data transfertypes.FungibleTokenPacketData, - metadata *types.SwapMetadata, -) error { - // parse the denomination from the full denom path - trace := transfertypes.ParseDenomTrace(data.Denom) - - // parse the transfer amount - transferAmount, ok := math.NewIntFromString(data.Amount) - if !ok { - return sdkerrors.Wrapf( - transfertypes.ErrInvalidAmount, - "unable to parse transfer amount (%s) into math.Int", - data.Amount, - ) - } - token := sdk.NewCoin(trace.IBCDenom(), transferAmount) - - // decode the creator address - receiver, err := sdk.AccAddressFromBech32(metadata.Creator) - if err != nil { - return err - } - - // if the sender chain is source that means a voucher was minted on Neutron when the ics20 transfer took place - if transfertypes.SenderChainIsSource(packet.SourcePort, packet.SourceChannel, data.Denom) { - // transfer coins from user account to transfer module - err = k.bankKeeper.SendCoinsFromAccountToModule( - ctx, - receiver, - types.ModuleName, - sdk.NewCoins(token), - ) - if err != nil { - return err - } - - // burn the coins - err = k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(token)) - if err != nil { - return err - } - - return nil - } - - // transfer coins from user account to escrow address - escrowAddress := transfertypes.GetEscrowAddress( - packet.GetSourcePort(), - packet.GetSourceChannel(), - ) - err = k.bankKeeper.SendCoins(ctx, receiver, escrowAddress, sdk.NewCoins(token)) - if err != nil { - return err - } - - return nil -} - -// SendCoins wraps the BankKeepers SendCoins function so it can be invoked from the middleware. -func (k Keeper) SendCoins(ctx sdk.Context, fromAddr, toAddr string, amt sdk.Coins) error { - from, err := sdk.AccAddressFromBech32(fromAddr) - if err != nil { - return err - } - - to, err := sdk.AccAddressFromBech32(toAddr) - if err != nil { - return err - } - - return k.bankKeeper.SendCoins(ctx, from, to, amt) -} - -func (k Keeper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { - return k.ics4Wrapper.GetAppVersion(ctx, portID, channelID) -} diff --git a/x/ibcswap/module.go b/x/ibcswap/module.go deleted file mode 100644 index 428ac1274..000000000 --- a/x/ibcswap/module.go +++ /dev/null @@ -1,144 +0,0 @@ -package ibcswap - -import ( - "encoding/json" - - "cosmossdk.io/core/appmodule" - - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/gorilla/mux" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/spf13/cobra" - - "github.com/neutron-org/neutron/v4/x/ibcswap/keeper" - "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -var ( - _ module.AppModuleBasic = AppModuleBasic{} - _ appmodule.AppModule = AppModule{} - _ module.AppModuleSimulation = AppModule{} -) - -// AppModuleBasic is the swap middleware AppModuleBasic. -type AppModuleBasic struct{} - -// Name implements AppModuleBasic interface. -func (AppModuleBasic) Name() string { - return types.ModuleName -} - -// RegisterLegacyAminoCodec implements AppModuleBasic interface. -func (AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) {} - -// RegisterInterfaces registers module concrete types into protobuf Any. -func (AppModuleBasic) RegisterInterfaces(_ codectypes.InterfaceRegistry) {} - -// DefaultGenesis returns default genesis state as raw bytes for the swap module. -func (AppModuleBasic) DefaultGenesis(_ codec.JSONCodec) json.RawMessage { - return nil -} - -// ValidateGenesis performs genesis state validation for the swap module. -func (AppModuleBasic) ValidateGenesis( - _ codec.JSONCodec, - _ client.TxEncodingConfig, - _ json.RawMessage, -) error { - return nil -} - -// RegisterRESTRoutes implements AppModuleBasic interface. -func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} - -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the swap module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *runtime.ServeMux) {} - -// GetTxCmd implements AppModuleBasic interface. -func (AppModuleBasic) GetTxCmd() *cobra.Command { - return nil -} - -// GetQueryCmd implements AppModuleBasic interface. -func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil -} - -// AppModule implements the module.AppModule -type AppModule struct { - AppModuleBasic - keeper keeper.Keeper -} - -func NewAppModule(keeper keeper.Keeper) *AppModule { - return &AppModule{ - keeper: keeper, - } -} - -// RegisterInvariants implements the AppModule interface. -func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} - -// QuerierRoute implements the AppModule interface. -func (AppModule) QuerierRoute() string { - return "" -} - -// RegisterServices registers module services. -func (am AppModule) RegisterServices(_ module.Configurator) {} - -// InitGenesis performs genesis initialization for the ibc-router module. It returns -// no validator updates. -func (am AppModule) InitGenesis( - _ sdk.Context, - _ codec.JSONCodec, - _ json.RawMessage, -) []abci.ValidatorUpdate { - return []abci.ValidatorUpdate{} -} - -// ExportGenesis returns the exported genesis state as raw bytes for the swap module. -func (am AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONCodec) json.RawMessage { - return nil -} - -// ConsensusVersion returns the consensus state breaking version for the swap module. -func (AppModule) ConsensusVersion() uint64 { return 1 } - -// BeginBlock implements the AppModule interface. -func (am AppModule) BeginBlock(_ sdk.Context) {} - -// EndBlock implements the AppModule interface. -func (am AppModule) EndBlock(_ sdk.Context) []abci.ValidatorUpdate { - return []abci.ValidatorUpdate{} -} - -// GenerateGenesisState implements the AppModuleSimulation interface. -func (AppModule) GenerateGenesisState(_ *module.SimulationState) {} - -// ProposalContents implements the AppModuleSimulation interface. -func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalMsg { - return nil -} - -// RegisterStoreDecoder implements the AppModuleSimulation interface. -func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) {} - -// WeightedOperations implements the AppModuleSimulation interface. -func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { - return nil -} - -// IsOnePerModuleType implements the depinject.OnePerModuleType interface. -func (am AppModule) IsOnePerModuleType() { // marker -} - -// IsAppModule implements the appmodule.AppModule interface. -func (am AppModule) IsAppModule() { // marker -} diff --git a/x/ibcswap/types/errors.go b/x/ibcswap/types/errors.go deleted file mode 100644 index 819589ae8..000000000 --- a/x/ibcswap/types/errors.go +++ /dev/null @@ -1,9 +0,0 @@ -package types - -import sdkerrors "cosmossdk.io/errors" - -var ( - ErrInvalidSwapMetadata = sdkerrors.Register(ModuleName, 2, "invalid swap metadata") - ErrSwapFailed = sdkerrors.Register(ModuleName, 3, "ibc swap failed") - ErrMsgHandlerInvalid = sdkerrors.Register(ModuleName, 4, "msg service handler not found") -) diff --git a/x/ibcswap/types/expected_keepers.go b/x/ibcswap/types/expected_keepers.go deleted file mode 100644 index 705463d97..000000000 --- a/x/ibcswap/types/expected_keepers.go +++ /dev/null @@ -1,14 +0,0 @@ -package types - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// BankKeeper defines the expected interface that the swap middleware needs in order to facilitate refunds. -type BankKeeper interface { - SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error - BurnCoins(ctx context.Context, moduleName string, amt sdk.Coins) error - SendCoinsFromAccountToModule(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error -} diff --git a/x/ibcswap/types/keys.go b/x/ibcswap/types/keys.go deleted file mode 100644 index 9a88fc669..000000000 --- a/x/ibcswap/types/keys.go +++ /dev/null @@ -1,8 +0,0 @@ -package types - -// ModuleName defines the name for the swap middleware. -const ModuleName = "swap-middleware" - -// ProcessedKey is used to signal to the swap middleware that a packet has already been processed by some other -// middleware and so invoking the transfer modules OnRecvPacket callback should be avoided. -type ProcessedKey struct{} diff --git a/x/ibcswap/types/swap.go b/x/ibcswap/types/swap.go deleted file mode 100644 index 9f5013a49..000000000 --- a/x/ibcswap/types/swap.go +++ /dev/null @@ -1,114 +0,0 @@ -package types - -import ( - "encoding/json" - - sdkerrors "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/iancoleman/orderedmap" - - dextypes "github.com/neutron-org/neutron/v4/x/dex/types" -) - -// PacketMetadata wraps the SwapMetadata. The root key in the incoming ICS20 transfer packet's memo needs to be set to the same -// value as the json tag in order for the swap middleware to process the swap. -type PacketMetadata struct { - Swap *SwapMetadata `json:"swap"` -} - -// SwapMetadata defines the parameters necessary to perform a swap utilizing the memo field from an incoming ICS20 -// transfer packet. The next field is a string so that you can nest any arbitrary metadata to be handled -// further in the middleware stack or on the counterparty. -type SwapMetadata struct { - *dextypes.MsgPlaceLimitOrder - // If a value is provided for NeutronRefundAddress and the swap fails the Transfer.Amount will be moved to this address for later recovery. - // If no NeutronRefundAddress is provided and a swap fails we will fail the ibc transfer and tokens will be refunded on the source chain. - NeutronRefundAddress string `json:"refund-address,omitempty"` - - // Using JSONObject so that objects for next property will not be mutated by golang's lexicographic key sort on map keys during Marshal. - // Supports primitives for Unmarshal/Marshal so that an escaped JSON-marshaled string is also valid. - Next *JSONObject `json:"next,omitempty"` -} - -// Validate ensures that all the required fields are present in the SwapMetadata and contain valid values. -func (sm SwapMetadata) Validate() error { - if err := sm.MsgPlaceLimitOrder.Validate(); err != nil { - return sdkerrors.Wrap(ErrInvalidSwapMetadata, err.Error()) - } - if sm.TokenIn == "" { - return sdkerrors.Wrap(ErrInvalidSwapMetadata, "limit order tokenIn cannot be an empty string") - } - if sm.TokenOut == "" { - return sdkerrors.Wrap(ErrInvalidSwapMetadata, "limit order tokenOut cannot be an empty string") - } - if sm.NeutronRefundAddress != "" { - _, err := sdk.AccAddressFromBech32(sm.NeutronRefundAddress) - if err != nil { - return sdkerrors.Wrapf(dextypes.ErrInvalidAddress, "%s is not a valid Neutron address", sm.NeutronRefundAddress) - } - } - - if !sm.OrderType.IsFoK() { - return sdkerrors.Wrap(ErrInvalidSwapMetadata, "Limit Order type must be FILL_OR_KILL") - } - - return nil -} - -// ContainsPFM checks if the Swapetadata is wrapping packet-forward-middleware -func (sm SwapMetadata) ContainsPFM() bool { - if sm.Next == nil { - return false - } - forward, _ := sm.Next.orderedMap.Get("forward") - - return forward != nil -} - -// JSONObject is a wrapper type to allow either a primitive type or a JSON object. -// In the case the value is a JSON object, OrderedMap type is used so that key order -// is retained across Unmarshal/Marshal. -type JSONObject struct { - obj bool - primitive []byte - orderedMap orderedmap.OrderedMap -} - -// NewJSONObject is a constructor used for tests. -// The usage of JSONObject in the middleware is only json Marshal/Unmarshal -func NewJSONObject(object bool, primitive []byte, orderedMap orderedmap.OrderedMap) *JSONObject { - return &JSONObject{ - obj: object, - primitive: primitive, - orderedMap: orderedMap, - } -} - -// UnmarshalJSON overrides the default json.Unmarshal behavior -func (o *JSONObject) UnmarshalJSON(b []byte) error { - if err := o.orderedMap.UnmarshalJSON(b); err != nil { - // If ordered map unmarshal fails, this is a primitive value - o.obj = false - // Attempt to unmarshal as string, this removes extra JSON escaping - var primitiveStr string - if err := json.Unmarshal(b, &primitiveStr); err != nil { - o.primitive = b - return nil - } - o.primitive = []byte(primitiveStr) - return nil - } - // This is a JSON object, now stored as an ordered map to retain key order. - o.obj = true - return nil -} - -// MarshalJSON overrides the default json.Marshal behavior -func (o *JSONObject) MarshalJSON() ([]byte, error) { - if o.obj { - // non-primitive, return marshaled ordered map. - return o.orderedMap.MarshalJSON() - } - // primitive, return raw bytes. - return o.primitive, nil -} diff --git a/x/ibcswap/types/swap_test.go b/x/ibcswap/types/swap_test.go deleted file mode 100644 index 50bc06772..000000000 --- a/x/ibcswap/types/swap_test.go +++ /dev/null @@ -1,248 +0,0 @@ -package types_test - -import ( - "encoding/json" - "testing" - - "github.com/neutron-org/neutron/v4/app/config" - - "cosmossdk.io/math" - pfmtypes "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward/types" - "github.com/iancoleman/orderedmap" - "github.com/stretchr/testify/require" - - "github.com/neutron-org/neutron/v4/testutil/common/sample" - "github.com/neutron-org/neutron/v4/x/dex/types" - dextypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -func init() { - _ = config.GetDefaultConfig() -} - -// TestPacketMetadata_Marshal asserts that the marshaling of the swap metadata works as intended. -func TestPacketMetadata_Marshal(t *testing.T) { - pm := dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "test-1", - Receiver: "test-1", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err := json.Marshal(pm) - require.NoError(t, err) -} - -// TestPacketMetadata_MarshalWithNext asserts that the marshaling of the swap metadata works as intended with next field initialized. -func TestPacketMetadata_MarshalWithNext(t *testing.T) { - forwardMedata := &pfmtypes.PacketMetadata{ - Forward: &pfmtypes.ForwardMetadata{ - Receiver: "cosmos14zde8usc4ur04y3aqnufzzmv2uqdpwwttr5uwv", - Port: "transfer", - Channel: "channel-0", - Timeout: 0, - Retries: nil, - Next: nil, - }, - } - nextBz, err := json.Marshal(forwardMedata) - require.NoError(t, err) - - pm := dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "test-1", - Receiver: "test-1", - TokenIn: "token-a", - TokenOut: "token-b", - TickIndexInToOut: 0, - AmountIn: math.NewInt(123), - OrderType: types.LimitOrderType_FILL_OR_KILL, - // MaxAmountOut: math.NewInt(456), - }, - Next: dextypes.NewJSONObject(false, nextBz, orderedmap.OrderedMap{}), - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) -} - -// TestPacketMetadata_Unmarshal asserts that unmarshaling works as intended. -func TestPacketMetadata_Unmarshal(t *testing.T) { - metadata := "{\n \"swap\": {\n \"creator\": \"test-1\",\n \"TickIndexInToOut\": 0,\n \"orderType\": 1,\n \"receiver\": \"test-1\",\n \"tokenIn\": \"token-a\",\n \"tokenOut\": \"token-b\",\n \"AmountIn\": \"123\",\n \"next\": \"\"\n }\n}" - pm := &dextypes.PacketMetadata{} - err := json.Unmarshal([]byte(metadata), pm) - require.NoError(t, err) -} - -// TestPacketMetadata_UnmarshalStringNext asserts that unmarshaling works as intended when next is escaped json string. -func TestPacketMetadata_UnmarshalStringNext(t *testing.T) { - metadata := "{\n \"swap\": {\n \"creator\": \"test-1\",\n \"receiver\": \"test-1\",\n \"tokenIn\": \"token-a\",\n \"tokenOut\": \"token-b\",\n \"AmountIn\": \"123\",\n \"TickIndexInToOut\": 0,\n \"orderType\": 1,\n \"next\": \" {\\\"forward\\\":{\\\"receiver\\\":\\\"cosmos1f4cur2krsua2th9kkp7n0zje4stea4p9tu70u8\\\",\\\"port\\\":\\\"transfer\\\",\\\"channel\\\":\\\"channel-0\\\",\\\"timeout\\\":0,\\\"next\\\":{\\\"forward\\\":{\\\"receiver\\\":\\\"cosmos1l505zhahp24v5jsmps9vs5asah759fdce06sfp\\\",\\\"port\\\":\\\"transfer\\\",\\\"channel\\\":\\\"channel-0\\\",\\\"timeout\\\":0}}}}\"\n }\n}" - pm := &dextypes.PacketMetadata{} - err := json.Unmarshal([]byte(metadata), pm) - require.NoError(t, err) -} - -// TestPacketMetadata_UnmarshalJSONNext asserts that unmarshaling works as intended when next is a raw json object. -func TestPacketMetadata_UnmarshalJSONNext(t *testing.T) { - metadata := "{\"swap\":{\"creator\":\"test-1\",\"receiver\":\"test-1\",\"tokenIn\":\"token-a\",\"tokenOut\":\"token-b\",\"AmountIn\":\"123\",\"TickIndexInToOut\":0, \"orderType\": 1, \"tokenIn\":\"token-in\",\"next\":{\"forward\":{\"receiver\":\"cosmos14zde8usc4ur04y3aqnufzzmv2uqdpwwttr5uwv\",\"port\":\"transfer\",\"channel\":\"channel-0\"}}}}" - pm := &dextypes.PacketMetadata{} - err := json.Unmarshal([]byte(metadata), pm) - require.NoError(t, err) -} - -func TestSwapMetadata_ValidatePass(t *testing.T) { - pm := dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: sample.AccAddress(), - Receiver: sample.AccAddress(), - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err := json.Marshal(pm) - require.NoError(t, err) - - require.NoError(t, pm.Swap.Validate()) -} - -func TestSwapMetadata_ValidateFail(t *testing.T) { - pm := dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "", - Receiver: "test-1", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err := json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "test-1", - TokenIn: "", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "receiver", - TokenIn: "token-a", - TokenOut: "", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "receiver", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(0), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "receiver", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(-1), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "receiver", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_GOOD_TIL_CANCELLED, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) -}