diff --git a/Makefile b/Makefile index ff3be81e1..95605c202 100644 --- a/Makefile +++ b/Makefile @@ -207,5 +207,22 @@ relayer-start: pica-upgrade: @echo "Starting upgrade" - bash ./scripts/upgrade/upgrade.sh + bash ./scripts/upgrade/upgrade. + + +############################################################################### +### Integration Tests ### +############################################################################### + +integration-test-all: init-test-framework \ + test-ibc-hooks + +init-test-framework: clean-testing-data install + @echo "Initializing both blockchains..." + ./scripts/tests/init-test-framework.sh + ./scripts/relayer/relayer-init.sh + +test-ibc-hooks: + @echo "Testing ibc-hooks..." + ./scripts/tests/ibc-hooks/increment.sh diff --git a/app/app.go b/app/app.go index e6c137c3f..a5df2033f 100644 --- a/app/app.go +++ b/app/app.go @@ -7,6 +7,8 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" + alliancemodule "github.com/terra-money/alliance/x/alliance" + alliancemoduletypes "github.com/terra-money/alliance/x/alliance/types" "io" "os" "path/filepath" @@ -211,6 +213,7 @@ var ( ibctransfermiddleware.AppModuleBasic{}, circuit.AppModuleBasic{}, wasm08.AppModuleBasic{}, + alliancemodule.AppModuleBasic{}, // this line is used by starport scaffolding # stargate/app/moduleBasic ) @@ -394,6 +397,7 @@ func NewComposableApp( icaModule, ratelimitModule, circuit.NewAppModule(appCodec, app.CircuitKeeper), + alliancemodule.NewAppModule(appCodec, app.AllianceKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry, app.GetSubspace(alliancemoduletypes.ModuleName)), // this line is used by starport scaffolding # stargate/app/appModule ) @@ -442,6 +446,7 @@ func NewComposableApp( stakingmiddlewaretypes.ModuleName, ibctransfermiddlewaretypes.ModuleName, wasm08types.ModuleName, + alliancemoduletypes.ModuleName, // this line is used by starport scaffolding # stargate/app/beginBlockers ) @@ -478,6 +483,7 @@ func NewComposableApp( stakingmiddlewaretypes.ModuleName, ibctransfermiddlewaretypes.ModuleName, wasm08types.ModuleName, + alliancemoduletypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -518,6 +524,7 @@ func NewComposableApp( stakingmiddlewaretypes.ModuleName, ibctransfermiddlewaretypes.ModuleName, wasm08types.ModuleName, + alliancemoduletypes.ModuleName, // this line is used by starport scaffolding # stargate/app/initGenesis ) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 3eebb16a1..35e2e9c69 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -2,6 +2,8 @@ package keepers import ( "fmt" + alliancemodulekeeper "github.com/terra-money/alliance/x/alliance/keeper" + alliancemoduletypes "github.com/terra-money/alliance/x/alliance/types" "math" "path/filepath" "strings" @@ -153,6 +155,7 @@ type AppKeepers struct { GroupKeeper groupkeeper.Keeper Wasm08Keeper wasm08Keeper.Keeper // TODO: use this name ? WasmKeeper wasmkeeper.Keeper + AllianceKeeper alliancemodulekeeper.Keeper IBCHooksKeeper *ibchookskeeper.Keeper Ics20WasmHooks *ibc_hooks.WasmHooks HooksICS4Wrapper ibc_hooks.ICS4Middleware @@ -201,7 +204,13 @@ func (appKeepers *AppKeepers) InitNormalKeepers( appKeepers.BankKeeper = custombankkeeper.NewBaseKeeper( logger, - appCodec, runtime.NewKVStoreService(appKeepers.keys[banktypes.StoreKey]), appKeepers.AccountKeeper, appKeepers.BlacklistedModuleAccountAddrs(maccPerms), &appKeepers.TransferMiddlewareKeeper, govModAddress) + appCodec, + runtime.NewKVStoreService(appKeepers.keys[banktypes.StoreKey]), + appKeepers.AccountKeeper, + appKeepers.BlacklistedModuleAccountAddrs(maccPerms), + &appKeepers.TransferMiddlewareKeeper, + govModAddress, + ) appKeepers.AuthzKeeper = authzkeeper.NewKeeper( runtime.NewKVStoreService(appKeepers.keys[authzkeeper.StoreKey]), @@ -272,11 +281,21 @@ func (appKeepers *AppKeepers) InitNormalKeepers( appKeepers.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, runtime.NewKVStoreService(appKeepers.keys[feegrant.StoreKey]), appKeepers.AccountKeeper) appKeepers.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, runtime.NewKVStoreService(appKeepers.keys[upgradetypes.StoreKey]), appCodec, homePath, bApp, govModAddress) - appKeepers.BankKeeper.RegisterKeepers(appKeepers.StakingKeeper) + appKeepers.AllianceKeeper = alliancemodulekeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(appKeepers.keys[alliancemoduletypes.StoreKey]), + appKeepers.AccountKeeper, + appKeepers.BankKeeper, + appKeepers.StakingKeeper, + appKeepers.DistrKeeper, + authtypes.FeeCollectorName, + govModAddress, + ) + appKeepers.BankKeeper.RegisterKeepers(appKeepers.AllianceKeeper, appKeepers.StakingKeeper) // register the staking hooks // NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks appKeepers.StakingKeeper.SetHooks( - stakingtypes.NewMultiStakingHooks(appKeepers.DistrKeeper.Hooks(), appKeepers.SlashingKeeper.Hooks()), + stakingtypes.NewMultiStakingHooks(appKeepers.DistrKeeper.Hooks(), appKeepers.SlashingKeeper.Hooks(), appKeepers.AllianceKeeper.StakingHooks()), ) // ... other modules keepers @@ -334,7 +353,7 @@ func (appKeepers *AppKeepers) InitNormalKeepers( appKeepers.PfmKeeper = pfmkeeper.NewKeeper( appCodec, appKeepers.keys[pfmtypes.StoreKey], - appKeepers.TransferKeeper.Keeper, + nil, appKeepers.IBCKeeper.ChannelKeeper, &appKeepers.DistrKeeper, appKeepers.BankKeeper, @@ -583,6 +602,7 @@ func (appKeepers *AppKeepers) initParamsKeeper(appCodec codec.BinaryCodec, legac paramsKeeper.Subspace(transfermiddlewaretypes.ModuleName).WithKeyTable(transfermiddlewaretypes.ParamKeyTable()) paramsKeeper.Subspace(stakingmiddlewaretypes.ModuleName) paramsKeeper.Subspace(ibctransfermiddlewaretypes.ModuleName) + paramsKeeper.Subspace(alliancemoduletypes.ModuleName).WithKeyTable(alliancemoduletypes.ParamKeyTable()) return paramsKeeper } diff --git a/app/keepers/keys.go b/app/keepers/keys.go index e185abde7..370a0530c 100644 --- a/app/keepers/keys.go +++ b/app/keepers/keys.go @@ -6,6 +6,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + alliancemoduletypes "github.com/terra-money/alliance/x/alliance/types" // bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" @@ -65,6 +66,7 @@ func (appKeepers *AppKeepers) GenerateKeys() { ibcexported.StoreKey, ibchookstypes.StoreKey, icahosttypes.StoreKey, ratelimitmoduletypes.StoreKey, txBoundaryTypes.StoreKey, + alliancemoduletypes.StoreKey, ) // Define transient store keys diff --git a/custom/bank/keeper/keeper.go b/custom/bank/keeper/keeper.go index 3ccfdd1e6..ace6a9320 100644 --- a/custom/bank/keeper/keeper.go +++ b/custom/bank/keeper/keeper.go @@ -2,28 +2,27 @@ package keeper import ( "context" - "cosmossdk.io/core/store" "cosmossdk.io/log" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + banktypes "github.com/notional-labs/composable/v6/custom/bank/types" + alliancekeeper "github.com/terra-money/alliance/x/alliance/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" "github.com/cosmos/cosmos-sdk/x/bank/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - banktypes "github.com/notional-labs/composable/v6/custom/bank/types" - transfermiddlewarekeeper "github.com/notional-labs/composable/v6/x/transfermiddleware/keeper" ) type Keeper struct { bankkeeper.BaseKeeper - tfmk banktypes.TransferMiddlewareKeeper sk banktypes.StakingKeeper - acck accountkeeper.AccountKeeper + ak alliancekeeper.Keeper } var _ bankkeeper.Keeper = Keeper{} @@ -40,12 +39,13 @@ func NewBaseKeeper( keeper := Keeper{ BaseKeeper: bankkeeper.NewBaseKeeper(cdc, storeService, ak, blockedAddrs, authority, logger), tfmk: tfmk, - acck: ak, + ak: alliancekeeper.Keeper{}, } return keeper } -func (k *Keeper) RegisterKeepers(sk banktypes.StakingKeeper) { +func (k *Keeper) RegisterKeepers(ak alliancekeeper.Keeper, sk banktypes.StakingKeeper) { + k.ak = ak k.sk = sk } diff --git a/custom/bank/keeper/msg_server.go b/custom/bank/keeper/msg_server.go new file mode 100644 index 000000000..49fdeccca --- /dev/null +++ b/custom/bank/keeper/msg_server.go @@ -0,0 +1,124 @@ +package keeper + +import ( + "context" + + "cosmossdk.io/core/address" + errorsmod "cosmossdk.io/errors" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/hashicorp/go-metrics" +) + +type msgServer struct { + types.MsgServer + + keeper bankkeeper.Keeper + addressCodec address.Codec +} + +var _ types.MsgServer = msgServer{} + +func NewMsgServerImpl(keeper Keeper, addressCodec address.Codec) types.MsgServer { + return &msgServer{ + MsgServer: bankkeeper.NewMsgServerImpl(keeper), + keeper: keeper, + addressCodec: addressCodec, + } +} + +func (k msgServer) Send(goCtx context.Context, msg *types.MsgSend) (*types.MsgSendResponse, error) { + from, err := k.addressCodec.StringToBytes(msg.FromAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid from address: %s", err) + } + to, err := k.addressCodec.StringToBytes(msg.ToAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %s", err) + } + + if !msg.Amount.IsValid() { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) + } + + if !msg.Amount.IsAllPositive() { + return nil, errorsmod.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := k.keeper.IsSendEnabledCoins(ctx, msg.Amount...); err != nil { + return nil, err + } + + if k.keeper.BlockedAddr(to) { + return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", msg.ToAddress) + } + + err = k.keeper.SendCoins(ctx, from, to, msg.Amount) + if err != nil { + return nil, err + } + + defer func() { + for _, a := range msg.Amount { + if a.Amount.IsInt64() { + telemetry.SetGaugeWithLabels( + []string{"tx", "msg", "send"}, + float32(a.Amount.Int64()), + []metrics.Label{telemetry.NewLabel("denom", a.Denom)}, + ) + } + } + }() + + return &types.MsgSendResponse{}, nil +} + +func (k msgServer) MultiSend(goCtx context.Context, msg *types.MsgMultiSend) (*types.MsgMultiSendResponse, error) { + if len(msg.Inputs) == 0 { + return nil, types.ErrNoInputs + } + + if len(msg.Inputs) != 1 { + return nil, types.ErrMultipleSenders + } + + if len(msg.Outputs) == 0 { + return nil, types.ErrNoOutputs + } + + if err := types.ValidateInputOutputs(msg.Inputs[0], msg.Outputs); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + // NOTE: totalIn == totalOut should already have been checked + for _, in := range msg.Inputs { + if err := k.keeper.IsSendEnabledCoins(ctx, in.Coins...); err != nil { + return nil, err + } + } + + for _, out := range msg.Outputs { + accAddr, err := k.addressCodec.StringToBytes(out.Address) + if err != nil { + return nil, err + } + + if k.keeper.BlockedAddr(accAddr) { + return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", out.Address) + } + } + + err := k.keeper.InputOutputCoins(ctx, msg.Inputs[0], msg.Outputs) + if err != nil { + return nil, err + } + + return &types.MsgMultiSendResponse{}, nil +} diff --git a/custom/bank/module.go b/custom/bank/module.go index 9b7879096..5a3b70164 100644 --- a/custom/bank/module.go +++ b/custom/bank/module.go @@ -1,6 +1,7 @@ package bank import ( + "cosmossdk.io/core/address" "fmt" "github.com/cosmos/cosmos-sdk/codec" @@ -15,17 +16,19 @@ import ( type AppModule struct { bankmodule.AppModule - keeper custombankkeeper.Keeper - subspace exported.Subspace + keeper custombankkeeper.Keeper + subspace exported.Subspace + addressCodec address.Codec } // NewAppModule creates a new AppModule object func NewAppModule(cdc codec.Codec, keeper custombankkeeper.Keeper, accountKeeper types.AccountKeeper, ss exported.Subspace) AppModule { bankModule := bankmodule.NewAppModule(cdc, keeper, accountKeeper, ss) return AppModule{ - AppModule: bankModule, - keeper: keeper, - subspace: ss, + AppModule: bankModule, + keeper: keeper, + subspace: ss, + addressCodec: accountKeeper.AddressCodec(), } } @@ -33,7 +36,7 @@ func NewAppModule(cdc codec.Codec, keeper custombankkeeper.Keeper, accountKeeper // NOTE: Overriding this method as not doing so will cause a panic // when trying to force this custom keeper into a bankkeeper.BaseKeeper func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), bankkeeper.NewMsgServerImpl(am.keeper)) + types.RegisterMsgServer(cfg.MsgServer(), custombankkeeper.NewMsgServerImpl(am.keeper, am.addressCodec)) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) m := bankkeeper.NewMigrator(am.keeper.BaseKeeper, am.subspace) diff --git a/go.mod b/go.mod index 7c049d859..6cff14654 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( google.golang.org/grpc v1.62.1 gotest.tools/v3 v3.5.1 mvdan.cc/gofumpt v0.4.0 + github.com/terra-money/alliance v0.4.3 ) require github.com/cometbft/cometbft-db v0.11.0 // indirect @@ -376,6 +377,5 @@ replace ( github.com/prometheus/common => github.com/prometheus/common v0.47.0 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 -// github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 => github.com/notional-labs/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.0-0.20240327105252-f31a09121d57 ) diff --git a/go.sum b/go.sum index d6e79579f..7c7717f92 100644 --- a/go.sum +++ b/go.sum @@ -1614,6 +1614,8 @@ github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/terra-money/alliance v0.4.3 h1:vlTsGkXOO78T8SJHjSQshbiTw7WSdieybWMOYsWyTmY= +github.com/terra-money/alliance v0.4.3/go.mod h1:ljXUIs49+2gHHbNljOoLrIaYV+1QHthS3vdtA7hODe0= github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= @@ -2551,4 +2553,4 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= \ No newline at end of file +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/scripts/relayer/chains/test-1.json b/scripts/relayer/chains/test-1.json index c733b0309..9ec7eeee0 100644 --- a/scripts/relayer/chains/test-1.json +++ b/scripts/relayer/chains/test-1.json @@ -5,11 +5,11 @@ "chain-id": "test-1", "rpc-addr": "http://localhost:16657", "grpc-addr": "", - "account-prefix": "centauri", + "account-prefix": "pica", "keyring-backend": "test", - "default-denom": "stake", + "default-denom": "ppica", "gas-adjustment": 1.5, - "gas-prices": "1stake", + "gas-prices": "100ppica", "coin-type": 118, "debug": true, "timeout": "10s", diff --git a/scripts/relayer/chains/test-2.json b/scripts/relayer/chains/test-2.json index f5d1c5d3e..dbea32fa3 100644 --- a/scripts/relayer/chains/test-2.json +++ b/scripts/relayer/chains/test-2.json @@ -5,11 +5,11 @@ "chain-id": "test-2", "rpc-addr": "http://localhost:26657", "grpc-addr": "", - "account-prefix": "centauri", + "account-prefix": "pica", "keyring-backend": "test", - "default-denom": "stake", + "default-denom": "ppica", "gas-adjustment": 1.5, - "gas-prices": "100stake", + "gas-prices": "100ppica", "coin-type": 118, "debug": true, "timeout": "10s", diff --git a/scripts/relayer/relayer-init.sh b/scripts/relayer/relayer-init.sh old mode 100644 new mode 100755 diff --git a/scripts/run-node.sh b/scripts/run-node.sh index c544a6398..227ca46cd 100755 --- a/scripts/run-node.sh +++ b/scripts/run-node.sh @@ -11,10 +11,10 @@ if [ "$CONTINUE" == "true" ]; then fi rm -rf mytestnet -pkill centaurid +pkill picad -# check DENOM is set. If not, set to upica -DENOM=${2:-upica} +# check DENOM is set. If not, set to ppica +DENOM=${2:-ppica} COMMISSION_RATE=0.01 COMMISSION_MAX_RATE=0.02 @@ -61,7 +61,7 @@ $BINARY add-genesis-account $KEY "1000000000000000000000${DENOM}" --keyring-back $BINARY add-genesis-account $KEY1 "1000000000000000000000${DENOM}" --keyring-backend $KEYRING --home $HOME_DIR $BINARY add-genesis-account $KEY2 "1000000000000000000000${DENOM}" --keyring-backend $KEYRING --home $HOME_DIR -update_test_genesis '.app_state["gov"]["params"]["voting_period"]="20s"' +# update_test_genesis '.app_state["gov"]["params"]["voting_period"]="20s"' update_test_genesis '.app_state["mint"]["params"]["mint_denom"]="'$DENOM'"' update_test_genesis '.app_state["gov"]["params"]["min_deposit"]=[{"denom":"'$DENOM'","amount": "1000000"}]' update_test_genesis '.app_state["crisis"]["constant_fee"]={"denom":"'$DENOM'","amount":"1000"}' @@ -71,11 +71,11 @@ update_test_genesis '.app_state["staking"]["params"]["bond_denom"]="'$DENOM'"' $SED_BINARY -i '0,/enable = false/s//enable = true/' $HOME_DIR/config/app.toml $SED_BINARY -i 's/swagger = false/swagger = true/' $HOME_DIR/config/app.toml $SED_BINARY -i -e 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' $HOME_DIR/config/app.toml -$SED_BINARY -i 's/minimum-gas-prices = "0.25upica"/minimum-gas-prices = "0.0upica"/' $HOME_DIR/config/app.toml +$SED_BINARY -i 's/minimum-gas-prices = "0.25upica"/minimum-gas-prices = "0.0ppica"/' $HOME_DIR/config/app.toml # Sign genesis transaction -$BINARY gentx $KEY "1000000000000000000000${DENOM}" --commission-rate=$COMMISSION_RATE --commission-max-rate=$COMMISSION_MAX_RATE --keyring-backend $KEYRING --chain-id $CHAIN_ID --home $HOME_DIR +$BINARY gentx $KEY "1000000000000000000${DENOM}" --commission-rate=$COMMISSION_RATE --commission-max-rate=$COMMISSION_MAX_RATE --keyring-backend $KEYRING --chain-id $CHAIN_ID --home $HOME_DIR # Collect genesis tx $BINARY collect-gentxs --home $HOME_DIR diff --git a/scripts/tests/ibc-hooks/counter/Cargo.toml b/scripts/tests/ibc-hooks/counter/Cargo.toml new file mode 100644 index 000000000..f164afc0e --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "counter" +description = "Cosmwasm counter dapp, with permissions for testing Osmosis wasmhooks" +version = "0.1.0" +authors = ["osmosis contributors"] +edition = "2021" + +exclude = [ + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# for more explicit tests, cargo test --features=backtraces +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[package.metadata.scripts] +optimize = """docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer:0.12.6 +""" + +[dependencies] +cosmwasm-schema = "1.1.3" +cosmwasm-std = "1.1.3" +cosmwasm-storage = "1.1.3" +cw-storage-plus = "0.16.0" +cw2 = "0.16.0" +schemars = "0.8.10" +serde = { version = "1.0.145", default-features = false, features = ["derive"] } +thiserror = { version = "1.0.31" } + +[dev-dependencies] +cw-multi-test = "0.16.0" diff --git a/scripts/tests/ibc-hooks/counter/README.md b/scripts/tests/ibc-hooks/counter/README.md new file mode 100644 index 000000000..f4394fe87 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/README.md @@ -0,0 +1,11 @@ +# Counter contract from [Osmosis Labs](https://github.com/osmosis-labs/osmosis/commit/64393a14e18b2562d72a3892eec716197a3716c7) + +This contract is a modification of the standard cosmwasm `counter` contract. +Namely, it tracks a counter, _by sender_. +This is a better way to test wasmhooks. + +This contract tracks any funds sent to it by adding it to the state under the `sender` key. + +This way we can verify that, independently of the sender, the funds will end up under the +`WasmHooksModuleAccount` address when the contract is executed via an IBC send that goes +through the wasmhooks module. diff --git a/scripts/tests/ibc-hooks/counter/artifacts/checksums.txt b/scripts/tests/ibc-hooks/counter/artifacts/checksums.txt new file mode 100644 index 000000000..1f542142d --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/artifacts/checksums.txt @@ -0,0 +1 @@ +c0e7a3b40d9710f6f72322293ba5cd871714008d9accd9a91c0fb08272609054 counter.wasm diff --git a/scripts/tests/ibc-hooks/counter/artifacts/checksums_intermediate.txt b/scripts/tests/ibc-hooks/counter/artifacts/checksums_intermediate.txt new file mode 100644 index 000000000..0394e5fc2 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/artifacts/checksums_intermediate.txt @@ -0,0 +1 @@ +bffb3256d4fd5668e497ae5671844ef3dcdf1a5f2594747b894dfc02e243ab0e ./target/wasm32-unknown-unknown/release/counter.wasm diff --git a/scripts/tests/ibc-hooks/counter/artifacts/counter.wasm b/scripts/tests/ibc-hooks/counter/artifacts/counter.wasm new file mode 100644 index 000000000..e3e5b53bd Binary files /dev/null and b/scripts/tests/ibc-hooks/counter/artifacts/counter.wasm differ diff --git a/scripts/tests/ibc-hooks/counter/src/contract.rs b/scripts/tests/ibc-hooks/counter/src/contract.rs new file mode 100644 index 000000000..259d36349 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/src/contract.rs @@ -0,0 +1,395 @@ +use std::collections::HashMap; + +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; +use cosmwasm_std::{ + to_binary, Binary, Coin, Deps, DepsMut, Env, MessageInfo, Response, StdResult, Uint128, +}; +use cw2::set_contract_version; + +use crate::error::ContractError; +use crate::msg::*; +use crate::state::{Counter, COUNTERS}; + +// version info for migration info +const CONTRACT_NAME: &str = "osmosis:permissioned_counter"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + let initial_counter = Counter { + count: msg.count, + total_funds: vec![], + owner: info.sender.clone(), + }; + COUNTERS.save(deps.storage, info.sender.clone(), &initial_counter)?; + + Ok(Response::new() + .add_attribute("method", "instantiate") + .add_attribute("owner", info.sender) + .add_attribute("count", msg.count.to_string())) +} + +pub mod utils { + use cosmwasm_std::Addr; + + use super::*; + + pub fn update_counter( + deps: DepsMut, + sender: Addr, + update_counter: &dyn Fn(&Option) -> i32, + update_funds: &dyn Fn(&Option) -> Vec, + ) -> Result { + COUNTERS + .update( + deps.storage, + sender.clone(), + |state| -> Result<_, ContractError> { + match state { + None => Ok(Counter { + count: update_counter(&None), + total_funds: update_funds(&None), + owner: sender, + }), + Some(counter) => Ok(Counter { + count: update_counter(&Some(counter.clone())), + total_funds: update_funds(&Some(counter)), + owner: sender, + }), + } + }, + ) + .map(|_r| true) + } +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::Increment {} => execute::increment(deps, info), + ExecuteMsg::Reset { count } => execute::reset(deps, info, count), + } +} + +pub mod execute { + use super::*; + + pub fn increment(deps: DepsMut, info: MessageInfo) -> Result { + utils::update_counter( + deps, + info.sender, + &|counter| match counter { + None => 0, + Some(counter) => counter.count + 1, + }, + &|counter| match counter { + None => info.funds.clone(), + Some(counter) => naive_add_coins(&info.funds, &counter.total_funds), + }, + )?; + Ok(Response::new().add_attribute("action", "increment")) + } + + pub fn reset(deps: DepsMut, info: MessageInfo, count: i32) -> Result { + utils::update_counter(deps, info.sender, &|_counter| count, &|_counter| vec![])?; + Ok(Response::new().add_attribute("action", "reset")) + } +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result { + match msg { + SudoMsg::IBCLifecycleComplete(IBCLifecycleComplete::IBCAck { + channel: _, + sequence: _, + ack: _, + success, + }) => sudo::receive_ack(deps, env.contract.address, success), + SudoMsg::IBCLifecycleComplete(IBCLifecycleComplete::IBCTimeout { + channel: _, + sequence: _, + }) => sudo::ibc_timeout(deps, env.contract.address), + } +} + +pub mod sudo { + use cosmwasm_std::Addr; + + use super::*; + + pub fn receive_ack( + deps: DepsMut, + contract: Addr, + _success: bool, + ) -> Result { + utils::update_counter( + deps, + contract, + &|counter| match counter { + None => 1, + Some(counter) => counter.count + 1, + }, + &|_counter| vec![], + )?; + Ok(Response::new().add_attribute("action", "ack")) + } + + pub(crate) fn ibc_timeout(deps: DepsMut, contract: Addr) -> Result { + utils::update_counter( + deps, + contract, + &|counter| match counter { + None => 10, + Some(counter) => counter.count + 10, + }, + &|_counter| vec![], + )?; + Ok(Response::new().add_attribute("action", "timeout")) + } +} + +pub fn naive_add_coins(lhs: &Vec, rhs: &Vec) -> Vec { + // This is a naive, inneficient implementation of Vec addition. + // This shouldn't be used in production but serves our purpose for this + // testing contract + let mut coins: HashMap = HashMap::new(); + for coin in lhs { + coins.insert(coin.denom.clone(), coin.amount); + } + + for coin in rhs { + coins + .entry(coin.denom.clone()) + .and_modify(|e| *e += coin.amount) + .or_insert(coin.amount); + } + coins.iter().map(|(d, &a)| Coin::new(a.into(), d)).collect() +} + +#[test] +fn coin_addition() { + let c1 = vec![Coin::new(1, "a"), Coin::new(2, "b")]; + let c2 = vec![Coin::new(7, "a"), Coin::new(2, "c")]; + + let mut sum = naive_add_coins(&c1, &c1); + sum.sort_by(|a, b| a.denom.cmp(&b.denom)); + assert_eq!(sum, vec![Coin::new(2, "a"), Coin::new(4, "b")]); + + let mut sum = naive_add_coins(&c1, &c2); + sum.sort_by(|a, b| a.denom.cmp(&b.denom)); + assert_eq!( + sum, + vec![Coin::new(8, "a"), Coin::new(2, "b"), Coin::new(2, "c"),] + ); + + let mut sum = naive_add_coins(&c2, &c2); + sum.sort_by(|a, b| a.denom.cmp(&b.denom)); + assert_eq!(sum, vec![Coin::new(14, "a"), Coin::new(4, "c"),]); + + let mut sum = naive_add_coins(&c2, &c1); + sum.sort_by(|a, b| a.denom.cmp(&b.denom)); + assert_eq!( + sum, + vec![Coin::new(8, "a"), Coin::new(2, "b"), Coin::new(2, "c"),] + ); + + let mut sum = naive_add_coins(&vec![], &c2); + sum.sort_by(|a, b| a.denom.cmp(&b.denom)); + assert_eq!(sum, c2); + + let mut sum = naive_add_coins(&c2, &vec![]); + sum.sort_by(|a, b| a.denom.cmp(&b.denom)); + assert_eq!(sum, c2); +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::GetCount { addr } => to_binary(&query::count(deps, addr)?), + QueryMsg::GetTotalFunds { addr } => to_binary(&query::total_funds(deps, addr)?), + } +} + +pub mod query { + use cosmwasm_std::Addr; + + use super::*; + + pub fn count(deps: Deps, addr: Addr) -> StdResult { + let state = COUNTERS.load(deps.storage, addr)?; + Ok(GetCountResponse { count: state.count }) + } + + pub fn total_funds(deps: Deps, addr: Addr) -> StdResult { + let state = COUNTERS.load(deps.storage, addr)?; + Ok(GetTotalFundsResponse { + total_funds: state.total_funds, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cosmwasm_std::Addr; + use cosmwasm_std::{coins, from_binary}; + + #[test] + fn proper_initialization() { + let mut deps = mock_dependencies(); + + let msg = InstantiateMsg { count: 17 }; + let info = mock_info("creator", &coins(1000, "earth")); + + // we can just call .unwrap() to assert this was a success + let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); + assert_eq!(0, res.messages.len()); + + // it worked, let's query the state + let res = query( + deps.as_ref(), + mock_env(), + QueryMsg::GetCount { + addr: Addr::unchecked("creator"), + }, + ) + .unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(17, value.count); + } + + #[test] + fn increment() { + let mut deps = mock_dependencies(); + + let msg = InstantiateMsg { count: 17 }; + let info = mock_info("creator", &coins(2, "token")); + let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); + + let msg = InstantiateMsg { count: 17 }; + let info = mock_info("someone-else", &coins(2, "token")); + let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); + + let info = mock_info("creator", &coins(2, "token")); + let msg = ExecuteMsg::Increment {}; + let _res = execute(deps.as_mut(), mock_env(), info, msg).unwrap(); + + // should increase counter by 1 + let res = query( + deps.as_ref(), + mock_env(), + QueryMsg::GetCount { + addr: Addr::unchecked("creator"), + }, + ) + .unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(18, value.count); + + // Counter for someone else is not incremented + let res = query( + deps.as_ref(), + mock_env(), + QueryMsg::GetCount { + addr: Addr::unchecked("someone-else"), + }, + ) + .unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(17, value.count); + } + + #[test] + fn reset() { + let mut deps = mock_dependencies(); + + let msg = InstantiateMsg { count: 17 }; + let info = mock_info("creator", &coins(2, "token")); + let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap(); + + // beneficiary can release it + let unauth_info = mock_info("anyone", &coins(2, "token")); + let msg = ExecuteMsg::Reset { count: 7 }; + let _res = execute(deps.as_mut(), mock_env(), unauth_info, msg); + + // should be 7 + let res = query( + deps.as_ref(), + mock_env(), + QueryMsg::GetCount { + addr: Addr::unchecked("anyone"), + }, + ) + .unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(7, value.count); + + // only the original creator can reset the counter + let auth_info = mock_info("creator", &coins(2, "token")); + let msg = ExecuteMsg::Reset { count: 5 }; + let _res = execute(deps.as_mut(), mock_env(), auth_info, msg).unwrap(); + + // should now be 5 + let res = query( + deps.as_ref(), + mock_env(), + QueryMsg::GetCount { + addr: Addr::unchecked("creator"), + }, + ) + .unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(5, value.count); + } + + #[test] + fn acks() { + let mut deps = mock_dependencies(); + let env = mock_env(); + let get_msg = QueryMsg::GetCount { + addr: Addr::unchecked(env.clone().contract.address), + }; + + // No acks + query(deps.as_ref(), env.clone(), get_msg.clone()).unwrap_err(); + + let msg = SudoMsg::ReceiveAck { + channel: format!("channel-0"), + sequence: 1, + ack: String::new(), + success: true, + }; + let _res = sudo(deps.as_mut(), env.clone(), msg).unwrap(); + + // should increase counter by 1 + let res = query(deps.as_ref(), env.clone(), get_msg.clone()).unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(1, value.count); + + let msg = SudoMsg::ReceiveAck { + channel: format!("channel-0"), + sequence: 1, + ack: String::new(), + success: true, + }; + let _res = sudo(deps.as_mut(), env.clone(), msg).unwrap(); + + // should increase counter by 1 + let res = query(deps.as_ref(), env, get_msg).unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(2, value.count); + } +} diff --git a/scripts/tests/ibc-hooks/counter/src/error.rs b/scripts/tests/ibc-hooks/counter/src/error.rs new file mode 100644 index 000000000..3caf0c5c5 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/src/error.rs @@ -0,0 +1,16 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("Unauthorized")] + Unauthorized {}, + + #[error("Custom Error val: {val:?}")] + CustomError { val: String }, + // Add any other custom errors you like here. + // Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details. +} diff --git a/scripts/tests/ibc-hooks/counter/src/helpers.rs b/scripts/tests/ibc-hooks/counter/src/helpers.rs new file mode 100644 index 000000000..c943c1365 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/src/helpers.rs @@ -0,0 +1,48 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::{ + to_binary, Addr, Coin, CosmosMsg, CustomQuery, Querier, QuerierWrapper, StdResult, WasmMsg, + WasmQuery, +}; + +use crate::msg::{ExecuteMsg, GetCountResponse, QueryMsg}; + +/// CwTemplateContract is a wrapper around Addr that provides a lot of helpers +/// for working with this. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct CwTemplateContract(pub Addr); + +impl CwTemplateContract { + pub fn addr(&self) -> Addr { + self.0.clone() + } + + pub fn call>(&self, msg: T) -> StdResult { + let msg = to_binary(&msg.into())?; + Ok(WasmMsg::Execute { + contract_addr: self.addr().into(), + msg, + funds: vec![], + } + .into()) + } + + /// Get Count + pub fn count(&self, querier: &Q, addr: Addr) -> StdResult + where + Q: Querier, + T: Into, + CQ: CustomQuery, + { + let msg = QueryMsg::GetCount { addr }; + let query = WasmQuery::Smart { + contract_addr: self.addr().into(), + msg: to_binary(&msg)?, + } + .into(); + let res: GetCountResponse = QuerierWrapper::::new(querier).query(&query)?; + Ok(res) + } +} + diff --git a/scripts/tests/ibc-hooks/counter/src/integration_tests.rs b/scripts/tests/ibc-hooks/counter/src/integration_tests.rs new file mode 100644 index 000000000..4c5078465 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/src/integration_tests.rs @@ -0,0 +1,71 @@ +#[cfg(test)] +mod tests { + use crate::helpers::CwTemplateContract; + use crate::msg::InstantiateMsg; + use cosmwasm_std::{Addr, Coin, Empty, Uint128}; + use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper, Executor}; + + pub fn contract_template() -> Box> { + let contract = ContractWrapper::new( + crate::contract::execute, + crate::contract::instantiate, + crate::contract::query, + ); + Box::new(contract) + } + + const USER: &str = "USER"; + const ADMIN: &str = "ADMIN"; + const NATIVE_DENOM: &str = "denom"; + + fn mock_app() -> App { + AppBuilder::new().build(|router, _, storage| { + router + .bank + .init_balance( + storage, + &Addr::unchecked(USER), + vec![Coin { + denom: NATIVE_DENOM.to_string(), + amount: Uint128::new(1), + }], + ) + .unwrap(); + }) + } + + fn proper_instantiate() -> (App, CwTemplateContract) { + let mut app = mock_app(); + let cw_template_id = app.store_code(contract_template()); + + let msg = InstantiateMsg { count: 1i32 }; + let cw_template_contract_addr = app + .instantiate_contract( + cw_template_id, + Addr::unchecked(ADMIN), + &msg, + &[], + "test", + None, + ) + .unwrap(); + + let cw_template_contract = CwTemplateContract(cw_template_contract_addr); + + (app, cw_template_contract) + } + + mod count { + use super::*; + use crate::msg::ExecuteMsg; + + #[test] + fn count() { + let (mut app, cw_template_contract) = proper_instantiate(); + + let msg = ExecuteMsg::Increment {}; + let cosmos_msg = cw_template_contract.call(msg).unwrap(); + app.execute(Addr::unchecked(USER), cosmos_msg).unwrap(); + } + } +} diff --git a/scripts/tests/ibc-hooks/counter/src/lib.rs b/scripts/tests/ibc-hooks/counter/src/lib.rs new file mode 100644 index 000000000..ffd1f6ac4 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/src/lib.rs @@ -0,0 +1,9 @@ +#![allow(unused_imports)] +pub mod contract; +mod error; +pub mod helpers; +pub mod integration_tests; +pub mod msg; +pub mod state; + +pub use crate::error::ContractError; diff --git a/scripts/tests/ibc-hooks/counter/src/msg.rs b/scripts/tests/ibc-hooks/counter/src/msg.rs new file mode 100644 index 000000000..037d8c577 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/src/msg.rs @@ -0,0 +1,63 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::{Addr, Coin}; + +#[cw_serde] +pub struct InstantiateMsg { + pub count: i32, +} + +#[cw_serde] +pub enum ExecuteMsg { + Increment {}, + Reset { count: i32 }, +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + // GetCount returns the current count as a json-encoded number + #[returns(GetCountResponse)] + GetCount { addr: Addr }, + #[returns(GetTotalFundsResponse)] + GetTotalFunds { addr: Addr }, +} + +// We define a custom struct for each query response +#[cw_serde] +pub struct GetCountResponse { + pub count: i32, +} + +#[cw_serde] +pub struct GetTotalFundsResponse { + pub total_funds: Vec, +} + +#[cw_serde] +#[serde(rename = "ibc_lifecycle_complete")] +pub enum IBCLifecycleComplete { + #[serde(rename = "ibc_ack")] + IBCAck { + /// The source channel (terra side) of the IBC packet + channel: String, + /// The sequence number that the packet was sent with + sequence: u64, + /// String encoded version of the ack as seen by OnAcknowledgementPacket(..) + ack: String, + /// Weather an ack is a success of failure according to the transfer spec + success: bool, + }, + #[serde(rename = "ibc_timeout")] + IBCTimeout { + /// The source channel (terra side) of the IBC packet + channel: String, + /// The sequence number that the packet was sent with + sequence: u64, + }, +} + +#[cw_serde] +pub enum SudoMsg { + #[serde(rename = "ibc_lifecycle_complete")] + IBCLifecycleComplete(IBCLifecycleComplete), +} diff --git a/scripts/tests/ibc-hooks/counter/src/state.rs b/scripts/tests/ibc-hooks/counter/src/state.rs new file mode 100644 index 000000000..4b8002fc4 --- /dev/null +++ b/scripts/tests/ibc-hooks/counter/src/state.rs @@ -0,0 +1,14 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::{Addr, Coin}; +use cw_storage_plus::{Item, Map}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +pub struct Counter { + pub count: i32, + pub total_funds: Vec, + pub owner: Addr, +} + +pub const COUNTERS: Map = Map::new("state"); diff --git a/scripts/tests/ibc-hooks/increment.sh b/scripts/tests/ibc-hooks/increment.sh new file mode 100755 index 000000000..0c243a688 --- /dev/null +++ b/scripts/tests/ibc-hooks/increment.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +echo "" +echo "#################" +echo "# IBC Hook call #" +echo "#################" +echo "" + +BINARY=picad +CHAIN_DIR=$(pwd)/data +WALLET_1=$($BINARY keys show wallet1 -a --keyring-backend test --home $CHAIN_DIR/test-1) +WALLET_2=$($BINARY keys show wallet2 -a --keyring-backend test --home $CHAIN_DIR/test-2) +DENOM=ppica + +# Deploy the smart contract on chain to test the callbacks. (find the source code under the following url: `~/scripts/tests/ibc-hooks/counter/src/contract.rs`) +echo "Deploying counter contract" + +TX_HASH=$($BINARY tx wasm store $(pwd)/scripts/tests/ibc-hooks/counter/artifacts/counter.wasm --from $WALLET_2 --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 --keyring-backend test -y --gas 10000000 --fees 6000000$DENOM -o json | jq -r '.txhash') +sleep 3 +CODE_ID=$($BINARY query tx $TX_HASH -o josn --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 | jq -r '.logs[0].events[1].attributes[1].value') + + +# Use Instantiate2 to instantiate the previous smart contract with a random hash to enable multiple instances of the same contract (when needed). +echo "Instantiating counter contract" +RANDOM_HASH=$(hexdump -vn16 -e'4/4 "%08X" 1 "\n"' /dev/urandom) +TX_HASH=$($BINARY tx wasm instantiate2 $CODE_ID '{"count": 0}' $RANDOM_HASH --no-admin --label="Label with $RANDOM_HASH" --from $WALLET_2 --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 --keyring-backend test -y --gas 10000000 --fees 6000000$DENOM -o json | jq -r '.txhash') + +echo "TX hash: $TX_HASH" +sleep 3 +CONTRACT_ADDRESS=$($BINARY query tx $TX_HASH -o josn --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 | jq -r '.logs[0].events[1].attributes[0].value') +echo "Contract address: $CONTRACT_ADDRESS" + +echo "Executing the IBC Hook to increment the counter" +# First execute an IBC transfer to create the entry in the smart contract with the sender address ... +IBC_HOOK_RES=$($BINARY tx ibc-transfer transfer transfer channel-0 $CONTRACT_ADDRESS 1$DENOM --memo='{"wasm":{"contract": "'"$CONTRACT_ADDRESS"'" ,"msg": {"increment": {}}}}' --chain-id test-1 --home $CHAIN_DIR/test-1 --node tcp://localhost:16657 --keyring-backend test --from $WALLET_1 --fees 6000000$DENOM -y -o json) +echo "IBC Hook response: $IBC_HOOK_RES" +sleep 3 +# ... then send another transfer to increments the count value from 0 to 1, send 1 more to the contract address to validate that it increased the value correctly. +IBC_HOOK_RES=$($BINARY tx ibc-transfer transfer transfer channel-0 $CONTRACT_ADDRESS 1$DENOM --memo='{"wasm":{"contract": "'"$CONTRACT_ADDRESS"'" ,"msg": {"increment": {}}}}' --chain-id test-1 --home $CHAIN_DIR/test-1 --fees 6000000$DENOM --node tcp://localhost:16657 --keyring-backend test --from $WALLET_1 -y -o json) +export WALLET_1_WASM_SENDER=$($BINARY q ibchooks wasm-sender channel-0 "$WALLET_1" --chain-id test-1 --home $CHAIN_DIR/test-1 --node tcp://localhost:16657) + +IBC_RECEIVER_BALANCE=$($BINARY query bank balances $WALLET_1 --chain-id test-1 --home $CHAIN_DIR/test-1 --node tcp://localhost:16657 -o json) +echo "IBC Receiver balance: $IBC_RECEIVER_BALANCE" + +echo "wallet 1 wasm sender: $WALLET_1_WASM_SENDER" + +COUNT_RES="" +COUNT_FUNDS_RES="" +while [ "$COUNT_RES" != "1" ] || [ "$COUNT_FUNDS_RES" != "2" ]; do + sleep 3 + # Get count res + RES=$($BINARY query wasm contract-state smart "$CONTRACT_ADDRESS" '{"get_count": {"addr": "'"$WALLET_1_WASM_SENDER"'"}}' --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 -o json) + echo "Query response: $RES" + + # Query to assert that the counter value is 1 and the fund send are (remeber that the first time fund are send to the contract the counter is set to 0 instead of 1) + COUNT_RES=$($BINARY query wasm contract-state smart "$CONTRACT_ADDRESS" '{"get_count": {"addr": "'"$WALLET_1_WASM_SENDER"'"}}' --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 -o json | jq -r '.data.count') + COUNT_FUNDS_RES=$($BINARY query wasm contract-state smart "$CONTRACT_ADDRESS" '{"get_total_funds": {"addr": "'"$WALLET_1_WASM_SENDER"'"}}' --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 -o json | jq -r '.data.total_funds[0].amount') + echo "transaction relayed count: $COUNT_RES and relayed funds: $COUNT_FUNDS_RES" +done + +echo "Executing the IBC Hook to increment the counter on callback" +# Execute an IBC transfer with ibc_callback to test the callback acknowledgement twice. +IBC_HOOK_RES=$($BINARY tx ibc-transfer transfer transfer channel-0 $WALLET_1_WASM_SENDER 1$DENOM --memo='{"ibc_callback":"'"$CONTRACT_ADDRESS"'"}' --chain-id test-2 --home $CHAIN_DIR/test-2 --fees 6000000$DENOM --node tcp://localhost:26657 --keyring-backend test --from $WALLET_2 -y -o json) + + +sleep 3 +IBC_HOOK_RES=$($BINARY tx ibc-transfer transfer transfer channel-0 $WALLET_1_WASM_SENDER 1$DENOM --memo='{"ibc_callback":"'"$CONTRACT_ADDRESS"'"}' --chain-id test-2 --home $CHAIN_DIR/test-2 --fees 6000000$DENOM --node tcp://localhost:26657 --keyring-backend test --from $WALLET_2 -y -o json) +export WALLET_2_WASM_SENDER=$($BINARY q ibchooks wasm-sender channel-0 "$WALLET_2" --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657) + +COUNT_RES="" +while [ "$COUNT_RES" != "2" ]; do + sleep 3 + # Query the smart contract to validate that it received the callback twice (notice that the queried addess is the contract address itself). + COUNT_RES=$($BINARY query wasm contract-state smart "$CONTRACT_ADDRESS" '{"get_count": {"addr": "'"$CONTRACT_ADDRESS"'"}}' --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 -o json | jq -r '.data.count') + echo "relayed callback transaction count: $COUNT_RES" +done + +echo "Executing the IBC Hook to increment the counter on callback with timeout" +# Prepare two callback queries but this time with a timeout height that is unreachable (0-1) to test the timeout callback. +IBC_HOOK_RES=$($BINARY tx ibc-transfer transfer transfer channel-0 $WALLET_1_WASM_SENDER 1$DENOM --packet-timeout-height="0-1" --memo='{"ibc_callback":"'"$CONTRACT_ADDRESS"'"}' --chain-id test-2 --home $CHAIN_DIR/test-2 --fees 6000000$DENOM --node tcp://localhost:26657 --keyring-backend test --from $WALLET_2 -y -o json) +sleep 3 +IBC_HOOK_RES=$($BINARY tx ibc-transfer transfer transfer channel-0 $WALLET_1_WASM_SENDER 1$DENOM --packet-timeout-height="0-1" --memo='{"ibc_callback":"'"$CONTRACT_ADDRESS"'"}' --chain-id test-2 --home $CHAIN_DIR/test-2 --fees 6000000$DENOM --node tcp://localhost:26657 --keyring-backend test --from $WALLET_2 -y -o json) +export WALLET_2_WASM_SENDER=$($BINARY q ibchooks wasm-sender channel-0 "$WALLET_2" --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657) + +COUNT_RES="" +while [ "$COUNT_RES" != "22" ]; do + sleep 3 + # Query the smart contract to validate that it received the timeout callback twice and keep in mind that per each timeout the contract increases 10 counts (notice that the queried addess is the contract address itself). + COUNT_RES=$($BINARY query wasm contract-state smart "$CONTRACT_ADDRESS" '{"get_count": {"addr": "'"$CONTRACT_ADDRESS"'"}}' --chain-id test-2 --home $CHAIN_DIR/test-2 --node tcp://localhost:26657 -o json | jq -r '.data.count') + echo "relayed timeout callback transaction count: $COUNT_RES" +done + +echo "" +echo "##########################" +echo "# SUCCESS: IBC Hook call #" +echo "##########################" +echo "" diff --git a/scripts/tests/init-test-framework.sh b/scripts/tests/init-test-framework.sh new file mode 100755 index 000000000..b9e736b58 --- /dev/null +++ b/scripts/tests/init-test-framework.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +BINARY=picad +CHAIN_DIR=$(pwd)/data +CHAINID_1=test-1 +CHAINID_2=test-2 + +### Custom genesis files +DENOM=ppica +GENESIS_1=$CHAIN_DIR/$CHAINID_1/config/genesis.json +TMP_GENESIS_1=$CHAIN_DIR/$CHAINID_1/config/genesis.json.tmp + +GENESIS_2=$CHAIN_DIR/$CHAINID_2/config/genesis.json +TMP_GENESIS_2=$CHAIN_DIR/$CHAINID_2/config/genesis.json.tmp + +VAL_MNEMONIC_1="clock post desk civil pottery foster expand merit dash seminar song memory figure uniform spice circle try happy obvious trash crime hybrid hood cushion" +VAL_MNEMONIC_2="angry twist harsh drastic left brass behave host shove marriage fall update business leg direct reward object ugly security warm tuna model broccoli choice" +WALLET_MNEMONIC_1="banner spread envelope side kite person disagree path silver will brother under couch edit food venture squirrel civil budget number acquire point work mass" +WALLET_MNEMONIC_2="veteran try aware erosion drink dance decade comic dawn museum release episode original list ability owner size tuition surface ceiling depth seminar capable only" +WALLET_MNEMONIC_3="vacuum burst ordinary enact leaf rabbit gather lend left chase park action dish danger green jeans lucky dish mesh language collect acquire waste load" +WALLET_MNEMONIC_4="open attitude harsh casino rent attitude midnight debris describe spare cancel crisp olive ride elite gallery leaf buffalo sheriff filter rotate path begin soldier" +RLY_MNEMONIC_1="alley afraid soup fall idea toss can goose become valve initial strong forward bright dish figure check leopard decide warfare hub unusual join cart" +RLY_MNEMONIC_2="record gift you once hip style during joke field prize dust unique length more pencil transfer quit train device arrive energy sort steak upset" + +P2PPORT_1=16656 +P2PPORT_2=26656 +RPCPORT_1=16657 +RPCPORT_2=26657 +RESTPORT_1=1316 +RESTPORT_2=1317 +ROSETTA_1=8080 +ROSETTA_2=8081 +GRPCPORT_1=8090 +GRPCPORT_2=9090 +GRPCWEB_1=8091 +GRPCWEB_2=9091 + +# Stop if it is already running +if pgrep -x "$BINARY" >/dev/null; then + echo "Terminating $BINARY..." + killall $BINARY +fi + +echo "Removing previous data..." +rm -rf $CHAIN_DIR/$CHAINID_1 &> /dev/null +rm -rf $CHAIN_DIR/$CHAINID_2 &> /dev/null + +# Add directories for both chains, exit if an error occurs +if ! mkdir -p $CHAIN_DIR/$CHAINID_1 2>/dev/null; then + echo "Failed to create chain folder. Aborting..." + exit 1 +fi + +if ! mkdir -p $CHAIN_DIR/$CHAINID_2 2>/dev/null; then + echo "Failed to create chain folder. Aborting..." + exit 1 +fi + +echo "Initializing $CHAINID_1 & $CHAINID_2..." +$BINARY init test --home $CHAIN_DIR/$CHAINID_1 --chain-id=$CHAINID_1 &> /dev/null +$BINARY init test --home $CHAIN_DIR/$CHAINID_2 --chain-id=$CHAINID_2 &> /dev/null + +echo "Adding genesis accounts..." +echo $VAL_MNEMONIC_1 | $BINARY keys add val1 --home $CHAIN_DIR/$CHAINID_1 --recover --keyring-backend=test +echo $VAL_MNEMONIC_2 | $BINARY keys add val2 --home $CHAIN_DIR/$CHAINID_2 --recover --keyring-backend=test +echo $WALLET_MNEMONIC_1 | $BINARY keys add wallet1 --home $CHAIN_DIR/$CHAINID_1 --recover --keyring-backend=test +echo $WALLET_MNEMONIC_2 | $BINARY keys add wallet2 --home $CHAIN_DIR/$CHAINID_2 --recover --keyring-backend=test +echo $WALLET_MNEMONIC_3 | $BINARY keys add wallet3 --home $CHAIN_DIR/$CHAINID_1 --recover --keyring-backend=test +echo $WALLET_MNEMONIC_4 | $BINARY keys add wallet4 --home $CHAIN_DIR/$CHAINID_2 --recover --keyring-backend=test +echo $RLY_MNEMONIC_1 | $BINARY keys add rly1 --home $CHAIN_DIR/$CHAINID_1 --recover --keyring-backend=test +echo $RLY_MNEMONIC_2 | $BINARY keys add rly2 --home $CHAIN_DIR/$CHAINID_2 --recover --keyring-backend=test + +VAL1_ADDR=$($BINARY keys show val1 --home $CHAIN_DIR/$CHAINID_1 --keyring-backend test -a) +VAL2_ADDR=$($BINARY keys show val2 --home $CHAIN_DIR/$CHAINID_2 --keyring-backend test -a) +WALLET1_ADDR=$($BINARY keys show wallet1 --home $CHAIN_DIR/$CHAINID_1 --keyring-backend test -a) +WALLET2_ADDR=$($BINARY keys show wallet2 --home $CHAIN_DIR/$CHAINID_2 --keyring-backend test -a) +WALLET3_ADDR=$($BINARY keys show wallet3 --home $CHAIN_DIR/$CHAINID_1 --keyring-backend test -a) +WALLET4_ADDR=$($BINARY keys show wallet4 --home $CHAIN_DIR/$CHAINID_2 --keyring-backend test -a) +RLY1_ADDR=$($BINARY keys show rly1 --home $CHAIN_DIR/$CHAINID_1 --keyring-backend test -a) +RLY2_ADDR=$($BINARY keys show rly2 --home $CHAIN_DIR/$CHAINID_2 --keyring-backend test -a) + +$BINARY add-genesis-account $VAL1_ADDR "1000000000000000000000${DENOM}" --home $CHAIN_DIR/$CHAINID_1 +$BINARY add-genesis-account $VAL2_ADDR "1000000000000000000000${DENOM}" --home $CHAIN_DIR/$CHAINID_2 +$BINARY add-genesis-account $WALLET1_ADDR "1000000000000000000000${DENOM}" --home $CHAIN_DIR/$CHAINID_1 +$BINARY add-genesis-account $WALLET2_ADDR "1000000000000000000000${DENOM}" --home $CHAIN_DIR/$CHAINID_2 +$BINARY add-genesis-account $WALLET3_ADDR "1000000000000000000000${DENOM}" --vesting-amount "10000000000${DENOM}" --vesting-start-time $(date +%s) --vesting-end-time $(($(date '+%s') + 100000023)) --home $CHAIN_DIR/$CHAINID_1 +$BINARY add-genesis-account $WALLET4_ADDR "1000000000000000000000${DENOM}" --vesting-amount "10000000000${DENOM}" --vesting-start-time $(date +%s) --vesting-end-time $(($(date '+%s') + 100000023)) --home $CHAIN_DIR/$CHAINID_2 +$BINARY add-genesis-account $RLY1_ADDR "1000000000000000000000${DENOM}" --home $CHAIN_DIR/$CHAINID_1 +$BINARY add-genesis-account $RLY2_ADDR "1000000000000000000000${DENOM}" --home $CHAIN_DIR/$CHAINID_2 + +echo "Creating and collecting gentx..." +$BINARY gentx val1 1000000000000000000000${DENOM} --home $CHAIN_DIR/$CHAINID_1 --chain-id $CHAINID_1 --keyring-backend test +$BINARY gentx val2 1000000000000000000000${DENOM} --home $CHAIN_DIR/$CHAINID_2 --chain-id $CHAINID_2 --keyring-backend test +$BINARY collect-gentxs --home $CHAIN_DIR/$CHAINID_1 &> /dev/null +$BINARY collect-gentxs --home $CHAIN_DIR/$CHAINID_2 &> /dev/null + +echo "Changing defaults and ports in app.toml and config.toml files..." +sed -i -e 's#"tcp://0.0.0.0:26656"#"tcp://localhost:'"$P2PPORT_1"'"#g' $CHAIN_DIR/$CHAINID_1/config/config.toml +sed -i -e 's#"tcp://127.0.0.1:26657"#"tcp://localhost:'"$RPCPORT_1"'"#g' $CHAIN_DIR/$CHAINID_1/config/config.toml +sed -i -e 's#"tcp://localhost:26657"#"tcp://localhost:'"$RPCPORT_1"'"#g' $CHAIN_DIR/$CHAINID_1/config/client.toml +sed -i -e 's/timeout_commit = "5s"/timeout_commit = "1s"/g' $CHAIN_DIR/$CHAINID_1/config/config.toml +sed -i -e 's/timeout_propose = "3s"/timeout_propose = "1s"/g' $CHAIN_DIR/$CHAINID_1/config/config.toml +sed -i -e 's/index_all_keys = false/index_all_keys = true/g' $CHAIN_DIR/$CHAINID_1/config/config.toml +sed -i -e 's/enable = false/enable = true/g' $CHAIN_DIR/$CHAINID_1/config/app.toml +sed -i -e 's/swagger = false/swagger = true/g' $CHAIN_DIR/$CHAINID_1/config/app.toml +sed -i -e 's#"tcp://localhost:1317"#"tcp://localhost:'"$RESTPORT_1"'"#g' $CHAIN_DIR/$CHAINID_1/config/app.toml +sed -i -e 's#":8080"#":'"$ROSETTA_1"'"#g' $CHAIN_DIR/$CHAINID_1/config/app.toml +sed -i -e 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' $CHAIN_DIR/$CHAINID_1/config/app.toml + + +sed -i -e 's#"tcp://0.0.0.0:26656"#"tcp://localhost:'"$P2PPORT_2"'"#g' $CHAIN_DIR/$CHAINID_2/config/config.toml +sed -i -e 's#"tcp://127.0.0.1:26657"#"tcp://localhost:'"$RPCPORT_2"'"#g' $CHAIN_DIR/$CHAINID_2/config/config.toml +sed -i -e 's#"tcp://localhost:26657"#"tcp://localhost:'"$RPCPORT_2"'"#g' $CHAIN_DIR/$CHAINID_2/config/client.toml +sed -i -e 's/timeout_commit = "5s"/timeout_commit = "1s"/g' $CHAIN_DIR/$CHAINID_2/config/config.toml +sed -i -e 's/timeout_propose = "3s"/timeout_propose = "1s"/g' $CHAIN_DIR/$CHAINID_2/config/config.toml +sed -i -e 's/index_all_keys = false/index_all_keys = true/g' $CHAIN_DIR/$CHAINID_2/config/config.toml +sed -i -e 's/enable = false/enable = true/g' $CHAIN_DIR/$CHAINID_2/config/app.toml +sed -i -e 's/swagger = false/swagger = true/g' $CHAIN_DIR/$CHAINID_2/config/app.toml +sed -i -e 's#"tcp://localhost:1317"#"tcp://localhost:'"$RESTPORT_2"'"#g' $CHAIN_DIR/$CHAINID_2/config/app.toml +sed -i -e 's#":8080"#":'"$ROSETTA_2"'"#g' $CHAIN_DIR/$CHAINID_2/config/app.toml +sed -i -e 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' $CHAIN_DIR/$CHAINID_2/config/app.toml + + +echo "Changing genesis.json..." +sed -i -e 's/"voting_period": "172800s"/"voting_period": "10s"/g' $CHAIN_DIR/$CHAINID_1/config/genesis.json +sed -i -e 's/"voting_period": "172800s"/"voting_period": "10s"/g' $CHAIN_DIR/$CHAINID_2/config/genesis.json +sed -i -e 's/"reward_delay_time": "604800s"/"reward_delay_time": "0s"/g' $CHAIN_DIR/$CHAINID_1/config/genesis.json +sed -i -e 's/"reward_delay_time": "604800s"/"reward_delay_time": "0s"/g' $CHAIN_DIR/$CHAINID_2/config/genesis.json + + +# Update the genesis file +update_test_genesis () { + jq "$1" $GENESIS_1 > $TMP_GENESIS_1 && mv $TMP_GENESIS_1 $GENESIS_1 + jq "$1" $GENESIS_2 > $TMP_GENESIS_2 && mv $TMP_GENESIS_2 $GENESIS_2 +} + +echo "update test genesis" +update_test_genesis ".app_state[\"staking\"][\"params\"][\"bond_denom\"]=\"$DENOM\"" +update_test_genesis ".app_state[\"mint\"][\"params\"][\"mint_denom\"]=\"$DENOM\"" +update_test_genesis ".app_state[\"crisis\"][\"constant_fee\"][\"denom\"]=\"$DENOM\"" +update_test_genesis ".app_state[\"gov\"][\"params\"][\"min_deposit\"][0][\"denom\"]=\"$DENOM\"" + + +# Starting the chain +echo "Starting $CHAINID_1 in $CHAIN_DIR..." +echo "Creating log file at $CHAIN_DIR/$CHAINID_1.log" +$BINARY start --log_level info --log_format json --p2p.pex=false --home $CHAIN_DIR/$CHAINID_1 --pruning=nothing --grpc.address="0.0.0.0:$GRPCPORT_1" > $CHAIN_DIR/$CHAINID_1.log 2>&1 & + +echo "Starting $CHAINID_2 in $CHAIN_DIR..." +echo "Creating log file at $CHAIN_DIR/$CHAINID_2.log" +$BINARY start --log_level info --log_format json --p2p.pex=false --home $CHAIN_DIR/$CHAINID_2 --pruning=nothing --grpc.address="0.0.0.0:$GRPCPORT_2" > $CHAIN_DIR/$CHAINID_2.log 2>&1 & diff --git a/x/ibc-hooks/relay_test.go b/x/ibc-hooks/relay_test.go index 1a38d98f5..1aef17d30 100644 --- a/x/ibc-hooks/relay_test.go +++ b/x/ibc-hooks/relay_test.go @@ -2,6 +2,7 @@ package ibchooks_test import ( "fmt" + customibctesting "github.com/cosmos/ibc-go/v8/testing" "testing" "time" @@ -11,7 +12,6 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/stretchr/testify/suite" - customibctesting "github.com/notional-labs/composable/v6/app/ibctesting" ibchookskeeper "github.com/notional-labs/composable/v6/x/ibc-hooks/keeper" ) @@ -52,8 +52,8 @@ func (suite *IBCHooksTestSuite) TestRecvHooks() { var ( transferAmount = sdkmath.NewInt(1000000000) timeoutHeight = clienttypes.NewHeight(1, 110) - // when transfer via sdk transfer from A (module) -> B (contract) - // nativeTokenSendOnChainA = sdk.NewCoin(sdk.DefaultBondDenom, transferAmount) + // when transfer via sdk transfer from A (module) -> B (contract) + // nativeTokenSendOnChainA = sdk.NewCoin(sdk.DefaultBondDenom, transferAmount) ) suite.SetupTest() // reset @@ -109,8 +109,8 @@ func (suite *IBCHooksTestSuite) TestAckHooks() { var ( transferAmount = sdkmath.NewInt(1000000000) timeoutHeight = clienttypes.NewHeight(0, 110) - // when transfer via sdk transfer from A (module) -> B (contract) - // nativeTokenSendOnChainA = sdk.NewCoin(sdk.DefaultBondDenom, transferAmount) + // when transfer via sdk transfer from A (module) -> B (contract) + // nativeTokenSendOnChainA = sdk.NewCoin(sdk.DefaultBondDenom, transferAmount) ) suite.SetupTest() // reset @@ -186,8 +186,8 @@ func (suite *IBCHooksTestSuite) TestTimeoutHooks() { var ( transferAmount = sdkmath.NewInt(1000000000) timeoutHeight = clienttypes.NewHeight(0, 500) - // when transfer via sdk transfer from A (module) -> B (contract) - // nativeTokenSendOnChainA = sdk.NewCoin(sdk.DefaultBondDenom, transferAmount) + // when transfer via sdk transfer from A (module) -> B (contract) + // nativeTokenSendOnChainA = sdk.NewCoin(sdk.DefaultBondDenom, transferAmount) ) suite.SetupTest() // reset diff --git a/x/transfermiddleware/pfm_test.go b/x/transfermiddleware/pfm_test.go index ac4e50b61..d5230931b 100644 --- a/x/transfermiddleware/pfm_test.go +++ b/x/transfermiddleware/pfm_test.go @@ -13,8 +13,6 @@ import ( transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/stretchr/testify/suite" - - customibctesting "github.com/notional-labs/composable/v6/app/ibctesting" ) type PacketMetadata struct { @@ -34,7 +32,7 @@ type ForwardMetadata struct { type TransferMiddlewareTestSuite struct { suite.Suite - coordinator *customibctesting.Coordinator + coordinator *ibctesting.Coordinator // testing chains used for convenience and readability chainA *customibctesting.TestChain