diff --git a/ante/evm/utils_test.go b/ante/evm/utils_test.go index 79900eaf7..9f0242b67 100644 --- a/ante/evm/utils_test.go +++ b/ante/evm/utils_test.go @@ -14,8 +14,8 @@ import ( "github.com/cosmos/evm/testutil" utiltx "github.com/cosmos/evm/testutil/tx" evmtypes "github.com/cosmos/evm/x/vm/types" - ibctypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibctypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + ibcclienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" sdkmath "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" diff --git a/cmd/evmd/cmd/root.go b/cmd/evmd/cmd/root.go index 5fa1f4d54..e72bf6053 100644 --- a/cmd/evmd/cmd/root.go +++ b/cmd/evmd/cmd/root.go @@ -5,6 +5,7 @@ import ( "io" "os" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/spf13/cast" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -13,10 +14,12 @@ import ( cmtcli "github.com/cometbft/cometbft/libs/cli" dbm "github.com/cosmos/cosmos-db" + cosmosevmcmd "github.com/cosmos/evm/client" evmdconfig "github.com/cosmos/evm/cmd/evmd/config" cosmosevmkeyring "github.com/cosmos/evm/crypto/keyring" "github.com/cosmos/evm/evmd" + "github.com/cosmos/evm/evmd/testutil" cosmosevmserver "github.com/cosmos/evm/server" cosmosevmserverconfig "github.com/cosmos/evm/server/config" srvflags "github.com/cosmos/evm/server/flags" @@ -49,14 +52,6 @@ import ( genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" ) -type emptyAppOptions struct{} - -func (ao emptyAppOptions) Get(_ string) interface{} { return nil } - -func NoOpEvmAppOptions(_ string) error { - return nil -} - // NewRootCmd creates a new root command for evmd. It is called once in the // main function. func NewRootCmd() *cobra.Command { @@ -68,8 +63,8 @@ func NewRootCmd() *cobra.Command { dbm.NewMemDB(), nil, true, - emptyAppOptions{}, - NoOpEvmAppOptions, + simtestutil.EmptyAppOptions{}, + testutil.NoOpEvmAppOptions, ) encodingConfig := sdktestutil.TestEncodingConfig{ diff --git a/contracts/package-lock.json b/contracts/package-lock.json index 8c787efa7..5b551bec8 100644 --- a/contracts/package-lock.json +++ b/contracts/package-lock.json @@ -1,11 +1,11 @@ { - "name": "evmos-contracts", + "name": "cosmos-evm-contracts", "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "evmos-contracts", + "name": "cosmos-evm-contracts", "version": "2.0.0", "license": "ISC", "devDependencies": { diff --git a/evmd/ante/cosmos_handler.go b/evmd/ante/cosmos_handler.go index 7154b7e3b..31250f38e 100644 --- a/evmd/ante/cosmos_handler.go +++ b/evmd/ante/cosmos_handler.go @@ -4,7 +4,7 @@ import ( cosmosante "github.com/cosmos/evm/ante/cosmos" evmante "github.com/cosmos/evm/ante/evm" evmtypes "github.com/cosmos/evm/x/vm/types" - ibcante "github.com/cosmos/ibc-go/v8/modules/core/ante" + ibcante "github.com/cosmos/ibc-go/v10/modules/core/ante" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/ante" diff --git a/evmd/ante/handler_options.go b/evmd/ante/handler_options.go index 05dfafaf3..c26c2d6ca 100644 --- a/evmd/ante/handler_options.go +++ b/evmd/ante/handler_options.go @@ -2,7 +2,7 @@ package ante import ( anteinterfaces "github.com/cosmos/evm/ante/interfaces" - ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" + ibckeeper "github.com/cosmos/ibc-go/v10/modules/core/keeper" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" diff --git a/evmd/app.go b/evmd/app.go index 7830ceaa5..b54fbf8da 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -8,6 +8,7 @@ import ( "os" "sort" + ibcapi "github.com/cosmos/ibc-go/v10/modules/core/api" "github.com/spf13/cast" // Force-load the tracer engines to trigger registration due to Go-Ethereum v1.10.15 changes @@ -17,6 +18,19 @@ import ( abci "github.com/cometbft/cometbft/abci/types" dbm "github.com/cosmos/cosmos-db" + + "github.com/cosmos/gogoproto/proto" + ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" + ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v10/modules/core" + ibcclienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + ibcconnectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v10/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v10/modules/core/keeper" + ibctm "github.com/cosmos/ibc-go/v10/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v10/testing" + evmante "github.com/cosmos/evm/ante" cosmosevmante "github.com/cosmos/evm/ante/evm" evmosencoding "github.com/cosmos/evm/encoding" @@ -27,30 +41,19 @@ import ( "github.com/cosmos/evm/x/erc20" erc20keeper "github.com/cosmos/evm/x/erc20/keeper" erc20types "github.com/cosmos/evm/x/erc20/types" + erc20v2 "github.com/cosmos/evm/x/erc20/v2" "github.com/cosmos/evm/x/feemarket" feemarketkeeper "github.com/cosmos/evm/x/feemarket/keeper" feemarkettypes "github.com/cosmos/evm/x/feemarket/types" + // NOTE: override ICS20 keeper to support IBC transfers of ERC20 tokens "github.com/cosmos/evm/x/ibc/transfer" transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" + transferv2 "github.com/cosmos/evm/x/ibc/transfer/v2" "github.com/cosmos/evm/x/vm" corevm "github.com/cosmos/evm/x/vm/core/vm" evmkeeper "github.com/cosmos/evm/x/vm/keeper" evmtypes "github.com/cosmos/evm/x/vm/types" - "github.com/cosmos/gogoproto/proto" - "github.com/cosmos/ibc-go/modules/capability" - capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - ibctransfer "github.com/cosmos/ibc-go/v8/modules/apps/transfer" - ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v8/modules/core" - ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" - ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" - ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - ibctestingtypes "github.com/cosmos/ibc-go/v8/testing/types" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" @@ -167,11 +170,10 @@ var ( var ( _ runtime.AppI = (*EVMD)(nil) _ servertypes.Application = (*EVMD)(nil) + _ ibctesting.TestingApp = (*EVMD)(nil) ) // EVMD extends an ABCI application, but with most of its parameters exported. -// They are exported for convenience in creating helper functions, as object -// capabilities aren't needed for testing. type EVMD struct { *baseapp.BaseApp @@ -188,7 +190,6 @@ type EVMD struct { // keepers AccountKeeper authkeeper.AccountKeeper BankKeeper bankkeeper.Keeper - CapabilityKeeper *capabilitykeeper.Keeper StakingKeeper *stakingkeeper.Keeper SlashingKeeper slashingkeeper.Keeper MintKeeper mintkeeper.Keeper @@ -202,10 +203,8 @@ type EVMD struct { ConsensusParamsKeeper consensusparamkeeper.Keeper // IBC keepers - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - TransferKeeper transferkeeper.Keeper - scopedIBCKeeper capabilitykeeper.ScopedKeeper - ScopedTransferKeeper capabilitykeeper.ScopedKeeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + TransferKeeper transferkeeper.Keeper // Cosmos EVM keepers FeeMarketKeeper feemarketkeeper.Keeper @@ -287,9 +286,8 @@ func NewExampleApp( keys := storetypes.NewKVStoreKeys( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, consensusparamtypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, - evidencetypes.StoreKey, capabilitytypes.StoreKey, - authzkeeper.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, consensusparamtypes.StoreKey, + upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, authzkeeper.StoreKey, // ibc keys ibcexported.StoreKey, ibctransfertypes.StoreKey, // Cosmos EVM store keys @@ -297,7 +295,6 @@ func NewExampleApp( ) tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey) - memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) // load state streaming if enabled if err := bApp.RegisterStreamingServices(appOpts, keys); err != nil { @@ -318,7 +315,6 @@ func NewExampleApp( interfaceRegistry: interfaceRegistry, keys: keys, tkeys: tkeys, - memKeys: memKeys, } app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) @@ -335,15 +331,6 @@ func NewExampleApp( ) bApp.SetParamStore(app.ConsensusParamsKeeper.ParamsStore) - app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) - - app.scopedIBCKeeper = app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName) - app.ScopedTransferKeeper = app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) - - // Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating - // their scoped modules in `NewApp` with `ScopeToModule` - app.CapabilityKeeper.Seal() - // add keepers app.AccountKeeper = authkeeper.NewAccountKeeper( appCodec, runtime.NewKVStoreService(keys[authtypes.StoreKey]), @@ -449,11 +436,9 @@ func NewExampleApp( // Create IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( appCodec, - keys[ibcexported.StoreKey], + runtime.NewKVStoreService(keys[ibcexported.StoreKey]), app.GetSubspace(ibcexported.ModuleName), - app.StakingKeeper, app.UpgradeKeeper, - app.scopedIBCKeeper, authAddr, ) @@ -523,17 +508,18 @@ func NewExampleApp( // instantiate IBC transfer keeper AFTER the ERC-20 keeper to use it in the instantiation app.TransferKeeper = transferkeeper.NewKeeper( - appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - nil, // we are passing no ics4 wrapper - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, - app.AccountKeeper, app.BankKeeper, app.ScopedTransferKeeper, + appCodec, + runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]), + app.GetSubspace(ibctransfertypes.ModuleName), + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.ChannelKeeper, + app.MsgServiceRouter(), + app.AccountKeeper, + app.BankKeeper, app.Erc20Keeper, // Add ERC20 Keeper for ERC20 transfers authAddr, ) - // Override the ICS20 app module - transferModule := transfer.NewAppModule(app.TransferKeeper) - /* Create Transfer Stack @@ -554,11 +540,26 @@ func NewExampleApp( transferStack = transfer.NewIBCModule(app.TransferKeeper) transferStack = erc20.NewIBCMiddleware(app.Erc20Keeper, transferStack) + var transferStackV2 ibcapi.IBCModule + transferStackV2 = transferv2.NewIBCModule(app.TransferKeeper) + transferStackV2 = erc20v2.NewIBCMiddleware(transferStackV2, app.Erc20Keeper) + // Create static IBC router, add transfer route, then set and seal it ibcRouter := porttypes.NewRouter() ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) + ibcRouterV2 := ibcapi.NewRouter() + ibcRouterV2.AddRoute(ibctransfertypes.ModuleName, transferStackV2) app.IBCKeeper.SetRouter(ibcRouter) + app.IBCKeeper.SetRouterV2(ibcRouterV2) + + clientKeeper := app.IBCKeeper.ClientKeeper + storeProvider := app.IBCKeeper.ClientKeeper.GetStoreProvider() + tmLightClientModule := ibctm.NewLightClientModule(appCodec, storeProvider) + clientKeeper.AddRoute(ibctm.ModuleName, &tmLightClientModule) + + // Override the ICS20 app module + transferModule := transfer.NewAppModule(app.TransferKeeper) // NOTE: we are adding all available Cosmos EVM EVM extensions. // Not all of them need to be enabled, which can be configured on a per-chain basis. @@ -589,7 +590,6 @@ func NewExampleApp( ), auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, app.GetSubspace(banktypes.ModuleName)), - capability.NewAppModule(appCodec, *app.CapabilityKeeper, false), feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry), gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)), mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), @@ -603,7 +603,7 @@ func NewExampleApp( consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), // IBC modules ibc.NewAppModule(app.IBCKeeper), - ibctm.NewAppModule(), + ibctm.NewAppModule(tmLightClientModule), transferModule, // Cosmos EVM modules vm.NewAppModule(app.EVMKeeper, app.AccountKeeper, app.GetSubspace(evmtypes.ModuleName)), @@ -643,7 +643,7 @@ func NewExampleApp( // NOTE: staking module is required if HistoricalEntries param > 0 // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) app.ModuleManager.SetOrderBeginBlockers( - capabilitytypes.ModuleName, minttypes.ModuleName, + minttypes.ModuleName, // IBC modules ibcexported.ModuleName, ibctransfertypes.ModuleName, @@ -664,7 +664,7 @@ func NewExampleApp( // to get the full block gas used. app.ModuleManager.SetOrderEndBlockers( govtypes.ModuleName, stakingtypes.ModuleName, - capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, + authtypes.ModuleName, banktypes.ModuleName, // Cosmos EVM EndBlockers evmtypes.ModuleName, erc20types.ModuleName, feemarkettypes.ModuleName, @@ -680,11 +680,8 @@ func NewExampleApp( // NOTE: The genutils module must occur after staking so that pools are // properly initialized with tokens from genesis accounts. // NOTE: The genutils module must also occur after auth so that it can access the params from auth. - // NOTE: Capability module must occur first so that it can initialize any capabilities - // so that other modules that want to create or claim capabilities afterwards in InitChain - // can do so safely. genesisModuleOrder := []string{ - capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, + authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, ibcexported.ModuleName, @@ -741,7 +738,6 @@ func NewExampleApp( // initialize stores app.MountKVStores(keys) app.MountTransientStores(tkeys) - app.MountMemoryStores(memKeys) maxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted)) @@ -914,6 +910,11 @@ func (app *EVMD) DefaultGenesis() map[string]json.RawMessage { erc20GenState := NewErc20GenesisState() genesis[erc20types.ModuleName] = app.appCodec.MustMarshalJSON(erc20GenState) + // This is for making tests easier, as we don't need to set gas prices. + // For example, without this, we must copy many util functions like SignAndDeliver to set gas prices to test IBC. + feeMarketState := NewFeeMarketGenesisState() + genesis[feemarkettypes.ModuleName] = app.appCodec.MustMarshalJSON(feeMarketState) + return genesis } @@ -1001,11 +1002,6 @@ func (app *EVMD) GetBaseApp() *baseapp.BaseApp { return app.BaseApp } -// GetStakingKeeper implements the TestingApp interface. -func (app *EVMD) GetStakingKeeper() ibctestingtypes.StakingKeeper { - return app.StakingKeeper -} - // GetStakingKeeperSDK implements the TestingApp interface. func (app *EVMD) GetStakingKeeperSDK() stakingkeeper.Keeper { return *app.StakingKeeper @@ -1016,11 +1012,6 @@ func (app *EVMD) GetIBCKeeper() *ibckeeper.Keeper { return app.IBCKeeper } -// GetScopedIBCKeeper implements the TestingApp interface. -func (app *EVMD) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { - return app.scopedIBCKeeper -} - // GetTxConfig implements the TestingApp interface. func (app *EVMD) GetTxConfig() client.TxConfig { return app.txConfig diff --git a/evmd/genesis.go b/evmd/genesis.go index c1009ef1a..f1f0cdb2b 100644 --- a/evmd/genesis.go +++ b/evmd/genesis.go @@ -4,6 +4,7 @@ import ( "encoding/json" erc20types "github.com/cosmos/evm/x/erc20/types" + feemarkettypes "github.com/cosmos/evm/x/feemarket/types" evmtypes "github.com/cosmos/evm/x/vm/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" @@ -50,3 +51,13 @@ func NewMintGenesisState() *minttypes.GenesisState { return mintGenState } + +// NewFeeMarketGenesisState returns the default genesis state for the feemarket module. +// +// NOTE: for the example chain implementation we are disabling the base fee. +func NewFeeMarketGenesisState() *feemarkettypes.GenesisState { + feeMarketGenState := feemarkettypes.DefaultGenesisState() + feeMarketGenState.Params.NoBaseFee = true + + return feeMarketGenState +} diff --git a/evmd/precompiles.go b/evmd/precompiles.go index e0089b6b1..5ae257fc6 100644 --- a/evmd/precompiles.go +++ b/evmd/precompiles.go @@ -6,6 +6,8 @@ import ( "github.com/ethereum/go-ethereum/common" + channelkeeper "github.com/cosmos/ibc-go/v10/modules/core/04-channel/keeper" + bankprecompile "github.com/cosmos/evm/precompiles/bank" "github.com/cosmos/evm/precompiles/bech32" distprecompile "github.com/cosmos/evm/precompiles/distribution" @@ -19,7 +21,6 @@ import ( transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" "github.com/cosmos/evm/x/vm/core/vm" evmkeeper "github.com/cosmos/evm/x/vm/keeper" - channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" evidencekeeper "cosmossdk.io/x/evidence/keeper" @@ -43,7 +44,7 @@ func NewAvailableStaticPrecompiles( erc20Keeper erc20Keeper.Keeper, authzKeeper authzkeeper.Keeper, transferKeeper transferkeeper.Keeper, - channelKeeper channelkeeper.Keeper, + channelKeeper *channelkeeper.Keeper, evmKeeper *evmkeeper.Keeper, govKeeper govkeeper.Keeper, slashingKeeper slashingkeeper.Keeper, diff --git a/evmd/test_helpers.go b/evmd/test_helpers.go index 7ce8e8774..456201d69 100644 --- a/evmd/test_helpers.go +++ b/evmd/test_helpers.go @@ -13,7 +13,7 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/evm/cmd/evmd/config" feemarkettypes "github.com/cosmos/evm/x/feemarket/types" - ibctesting "github.com/cosmos/ibc-go/v8/testing" + ibctesting "github.com/cosmos/ibc-go/v10/testing" "cosmossdk.io/log" "cosmossdk.io/math" diff --git a/evmd/testutil/app.go b/evmd/testutil/app.go new file mode 100644 index 000000000..2aefc0c66 --- /dev/null +++ b/evmd/testutil/app.go @@ -0,0 +1,5 @@ +package testutil + +func NoOpEvmAppOptions(_ string) error { + return nil +} diff --git a/go.mod b/go.mod index 3c3736f08..7c6afffe1 100644 --- a/go.mod +++ b/go.mod @@ -24,11 +24,11 @@ require ( github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/ibc-go/modules/capability v1.0.1 - github.com/cosmos/ibc-go/v8 v8.7.0 + github.com/cosmos/ibc-go/v10 v10.1.0 github.com/creachadair/tomledit v0.0.24 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf - github.com/ethereum/go-ethereum v1.11.5 + github.com/ethereum/go-ethereum v1.15.5 github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 @@ -56,7 +56,7 @@ require ( golang.org/x/text v0.21.0 google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a google.golang.org/grpc v1.70.0 - google.golang.org/protobuf v1.36.4 + google.golang.org/protobuf v1.36.5 sigs.k8s.io/yaml v1.4.0 ) @@ -69,24 +69,24 @@ require ( cloud.google.com/go/storage v1.41.0 // indirect cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/depinject v1.1.0 // indirect - cosmossdk.io/x/circuit v0.1.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect - github.com/99designs/keyring v1.2.1 // indirect - github.com/DataDog/datadog-go v3.2.0+incompatible // indirect + github.com/99designs/keyring v1.2.2 // indirect + github.com/DataDog/datadog-go v4.8.3+incompatible // indirect github.com/DataDog/zstd v1.5.5 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect github.com/aws/aws-sdk-go v1.44.224 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect - github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/bits-and-blooms/bitset v1.8.0 // indirect + github.com/bgentry/speakeasy v0.2.0 // indirect + github.com/bits-and-blooms/bitset v1.17.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/bytedance/sonic v1.12.3 // indirect github.com/bytedance/sonic/loader v0.2.0 // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -94,7 +94,7 @@ require ( github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/cockroachdb/errors v1.11.3 // indirect - github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect + github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v1.1.2 // indirect github.com/cockroachdb/redact v1.1.5 // indirect @@ -106,21 +106,21 @@ require ( github.com/cosmos/ics23/go v0.11.0 // indirect github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect github.com/creachadair/atomicfile v0.3.1 // indirect - github.com/danieljoos/wincred v1.1.2 // indirect + github.com/danieljoos/wincred v1.2.1 // indirect github.com/deckarep/golang-set v1.8.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect - github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect + github.com/desertbit/timer v1.0.1 // indirect github.com/dgraph-io/badger/v4 v4.2.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/dvsekhvalnov/jose2go v1.6.0 // indirect + github.com/dvsekhvalnov/jose2go v1.7.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/dot v1.6.2 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/getsentry/sentry-go v0.27.0 // indirect + github.com/getsentry/sentry-go v0.28.1 // indirect github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect @@ -136,9 +136,9 @@ require ( github.com/golang/glog v1.2.4 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/flatbuffers v23.5.26+incompatible // indirect + github.com/google/flatbuffers v24.3.25+incompatible // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect @@ -151,9 +151,9 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.5 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-plugin v1.5.2 // indirect + github.com/hashicorp/go-plugin v1.6.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect @@ -161,7 +161,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/hdevalence/ed25519consensus v0.1.0 // indirect + github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect @@ -178,7 +178,7 @@ require ( github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -197,10 +197,11 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/tsdb v0.10.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/rivo/uniseg v0.2.0 // indirect github.com/rjeczalik/notify v0.9.3 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/zerolog v1.33.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect @@ -220,7 +221,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/zondax/ledger-go v0.14.3 // indirect - go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect + go.etcd.io/bbolt v1.4.0-alpha.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect @@ -232,7 +233,7 @@ require ( golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sys v0.29.0 // indirect golang.org/x/term v0.28.0 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.28.0 // indirect google.golang.org/api v0.186.0 // indirect google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect @@ -242,7 +243,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect - nhooyr.io/websocket v1.8.7 // indirect + nhooyr.io/websocket v1.8.11 // indirect pgregory.net/rapid v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index 0e6f52c04..7676d322a 100644 --- a/go.sum +++ b/go.sum @@ -204,8 +204,6 @@ cosmossdk.io/math v1.5.0 h1:sbOASxee9Zxdjd6OkzogvBZ25/hP929vdcYcBJQbkLc= cosmossdk.io/math v1.5.0/go.mod h1:AAwwBmUhqtk2nlku174JwSll+/DepUXW3rWIXN5q+Nw= cosmossdk.io/tools/confix v0.1.2 h1:2hoM1oFCNisd0ltSAAZw2i4ponARPmlhuNu3yy0VwI4= cosmossdk.io/tools/confix v0.1.2/go.mod h1:7XfcbK9sC/KNgVGxgLM0BrFbVcR/+6Dg7MFfpx7duYo= -cosmossdk.io/x/circuit v0.1.1 h1:KPJCnLChWrxD4jLwUiuQaf5mFD/1m7Omyo7oooefBVQ= -cosmossdk.io/x/circuit v0.1.1/go.mod h1:B6f/urRuQH8gjt4eLIXfZJucrbreuYrKh5CSjaOxr+Q= cosmossdk.io/x/evidence v0.1.1 h1:Ks+BLTa3uftFpElLTDp9L76t2b58htjVbSZ86aoK/E4= cosmossdk.io/x/evidence v0.1.1/go.mod h1:OoDsWlbtuyqS70LY51aX8FBTvguQqvFrt78qL7UzeNc= cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= @@ -223,13 +221,14 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q= +github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -273,10 +272,10 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= -github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c= -github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E= +github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.17.0 h1:1X2TS7aHz1ELcC0yU1y2stUs/0ig5oMU6STFZGrhvHI= +github.com/bits-and-blooms/bitset v1.17.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= @@ -317,8 +316,8 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= @@ -364,8 +363,8 @@ github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaY github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a h1:f52TdbU4D5nozMAhO9TvTJ2ZMCXtN4VIAmfrrZ0JXQ4= +github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= @@ -408,8 +407,8 @@ github.com/cosmos/iavl v1.2.2 h1:qHhKW3I70w+04g5KdsdVSHRbFLgt3yY3qTMd4Xa4rC8= github.com/cosmos/iavl v1.2.2/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= -github.com/cosmos/ibc-go/v8 v8.7.0 h1:HqhVOkO8bDpClXE81DFQgFjroQcTvtpm0tCS7SQVKVY= -github.com/cosmos/ibc-go/v8 v8.7.0/go.mod h1:G2z+Q6ZQSMcyHI2+BVcJdvfOupb09M2h/tgpXOEdY6k= +github.com/cosmos/ibc-go/v10 v10.1.0 h1:2liTTnPTHkRlwin+jAtJoIQ8uGly2lothdsUpefeNwQ= +github.com/cosmos/ibc-go/v10 v10.1.0/go.mod h1:Lgp7NUqBMjZhDcHzkj7IYTKHMq09GNe2iUc/qXb+rts= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= @@ -425,8 +424,8 @@ github.com/creachadair/tomledit v0.0.24 h1:5Xjr25R2esu1rKCbQEmjZYlrhFkDspoAbAKb6 github.com/creachadair/tomledit v0.0.24/go.mod h1:9qHbShRWQzSCcn617cMzg4eab1vbLCOjOshAWSzWr8U= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= -github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= +github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -441,8 +440,9 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeC github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/desertbit/timer v1.0.1 h1:yRpYNn5Vaaj6QXecdLMPMJsW81JLiI1eokUft5nBmeo= +github.com/desertbit/timer v1.0.1/go.mod h1:htRrYeY5V/t4iu1xCJ5XsQvp4xve8QulXXctAzxqcwE= github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= @@ -466,8 +466,8 @@ github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:Htrtb github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY= -github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= +github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= @@ -489,8 +489,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= @@ -505,16 +505,13 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= -github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k= +github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= @@ -543,11 +540,8 @@ github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= @@ -557,13 +551,9 @@ github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= @@ -622,14 +612,15 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= -github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= +github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -735,8 +726,8 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4= github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -744,8 +735,8 @@ github.com/hashicorp/go-metrics v0.5.3 h1:M5uADWMOGCTUNU1YuC4hfknOeHNaX54LDm4oYS github.com/hashicorp/go-metrics v0.5.3/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= -github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= +github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI= +github.com/hashicorp/go-plugin v1.6.1/go.mod h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1hZyMK0PWAw0= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= @@ -775,8 +766,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= -github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= +github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= @@ -820,7 +811,6 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -855,7 +845,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -883,8 +872,9 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= @@ -905,11 +895,9 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= @@ -928,8 +916,8 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -1033,6 +1021,8 @@ github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSg github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -1051,8 +1041,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -1141,7 +1131,6 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= @@ -1165,8 +1154,8 @@ github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWp github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 h1:qxen9oVGzDdIRP6ejyAJc760RwW4SnVDiTYTzwnXuxo= -go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5/go.mod h1:eW0HG9/oHQhvRCvb1/pIXW4cOvtDqeQK+XSi3TnwaXY= +go.etcd.io/bbolt v1.4.0-alpha.1 h1:3yrqQzbRRPFPdOMWS/QQIVxVnzSkAZQYeWlZFv1kbj4= +go.etcd.io/bbolt v1.4.0-alpha.1/go.mod h1:S/Z/Nm3iuOnyO1W4XuFfPci51Gj6F1Hv0z8hisyYYOw= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1268,8 +1257,6 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1448,7 +1435,6 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1511,8 +1497,8 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1819,8 +1805,8 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= -google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1866,8 +1852,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= +nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= diff --git a/ibc/errors.go b/ibc/errors.go index 57ffeb7db..1b1954597 100644 --- a/ibc/errors.go +++ b/ibc/errors.go @@ -3,7 +3,7 @@ package ibc import "errors" var ( - ErrNoIBCVoucherDenom = errors.New("denom is not an IBC voucher") - ErrDenomTraceNotFound = errors.New("denom trace not found") - ErrInvalidBaseDenom = errors.New("invalid base denomination") + ErrNoIBCVoucherDenom = errors.New("denom is not an IBC voucher") + ErrDenomNotFound = errors.New("denom not found") + ErrInvalidBaseDenom = errors.New("invalid base denomination") ) diff --git a/ibc/module.go b/ibc/module.go index 94773e15b..0b4de543a 100644 --- a/ibc/module.go +++ b/ibc/module.go @@ -1,10 +1,9 @@ package ibc import ( - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v10/modules/core/exported" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -31,11 +30,10 @@ func (im Module) OnChanOpenInit( 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) + return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, version) } // OnChanOpenTry implements the Module interface. @@ -46,11 +44,10 @@ func (im Module) OnChanOpenTry( 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) + return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, counterpartyVersion) } // OnChanOpenAck implements the Module interface. @@ -99,29 +96,32 @@ func (im Module) OnChanCloseConfirm( // It calls the underlying app's OnRecvPacket callback. func (im Module) OnRecvPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) exported.Acknowledgement { - return im.app.OnRecvPacket(ctx, packet, relayer) + return im.app.OnRecvPacket(ctx, channelVersion, packet, relayer) } // OnAcknowledgementPacket implements the Module interface. // It calls the underlying app's OnAcknowledgementPacket callback. func (im Module) OnAcknowledgementPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, ) error { - return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + return im.app.OnAcknowledgementPacket(ctx, channelVersion, packet, acknowledgement, relayer) } // OnTimeoutPacket implements the Module interface. // It calls the underlying app's OnTimeoutPacket callback. func (im Module) OnTimeoutPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - return im.app.OnTimeoutPacket(ctx, packet, relayer) + return im.app.OnTimeoutPacket(ctx, channelVersion, packet, relayer) } diff --git a/ibc/module_test.go b/ibc/module_test.go index ced2ffc61..4515dad8e 100644 --- a/ibc/module_test.go +++ b/ibc/module_test.go @@ -7,11 +7,10 @@ import ( "github.com/stretchr/testify/require" cosmosevmibc "github.com/cosmos/evm/ibc" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v10/modules/core/exported" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -36,7 +35,6 @@ func (m MockIBCModule) OnChanOpenInit( connectionHops []string, portID string, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) { @@ -56,7 +54,6 @@ func (m MockIBCModule) OnChanOpenTry( connectionHops []string, portID, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (version string, err error) { @@ -134,6 +131,7 @@ func (m MockIBCModule) OnChanCloseConfirm( //nolint:all // escaping govet since we can copy locks here as it is a test func (m MockIBCModule) OnRecvPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) exported.Acknowledgement { @@ -149,6 +147,7 @@ func (m MockIBCModule) OnRecvPacket( //nolint:all // escaping govet since we can copy locks here as it is a test func (m MockIBCModule) OnAcknowledgementPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, @@ -165,6 +164,7 @@ func (m MockIBCModule) OnAcknowledgementPacket( //nolint:all // escaping govet since we can copy locks here as it is a test func (m MockIBCModule) OnTimeoutPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) error { @@ -187,9 +187,9 @@ func TestModule(t *testing.T) { module := cosmosevmibc.NewModule(mockModule) // mock calls for abstraction - _, err := module.OnChanOpenInit(sdk.Context{}, channeltypes.ORDERED, nil, transfertypes.PortID, "channel-0", &capabilitytypes.Capability{}, channeltypes.Counterparty{}, "") + _, err := module.OnChanOpenInit(sdk.Context{}, channeltypes.ORDERED, nil, transfertypes.PortID, "channel-0", channeltypes.Counterparty{}, "") require.NoError(t, err) - _, err = module.OnChanOpenTry(sdk.Context{}, channeltypes.ORDERED, nil, transfertypes.PortID, "channel-0", &capabilitytypes.Capability{}, channeltypes.Counterparty{}, "") + _, err = module.OnChanOpenTry(sdk.Context{}, channeltypes.ORDERED, nil, transfertypes.PortID, "channel-0", channeltypes.Counterparty{}, "") require.NoError(t, err) err = module.OnChanOpenAck(sdk.Context{}, transfertypes.PortID, "channel-0", "channel-0", "") require.NoError(t, err) @@ -199,10 +199,10 @@ func TestModule(t *testing.T) { require.NoError(t, err) err = module.OnChanCloseConfirm(sdk.Context{}, transfertypes.PortID, "channel-0") require.NoError(t, err) - ack := module.OnRecvPacket(sdk.Context{}, channeltypes.Packet{}, nil) + ack := module.OnRecvPacket(sdk.Context{}, "", channeltypes.Packet{}, nil) require.NotNil(t, ack) - err = module.OnAcknowledgementPacket(sdk.Context{}, channeltypes.Packet{}, nil, nil) + err = module.OnAcknowledgementPacket(sdk.Context{}, "", channeltypes.Packet{}, nil, nil) require.NoError(t, err) - err = module.OnTimeoutPacket(sdk.Context{}, channeltypes.Packet{}, nil) + err = module.OnTimeoutPacket(sdk.Context{}, "", channeltypes.Packet{}, nil) require.NoError(t, err) } diff --git a/ibc/testing/README.md b/ibc/testing/README.md index aa0917e98..915407889 100644 --- a/ibc/testing/README.md +++ b/ibc/testing/README.md @@ -1,8 +1,18 @@ # IBC Testing Package +This package is adapted from [ibc-go's testing package](https://github.com/cosmos/ibc-go/blob/121f1fb5eb5c9db84e233c7cc25a2ebde8de8caf/testing), with several files copied and modified to suit specific testing needs. + +### Why Copied? +To test certain key scenarios involving EVM messages (e.g., deploying an ERC20 contract), we needed a block header context with a proposer address. This required: +- A custom `TestChain` to handle these messages. +- A custom `SignAndDeliver` function to support the transaction signing and delivery process. +- A custom `Coordinator` to integrate this tailored `TestChain`. + +Since `TestChain` and `SignAndDeliver` are directly or indirectly tied to most components in the testing package, and ibc-go cannot use a `TestChain` struct defined in our separate package, we had to copy and adapt nearly all related files to ensure compatibility and functionality. + ## Components -The testing package comprises of four parts constructed as a stack: +The testing package is comprised of four parts constructed as a stack. - coordinator - chain @@ -47,21 +57,20 @@ will need to be extended to fulfill the `TestingApp` interface. ```go type TestingApp interface { - abci.Application + abci.Application - // ibc-go additions - GetBaseApp() *baseapp.BaseApp - GetStakingKeeper() stakingkeeper.Keeper - GetIBCKeeper() *keeper.Keeper - GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper - GetTxConfig() client.TxConfig + // ibc-go additions + GetBaseApp() *baseapp.BaseApp + GetStakingKeeper() ibctestingtypes.StakingKeeper + GetIBCKeeper() *keeper.Keeper + GetTxConfig() client.TxConfig - // Implemented by SimApp - AppCodec() codec.Codec + // Implemented by SimApp + AppCodec() codec.Codec - // Implemented by BaseApp - LastCommitID() sdk.CommitID - LastBlockHeight() int64 + // Implemented by BaseApp + LastCommitID() sdk.CommitID + LastBlockHeight() int64 } ``` @@ -73,27 +82,22 @@ To begin, you will need to extend your application by adding the following funct // GetBaseApp implements the TestingApp interface. func (app *SimApp) GetBaseApp() *baseapp.BaseApp { - return app.BaseApp + return app.BaseApp } // GetStakingKeeper implements the TestingApp interface. -func (app *SimApp) GetStakingKeeper() stakingkeeper.Keeper { - return app.StakingKeeper +func (app *SimApp) GetStakingKeeper() ibctestingtypes.Keeper { + return app.StakingKeeper } // GetIBCKeeper implements the TestingApp interface. func (app *SimApp) GetIBCKeeper() *ibckeeper.Keeper { - return app.IBCKeeper -} - -// GetScopedIBCKeeper implements the TestingApp interface. -func (app *SimApp) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { - return app.ScopedIBCKeeper + return app.IBCKeeper } // GetTxConfig implements the TestingApp interface. func (app *SimApp) GetTxConfig() client.TxConfig { - return MakeTestEncodingConfig().TxConfig + return app.txConfig } ``` @@ -106,24 +110,21 @@ Your application may need to define `AppCodec()` if it does not already exist: // NOTE: This is solely to be used for testing purposes as it may be desirable // for modules to register their own custom testing types. func (app *SimApp) AppCodec() codec.Codec { - return app.appCodec + return app.appCodec } ``` -It is assumed your application contains an embedded BaseApp and thus implements the abci.Application interface, -`LastCommitID()` and `LastBlockHeight()` +It is assumed your application contains an embedded BaseApp and thus implements the abci.Application interface, `LastCommitID()` and `LastBlockHeight()` ### Initialize TestingApp -The testing package requires that you provide a function to initialize your TestingApp. -This is how ibc-go implements the initialize function with its `SimApp`: +The testing package requires that you provide a function to initialize your TestingApp. This is how ibc-go implements the initialize function with its `SimApp`: ```go func SetupTestingApp() (TestingApp, map[string]json.RawMessage) { db := dbm.NewMemDB() - encCdc := simapp.MakeTestEncodingConfig() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encCdc, simapp.EmptyAppOptions{}) - return app, simapp.NewDefaultGenesisState(encCdc.Marshaler) + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, simtestutil.EmptyAppOptions{}) + return app, app.DefaultGenesis() } ``` @@ -133,9 +134,8 @@ Change the value of `DefaultTestingAppInit` to use your function: ```go func init() { - ibctesting.DefaultTestingAppInit = MySetupTestingAppFunction + ibctesting.DefaultTestingAppInit = SetupTestingApp } - ``` ## Example @@ -145,29 +145,30 @@ Here is an example of how to setup your testing environment in every package you ```go // KeeperTestSuite is a testing suite to test keeper functions. type KeeperTestSuite struct { - suite.Suite + testifysuite.Suite - coordinator *ibctesting.Coordinator + coordinator *ibctesting.Coordinator - // testing chains used for convenience and readability - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain + // testing chains used for convenience and readability + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain } // TestKeeperTestSuite runs all the tests within this package. func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(KeeperTestSuite)) + testifysuite.Run(t, new(KeeperTestSuite)) } // SetupTest creates a coordinator with 2 test chains. func (suite *KeeperTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) // initializes 2 test chains - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) // convenience and readability - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) // convenience and readability + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) // initializes 2 test chains + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) // convenience and readability + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) // convenience and readability } + ``` -To create interaction between chainA and chainB, we need to contruct a `Path` these chains will use. +To create interaction between chainA and chainB, we need to construct a `Path` these chains will use. A path contains two endpoints, `EndpointA` and `EndpointB` (corresponding to the order of the chains passed into the `NewPath` function). A path is a pointer and its values will be filled in as necessary during the setup portion of testing. @@ -180,15 +181,15 @@ Endpoint Struct: // configuration parameters. Endpoint functions will utilize the parameters // set in the configuration structs when executing IBC messages. type Endpoint struct { - Chain *TestChain - Counterparty *Endpoint - ClientID string - ConnectionID string - ChannelID string - - ClientConfig ClientConfig - ConnectionConfig *ConnectionConfig - ChannelConfig *ChannelConfig + Chain *TestChain + Counterparty *Endpoint + ClientID string + ConnectionID string + ChannelID string + + ClientConfig ClientConfig + ConnectionConfig *ConnectionConfig + ChannelConfig *ChannelConfig } ``` @@ -200,11 +201,11 @@ use your Port IDs, you might add a helper function similar to the one found in t ```go func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { - path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort - path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort - return path + return path } ``` @@ -220,33 +221,33 @@ To initialize the clients, connections, and channels for a path we can call the Here is a basic example of the testing package being used to simulate IBC functionality: ```go - path := ibctesting.NewPath(suite.chainA, suite.chainB) // clientID, connectionID, channelID empty - suite.coordinator.Setup(path) // clientID, connectionID, channelID filled - suite.Require().Equal("07-tendermint-0", path.EndpointA.ClientID) - suite.Require().Equal("connection-0", path.EndpointA.ClientID) - suite.Require().Equal("channel-0", path.EndpointA.ClientID) + path := ibctesting.NewPath(suite.chainA, suite.chainB) // clientID, connectionID, channelID empty + suite.coordinator.Setup(path) // clientID, connectionID, channelID filled + suite.Require().Equal("07-tendermint-0", path.EndpointA.ClientID) + suite.Require().Equal("connection-0", path.EndpointA.ClientID) + suite.Require().Equal("channel-0", path.EndpointA.ClientID) - // create packet 1 - packet1 := NewPacket() // NewPacket would construct your packet + // send on endpointA + sequence, err := path.EndpointA.SendPacket(timeoutHeight1, timeoutTimestamp1, packet1Data) - // send on endpointA - path.EndpointA.SendPacket(packet1) + // create packet 1 + packet1 := NewPacket() // NewPacket would construct your packet - // receive on endpointB - path.EndpointB.RecvPacket(packet1) + // receive on endpointB + path.EndpointB.RecvPacket(packet1) - // acknowledge the receipt of the packet - path.EndpointA.AcknowledgePacket(packet1, ack) + // acknowledge the receipt of the packet + path.EndpointA.AcknowledgePacket(packet1, ack) - // we can also relay - packet2 := NewPacket() + // we can also relay + sequence, err := path.EndpointA.SendPacket(timeoutHeight2, timeoutTimestamp2, packet2Data) - path.EndpointA.SendPacket(packet2) + packet2 := NewPacket() - path.Relay(packet2, expectedAck) + path.RelayPacket(packet2) - // if needed we can update our clients - path.EndpointB.UpdateClient() + // if needed we can update our clients + path.EndpointB.UpdateClient() ``` ### Transfer Testing Example @@ -257,62 +258,70 @@ If ICS 20 had its own simapp, its testing setup might include a `testing/app.go` package transfertesting import ( - "encoding/json" + "encoding/json" - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" + "github.com/cometbft/cometbft/libs/log" + dbm "github.com/cometbft/cometbft-db" - "github.com/cosmos/ibc-go/v6/modules/apps/transfer/simapp" - ibctesting "github.com/cosmos/ibc-go/v6/testing" + "github.com/cosmos/ibc-go/v10/modules/apps/transfer/simapp" + ibctesting "github.com/cosmos/ibc-go/v10/testing" ) func SetupTransferTestingApp() (ibctesting.TestingApp, map[string]json.RawMessage) { - db := dbm.NewMemDB() - encCdc := simapp.MakeTestEncodingConfig() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encCdc, simapp.EmptyAppOptions{}) - return app, simapp.NewDefaultGenesisState(encCdc.Marshaler) + db := dbm.NewMemDB() + encCdc := simapp.MakeTestEncodingConfig() + app := simapp.NewSimApp( + log.NewNopLogger(), + db, + nil, + true, + map[int64]bool{}, + simapp.DefaultNodeHome, + 5, + encCdc, + simapp.EmptyAppOptions{}, + ) + return app, simapp.NewDefaultGenesisState(encCdc.Marshaler) } func init() { - ibctesting.DefaultTestingAppInit = SetupTransferTestingApp + ibctesting.DefaultTestingAppInit = SetupTransferTestingApp } func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { - path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort - path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + path := ibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort - return path + return path } func GetTransferSimApp(chain *ibctesting.TestChain) *simapp.SimApp { - app, ok := chain.App.(*simapp.SimApp) - if !ok { - panic("not transfer app") - } + app, ok := chain.App.(*simapp.SimApp) + if !ok { + panic("not transfer app") + } - return app + return app } ``` ### Middleware Testing When writing IBC applications acting as middleware, it might be desirable to test integration points. -This can be done by wiring a middleware stack in the app.go file -using existing applications as middleware and IBC base applications. -The mock module may also be leveraged to act as a base application in the instance -that such an application is not available for testing or causes dependency concerns. +This can be done by wiring a middleware stack in the app.go file using existing applications as middleware and IBC base applications. +The mock module may also be leveraged to act as a base application in the instance that such an application is not available for testing or causes dependency concerns. The mock IBC module contains a `MockIBCApp`. This struct contains a function field for every IBC App Module callback. -Each of these functions can be individually set to mock expected behavior of a base application. +Each of these functions can be individually set to mock expected behaviour of a base application. +The portID and scoped keeper for the `MockIBCApp` should be set within `MockIBCApp` before calling `NewIBCModule`. -For example, if one wanted to test that the base application cannot affect the outcome of the `OnChanOpenTry` callback, -the mock module base application callback could be updated as such: +For example, if one wanted to test that the base application cannot affect the outcome of the `OnChanOpenTry` callback, the mock module base application callback could be updated as such: ```go - mockModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, portID, channelID, version string) error { - return fmt.Errorf("mock base app must not be called for OnChanOpenTry") - } +mockModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, portID, channelID, version string) error { + return fmt.Errorf("mock base app must not be called for OnChanOpenTry") +} ``` Using a mock module as a base application in a middleware stack may require adding the module to your `SimApp`. @@ -322,10 +331,10 @@ sits at the top of middleware stack will need to be accessed via a public field This might look like: ```go - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, version string, - ) error { - return fmt.Errorf("mock ica auth fails") - } +suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func( +ctx sdk.Context, order channeltypes.Order, connectionHops []string, +portID, channelID string, counterparty channeltypes.Counterparty, version string, +) error { +return fmt.Errorf("mock ica auth fails") +} ``` diff --git a/ibc/testing/app.go b/ibc/testing/app.go deleted file mode 100644 index 2745e74e0..000000000 --- a/ibc/testing/app.go +++ /dev/null @@ -1,120 +0,0 @@ -package ibctesting - -import ( - "encoding/json" - "testing" - "time" - - "github.com/stretchr/testify/require" - - abci "github.com/cometbft/cometbft/abci/types" - cmttypes "github.com/cometbft/cometbft/types" - - exampleapp "github.com/cosmos/evm/evmd" - chainutil "github.com/cosmos/evm/evmd/testutil" - "github.com/cosmos/evm/testutil/constants" - cosmosevmtypes "github.com/cosmos/evm/types" - ibcgotesting "github.com/cosmos/ibc-go/v8/testing" - - "cosmossdk.io/math" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -// DefaultTestingAppInit is a test helper function used to initialize an App -// on the ibc testing pkg -// need this design to make it compatible with the SetupTestinApp func on ibctesting pkg -var DefaultTestingAppInit func(chainID string) func() (ibcgotesting.TestingApp, map[string]json.RawMessage) = exampleapp.SetupTestingApp - -// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts -// that also act as delegators. For simplicity, each validator is bonded with a delegation -// of one consensus engine unit (10^6) in the default token of the simapp from first genesis -// account. A Nop logger is set in SimApp. -func SetupWithGenesisValSet(t *testing.T, valSet *cmttypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, balances ...banktypes.Balance) ibcgotesting.TestingApp { - t.Helper() - app, genesisState := DefaultTestingAppInit(chainID)() - // set genesis accounts - authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) - genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) - - validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) - delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) - - bondAmt := sdk.TokensFromConsensusPower(1, cosmosevmtypes.AttoPowerReduction) - - for _, val := range valSet.Validators { - pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) //nolint:staticcheck - require.NoError(t, err) - pkAny, err := codectypes.NewAnyWithValue(pk) - require.NoError(t, err) - validator := stakingtypes.Validator{ - OperatorAddress: sdk.ValAddress(val.Address).String(), - ConsensusPubkey: pkAny, - Jailed: false, - Status: stakingtypes.Bonded, - Tokens: bondAmt, - DelegatorShares: math.LegacyOneDec(), - Description: stakingtypes.Description{}, - UnbondingHeight: int64(0), - UnbondingTime: time.Unix(0, 0).UTC(), - Commission: stakingtypes.NewCommission(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec()), - MinSelfDelegation: math.ZeroInt(), - } - validators = append(validators, validator) - delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress().String(), sdk.ValAddress(val.Address).String(), math.LegacyOneDec())) - } - - // set validators and delegations - stakingParams := stakingtypes.DefaultParams() - // set bond demon to be aatom - stakingParams.BondDenom = constants.ExampleAttoDenom - stakingGenesis := stakingtypes.NewGenesisState(stakingParams, validators, delegations) - genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) - - totalSupply := sdk.NewCoins() - for _, b := range balances { - // add genesis acc tokens and delegated tokens to total supply - totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(constants.ExampleAttoDenom, bondAmt))...) - } - - // add bonded amount to bonded pool module account - balances = append(balances, banktypes.Balance{ - Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), - Coins: sdk.Coins{sdk.NewCoin(stakingParams.BondDenom, bondAmt)}, - }) - - // update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}, []banktypes.SendEnabled{}) - genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) - - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - require.NoError(t, err) - - // init chain will set the validator set and initialize the genesis accounts - _, err = app.InitChain( - &abci.RequestInitChain{ - ChainId: chainID, - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: chainutil.DefaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) - require.NoError(t, err) - - // commit genesis changes - _, err = app.Commit() - require.NoError(t, err) - - _, err = app.FinalizeBlock(&abci.RequestFinalizeBlock{ - Height: app.LastBlockHeight(), - NextValidatorsHash: valSet.Hash(), - }) - require.NoError(t, err) - - return app -} diff --git a/ibc/testing/chain.go b/ibc/testing/chain.go index ccc4f794f..f43a30e34 100644 --- a/ibc/testing/chain.go +++ b/ibc/testing/chain.go @@ -1,76 +1,149 @@ package ibctesting import ( + "fmt" "testing" + "time" - "github.com/stretchr/testify/require" - - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmtprotoversion "github.com/cometbft/cometbft/proto/tendermint/version" cmttypes "github.com/cometbft/cometbft/types" - - "github.com/cosmos/evm/crypto/ethsecp256k1" - "github.com/cosmos/evm/testutil/constants" - cosmosevmtypes "github.com/cosmos/evm/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - ibcgotesting "github.com/cosmos/ibc-go/v8/testing" - "github.com/cosmos/ibc-go/v8/testing/mock" - + cmtversion "github.com/cometbft/cometbft/version" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v10/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v10/modules/core/24-host" + "github.com/cosmos/ibc-go/v10/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v10/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v10/testing" + "github.com/cosmos/ibc-go/v10/testing/simapp" + "github.com/stretchr/testify/require" + + "github.com/cosmos/evm/crypto/ethsecp256k1" + "github.com/cosmos/evm/evmd" ) -// ChainIDPrefix defines the default chain ID prefix for Cosmos EVM test chains -var ( - ChainIDPrefix = constants.ExampleChainID - ChainIDSuffix = "" +var MaxAccounts = 10 + +type SenderAccount struct { + SenderPrivKey cryptotypes.PrivKey + SenderAccount sdk.AccountI +} + +const ( + DefaultGenesisAccBalance = "10000000000000000000" ) -func init() { - ibcgotesting.ChainIDPrefix = ChainIDPrefix - ibcgotesting.ChainIDSuffix = ChainIDSuffix +// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI +// header and the validators of the TestChain. It also contains a field called ChainID. This +// is the clientID that *other* chains use to refer to this TestChain. The SenderAccount +// is used for delivering transactions through the application state. +// NOTE: the actual application uses an empty chain-id for ease of testing. +type TestChain struct { + testing.TB + + Coordinator *Coordinator + App ibctesting.TestingApp + ChainID string + LatestCommittedHeader *ibctm.Header // header for last block height committed + ProposedHeader cmtproto.Header // proposed (uncommitted) header for current block height + TxConfig client.TxConfig + Codec codec.Codec + + Vals *cmttypes.ValidatorSet + NextVals *cmttypes.ValidatorSet + + // Signers is a map from validator address to the PrivValidator + // The map is converted into an array that is the same order as the validators right before signing commit + // This ensures that signers will always be in correct order even as validator powers change. + // If a test adds a new validator after chain creation, then the signer map must be updated to include + // the new PrivValidator entry. + Signers map[string]cmttypes.PrivValidator + + // TrustedValidators is a mapping used to obtain the validator set from which we can prove a header update. + // It maps from a header height to the next validator set associated with that header. + TrustedValidators map[uint64]*cmttypes.ValidatorSet + + // autogenerated sender private key + SenderPrivKey cryptotypes.PrivKey + SenderAccount sdk.AccountI + + SenderAccounts []SenderAccount + + // Short-term solution to override the logic of the standard SendMsgs function. + // See issue https://github.com/cosmos/ibc-go/issues/3123 for more information. + SendMsgsOverride func(msgs ...sdk.Msg) (*abci.ExecTxResult, error) } -// NewTestChain initializes a new TestChain instance with a single validator set using a -// generated private key. It also creates a sender account to be used for delivering transactions. +// NewTestChainWithValSet initializes a new TestChain instance with the given validator set +// and signer array. It also initializes 10 Sender accounts with a balance of 10000000000000000000 coins of +// bond denom to use for tests. // // The first block height is committed to state in order to allow for client creations on // counterparty chains. The TestChain will return with a block height starting at 2. // // Time management is handled by the Coordinator in order to ensure synchrony between chains. // Each update of any chain increments the block header time for all chains by 5 seconds. -func NewTestChain(t *testing.T, coord *ibcgotesting.Coordinator, chainID string) *ibcgotesting.TestChain { - t.Helper() - // generate validator private/public key - privVal := mock.NewPV() - pubKey, err := privVal.GetPubKey() - require.NoError(t, err) - - // create validator set with single validator - validator := cmttypes.NewValidator(pubKey, 1) - valSet := cmttypes.NewValidatorSet([]*cmttypes.Validator{validator}) - signers := make(map[string]cmttypes.PrivValidator) - signers[pubKey.Address().String()] = privVal - - // generate genesis account - senderPrivKey, err := ethsecp256k1.GenerateKey() - if err != nil { - panic(err) - } +// +// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this +// constructor function. +// +// CONTRACT: Validator array must be provided in the order expected by Tendermint. +// i.e. sorted first by power and then lexicographically by address. +func NewTestChainWithValSet(tb testing.TB, isEVM bool, coord *Coordinator, chainID string, valSet *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator) *TestChain { + tb.Helper() + genAccs := []authtypes.GenesisAccount{} + genBals := []banktypes.Balance{} + senderAccs := []SenderAccount{} - baseAcc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) + // generate genesis accounts + for i := 0; i < MaxAccounts; i++ { + var senderPrivKey cryptotypes.PrivKey + var err error + if isEVM { + senderPrivKey, err = ethsecp256k1.GenerateKey() + } else { + senderPrivKey = secp256k1.GenPrivKey() + } + require.NoError(tb, err) + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0) + amount, ok := sdkmath.NewIntFromString(DefaultGenesisAccBalance) + require.True(tb, ok) - amount := sdk.TokensFromConsensusPower(1, cosmosevmtypes.AttoPowerReduction) + // add sender account + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins( + sdk.NewCoin(sdk.DefaultBondDenom, amount), + sdk.NewCoin(evmd.ExampleChainDenom, amount), + ), + } - balance := banktypes.Balance{ - Address: baseAcc.GetAddress().String(), - Coins: sdk.NewCoins(sdk.NewCoin(constants.ExampleAttoDenom, amount)), - } + genAccs = append(genAccs, acc) + genBals = append(genBals, balance) + + senderAcc := SenderAccount{ + SenderAccount: acc, + SenderPrivKey: senderPrivKey, + } - app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{baseAcc}, chainID, balance) + senderAccs = append(senderAccs, senderAcc) + } + app := ibctesting.SetupWithGenesisValSet(tb, valSet, genAccs, chainID, sdk.DefaultPowerReduction, genBals...) // create current header and call begin block - header := tmproto.Header{ + header := cmtproto.Header{ ChainID: chainID, Height: 1, Time: coord.CurrentTime.UTC(), @@ -79,36 +152,471 @@ func NewTestChain(t *testing.T, coord *ibcgotesting.Coordinator, chainID string) txConfig := app.GetTxConfig() // create an account to send transactions from - chain := &ibcgotesting.TestChain{ - TB: t, - Coordinator: coord, - ChainID: chainID, - App: app, - CurrentHeader: header, - QueryServer: app.GetIBCKeeper(), - TxConfig: txConfig, - Codec: app.AppCodec(), - Vals: valSet, - Signers: signers, - SenderPrivKey: senderPrivKey, - SenderAccount: baseAcc, - NextVals: valSet, - } - - coord.CommitBlock(chain) + chain := &TestChain{ + TB: tb, + Coordinator: coord, + ChainID: chainID, + App: app, + ProposedHeader: header, + TxConfig: txConfig, + Codec: app.AppCodec(), + Vals: valSet, + NextVals: valSet, + Signers: signers, + TrustedValidators: make(map[uint64]*cmttypes.ValidatorSet, 0), + SenderPrivKey: senderAccs[0].SenderPrivKey, + SenderAccount: senderAccs[0].SenderAccount, + SenderAccounts: senderAccs, + } + + // commit genesis block + chain.NextBlock() return chain } -func NewTransferPath(chainA, chainB *ibcgotesting.TestChain) *Path { - path := NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = ibcgotesting.TransferPort - path.EndpointB.ChannelConfig.PortID = ibcgotesting.TransferPort +// NewTestChain initializes a new test chain with a default of 4 validators +// Use this function if the tests do not need custom control over the validator set +func NewTestChain(t *testing.T, isEVM bool, coord *Coordinator, chainID string) *TestChain { + t.Helper() + // generate validator private/public key + var ( + validatorsPerChain = 4 + validators []*cmttypes.Validator + signersByAddress = make(map[string]cmttypes.PrivValidator, validatorsPerChain) + ) + + for i := 0; i < validatorsPerChain; i++ { + _, privVal := cmttypes.RandValidator(false, 100) + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + validators = append(validators, cmttypes.NewValidator(pubKey, 1)) + signersByAddress[pubKey.Address().String()] = privVal + } + // construct validator set; + // Note that the validators are sorted by voting power + // or, if equal, by address lexical order + valSet := cmttypes.NewValidatorSet(validators) + + return NewTestChainWithValSet(t, isEVM, coord, chainID, valSet, signersByAddress) +} + +// GetContext returns the current context for the application. +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.GetBaseApp().NewUncachedContext(false, chain.ProposedHeader) +} + +// GetSimApp returns the SimApp to allow usage ofnon-interface fields. +// CONTRACT: This function should not be called by third parties implementing +// their own SimApp. +func (chain *TestChain) GetSimApp() *simapp.SimApp { + app, ok := chain.App.(*simapp.SimApp) + require.True(chain.TB, ok) + + return app +} + +// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. +func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { + return chain.QueryProofAtHeight(key, chain.App.LastBlockHeight()) +} + +// QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. Only the IBC +// store is supported +func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) { + return chain.QueryProofForStore(exported.StoreKey, key, height) +} + +// QueryProofForStore performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. +func (chain *TestChain) QueryProofForStore(storeKey string, key []byte, height int64) ([]byte, clienttypes.Height) { + res, err := chain.App.Query( + chain.GetContext().Context(), + &abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", storeKey), + Height: height - 1, + Data: key, + Prove: true, + }) + require.NoError(chain.TB, err) + + merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) + require.NoError(chain.TB, err) + + proof, err := chain.App.AppCodec().Marshal(&merkleProof) + require.NoError(chain.TB, err) + + revision := clienttypes.ParseChainID(chain.ChainID) + + // proof height + 1 is returned as the proof created corresponds to the height the proof + // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it + // have heights 1 above the IAVL tree. Thus we return proof height + 1 + return proof, clienttypes.NewHeight(revision, uint64(res.Height)+1) +} + +// QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. +func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) { + res, err := chain.App.Query( + chain.GetContext().Context(), + &abci.RequestQuery{ + Path: "store/upgrade/key", + Height: int64(height - 1), + Data: key, + Prove: true, + }) + require.NoError(chain.TB, err) + + merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) + require.NoError(chain.TB, err) + + proof, err := chain.App.AppCodec().Marshal(&merkleProof) + require.NoError(chain.TB, err) + + revision := clienttypes.ParseChainID(chain.ChainID) + + // proof height + 1 is returned as the proof created corresponds to the height the proof + // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it + // have heights 1 above the IAVL tree. Thus we return proof height + 1 + return proof, clienttypes.NewHeight(revision, uint64(res.Height+1)) +} - path.EndpointA.ChannelConfig.Order = channeltypes.UNORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.UNORDERED - path.EndpointA.ChannelConfig.Version = "ics20-1" - path.EndpointB.ChannelConfig.Version = "ics20-1" +// QueryConsensusStateProof performs an abci query for a consensus state +// stored on the given clientID. The proof and consensusHeight are returned. +func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) { + consensusHeight, ok := chain.GetClientLatestHeight(clientID).(clienttypes.Height) + require.True(chain.TB, ok) + consensusKey := host.FullConsensusStateKey(clientID, consensusHeight) + consensusProof, _ := chain.QueryProof(consensusKey) - return path + return consensusProof, consensusHeight +} + +// NextBlock sets the last header to the current header and increments the current header to be +// at the next block height. It does not update the time as that is handled by the Coordinator. +// It will call FinalizeBlock and Commit and apply the validator set changes to the next validators +// of the next block being created. This follows the Tendermint protocol of applying valset changes +// returned on block `n` to the validators of block `n+2`. +// It calls BeginBlock with the new block created before returning. +func (chain *TestChain) NextBlock() { + res, err := chain.App.FinalizeBlock(&abci.RequestFinalizeBlock{ + Height: chain.ProposedHeader.Height, + Time: chain.ProposedHeader.GetTime(), + NextValidatorsHash: chain.NextVals.Hash(), + ProposerAddress: chain.ProposedHeader.ProposerAddress, + }) + require.NoError(chain.TB, err) + chain.commitBlock(res) +} + +func (chain *TestChain) commitBlock(res *abci.ResponseFinalizeBlock) { + _, err := chain.App.Commit() + require.NoError(chain.TB, err) + + // set the last header to the current header + // use nil trusted fields + chain.LatestCommittedHeader = chain.CurrentTMClientHeader() + // set the trusted validator set to the next validator set + // The latest trusted validator set is the next validator set + // associated with the header being committed in storage. This will + // allow for header updates to be proved against these validators. + chain.TrustedValidators[uint64(chain.ProposedHeader.Height)] = chain.NextVals + + // val set changes returned from previous block get applied to the next validators + // of this block. See tendermint spec for details. + chain.Vals = chain.NextVals + chain.NextVals = ibctesting.ApplyValSetChanges(chain, chain.Vals, res.ValidatorUpdates) + + // increment the proposer priority of validators + chain.Vals.IncrementProposerPriority(1) + + // increment the current header + chain.ProposedHeader = cmtproto.Header{ + ChainID: chain.ChainID, + Height: chain.App.LastBlockHeight() + 1, + AppHash: chain.App.LastCommitID().Hash, + // NOTE: the time is increased by the coordinator to maintain time synchrony amongst + // chains. + Time: chain.ProposedHeader.Time, + ValidatorsHash: chain.Vals.Hash(), + NextValidatorsHash: chain.NextVals.Hash(), + ProposerAddress: chain.Vals.Proposer.Address, + } +} + +// sendMsgs delivers a transaction through the application without returning the result. +func (chain *TestChain) sendMsgs(msgs ...sdk.Msg) error { + _, err := chain.SendMsgs(msgs...) + return err +} + +// SendMsgs delivers a transaction through the application using a predefined sender. +// It updates the senders sequence number and updates the TestChain's headers. +// It returns the result and error if one occurred. +func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) { + senderAccount := SenderAccount{ + SenderPrivKey: chain.SenderPrivKey, + SenderAccount: chain.SenderAccount, + } + + return chain.SendMsgsWithSender(senderAccount, msgs...) +} + +// SendMsgsWithSender delivers a transaction through the application using the provided sender. +func (chain *TestChain) SendMsgsWithSender(sender SenderAccount, msgs ...sdk.Msg) (*abci.ExecTxResult, error) { + if chain.SendMsgsOverride != nil { + return chain.SendMsgsOverride(msgs...) + } + + // ensure the chain has the latest time + chain.Coordinator.UpdateTimeForChain(chain) + + // increment acc sequence regardless of success or failure tx execution + defer func() { + err := sender.SenderAccount.SetSequence(sender.SenderAccount.GetSequence() + 1) + if err != nil { + panic(err) + } + }() + + resp, err := SignAndDeliver( + chain.TB, + sdk.AccAddress(chain.ProposedHeader.ProposerAddress), + chain.TxConfig, + chain.App.GetBaseApp(), + msgs, + chain.ChainID, + []uint64{sender.SenderAccount.GetAccountNumber()}, + []uint64{sender.SenderAccount.GetSequence()}, + true, + chain.ProposedHeader.GetTime(), + chain.NextVals.Hash(), + sender.SenderPrivKey, + ) + if err != nil { + return nil, err + } + + chain.commitBlock(resp) + + require.Len(chain.TB, resp.TxResults, 1) + txResult := resp.TxResults[0] + + if txResult.Code != 0 { + return txResult, fmt.Errorf("%s/%d: %q", txResult.Codespace, txResult.Code, txResult.Log) + } + + chain.Coordinator.IncrementTime() + + return txResult, nil +} + +// GetClientState retrieves the client state for the provided clientID. The client is +// expected to exist otherwise testing will fail. +func (chain *TestChain) GetClientState(clientID string) exported.ClientState { + clientState, found := chain.App.GetIBCKeeper().ClientKeeper.GetClientState(chain.GetContext(), clientID) + require.True(chain.TB, found) + + return clientState +} + +// GetConsensusState retrieves the consensus state for the provided clientID and height. +// It will return a success boolean depending on if consensus state exists or not. +func (chain *TestChain) GetConsensusState(clientID string, height exported.Height) (exported.ConsensusState, bool) { + return chain.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(chain.GetContext(), clientID, height) +} + +// GetAcknowledgement retrieves an acknowledgement for the provided packet. If the +// acknowledgement does not exist then testing will fail. +func (chain *TestChain) GetAcknowledgement(packet channeltypes.Packet) []byte { + ack, found := chain.App.GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + require.True(chain.TB, found) + + return ack +} + +// GetPrefix returns the prefix for used by a chain in connection creation +func (chain *TestChain) GetPrefix() commitmenttypes.MerklePrefix { + return commitmenttypes.NewMerklePrefix(chain.App.GetIBCKeeper().ConnectionKeeper.GetCommitmentPrefix().Bytes()) +} + +// ExpireClient fast forwards the chain's block time by the provided amount of time which will +// expire any clients with a trusting period less than or equal to this amount of time. +func (chain *TestChain) ExpireClient(amount time.Duration) { + chain.Coordinator.IncrementTimeBy(amount) +} + +// CurrentTMClientHeader creates a TM header using the current header parameters +// on the chain. The trusted fields in the header are set to nil. +func (chain *TestChain) CurrentTMClientHeader() *ibctm.Header { + return chain.CreateTMClientHeader( + chain.ChainID, + chain.ProposedHeader.Height, + clienttypes.Height{}, + chain.ProposedHeader.Time, + chain.Vals, + chain.NextVals, + nil, + chain.Signers, + ) +} + +// CommitHeader takes in a proposed header and returns a signed cometbft header. +// The signers passed in must match the validator set provided. The signers will +// be used to sign over the proposed header. +func CommitHeader(proposedHeader cmttypes.Header, valSet *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator) (*cmtproto.SignedHeader, error) { + hhash := proposedHeader.Hash() + blockID := MakeBlockID(hhash, 3, unusedHash) + voteSet := cmttypes.NewVoteSet(proposedHeader.ChainID, proposedHeader.Height, 1, cmtproto.PrecommitType, valSet) + + // MakeExtCommit expects a signer array in the same order as the validator array. + // Thus we iterate over the ordered validator set and construct a signer array + // from the signer map in the same order. + signerArr := make([]cmttypes.PrivValidator, len(valSet.Validators)) + for i, v := range valSet.Validators { //nolint:staticcheck // need to check for nil validator set + signerArr[i] = signers[v.Address.String()] + } + + extCommit, err := cmttypes.MakeExtCommit(blockID, proposedHeader.Height, 1, voteSet, signerArr, proposedHeader.Time, false) + if err != nil { + return nil, err + } + + signedHeader := &cmtproto.SignedHeader{ + Header: proposedHeader.ToProto(), + Commit: extCommit.ToCommit().ToProto(), + } + + return signedHeader, nil +} + +// CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow +// caller flexibility to use params that differ from the chain. +func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, cmtValSet, nextVals, cmtTrustedVals *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator) *ibctm.Header { + var ( + valSet *cmtproto.ValidatorSet + trustedVals *cmtproto.ValidatorSet + ) + require.NotNil(chain.TB, cmtValSet) + + proposedHeader := cmttypes.Header{ + Version: cmtprotoversion.Consensus{Block: cmtversion.BlockProtocol, App: 2}, + ChainID: chainID, + Height: blockHeight, + Time: timestamp, + LastBlockID: MakeBlockID(make([]byte, tmhash.Size), 10_000, make([]byte, tmhash.Size)), + LastCommitHash: chain.App.LastCommitID().Hash, + DataHash: unusedHash, + ValidatorsHash: cmtValSet.Hash(), + NextValidatorsHash: nextVals.Hash(), + ConsensusHash: unusedHash, + AppHash: chain.ProposedHeader.AppHash, + LastResultsHash: unusedHash, + EvidenceHash: unusedHash, + ProposerAddress: cmtValSet.Proposer.Address, //nolint:staticcheck + } + + signedHeader, err := CommitHeader(proposedHeader, cmtValSet, signers) + require.NoError(chain.TB, err) + + if cmtValSet != nil { //nolint:staticcheck + valSet, err = cmtValSet.ToProto() + require.NoError(chain.TB, err) + valSet.TotalVotingPower = cmtValSet.TotalVotingPower() + } + + if cmtTrustedVals != nil { + trustedVals, err = cmtTrustedVals.ToProto() + require.NoError(chain.TB, err) + trustedVals.TotalVotingPower = cmtTrustedVals.TotalVotingPower() + } + + // The trusted fields may be nil. They may be filled before relaying messages to a client. + // The relayer is responsible for querying client and injecting appropriate trusted fields. + return &ibctm.Header{ + SignedHeader: signedHeader, + ValidatorSet: valSet, + TrustedHeight: trustedHeight, + TrustedValidators: trustedVals, + } +} + +// MakeBlockID copied unimported test functions from cmttypes to use them here +func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) cmttypes.BlockID { + return cmttypes.BlockID{ + Hash: hash, + PartSetHeader: cmttypes.PartSetHeader{ + Total: partSetSize, + Hash: partSetHash, + }, + } +} + +// GetClientLatestHeight returns the latest height for the client state with the given client identifier. +// If an invalid client identifier is provided then a zero value height will be returned and testing will fail. +func (chain *TestChain) GetClientLatestHeight(clientID string) exported.Height { + latestHeight := chain.App.GetIBCKeeper().ClientKeeper.GetClientLatestHeight(chain.GetContext(), clientID) + require.False(chain.TB, latestHeight.IsZero()) + return latestHeight +} + +// GetTimeoutHeight is a convenience function which returns a IBC packet timeout height +// to be used for testing. It returns the current IBC height + 100 blocks +func (chain *TestChain) GetTimeoutHeight() clienttypes.Height { + return clienttypes.NewHeight(clienttypes.ParseChainID(chain.ChainID), uint64(chain.GetContext().BlockHeight())+100) +} + +// GetTimeoutTimestamp is a convenience function which returns a IBC packet timeout timestamp +// to be used for testing. It returns the current block timestamp + default timestamp delta (1 hour). +func (chain *TestChain) GetTimeoutTimestamp() uint64 { + return uint64(chain.GetContext().BlockTime().UnixNano()) + DefaultTimeoutTimestampDelta +} + +// GetTimeoutTimestampSecs is a convenience function which returns a IBC packet timeout timestamp in seconds +// to be used for testing. It returns the current block timestamp + default timestamp delta (1 hour). +func (chain *TestChain) GetTimeoutTimestampSecs() uint64 { + return uint64(chain.GetContext().BlockTime().Unix()) + uint64(time.Hour.Seconds()) +} + +// DeleteKey deletes the specified key from the ibc store. +func (chain *TestChain) DeleteKey(key []byte) { + storeKey := chain.GetSimApp().GetKey(exported.StoreKey) + kvStore := chain.GetContext().KVStore(storeKey) + kvStore.Delete(key) +} + +// IBCClientHeader will construct a 07-tendermint Header to update the light client +// on the counterparty chain. The trustedHeight must be passed in as a non-zero height. +func (chain *TestChain) IBCClientHeader(header *ibctm.Header, trustedHeight clienttypes.Height) (*ibctm.Header, error) { + if trustedHeight.IsZero() { + return nil, errorsmod.Wrap(ibctm.ErrInvalidHeaderHeight, "trustedHeight must be a non-zero height") + } + + cmtTrustedVals, ok := chain.TrustedValidators[trustedHeight.RevisionHeight] + if !ok { + return nil, fmt.Errorf("unable to find trusted validators at height %d", trustedHeight.RevisionHeight) + } + + trustedVals, err := cmtTrustedVals.ToProto() + if err != nil { + return nil, err + } + + header.TrustedHeight = trustedHeight + trustedVals.TotalVotingPower = cmtTrustedVals.TotalVotingPower() + header.TrustedValidators = trustedVals + + return header, nil +} + +// GetSenderAccount returns the sender account associated with the provided private key. +func (chain *TestChain) GetSenderAccount(privKey cryptotypes.PrivKey) SenderAccount { + account := chain.GetSimApp().AccountKeeper.GetAccount(chain.GetContext(), sdk.AccAddress(privKey.PubKey().Address())) + + return SenderAccount{ + SenderPrivKey: privKey, + SenderAccount: account, + } } diff --git a/ibc/testing/config.go b/ibc/testing/config.go new file mode 100644 index 000000000..879d61d07 --- /dev/null +++ b/ibc/testing/config.go @@ -0,0 +1,61 @@ +package ibctesting + +import ( + "time" + + connectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v10/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v10/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v10/testing/mock" +) + +type ClientConfig interface { + GetClientType() string +} + +type TendermintConfig struct { + TrustLevel ibctm.Fraction + TrustingPeriod time.Duration + UnbondingPeriod time.Duration + MaxClockDrift time.Duration +} + +func NewTendermintConfig() *TendermintConfig { + return &TendermintConfig{ + TrustLevel: DefaultTrustLevel, + TrustingPeriod: TrustingPeriod, + UnbondingPeriod: UnbondingPeriod, + MaxClockDrift: MaxClockDrift, + } +} + +func (*TendermintConfig) GetClientType() string { + return exported.Tendermint +} + +type ConnectionConfig struct { + DelayPeriod uint64 + Version *connectiontypes.Version +} + +func NewConnectionConfig() *ConnectionConfig { + return &ConnectionConfig{ + DelayPeriod: DefaultDelayPeriod, + Version: ConnectionVersion, + } +} + +type ChannelConfig struct { + PortID string + Version string + Order channeltypes.Order +} + +func NewChannelConfig() *ChannelConfig { + return &ChannelConfig{ + PortID: mock.PortID, + Version: DefaultChannelVersion, + Order: channeltypes.UNORDERED, + } +} diff --git a/ibc/testing/coordinator.go b/ibc/testing/coordinator.go index 99c0d4141..ebd856fa9 100644 --- a/ibc/testing/coordinator.go +++ b/ibc/testing/coordinator.go @@ -1,48 +1,56 @@ package ibctesting import ( - "math/rand" + "fmt" + "strconv" "testing" "time" + ibctesting "github.com/cosmos/ibc-go/v10/testing" "github.com/stretchr/testify/require" - exampleapp "github.com/cosmos/evm/evmd" - ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/evm/evmd" +) - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/client" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" +var ( + ChainIDPrefix = "testchain" + // to disable revision format, set ChainIDSuffix to "" + ChainIDSuffix = "-1" + globalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + TimeIncrement = time.Second * 5 ) -const DefaultFeeAmt = int64(150_000_000_000_000_000) // 0.15 ATOM +// Coordinator is a testing struct which contains N TestChain's. It handles keeping all chains +// in sync with regards to time. +type Coordinator struct { + *testing.T -var globalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + CurrentTime time.Time + Chains map[string]*TestChain +} // NewCoordinator initializes Coordinator with N EVM TestChain's (Cosmos EVM apps) and M Cosmos chains (Simulation Apps) -func NewCoordinator(t *testing.T, nEVMChains, mCosmosChains int) *ibctesting.Coordinator { +func NewCoordinator(t *testing.T, nEVMChains, mCosmosChains int) *Coordinator { t.Helper() - chains := make(map[string]*ibctesting.TestChain) - coord := &ibctesting.Coordinator{ + chains := make(map[string]*TestChain) + coord := &Coordinator{ T: t, CurrentTime: globalStartTime, } + evmd.EvmAppOptions("cosmos_9001-1") + ibctesting.DefaultTestingAppInit = SetupExampleApp for i := 1; i <= nEVMChains; i++ { - chainID := ibctesting.GetChainID(i) + chainID := GetChainID(i) // setup EVM chains - ibctesting.DefaultTestingAppInit = DefaultTestingAppInit(chainID) - chains[chainID] = NewTestChain(t, coord, chainID) + chains[chainID] = NewTestChain(t, true, coord, chainID) } // setup Cosmos chains ibctesting.DefaultTestingAppInit = ibctesting.SetupTestingApp - for j := 1 + nEVMChains; j <= nEVMChains+mCosmosChains; j++ { - chainID := ibctesting.GetChainID(j) - chains[chainID] = ibctesting.NewTestChain(t, coord, chainID) + chainID := GetChainID(j) + chains[chainID] = NewTestChain(t, false, coord, chainID) } coord.Chains = chains @@ -50,160 +58,120 @@ func NewCoordinator(t *testing.T, nEVMChains, mCosmosChains int) *ibctesting.Coo return coord } -// SetupPath constructs a TM client, connection, and channel on both chains provided. It will -// fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned -// for both chains. The channels created are connected to the ibc-transfer application. -func SetupPath(coord *ibctesting.Coordinator, path *Path) { - SetupConnections(coord, path) - - // channels can also be referenced through the returned connections - CreateChannels(coord, path) +// IncrementTime iterates through all the TestChain's and increments their current header time +// by 5 seconds. +// +// CONTRACT: this function must be called after every Commit on any TestChain. +func (coord *Coordinator) IncrementTime() { + coord.IncrementTimeBy(TimeIncrement) } -// SetupConnections is a helper function to create clients and the appropriate -// connections on both the source and counterparty chain. It assumes the caller does not -// anticipate any errors. -func SetupConnections(coord *ibctesting.Coordinator, path *Path) { - SetupClients(coord, path) - - CreateConnections(coord, path) +// IncrementTimeBy iterates through all the TestChain's and increments their current header time +// by specified time. +func (coord *Coordinator) IncrementTimeBy(increment time.Duration) { + coord.CurrentTime = coord.CurrentTime.Add(increment).UTC() + coord.UpdateTime() } -// CreateChannel constructs and executes channel handshake messages in order to create -// OPEN channels on chainA and chainB. The function expects the channels to be successfully -// opened otherwise testing will fail. -func CreateChannels(coord *ibctesting.Coordinator, path *Path) { - err := path.EndpointA.ChanOpenInit() - require.NoError(coord.T, err) +// UpdateTime updates all clocks for the TestChains to the current global time. +func (coord *Coordinator) UpdateTime() { + for _, chain := range coord.Chains { + coord.UpdateTimeForChain(chain) + } +} - err = path.EndpointB.ChanOpenTry() - require.NoError(coord.T, err) +// UpdateTimeForChain updates the clock for a specific chain. +func (coord *Coordinator) UpdateTimeForChain(chain *TestChain) { + chain.ProposedHeader.Time = coord.CurrentTime.UTC() +} - err = path.EndpointA.ChanOpenAck() - require.NoError(coord.T, err) +// Setup constructs a TM client, connection, and channel on both chains provided. It will +// fail if any error occurs. +// Deprecated: please use path.Setup(), this function will be removed in v10 +func (*Coordinator) Setup(path *Path) { + path.Setup() +} - err = path.EndpointB.ChanOpenConfirm() - require.NoError(coord.T, err) +// SetupClients is a helper function to create clients on both chains. It assumes the +// caller does not anticipate any errors. +// Deprecated: please use path.SetupClients(), this function will be removed in v10 +func (*Coordinator) SetupClients(path *Path) { + path.SetupClients() +} - // ensure counterparty is up to date - err = path.EndpointA.UpdateClient() - require.NoError(coord.T, err) +// SetupConnections is a helper function to create clients and the appropriate +// connections on both the source and counterparty chain. It assumes the caller does not +// anticipate any errors. +// Deprecated: please use path.SetupConnections(), this function will be removed in v10 +func (*Coordinator) SetupConnections(path *Path) { + path.SetupConnections() } -// CreateConnection constructs and executes connection handshake messages in order to create +// CreateConnections constructs and executes connection handshake messages in order to create // OPEN channels on chainA and chainB. The connection information of for chainA and chainB // are returned within a TestConnection struct. The function expects the connections to be // successfully opened otherwise testing will fail. -func CreateConnections(coord *ibctesting.Coordinator, path *Path) { - err := path.EndpointA.ConnOpenInit() - require.NoError(coord.T, err) - - err = path.EndpointB.ConnOpenTry() - require.NoError(coord.T, err) - - err = path.EndpointA.ConnOpenAck() - require.NoError(coord.T, err) +// Deprecated: please use path.CreateConnections(), this function will be removed in v10 +func (*Coordinator) CreateConnections(path *Path) { + path.CreateConnections() +} - err = path.EndpointB.ConnOpenConfirm() - require.NoError(coord.T, err) +// CreateMockChannels constructs and executes channel handshake messages to create OPEN +// channels that use a mock application module that returns nil on all callbacks. This +// function is expects the channels to be successfully opened otherwise testing will +// fail. +func (*Coordinator) CreateMockChannels(path *Path) { + path.EndpointA.ChannelConfig.PortID = MockPort + path.EndpointB.ChannelConfig.PortID = MockPort - // ensure counterparty is up to date - err = path.EndpointA.UpdateClient() - require.NoError(coord.T, err) + path.CreateChannels() } -// SetupClients is a helper function to create clients on both chains. It assumes the -// caller does not anticipate any errors. -func SetupClients(coord *ibctesting.Coordinator, path *Path) { - err := path.EndpointA.CreateClient() - require.NoError(coord.T, err) - - err = path.EndpointB.CreateClient() - require.NoError(coord.T, err) -} - -func SendMsgs(chain *ibctesting.TestChain, feeAmt int64, msgs ...sdk.Msg) (*sdk.Result, error) { - var ( - bondDenom string - err error - ) - // ensure the chain has the latest time - chain.Coordinator.UpdateTimeForChain(chain) - - if cosmosEVMChain, ok := chain.App.(*exampleapp.EVMD); ok { - bondDenom, err = cosmosEVMChain.StakingKeeper.BondDenom(chain.GetContext()) - } else { - bondDenom, err = chain.GetSimApp().StakingKeeper.BondDenom(chain.GetContext()) - } - if err != nil { - return nil, err - } - - fee := sdk.Coins{sdk.NewInt64Coin(bondDenom, feeAmt)} - _, r, err := SignAndDeliver( - chain.TB, - chain.TxConfig, - chain.App.GetBaseApp(), - msgs, - fee, - chain.ChainID, - []uint64{chain.SenderAccount.GetAccountNumber()}, - []uint64{chain.SenderAccount.GetSequence()}, - true, chain.SenderPrivKey, - ) - if err != nil { - return nil, err - } +// CreateTransferChannels constructs and executes channel handshake messages to create OPEN +// ibc-transfer channels on chainA and chainB. The function expects the channels to be +// successfully opened otherwise testing will fail. +func (*Coordinator) CreateTransferChannels(path *Path) { + path.EndpointA.ChannelConfig.PortID = TransferPort + path.EndpointB.ChannelConfig.PortID = TransferPort - // NextBlock calls app.Commit() - chain.NextBlock() + path.CreateChannels() +} - // increment sequence for successful transaction execution - err = chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) - if err != nil { - return nil, err - } +// CreateChannels constructs and executes channel handshake messages in order to create +// OPEN channels on chainA and chainB. The function expects the channels to be successfully +// opened otherwise testing will fail. +// Deprecated: please use path.CreateChannels(), this function will be removed in v10 +func (*Coordinator) CreateChannels(path *Path) { + path.CreateChannels() +} - chain.Coordinator.IncrementTime() +// GetChain returns the TestChain using the given chainID and returns an error if it does +// not exist. +func (coord *Coordinator) GetChain(chainID string) *TestChain { + chain, found := coord.Chains[chainID] + require.True(coord.T, found, fmt.Sprintf("%s chain does not exist", chainID)) + return chain +} - return r, nil +// GetChainID returns the chainID used for the provided index. +func GetChainID(index int) string { + return ChainIDPrefix + strconv.Itoa(index) + ChainIDSuffix } -// SignAndDeliver signs and delivers a transaction. No simulation occurs as the -// ibc testing package causes checkState and deliverState to diverge in block time. +// CommitBlock commits a block on the provided indexes and then increments the global time. // -// CONTRACT: BeginBlock must be called before this function. -// Is a customization of IBC-go function that allows to modify the fee denom and amount -// IBC-go implementation: https://github.com/cosmos/ibc-go/blob/d34cef7e075dda1a24a0a3e9b6d3eff406cc606c/testing/simapp/test_helpers.go#L332-L364 -func SignAndDeliver( - tb testing.TB, txCfg client.TxConfig, app *baseapp.BaseApp, msgs []sdk.Msg, - fee sdk.Coins, - chainID string, accNums, accSeqs []uint64, expPass bool, priv ...cryptotypes.PrivKey, -) (sdk.GasInfo, *sdk.Result, error) { - tb.Helper() - tx, err := simtestutil.GenSignedMockTx( - rand.New(rand.NewSource(time.Now().UnixNano())), - txCfg, - msgs, - fee, - simtestutil.DefaultGenTxGas, - chainID, - accNums, - accSeqs, - priv..., - ) - require.NoError(tb, err) - - // Simulate a sending a transaction - gInfo, res, err := app.SimDeliver(txCfg.TxEncoder(), tx) - - if expPass { - require.NoError(tb, err) - require.NotNil(tb, res) - } else { - require.Error(tb, err) - require.Nil(tb, res) +// CONTRACT: the passed in list of indexes must not contain duplicates +func (coord *Coordinator) CommitBlock(chains ...*TestChain) { + for _, chain := range chains { + chain.NextBlock() } + coord.IncrementTime() +} - return gInfo, res, err +// CommitNBlocks commits n blocks to state and updates the block height by 1 for each commit. +func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) { + for i := uint64(0); i < n; i++ { + chain.NextBlock() + coord.IncrementTime() + } } diff --git a/ibc/testing/endpoint.go b/ibc/testing/endpoint.go index 51fdfc262..bf1f909b8 100644 --- a/ibc/testing/endpoint.go +++ b/ibc/testing/endpoint.go @@ -1,22 +1,24 @@ package ibctesting import ( + "errors" "fmt" - "time" + "strings" "github.com/stretchr/testify/require" - // For now we'll keep this. Pending to review if we can remove it - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" - "github.com/cosmos/ibc-go/v8/modules/core/exported" - ibclightclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/ibc-go/v8/testing" - - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/baseapp" + + abci "github.com/cometbft/cometbft/abci/types" + + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v10/modules/core/23-commitment/types" + commitmenttypesv2 "github.com/cosmos/ibc-go/v10/modules/core/23-commitment/types/v2" + host "github.com/cosmos/ibc-go/v10/modules/core/24-host" + "github.com/cosmos/ibc-go/v10/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v10/modules/light-clients/07-tendermint" ) // Endpoint is a which represents a channel endpoint and its associated @@ -24,57 +26,64 @@ import ( // configuration parameters. Endpoint functions will utilize the parameters // set in the configuration structs when executing IBC messages. type Endpoint struct { - Chain *ibctesting.TestChain + Chain *TestChain Counterparty *Endpoint ClientID string ConnectionID string ChannelID string - ClientConfig ibctesting.ClientConfig - ConnectionConfig *ibctesting.ConnectionConfig - ChannelConfig *ibctesting.ChannelConfig + ClientConfig ClientConfig + ConnectionConfig *ConnectionConfig + ChannelConfig *ChannelConfig + + MerklePathPrefix commitmenttypesv2.MerklePath + // disableUniqueChannelIDs is used to enforce, in a test, + // the old way to generate channel IDs (all channels are called channel-0) + // It is used only by one test suite and should not be used for new tests. + disableUniqueChannelIDs bool } // NewEndpoint constructs a new endpoint without the counterparty. // CONTRACT: the counterparty endpoint must be set by the caller. func NewEndpoint( - chain *ibctesting.TestChain, clientConfig ibctesting.ClientConfig, - connectionConfig *ibctesting.ConnectionConfig, channelConfig *ibctesting.ChannelConfig, + chain *TestChain, clientConfig ClientConfig, + connectionConfig *ConnectionConfig, channelConfig *ChannelConfig, ) *Endpoint { return &Endpoint{ Chain: chain, ClientConfig: clientConfig, ConnectionConfig: connectionConfig, ChannelConfig: channelConfig, + MerklePathPrefix: MerklePath, } } // NewDefaultEndpoint constructs a new endpoint using default values. // CONTRACT: the counterparty endpoitn must be set by the caller. -func NewDefaultEndpoint(chain *ibctesting.TestChain) *Endpoint { +func NewDefaultEndpoint(chain *TestChain) *Endpoint { return &Endpoint{ Chain: chain, - ClientConfig: ibctesting.NewTendermintConfig(), - ConnectionConfig: ibctesting.NewConnectionConfig(), - ChannelConfig: ibctesting.NewChannelConfig(), + ClientConfig: NewTendermintConfig(), + ConnectionConfig: NewConnectionConfig(), + ChannelConfig: NewChannelConfig(), + MerklePathPrefix: MerklePath, } } // QueryProof queries proof associated with this endpoint using the latest client state // height on the counterparty chain. func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) { - // obtain the counterparty client representing the chain associated with the endpoint - clientState := endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) - + // obtain the counterparty client height. + latestCounterpartyHeight := endpoint.Counterparty.GetClientLatestHeight() // query proof on the counterparty using the latest height of the IBC client - return endpoint.QueryProofAtHeight(key, clientState.GetLatestHeight().GetRevisionHeight()) + return endpoint.QueryProofAtHeight(key, latestCounterpartyHeight.GetRevisionHeight()) } // QueryProofAtHeight queries proof associated with this endpoint using the proof height // provided func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) { // query proof on the counterparty using the latest height of the IBC client - return endpoint.Chain.QueryProofAtHeight(key, int64(height)) //#nosec G115 + return endpoint.Chain.QueryProofAtHeight(key, int64(height)) } // CreateClient creates an IBC client on the endpoint. It will update the @@ -91,17 +100,20 @@ func (endpoint *Endpoint) CreateClient() (err error) { switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: - tmConfig, ok := endpoint.ClientConfig.(*ibctesting.TendermintConfig) + tmConfig, ok := endpoint.ClientConfig.(*TendermintConfig) require.True(endpoint.Chain.TB, ok) - height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height) - clientState = ibclightclient.NewClientState( + height, ok := endpoint.Counterparty.Chain.LatestCommittedHeader.GetHeight().(clienttypes.Height) + require.True(endpoint.Chain.TB, ok) + clientState = ibctm.NewClientState( endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift, - height, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, - ) - consensusState = endpoint.Counterparty.Chain.LastHeader.ConsensusState() + height, commitmenttypes.GetSDKSpecs(), UpgradePath) + consensusState = endpoint.Counterparty.Chain.LatestCommittedHeader.ConsensusState() case exported.Solomachine: - + // TODO + // solo := NewSolomachine(endpoint.Chain.TB, endpoint.Chain.Codec, clientID, "", 1) + // clientState = solo.ClientState() + // consensusState = solo.ConsensusState() default: err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType()) } @@ -110,29 +122,17 @@ func (endpoint *Endpoint) CreateClient() (err error) { return err } - require.NotNil( - endpoint.Chain.TB, endpoint.Chain.SenderAccount, - fmt.Sprintf("expected sender account on chain with ID %q not to be nil", endpoint.Chain.ChainID), - ) - - zeroTimestamp := uint64(time.Time{}.UnixNano()) //#nosec G115 -- will not exceed uint64 - require.NotEqual( - endpoint.Chain.TB, consensusState.GetTimestamp(), zeroTimestamp, - "current timestamp on the last header is the zero time; it might be necessary to commit blocks with the IBC coordinator", - ) - msg, err := clienttypes.NewMsgCreateClient( clientState, consensusState, endpoint.Chain.SenderAccount.GetAddress().String(), ) require.NoError(endpoint.Chain.TB, err) - require.NoError(endpoint.Chain.TB, msg.ValidateBasic(), "failed to validate create client msg") - res, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) + res, err := endpoint.Chain.SendMsgs(msg) if err != nil { return err } - endpoint.ClientID, err = ibctesting.ParseClientIDFromEvents(res.GetEvents().ToABCIEvents()) + endpoint.ClientID, err = ParseClientIDFromEvents(res.Events) require.NoError(endpoint.Chain.TB, err) return nil @@ -143,12 +143,13 @@ func (endpoint *Endpoint) UpdateClient() (err error) { // ensure counterparty has committed state endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) - var header *ibclightclient.Header + var header exported.ClientMessage switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: - header, err = endpoint.Chain.ConstructUpdateTMClientHeader(endpoint.Counterparty.Chain, endpoint.ClientID) - + trustedHeight, ok := endpoint.GetClientLatestHeight().(clienttypes.Height) + require.True(endpoint.Chain.TB, ok) + header, err = endpoint.Counterparty.Chain.IBCClientHeader(endpoint.Counterparty.Chain.LatestCommittedHeader, trustedHeight) default: err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType()) } @@ -163,8 +164,72 @@ func (endpoint *Endpoint) UpdateClient() (err error) { ) require.NoError(endpoint.Chain.TB, err) - _, err = SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) - return err + return endpoint.Chain.sendMsgs(msg) +} + +// FreezeClient freezes the IBC client associated with the endpoint. +func (endpoint *Endpoint) FreezeClient() { + clientState := endpoint.Chain.GetClientState(endpoint.ClientID) + tmClientState, ok := clientState.(*ibctm.ClientState) + require.True(endpoint.Chain.TB, ok) + + tmClientState.FrozenHeight = clienttypes.NewHeight(0, 1) + endpoint.Chain.App.GetIBCKeeper().ClientKeeper.SetClientState(endpoint.Chain.GetContext(), endpoint.ClientID, tmClientState) +} + +// UpgradeChain will upgrade a chain's chainID to the next revision number. +// It will also update the counterparty client. +// TODO: implement actual upgrade chain functionality via scheduling an upgrade +// and upgrading the client via MsgUpgradeClient +// see reference https://github.com/cosmos/ibc-go/pull/1169 +func (endpoint *Endpoint) UpgradeChain() error { + if strings.TrimSpace(endpoint.Counterparty.ClientID) == "" { + return errors.New("cannot upgrade chain if there is no counterparty client") + } + + clientState := endpoint.Counterparty.GetClientState() + tmClientState, ok := clientState.(*ibctm.ClientState) + require.True(endpoint.Chain.TB, ok) + + // increment revision number in chainID + oldChainID := tmClientState.ChainId + if !clienttypes.IsRevisionFormat(oldChainID) { + return fmt.Errorf("cannot upgrade chain which is not of revision format: %s", oldChainID) + } + + revisionNumber := clienttypes.ParseChainID(oldChainID) + newChainID, err := clienttypes.SetRevisionNumber(oldChainID, revisionNumber+1) + if err != nil { + return err + } + + // update chain + baseapp.SetChainID(newChainID)(endpoint.Chain.App.GetBaseApp()) + endpoint.Chain.ChainID = newChainID + endpoint.Chain.ProposedHeader.ChainID = newChainID + endpoint.Chain.NextBlock() // commit changes + + // update counterparty client manually + tmClientState.ChainId = newChainID + tmClientState.LatestHeight = clienttypes.NewHeight(revisionNumber+1, tmClientState.LatestHeight.GetRevisionHeight()+1) + + endpoint.Counterparty.SetClientState(clientState) + + tmConsensusState := &ibctm.ConsensusState{ + Timestamp: endpoint.Chain.LatestCommittedHeader.GetTime(), + Root: commitmenttypes.NewMerkleRoot(endpoint.Chain.LatestCommittedHeader.Header.GetAppHash()), + NextValidatorsHash: endpoint.Chain.LatestCommittedHeader.Header.NextValidatorsHash, + } + + latestHeight := endpoint.Counterparty.GetClientLatestHeight() + + endpoint.Counterparty.SetConsensusState(tmConsensusState, latestHeight) + + // ensure the next update isn't identical to the one set in state + endpoint.Chain.Coordinator.IncrementTime() + endpoint.Chain.NextBlock() + + return endpoint.Counterparty.UpdateClient() } // ConnOpenInit will construct and execute a MsgConnectionOpenInit on the associated endpoint. @@ -172,15 +237,15 @@ func (endpoint *Endpoint) ConnOpenInit() error { msg := connectiontypes.NewMsgConnectionOpenInit( endpoint.ClientID, endpoint.Counterparty.ClientID, - endpoint.Counterparty.Chain.GetPrefix(), ibctesting.DefaultOpenInitVersion, endpoint.ConnectionConfig.DelayPeriod, + endpoint.Counterparty.Chain.GetPrefix(), DefaultOpenInitVersion, endpoint.ConnectionConfig.DelayPeriod, endpoint.Chain.SenderAccount.GetAddress().String(), ) - res, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) + res, err := endpoint.Chain.SendMsgs(msg) if err != nil { return err } - endpoint.ConnectionID, err = ibctesting.ParseConnectionIDFromEvents(res.GetEvents().ToABCIEvents()) + endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.Events) require.NoError(endpoint.Chain.TB, err) return nil @@ -191,22 +256,21 @@ func (endpoint *Endpoint) ConnOpenTry() error { err := endpoint.UpdateClient() require.NoError(endpoint.Chain.TB, err) - counterpartyClient, proofClient, proofConsensus, consensusHeight, proofInit, proofHeight := endpoint.QueryConnectionHandshakeProof() + initProof, proofHeight := endpoint.QueryConnectionHandshakeProof() msg := connectiontypes.NewMsgConnectionOpenTry( endpoint.ClientID, endpoint.Counterparty.ConnectionID, endpoint.Counterparty.ClientID, - counterpartyClient, endpoint.Counterparty.Chain.GetPrefix(), []*connectiontypes.Version{ibctesting.ConnectionVersion}, endpoint.ConnectionConfig.DelayPeriod, - proofInit, proofClient, proofConsensus, - proofHeight, consensusHeight, + endpoint.Counterparty.Chain.GetPrefix(), []*connectiontypes.Version{ConnectionVersion}, + endpoint.ConnectionConfig.DelayPeriod, initProof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), ) - res, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) + res, err := endpoint.Chain.SendMsgs(msg) if err != nil { return err } if endpoint.ConnectionID == "" { - endpoint.ConnectionID, err = ibctesting.ParseConnectionIDFromEvents(res.GetEvents().ToABCIEvents()) + endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.Events) require.NoError(endpoint.Chain.TB, err) } @@ -218,17 +282,14 @@ func (endpoint *Endpoint) ConnOpenAck() error { err := endpoint.UpdateClient() require.NoError(endpoint.Chain.TB, err) - counterpartyClient, proofClient, proofConsensus, consensusHeight, proofTry, proofHeight := endpoint.QueryConnectionHandshakeProof() + tryProof, proofHeight := endpoint.QueryConnectionHandshakeProof() msg := connectiontypes.NewMsgConnectionOpenAck( - endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, counterpartyClient, // testing doesn't use flexible selection - proofTry, proofClient, proofConsensus, - proofHeight, consensusHeight, - ibctesting.ConnectionVersion, + endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, // testing doesn't use flexible selection + tryProof, proofHeight, ConnectionVersion, endpoint.Chain.SenderAccount.GetAddress().String(), ) - _, err = SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) - return err + return endpoint.Chain.sendMsgs(msg) } // ConnOpenConfirm will construct and execute a MsgConnectionOpenConfirm on the associated endpoint. @@ -244,64 +305,62 @@ func (endpoint *Endpoint) ConnOpenConfirm() error { proof, height, endpoint.Chain.SenderAccount.GetAddress().String(), ) - _, err = SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) - return err + return endpoint.Chain.sendMsgs(msg) } // QueryConnectionHandshakeProof returns all the proofs necessary to execute OpenTry or Open Ack of -// the connection handshakes. It returns the counterparty client state, proof of the counterparty -// client state, proof of the counterparty consensus state, the consensus state height, proof of -// the counterparty connection, and the proof height for all the proofs returned. +// the connection handshakes. It returns the proof of the counterparty connection and the proof height. func (endpoint *Endpoint) QueryConnectionHandshakeProof() ( - clientState exported.ClientState, proofClient, - proofConsensus []byte, consensusHeight clienttypes.Height, - proofConnection []byte, proofHeight clienttypes.Height, + connectionProof []byte, proofHeight clienttypes.Height, ) { - // obtain the client state on the counterparty chain - clientState = endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) - - // query proof for the client state on the counterparty - clientKey := host.FullClientStateKey(endpoint.Counterparty.ClientID) - proofClient, proofHeight = endpoint.Counterparty.QueryProof(clientKey) - - consensusHeight = clientState.GetLatestHeight().(clienttypes.Height) - - // query proof for the consensus state on the counterparty - consensusKey := host.FullConsensusStateKey(endpoint.Counterparty.ClientID, consensusHeight) - proofConsensus, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight()) - // query proof for the connection on the counterparty connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID) - proofConnection, _ = endpoint.Counterparty.QueryProofAtHeight(connectionKey, proofHeight.GetRevisionHeight()) + connectionProof, proofHeight = endpoint.Counterparty.QueryProof(connectionKey) + + return connectionProof, proofHeight +} + +var sequenceNumber int - return +// IncrementNextChannelSequence incrementes the value "nextChannelSequence" in the store, +// which is used to determine the next channel ID. +// This guarantees that we'll have always different IDs while running tests. +func (endpoint *Endpoint) IncrementNextChannelSequence() { + if endpoint.disableUniqueChannelIDs { + return + } + sequenceNumber++ + endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetNextChannelSequence(endpoint.Chain.GetContext(), uint64(sequenceNumber)) } // ChanOpenInit will construct and execute a MsgChannelOpenInit on the associated endpoint. func (endpoint *Endpoint) ChanOpenInit() error { + endpoint.IncrementNextChannelSequence() msg := channeltypes.NewMsgChannelOpenInit( endpoint.ChannelConfig.PortID, endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID}, endpoint.Counterparty.ChannelConfig.PortID, endpoint.Chain.SenderAccount.GetAddress().String(), ) - res, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) + res, err := endpoint.Chain.SendMsgs(msg) if err != nil { return err } - endpoint.ChannelID, err = ibctesting.ParseChannelIDFromEvents(res.GetEvents().ToABCIEvents()) + endpoint.ChannelID, err = ParseChannelIDFromEvents(res.Events) require.NoError(endpoint.Chain.TB, err) // update version to selected app version // NOTE: this update must be performed after SendMsgs() endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + endpoint.Counterparty.ChannelConfig.Version = endpoint.GetChannel().Version return nil } // ChanOpenTry will construct and execute a MsgChannelOpenTry on the associated endpoint. func (endpoint *Endpoint) ChanOpenTry() error { + endpoint.IncrementNextChannelSequence() err := endpoint.UpdateClient() require.NoError(endpoint.Chain.TB, err) @@ -315,19 +374,20 @@ func (endpoint *Endpoint) ChanOpenTry() error { proof, height, endpoint.Chain.SenderAccount.GetAddress().String(), ) - res, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) + res, err := endpoint.Chain.SendMsgs(msg) if err != nil { return err } if endpoint.ChannelID == "" { - endpoint.ChannelID, err = ibctesting.ParseChannelIDFromEvents(res.GetEvents().ToABCIEvents()) + endpoint.ChannelID, err = ParseChannelIDFromEvents(res.Events) require.NoError(endpoint.Chain.TB, err) } // update version to selected app version // NOTE: this update must be performed after the endpoint channelID is set endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + endpoint.Counterparty.ChannelConfig.Version = endpoint.GetChannel().Version return nil } @@ -347,7 +407,7 @@ func (endpoint *Endpoint) ChanOpenAck() error { endpoint.Chain.SenderAccount.GetAddress().String(), ) - if _, err = SendMsgs(endpoint.Chain, DefaultFeeAmt, msg); err != nil { + if err = endpoint.Chain.sendMsgs(msg); err != nil { return err } @@ -369,8 +429,7 @@ func (endpoint *Endpoint) ChanOpenConfirm() error { proof, height, endpoint.Chain.SenderAccount.GetAddress().String(), ) - _, err = SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) - return err + return endpoint.Chain.sendMsgs(msg) } // ChanCloseInit will construct and execute a MsgChannelCloseInit on the associated endpoint. @@ -381,8 +440,7 @@ func (endpoint *Endpoint) ChanCloseInit() error { endpoint.ChannelConfig.PortID, endpoint.ChannelID, endpoint.Chain.SenderAccount.GetAddress().String(), ) - _, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, msg) - return err + return endpoint.Chain.sendMsgs(msg) } // SendPacket sends a packet through the channel keeper using the associated endpoint @@ -394,10 +452,8 @@ func (endpoint *Endpoint) SendPacket( timeoutTimestamp uint64, data []byte, ) (uint64, error) { - channelCap := endpoint.Chain.GetChannelCapability(endpoint.ChannelConfig.PortID, endpoint.ChannelID) - // no need to send message, acting as a module - sequence, err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), channelCap, endpoint.ChannelConfig.PortID, endpoint.ChannelID, timeoutHeight, timeoutTimestamp, data) + sequence, err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, timeoutHeight, timeoutTimestamp, data) if err != nil { return 0, err } @@ -426,7 +482,7 @@ func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error { // RecvPacketWithResult receives a packet on the associated endpoint and the result // of the transaction is returned. The counterparty client is updated. -func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*sdk.Result, error) { +func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*abci.ExecTxResult, error) { // get proof of packet commitment on source packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) proof, proofHeight := endpoint.Counterparty.Chain.QueryProof(packetKey) @@ -434,7 +490,7 @@ func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*sdk recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) // receive on counterparty and update source client - res, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, recvMsg) + res, err := endpoint.Chain.SendMsgs(recvMsg) if err != nil { return nil, err } @@ -449,10 +505,8 @@ func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*sdk // WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint. // The counterparty client is updated. func (endpoint *Endpoint) WriteAcknowledgement(ack exported.Acknowledgement, packet exported.PacketI) error { - channelCap := endpoint.Chain.GetChannelCapability(packet.GetDestPort(), packet.GetDestChannel()) - // no need to send message, acting as a handler - err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), channelCap, packet, ack) + err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), packet, ack) if err != nil { return err } @@ -471,12 +525,22 @@ func (endpoint *Endpoint) AcknowledgePacket(packet channeltypes.Packet, ack []by ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) - _, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, ackMsg) - return err + return endpoint.Chain.sendMsgs(ackMsg) } -// TimeoutPacket sends a MsgTimeout to the channel associated with the endpoint. -func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { +// AcknowledgePacketWithResult sends a MsgAcknowledgement to the channel associated with the endpoint and returns the result. +func (endpoint *Endpoint) AcknowledgePacketWithResult(packet channeltypes.Packet, ack []byte) (*abci.ExecTxResult, error) { + // get proof of acknowledgement on counterparty + packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + + ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) + + return endpoint.Chain.SendMsgs(ackMsg) +} + +// TimeoutPacketWithResult sends a MsgTimeout to the channel associated with the endpoint. +func (endpoint *Endpoint) TimeoutPacketWithResult(packet channeltypes.Packet) (*abci.ExecTxResult, error) { // get proof for timeout based on channel order var packetKey []byte @@ -486,11 +550,12 @@ func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { case channeltypes.UNORDERED: packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) default: - return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) + return nil, fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) } - proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) - nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + counterparty := endpoint.Counterparty + proof, proofHeight := counterparty.QueryProof(packetKey) + nextSeqRecv, found := counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(counterparty.Chain.GetContext(), counterparty.ChannelConfig.PortID, counterparty.ChannelID) require.True(endpoint.Chain.TB, found) timeoutMsg := channeltypes.NewMsgTimeout( @@ -498,7 +563,12 @@ func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), ) - _, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, timeoutMsg) + return endpoint.Chain.SendMsgs(timeoutMsg) +} + +// TimeoutPacket sends a MsgTimeout to the channel associated with the endpoint. +func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { + _, err := endpoint.TimeoutPacketWithResult(packet) return err } @@ -519,25 +589,25 @@ func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error { proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) - proofClosed, _ := endpoint.Counterparty.QueryProof(channelKey) + closedProof, _ := endpoint.Counterparty.QueryProof(channelKey) - nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) require.True(endpoint.Chain.TB, found) timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose( packet, nextSeqRecv, - proof, proofClosed, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + proof, closedProof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), ) - _, err := SendMsgs(endpoint.Chain, DefaultFeeAmt, timeoutOnCloseMsg) - return err + return endpoint.Chain.sendMsgs(timeoutOnCloseMsg) } -// SetChannelClosed sets a channel state to CLOSED. -func (endpoint *Endpoint) SetChannelClosed() error { +// Deprecated: usage of this function should be replaced by `UpdateChannel` +// SetChannelState sets a channel state +func (endpoint *Endpoint) SetChannelState(state channeltypes.State) error { channel := endpoint.GetChannel() - channel.State = channeltypes.CLOSED + channel.State = state endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) @@ -545,7 +615,26 @@ func (endpoint *Endpoint) SetChannelClosed() error { return endpoint.Counterparty.UpdateClient() } -// GetClientState retrieves the Client State for this endpoint. The +// UpdateChannel updates the channel associated with the given endpoint. It accepts a +// closure which takes a channel allowing the caller to modify its fields. +func (endpoint *Endpoint) UpdateChannel(updater func(channel *channeltypes.Channel)) { + channel := endpoint.GetChannel() + updater(&channel) + endpoint.SetChannel(channel) + + endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) + + err := endpoint.Counterparty.UpdateClient() + require.NoError(endpoint.Chain.TB, err) +} + +// GetClientLatestHeight returns the latest height for the client state for this endpoint. +// The client state is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetClientLatestHeight() exported.Height { + return endpoint.Chain.GetClientLatestHeight(endpoint.ClientID) +} + +// GetClientState retrieves the client state for this endpoint. The // client state is expected to exist otherwise testing will fail. func (endpoint *Endpoint) GetClientState() exported.ClientState { return endpoint.Chain.GetClientState(endpoint.ClientID) @@ -605,7 +694,16 @@ func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) clientState := endpoint.GetClientState() clientKey := host.FullClientStateKey(endpoint.ClientID) - proofClient, _ := endpoint.QueryProof(clientKey) + clientProof, _ := endpoint.QueryProof(clientKey) + + return clientState, clientProof +} + +// UpdateConnection updates the connection associated with the given endpoint. It accepts a +// closure which takes a connection allowing the caller to modify the connection fields. +func (endpoint *Endpoint) UpdateConnection(updater func(connection *connectiontypes.ConnectionEnd)) { + connection := endpoint.GetConnection() + updater(&connection) - return clientState, proofClient + endpoint.SetConnection(connection) } diff --git a/ibc/testing/endpoint_v2.go b/ibc/testing/endpoint_v2.go new file mode 100644 index 000000000..c020ccc17 --- /dev/null +++ b/ibc/testing/endpoint_v2.go @@ -0,0 +1,105 @@ +package ibctesting + +import ( + "github.com/cosmos/gogoproto/proto" + + sdk "github.com/cosmos/cosmos-sdk/types" + + clientv2types "github.com/cosmos/ibc-go/v10/modules/core/02-client/v2/types" + channeltypesv2 "github.com/cosmos/ibc-go/v10/modules/core/04-channel/v2/types" + hostv2 "github.com/cosmos/ibc-go/v10/modules/core/24-host/v2" +) + +// RegisterCounterparty will construct and execute a MsgRegisterCounterparty on the associated endpoint. +func (endpoint *Endpoint) RegisterCounterparty() (err error) { + msg := clientv2types.NewMsgRegisterCounterparty(endpoint.ClientID, endpoint.Counterparty.MerklePathPrefix.KeyPath, endpoint.Counterparty.ClientID, endpoint.Chain.SenderAccount.GetAddress().String()) + + // setup counterparty + _, err = endpoint.Chain.SendMsgs(msg) + + return err +} + +// MsgSendPacket sends a packet on the associated endpoint using a predefined sender. The constructed packet is returned. +func (endpoint *Endpoint) MsgSendPacket(timeoutTimestamp uint64, payload channeltypesv2.Payload) (channeltypesv2.Packet, error) { + senderAccount := SenderAccount{ + SenderPrivKey: endpoint.Chain.SenderPrivKey, + SenderAccount: endpoint.Chain.SenderAccount, + } + + return endpoint.MsgSendPacketWithSender(timeoutTimestamp, payload, senderAccount) +} + +// MsgSendPacketWithSender sends a packet on the associated endpoint using the provided sender. The constructed packet is returned. +func (endpoint *Endpoint) MsgSendPacketWithSender(timeoutTimestamp uint64, payload channeltypesv2.Payload, sender SenderAccount) (channeltypesv2.Packet, error) { + msgSendPacket := channeltypesv2.NewMsgSendPacket(endpoint.ClientID, timeoutTimestamp, sender.SenderAccount.GetAddress().String(), payload) + + res, err := endpoint.Chain.SendMsgsWithSender(sender, msgSendPacket) + if err != nil { + return channeltypesv2.Packet{}, err + } + + if err := endpoint.Counterparty.UpdateClient(); err != nil { + return channeltypesv2.Packet{}, err + } + + // TODO: parse the packet from events instead of from the response. https://github.com/cosmos/ibc-go/issues/7459 + // get sequence from msg response + var msgData sdk.TxMsgData + err = proto.Unmarshal(res.Data, &msgData) + if err != nil { + return channeltypesv2.Packet{}, err + } + msgResponse := msgData.MsgResponses[0] + var sendResponse channeltypesv2.MsgSendPacketResponse + err = proto.Unmarshal(msgResponse.Value, &sendResponse) + if err != nil { + return channeltypesv2.Packet{}, err + } + packet := channeltypesv2.NewPacket(sendResponse.Sequence, endpoint.ClientID, endpoint.Counterparty.ClientID, timeoutTimestamp, payload) + + return packet, nil +} + +// MsgRecvPacket sends a MsgRecvPacket on the associated endpoint with the provided packet. +func (endpoint *Endpoint) MsgRecvPacket(packet channeltypesv2.Packet) error { + // get proof of packet commitment from chainA + packetKey := hostv2.PacketCommitmentKey(packet.SourceClient, packet.Sequence) + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + + msg := channeltypesv2.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) + + if err := endpoint.Chain.sendMsgs(msg); err != nil { + return err + } + + return endpoint.Counterparty.UpdateClient() +} + +// MsgAcknowledgePacket sends a MsgAcknowledgement on the associated endpoint with the provided packet and ack. +func (endpoint *Endpoint) MsgAcknowledgePacket(packet channeltypesv2.Packet, ack channeltypesv2.Acknowledgement) error { + packetKey := hostv2.PacketAcknowledgementKey(packet.DestinationClient, packet.Sequence) + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + + msg := channeltypesv2.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) + + if err := endpoint.Chain.sendMsgs(msg); err != nil { + return err + } + + return endpoint.Counterparty.UpdateClient() +} + +// MsgTimeoutPacket sends a MsgTimeout on the associated endpoint with the provided packet. +func (endpoint *Endpoint) MsgTimeoutPacket(packet channeltypesv2.Packet) error { + packetKey := hostv2.PacketReceiptKey(packet.DestinationClient, packet.Sequence) + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + + msg := channeltypesv2.NewMsgTimeout(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) + + if err := endpoint.Chain.sendMsgs(msg); err != nil { + return err + } + + return endpoint.Counterparty.UpdateClient() +} diff --git a/ibc/testing/events.go b/ibc/testing/events.go new file mode 100644 index 000000000..0cbcc10ef --- /dev/null +++ b/ibc/testing/events.go @@ -0,0 +1,253 @@ +package ibctesting + +import ( + "encoding/hex" + "errors" + "fmt" + "slices" + "strconv" + + testifysuite "github.com/stretchr/testify/suite" + + abci "github.com/cometbft/cometbft/abci/types" + + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" +) + +// ParseClientIDFromEvents parses events emitted from a MsgCreateClient and returns the +// client identifier. +func ParseClientIDFromEvents(events []abci.Event) (string, error) { + for _, ev := range events { + if ev.Type == clienttypes.EventTypeCreateClient { + if attribute, found := attributeByKey(ev.Attributes, clienttypes.AttributeKeyClientID); found { + return attribute.Value, nil + } + } + } + return "", errors.New("client identifier event attribute not found") +} + +// ParseConnectionIDFromEvents parses events emitted from a MsgConnectionOpenInit or +// MsgConnectionOpenTry and returns the connection identifier. +func ParseConnectionIDFromEvents(events []abci.Event) (string, error) { + for _, ev := range events { + if ev.Type == connectiontypes.EventTypeConnectionOpenInit || + ev.Type == connectiontypes.EventTypeConnectionOpenTry { + if attribute, found := attributeByKey(ev.Attributes, connectiontypes.AttributeKeyConnectionID); found { + return attribute.Value, nil + } + } + } + return "", errors.New("connection identifier event attribute not found") +} + +// ParseChannelIDFromEvents parses events emitted from a MsgChannelOpenInit or +// MsgChannelOpenTry or a MsgCreateChannel and returns the channel identifier. +func ParseChannelIDFromEvents(events []abci.Event) (string, error) { + for _, ev := range events { + if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry { + if attribute, found := attributeByKey(ev.Attributes, channeltypes.AttributeKeyChannelID); found { + return attribute.Value, nil + } + } + } + return "", errors.New("channel identifier event attribute not found") +} + +// ParsePacketFromEvents parses events emitted from a send packet and returns +// the first EventTypeSendPacket packet found. +// Returns an error if no packet is found. +func ParsePacketFromEvents(events []abci.Event) (channeltypes.Packet, error) { + packets, err := ParsePacketsFromEvents(channeltypes.EventTypeSendPacket, events) + if err != nil { + return channeltypes.Packet{}, err + } + return packets[0], nil +} + +// ParseRecvPacketFromEvents parses events emitted from a MsgRecvPacket and returns +// the first EventTypeRecvPacket packet found. +// Returns an error if no packet is found. +func ParseRecvPacketFromEvents(events []abci.Event) (channeltypes.Packet, error) { + packets, err := ParsePacketsFromEvents(channeltypes.EventTypeRecvPacket, events) + if err != nil { + return channeltypes.Packet{}, err + } + return packets[0], nil +} + +// ParsePacketsFromEvents parses events emitted from a MsgRecvPacket and returns +// all the packets found. +// Returns an error if no packet is found. +func ParsePacketsFromEvents(eventType string, events []abci.Event) ([]channeltypes.Packet, error) { + ferr := func(err error) ([]channeltypes.Packet, error) { + return nil, fmt.Errorf("ibctesting.ParsePacketsFromEvents: %w", err) + } + var packets []channeltypes.Packet + for _, ev := range events { + if ev.Type == eventType { + var packet channeltypes.Packet + for _, attr := range ev.Attributes { + switch attr.Key { + case channeltypes.AttributeKeyDataHex: + data, err := hex.DecodeString(attr.Value) + if err != nil { + return ferr(err) + } + packet.Data = data + case channeltypes.AttributeKeySequence: + seq, err := strconv.ParseUint(attr.Value, 10, 64) + if err != nil { + return ferr(err) + } + + packet.Sequence = seq + + case channeltypes.AttributeKeySrcPort: + packet.SourcePort = attr.Value + + case channeltypes.AttributeKeySrcChannel: + packet.SourceChannel = attr.Value + + case channeltypes.AttributeKeyDstPort: + packet.DestinationPort = attr.Value + + case channeltypes.AttributeKeyDstChannel: + packet.DestinationChannel = attr.Value + + case channeltypes.AttributeKeyTimeoutHeight: + height, err := clienttypes.ParseHeight(attr.Value) + if err != nil { + return ferr(err) + } + + packet.TimeoutHeight = height + + case channeltypes.AttributeKeyTimeoutTimestamp: + timestamp, err := strconv.ParseUint(attr.Value, 10, 64) + if err != nil { + return ferr(err) + } + + packet.TimeoutTimestamp = timestamp + + default: + continue + } + } + + packets = append(packets, packet) + } + } + if len(packets) == 0 { + return ferr(errors.New("acknowledgement event attribute not found")) + } + return packets, nil +} + +// ParseAckFromEvents parses events emitted from a MsgRecvPacket and returns the +// acknowledgement. +func ParseAckFromEvents(events []abci.Event) ([]byte, error) { + for _, ev := range events { + if ev.Type == channeltypes.EventTypeWriteAck { + if attribute, found := attributeByKey(ev.Attributes, channeltypes.AttributeKeyAckHex); found { + value, err := hex.DecodeString(attribute.Value) + if err != nil { + return nil, err + } + return value, nil + } + } + } + return nil, errors.New("acknowledgement event attribute not found") +} + +// ParseProposalIDFromEvents parses events emitted from MsgSubmitProposal and returns proposalID +func ParseProposalIDFromEvents(events []abci.Event) (uint64, error) { + for _, event := range events { + if attribute, found := attributeByKey(event.Attributes, "proposal_id"); found { + return strconv.ParseUint(attribute.Value, 10, 64) + } + } + return 0, errors.New("proposalID event attribute not found") +} + +// ParsePacketSequenceFromEvents parses events emitted from MsgRecvPacket and returns the packet sequence +func ParsePacketSequenceFromEvents(events []abci.Event) (uint64, error) { + for _, event := range events { + if attribute, found := attributeByKey(event.Attributes, "packet_sequence"); found { + return strconv.ParseUint(attribute.Value, 10, 64) + } + } + return 0, errors.New("packet sequence event attribute not found") +} + +// AssertEvents asserts that expected events are present in the actual events. +func AssertEvents( + suite *testifysuite.Suite, + expected []abci.Event, + actual []abci.Event, +) { + foundEvents := make(map[int]bool) + + for i, expectedEvent := range expected { + for _, actualEvent := range actual { + if shouldProcessEvent(expectedEvent, actualEvent) { + attributeMatch := true + for _, expectedAttr := range expectedEvent.Attributes { + // any expected attributes that are not contained in the actual events will cause this event + // not to match + attributeMatch = attributeMatch && containsAttribute(actualEvent.Attributes, expectedAttr.Key, expectedAttr.Value) + } + + if attributeMatch { + foundEvents[i] = true + } + } + } + } + + for i, expectedEvent := range expected { + suite.Require().True(foundEvents[i], "event: %s was not found in events", expectedEvent.Type) + } +} + +// shouldProcessEvent returns true if the given expected event should be processed based on event type. +func shouldProcessEvent(expectedEvent abci.Event, actualEvent abci.Event) bool { + if expectedEvent.Type != actualEvent.Type { + return false + } + // the actual event will have an extra attribute added automatically + // by Cosmos SDK since v0.50, that's why we subtract 1 when comparing + // with the number of attributes in the expected event. + if containsAttributeKey(actualEvent.Attributes, "msg_index") { + return len(expectedEvent.Attributes) == len(actualEvent.Attributes)-1 + } + + return len(expectedEvent.Attributes) == len(actualEvent.Attributes) +} + +// containsAttribute returns true if the given key/value pair is contained in the given attributes. +// NOTE: this ignores the indexed field, which can be set or unset depending on how the events are retrieved. +func containsAttribute(attrs []abci.EventAttribute, key, value string) bool { + return slices.ContainsFunc(attrs, func(attr abci.EventAttribute) bool { + return attr.Key == key && attr.Value == value + }) +} + +// containsAttributeKey returns true if the given key is contained in the given attributes. +func containsAttributeKey(attrs []abci.EventAttribute, key string) bool { + _, found := attributeByKey(attrs, key) + return found +} + +// attributeByKey returns the event attribute's value keyed by the given key and a boolean indicating its presence in the given attributes. +func attributeByKey(attributes []abci.EventAttribute, key string) (abci.EventAttribute, bool) { + idx := slices.IndexFunc(attributes, func(a abci.EventAttribute) bool { return a.Key == key }) + if idx == -1 { + return abci.EventAttribute{}, false + } + return attributes[idx], true +} diff --git a/ibc/testing/helpers.go b/ibc/testing/helpers.go new file mode 100644 index 000000000..e994c85c9 --- /dev/null +++ b/ibc/testing/helpers.go @@ -0,0 +1,49 @@ +package ibctesting + +import ( + "math/rand" + "testing" + "time" + + abci "github.com/cometbft/cometbft/abci/types" + bam "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +// SignAndDeliver signs and delivers a transaction. No simulation occurs as the +// ibc testing package causes checkState and deliverState to diverge in block time. +// +// CONTRACT: BeginBlock must be called before this function. +func SignAndDeliver( + tb testing.TB, proposerAddress sdk.AccAddress, txCfg client.TxConfig, app *bam.BaseApp, msgs []sdk.Msg, + chainID string, accNums, accSeqs []uint64, expPass bool, blockTime time.Time, nextValHash []byte, priv ...cryptotypes.PrivKey, +) (*abci.ResponseFinalizeBlock, error) { + tb.Helper() + tx, err := simtestutil.GenSignedMockTx( + rand.New(rand.NewSource(time.Now().UnixNano())), + txCfg, + msgs, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, + simtestutil.DefaultGenTxGas, + chainID, + accNums, + accSeqs, + priv..., + ) + require.NoError(tb, err) + + txBytes, err := txCfg.TxEncoder()(tx) + require.NoError(tb, err) + + return app.FinalizeBlock(&abci.RequestFinalizeBlock{ + Height: app.LastBlockHeight() + 1, + Time: blockTime, + NextValidatorsHash: nextValHash, + Txs: [][]byte{txBytes}, + ProposerAddress: proposerAddress, + }) +} diff --git a/ibc/testing/path.go b/ibc/testing/path.go index cbe540b7f..c58cb3e70 100644 --- a/ibc/testing/path.go +++ b/ibc/testing/path.go @@ -2,10 +2,12 @@ package ibctesting import ( "bytes" - "fmt" + "errors" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v8/testing" + abci "github.com/cometbft/cometbft/abci/types" + + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" ) // Path contains two endpoints representing two chains connected over IBC @@ -17,7 +19,7 @@ type Path struct { // NewPath constructs an endpoint for each chain using the default values // for the endpoints. Each endpoint is updated to have a pointer to the // counterparty endpoint. -func NewPath(chainA, chainB *ibctesting.TestChain) *Path { +func NewPath(chainA, chainB *TestChain) *Path { endpointA := NewDefaultEndpoint(chainA) endpointB := NewDefaultEndpoint(chainB) @@ -30,57 +32,214 @@ func NewPath(chainA, chainB *ibctesting.TestChain) *Path { } } +// NewTransferPath constructs a new path between each chain suitable for use with +// the transfer module. +func NewTransferPath(chainA, chainB *TestChain) *Path { + path := NewPath(chainA, chainB) + path.EndpointA.ChannelConfig.PortID = TransferPort + path.EndpointB.ChannelConfig.PortID = TransferPort + path.EndpointA.ChannelConfig.Version = transfertypes.V1 + path.EndpointB.ChannelConfig.Version = transfertypes.V1 + + return path +} + // SetChannelOrdered sets the channel order for both endpoints to ORDERED. func (path *Path) SetChannelOrdered() { path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED } +// DisableUniqueChannelIDs provides an opt-out way to not have all channel IDs be different +// while testing. +func (path *Path) DisableUniqueChannelIDs() *Path { + path.EndpointA.disableUniqueChannelIDs = true + path.EndpointB.disableUniqueChannelIDs = true + return path +} + // RelayPacket attempts to relay the packet first on EndpointA and then on EndpointB // if EndpointA does not contain a packet commitment for that packet. An error is returned // if a relay step fails or the packet commitment does not exist on either endpoint. func (path *Path) RelayPacket(packet channeltypes.Packet) error { - pc := path.EndpointA.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointA.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointA.Chain.App.AppCodec(), packet)) { + _, _, err := path.RelayPacketWithResults(packet) + return err +} +// RelayPacketWithResults attempts to relay the packet first on EndpointA and then on EndpointB +// if EndpointA does not contain a packet commitment for that packet. The function returns: +// - The result of the packet receive transaction. +// - The acknowledgement written on the receiving chain. +// - An error if a relay step fails or the packet commitment does not exist on either endpoint. +func (path *Path) RelayPacketWithResults(packet channeltypes.Packet) (*abci.ExecTxResult, []byte, error) { + pc := path.EndpointA.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointA.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + if bytes.Equal(pc, channeltypes.CommitPacket(packet)) { // packet found, relay from A to B if err := path.EndpointB.UpdateClient(); err != nil { - return err + return nil, nil, err } res, err := path.EndpointB.RecvPacketWithResult(packet) if err != nil { - return err + return nil, nil, err } - ack, err := ibctesting.ParseAckFromEvents(res.GetEvents().ToABCIEvents()) + ack, err := ParseAckFromEvents(res.Events) if err != nil { - return err + return nil, nil, err + } + + if err := path.EndpointA.AcknowledgePacket(packet, ack); err != nil { + return nil, nil, err } - return path.EndpointA.AcknowledgePacket(packet, ack) + return res, ack, nil } pc = path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointB.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointB.Chain.App.AppCodec(), packet)) { - + if bytes.Equal(pc, channeltypes.CommitPacket(packet)) { // packet found, relay B to A if err := path.EndpointA.UpdateClient(); err != nil { - return err + return nil, nil, err } res, err := path.EndpointA.RecvPacketWithResult(packet) if err != nil { - return err + return nil, nil, err } - ack, err := ibctesting.ParseAckFromEvents(res.GetEvents().ToABCIEvents()) + ack, err := ParseAckFromEvents(res.Events) if err != nil { - return err + return nil, nil, err } - return path.EndpointB.AcknowledgePacket(packet, ack) + if err := path.EndpointB.AcknowledgePacket(packet, ack); err != nil { + return nil, nil, err + } + + return res, ack, nil } - return fmt.Errorf("packet commitment does not exist on either endpoint for provided packet") + return nil, nil, errors.New("packet commitment does not exist on either endpoint for provided packet") +} + +// Reversed returns a new path with endpoints reversed. +func (path *Path) Reversed() *Path { + reversedPath := *path + reversedPath.EndpointA, reversedPath.EndpointB = path.EndpointB, path.EndpointA + return &reversedPath +} + +// Setup constructs a TM client, connection, and channel on both chains provided. It will +// fail if any error occurs. +func (path *Path) Setup() { + path.SetupConnections() + + // channels can also be referenced through the returned connections + path.CreateChannels() +} + +// SetupV2 constructs clients on both sides and then provides the counterparties for both sides +// This is all that is necessary for path setup with the IBC v2 protocol +func (path *Path) SetupV2() { + path.SetupClients() + + path.SetupCounterparties() +} + +// SetupClients is a helper function to create clients on both chains. It assumes the +// caller does not anticipate any errors. +func (path *Path) SetupClients() { + err := path.EndpointA.CreateClient() + if err != nil { + panic(err) + } + + err = path.EndpointB.CreateClient() + if err != nil { + panic(err) + } +} + +// SetupCounterparties is a helper function to set the counterparties supporting IBC v2 on both +// chains. It assumes the caller does not anticipate any errors. +func (path *Path) SetupCounterparties() { + if err := path.EndpointB.RegisterCounterparty(); err != nil { + panic(err) + } + + if err := path.EndpointA.RegisterCounterparty(); err != nil { + panic(err) + } +} + +// SetupConnections is a helper function to create clients and the appropriate +// connections on both the source and counterparty chain. It assumes the caller does not +// anticipate any errors. +func (path *Path) SetupConnections() { + path.SetupClients() + + path.CreateConnections() +} + +// CreateConnections constructs and executes connection handshake messages in order to create +// OPEN connections on chainA and chainB. The function expects the connections to be +// successfully opened otherwise testing will fail. +func (path *Path) CreateConnections() { + err := path.EndpointA.ConnOpenInit() + if err != nil { + panic(err) + } + + err = path.EndpointB.ConnOpenTry() + if err != nil { + panic(err) + } + + err = path.EndpointA.ConnOpenAck() + if err != nil { + panic(err) + } + + err = path.EndpointB.ConnOpenConfirm() + if err != nil { + panic(err) + } + + // ensure counterparty is up to date + err = path.EndpointA.UpdateClient() + if err != nil { + panic(err) + } +} + +// CreateChannels constructs and executes channel handshake messages in order to create +// OPEN channels on chainA and chainB. The function expects the channels to be successfully +// opened otherwise testing will fail. +func (path *Path) CreateChannels() { + err := path.EndpointA.ChanOpenInit() + if err != nil { + panic(err) + } + + err = path.EndpointB.ChanOpenTry() + if err != nil { + panic(err) + } + + err = path.EndpointA.ChanOpenAck() + if err != nil { + panic(err) + } + + err = path.EndpointB.ChanOpenConfirm() + if err != nil { + panic(err) + } + + // ensure counterparty is up to date + err = path.EndpointA.UpdateClient() + if err != nil { + panic(err) + } } diff --git a/ibc/testing/testing_app.go b/ibc/testing/testing_app.go new file mode 100644 index 000000000..2c27f995e --- /dev/null +++ b/ibc/testing/testing_app.go @@ -0,0 +1,25 @@ +package ibctesting + +import ( + "encoding/json" + + "cosmossdk.io/log" + dbm "github.com/cosmos/cosmos-db" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + ibctesting "github.com/cosmos/ibc-go/v10/testing" + + "github.com/cosmos/evm/evmd" + "github.com/cosmos/evm/evmd/testutil" +) + +func SetupExampleApp() (ibctesting.TestingApp, map[string]json.RawMessage) { + app := evmd.NewExampleApp( + log.NewNopLogger(), + dbm.NewMemDB(), + nil, + true, + simtestutil.EmptyAppOptions{}, + testutil.NoOpEvmAppOptions, + ) + return app, app.DefaultGenesis() +} diff --git a/ibc/testing/values.go b/ibc/testing/values.go new file mode 100644 index 000000000..5a8a7ade8 --- /dev/null +++ b/ibc/testing/values.go @@ -0,0 +1,79 @@ +/* +This file contains the variables, constants, and default values +used in the testing package and commonly defined in tests. +*/ +package ibctesting + +import ( + "time" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cometbft/cometbft/crypto/tmhash" + + ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + connectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" + commitmenttypes "github.com/cosmos/ibc-go/v10/modules/core/23-commitment/types" + ibctm "github.com/cosmos/ibc-go/v10/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v10/testing/mock" +) + +const ( + FirstClientID = "07-tendermint-0" + SecondClientID = "07-tendermint-1" + FirstChannelID = "channel-0" + SecondChannelID = "channel-1" + FirstConnectionID = "connection-0" + SecondConnectionID = "connection-1" + + // Default params constants used to create a TM client + TrustingPeriod time.Duration = time.Hour * 24 * 7 * 2 + UnbondingPeriod time.Duration = time.Hour * 24 * 7 * 3 + MaxClockDrift time.Duration = time.Second * 10 + DefaultDelayPeriod uint64 = 0 + + DefaultChannelVersion = mock.Version + InvalidID = "IDisInvalid" + + // Application Ports + TransferPort = ibctransfertypes.ModuleName + MockPort = mock.ModuleName + + // used for testing proposals + Title = "title" + Description = "description" + + // character set used for generating a random string in GenerateString + charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" +) + +var ( + DefaultOpenInitVersion *connectiontypes.Version + + // DefaultTrustLevel sets params variables used to create a TM client + DefaultTrustLevel = ibctm.DefaultTrustLevel + + DefaultTimeoutTimestampDelta = uint64(time.Hour.Nanoseconds()) + DefaultCoinAmount = sdkmath.NewInt(100) + + TestAccAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, DefaultCoinAmount) + SecondaryDenom = "ufoo" + SecondaryTestCoin = sdk.NewCoin(SecondaryDenom, DefaultCoinAmount) + TestCoins = sdk.NewCoins(TestCoin, SecondaryTestCoin) + + UpgradePath = []string{"upgrade", "upgradedIBCState"} + + ConnectionVersion = connectiontypes.GetCompatibleVersions()[0] + + MockAcknowledgement = mock.MockAcknowledgement.Acknowledgement() + MockPacketData = mock.MockPacketData + MockFailPacketData = mock.MockFailPacketData + + prefix = commitmenttypes.NewMerklePrefix([]byte("ibc")) + // unusedHash is a placeholder hash used for testing. + unusedHash = tmhash.Sum([]byte{0x00}) + MerklePath = commitmenttypes.NewMerklePath([]byte("ibc"), []byte("")) +) diff --git a/ibc/utils.go b/ibc/utils.go index b0dfe2d98..cbad50a20 100644 --- a/ibc/utils.go +++ b/ibc/utils.go @@ -3,10 +3,11 @@ package ibc import ( "strings" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + "github.com/cosmos/evm/utils" transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" @@ -122,39 +123,39 @@ func GetSentCoin(rawDenom, rawAmt string) sdk.Coin { // If the coin denom starts with `factory/` then it is a token factory coin, and we should not convert it // NOTE: Check https://docs.osmosis.zone/osmosis-core/modules/tokenfactory/ for more information func IsBaseDenomFromSourceChain(rawDenom string) bool { - // Parse the raw denomination to get its DenomTrace - denomTrace := transfertypes.ParseDenomTrace(rawDenom) + // Parse the raw denomination to get its Denom + denom := transfertypes.ExtractDenomFromPath(rawDenom) - // Split the denom of the DenomTrace into its components - denomComponents := strings.Split(denomTrace.BaseDenom, "/") + // Split the denom of the Denom into its components + denomComponents := strings.Split(denom.Base, "/") // Each hop in the path is represented by a pair of port and channel ids // If the number of components in the path is equal to or more than 2, it has hopped multiple chains - return len(denomTrace.Path) == 0 && len(denomComponents) == 1 + return len(denom.GetTrace()) == 0 && len(denomComponents) == 1 } -// GetDenomTrace returns the denomination trace from the corresponding IBC denomination. If the +// GetDenom returns the denomination trace from the corresponding IBC denomination. If the // denomination is not an IBC voucher or the trace is not found, it returns an error. -func GetDenomTrace( +func GetDenom( transferKeeper transferkeeper.Keeper, ctx sdk.Context, - denom string, -) (transfertypes.DenomTrace, error) { - if !strings.HasPrefix(denom, "ibc/") { - return transfertypes.DenomTrace{}, errorsmod.Wrapf(ErrNoIBCVoucherDenom, "denom: %s", denom) + voucherDenom string, +) (transfertypes.Denom, error) { + if !strings.HasPrefix(voucherDenom, "ibc/") { + return transfertypes.Denom{}, errorsmod.Wrapf(ErrNoIBCVoucherDenom, "denom: %s", voucherDenom) } - hash, err := transfertypes.ParseHexHash(denom[4:]) + hash, err := transfertypes.ParseHexHash(voucherDenom[4:]) if err != nil { - return transfertypes.DenomTrace{}, err + return transfertypes.Denom{}, err } - denomTrace, found := transferKeeper.GetDenomTrace(ctx, hash) + denom, found := transferKeeper.GetDenom(ctx, hash) if !found { - return transfertypes.DenomTrace{}, ErrDenomTraceNotFound + return transfertypes.Denom{}, ErrDenomNotFound } - return denomTrace, nil + return denom, nil } // DeriveDecimalsFromDenom returns the number of decimals of an IBC coin diff --git a/ibc/utils_test.go b/ibc/utils_test.go index 222313dda..7e4ff799e 100644 --- a/ibc/utils_test.go +++ b/ibc/utils_test.go @@ -5,12 +5,13 @@ import ( "github.com/stretchr/testify/require" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v10/testing" + cosmosevmibc "github.com/cosmos/evm/ibc" precompilestestutil "github.com/cosmos/evm/precompiles/testutil" testconstants "github.com/cosmos/evm/testutil/constants" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v8/testing" "cosmossdk.io/math" @@ -199,7 +200,7 @@ func TestGetReceivedCoin(t *testing.T) { "channel-0", "uosmo", "10", - sdk.Coin{Denom: precompilestestutil.UosmoIbcdenom, Amount: math.NewInt(10)}, + sdk.Coin{Denom: precompilestestutil.UosmoIbcDenom, Amount: math.NewInt(10)}, }, { "transfer ibc wrapped coin to destination which is its source", @@ -219,7 +220,7 @@ func TestGetReceivedCoin(t *testing.T) { "channel-2", "transfer/channel-0/transfer/channel-1/uatom", "10", - sdk.Coin{Denom: precompilestestutil.UatomIbcdenom, Amount: math.NewInt(10)}, + sdk.Coin{Denom: precompilestestutil.UatomIbcDenom, Amount: math.NewInt(10)}, }, { "transfer ibc wrapped coin to destination which is not its source", @@ -229,7 +230,7 @@ func TestGetReceivedCoin(t *testing.T) { "channel-0", "transfer/channel-1/uatom", "10", - sdk.Coin{Denom: precompilestestutil.UatomOsmoIbcdenom, Amount: math.NewInt(10)}, + sdk.Coin{Denom: precompilestestutil.UatomOsmoIbcDenom, Amount: math.NewInt(10)}, }, } @@ -258,25 +259,25 @@ func TestGetSentCoin(t *testing.T) { "get ibc wrapped aatom coin", "transfer/channel-0/aatom", "10", - sdk.Coin{Denom: precompilestestutil.AAtomIbcdenom, Amount: math.NewInt(10)}, + sdk.Coin{Denom: precompilestestutil.AatomIbcDenom, Amount: math.NewInt(10)}, }, { "get ibc wrapped uosmo coin", "transfer/channel-0/uosmo", "10", - sdk.Coin{Denom: precompilestestutil.UosmoIbcdenom, Amount: math.NewInt(10)}, + sdk.Coin{Denom: precompilestestutil.UosmoIbcDenom, Amount: math.NewInt(10)}, }, { "get ibc wrapped uatom coin", "transfer/channel-1/uatom", "10", - sdk.Coin{Denom: precompilestestutil.UatomIbcdenom, Amount: math.NewInt(10)}, + sdk.Coin{Denom: precompilestestutil.UatomIbcDenom, Amount: math.NewInt(10)}, }, { "get 2x ibc wrapped uatom coin", "transfer/channel-0/transfer/channel-1/uatom", "10", - sdk.Coin{Denom: precompilestestutil.UatomOsmoIbcdenom, Amount: math.NewInt(10)}, + sdk.Coin{Denom: precompilestestutil.UatomOsmoIbcDenom, Amount: math.NewInt(10)}, }, } diff --git a/precompiles/erc20/errors.go b/precompiles/erc20/errors.go index e3aa329a2..22d2ab8d6 100644 --- a/precompiles/erc20/errors.go +++ b/precompiles/erc20/errors.go @@ -83,7 +83,7 @@ func ConvertErrToERC20Error(err error) error { case strings.Contains(err.Error(), cmn.ErrIntegerOverflow): return vm.ErrExecutionReverted case errors.Is(err, ibc.ErrNoIBCVoucherDenom) || - errors.Is(err, ibc.ErrDenomTraceNotFound) || + errors.Is(err, ibc.ErrDenomNotFound) || strings.Contains(err.Error(), "invalid base denomination") || strings.Contains(err.Error(), "display denomination not found") || strings.Contains(err.Error(), "invalid decimals"): diff --git a/precompiles/erc20/query.go b/precompiles/erc20/query.go index 737676a48..e58048371 100644 --- a/precompiles/erc20/query.go +++ b/precompiles/erc20/query.go @@ -99,13 +99,13 @@ func (p Precompile) Decimals( ) ([]byte, error) { metadata, found := p.BankKeeper.GetDenomMetaData(ctx, p.tokenPair.Denom) if !found { - denomTrace, err := ibc.GetDenomTrace(p.transferKeeper, ctx, p.tokenPair.Denom) + denom, err := ibc.GetDenom(p.transferKeeper, ctx, p.tokenPair.Denom) if err != nil { return nil, ConvertErrToERC20Error(err) } // we assume the decimal from the first character of the denomination - decimals, err := ibc.DeriveDecimalsFromDenom(denomTrace.BaseDenom) + decimals, err := ibc.DeriveDecimalsFromDenom(denom.Base) if err != nil { return nil, ConvertErrToERC20Error(err) } @@ -229,19 +229,19 @@ func GetAuthzExpirationAndAllowance( } // getBaseDenomFromIBCVoucher returns the base denomination from the given IBC voucher denomination. -func (p Precompile) getBaseDenomFromIBCVoucher(ctx sdk.Context, denom string) (string, error) { - // Infer the denomination name from the coin denomination base denom - denomTrace, err := ibc.GetDenomTrace(p.transferKeeper, ctx, denom) +func (p Precompile) getBaseDenomFromIBCVoucher(ctx sdk.Context, voucherDenom string) (string, error) { + // Infer the denomination name from the coin denomination base voucherDenom + denom, err := ibc.GetDenom(p.transferKeeper, ctx, voucherDenom) if err != nil { // FIXME: return 'not supported' (same error as when you call the method on an ERC20.sol) return "", err } // safety check - if len(denomTrace.BaseDenom) < 3 { + if len(denom.Base) < 3 { // FIXME: return not supported (same error as when you call the method on an ERC20.sol) - return "", fmt.Errorf("invalid base denomination; should be at least length 3; got: %q", denomTrace.BaseDenom) + return "", fmt.Errorf("invalid base denomination; should be at least length 3; got: %q", denom.Base) } - return denomTrace.BaseDenom, nil + return denom.Base, nil } diff --git a/precompiles/erc20/query_test.go b/precompiles/erc20/query_test.go index 90573eaf4..d0e397f7f 100644 --- a/precompiles/erc20/query_test.go +++ b/precompiles/erc20/query_test.go @@ -4,32 +4,33 @@ import ( "math" "math/big" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/common" + "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + app "github.com/cosmos/evm/evmd" chainutil "github.com/cosmos/evm/evmd/testutil" auth "github.com/cosmos/evm/precompiles/authorization" "github.com/cosmos/evm/precompiles/erc20" "github.com/cosmos/evm/x/vm/core/vm" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" ) // Define useful variables for tests here. var ( - // tooShortTrace is a denomination trace with a name that will raise the "denom too short" error - tooShortTrace = types.DenomTrace{Path: "channel-0", BaseDenom: "ab"} - // validTraceDenom is a denomination trace with a valid IBC voucher name - validTraceDenom = types.DenomTrace{Path: "channel-0", BaseDenom: "uosmo"} - // validAttoTraceDenom is a denomination trace with a valid IBC voucher name and 18 decimals - validAttoTraceDenom = types.DenomTrace{Path: "channel-0", BaseDenom: "aatom"} - // validTraceDenomNoMicroAtto is a denomination trace with a valid IBC voucher name but no micro or atto prefix - validTraceDenomNoMicroAtto = types.DenomTrace{Path: "channel-0", BaseDenom: "matom"} + // tooShort is a denomination trace with a name that will raise the "denom too short" error + tooShort = types.NewDenom("ab", types.NewHop(types.PortID, "channel-0")) + // validDenom is a denomination trace with a valid IBC voucher name + validDenom = types.NewDenom("uosmo", types.NewHop(types.PortID, "channel-0")) + // validAttoDenom is a denomination trace with a valid IBC voucher name and 18 decimals + validAttoDenom = types.NewDenom("aatom", types.NewHop(types.PortID, "channel-0")) + // validDenomNoMicroAtto is a denomination trace with a valid IBC voucher name but no micro or atto prefix + validDenomNoMicroAtto = types.NewDenom("matom", types.NewHop(types.PortID, "channel-0")) // -------------------- // Variables for coin with valid metadata @@ -125,19 +126,19 @@ func (s *PrecompileTestSuite) TestNameSymbol() { }, { name: "fail - invalid denom trace", - denom: tooShortTrace.IBCDenom()[:len(tooShortTrace.IBCDenom())-1], + denom: tooShort.IBCDenom()[:len(tooShort.IBCDenom())-1], errContains: "odd length hex string", }, { name: "fail - denom not found", - denom: types.DenomTrace{Path: "channel-0", BaseDenom: "notfound"}.IBCDenom(), + denom: types.NewDenom("notfound", types.NewHop(types.PortID, "channel-0")).IBCDenom(), errContains: vm.ErrExecutionReverted.Error(), }, { name: "fail - invalid denom (too short < 3 chars)", - denom: tooShortTrace.IBCDenom(), + denom: tooShort.IBCDenom(), malleate: func(ctx sdk.Context, app *app.EVMD) { - app.TransferKeeper.SetDenomTrace(ctx, tooShortTrace) + app.TransferKeeper.SetDenom(ctx, tooShort) }, errContains: vm.ErrExecutionReverted.Error(), }, @@ -148,9 +149,9 @@ func (s *PrecompileTestSuite) TestNameSymbol() { }, { name: "pass - valid ibc denom without metadata and neither atto nor micro prefix", - denom: validTraceDenomNoMicroAtto.IBCDenom(), + denom: validDenomNoMicroAtto.IBCDenom(), malleate: func(ctx sdk.Context, app *app.EVMD) { - app.TransferKeeper.SetDenomTrace(ctx, validTraceDenomNoMicroAtto) + app.TransferKeeper.SetDenom(ctx, validDenomNoMicroAtto) }, expPass: true, expName: "Atom", @@ -173,9 +174,9 @@ func (s *PrecompileTestSuite) TestNameSymbol() { }, { name: "pass - valid ibc denom without metadata", - denom: validTraceDenom.IBCDenom(), + denom: validDenom.IBCDenom(), malleate: func(ctx sdk.Context, app *app.EVMD) { - app.TransferKeeper.SetDenomTrace(ctx, validTraceDenom) + app.TransferKeeper.SetDenom(ctx, validDenom) }, expPass: true, expName: "Osmo", @@ -240,12 +241,12 @@ func (s *PrecompileTestSuite) TestDecimals() { }, { name: "fail - invalid denom trace", - denom: tooShortTrace.IBCDenom()[:len(tooShortTrace.IBCDenom())-1], + denom: tooShort.IBCDenom()[:len(tooShort.IBCDenom())-1], errContains: "odd length hex string", }, { name: "fail - denom not found", - denom: types.DenomTrace{Path: "channel-0", BaseDenom: "notfound"}.IBCDenom(), + denom: types.NewDenom("notfound", types.NewHop(types.PortID, "channel-0")).IBCDenom(), errContains: vm.ErrExecutionReverted.Error(), }, { @@ -255,17 +256,17 @@ func (s *PrecompileTestSuite) TestDecimals() { }, { name: "fail - valid ibc denom without metadata and neither atto nor micro prefix", - denom: validTraceDenomNoMicroAtto.IBCDenom(), + denom: validDenomNoMicroAtto.IBCDenom(), malleate: func(ctx sdk.Context, app *app.EVMD) { - app.TransferKeeper.SetDenomTrace(ctx, validTraceDenomNoMicroAtto) + app.TransferKeeper.SetDenom(ctx, validDenomNoMicroAtto) }, errContains: vm.ErrExecutionReverted.Error(), }, { name: "pass - invalid denom (too short < 3 chars)", - denom: tooShortTrace.IBCDenom(), + denom: tooShort.IBCDenom(), malleate: func(ctx sdk.Context, app *app.EVMD) { - app.TransferKeeper.SetDenomTrace(ctx, tooShortTrace) + app.TransferKeeper.SetDenom(ctx, tooShort) }, expPass: true, // TODO: do we want to check in decimals query for the above error? expDecimals: 18, // expect 18 decimals here because of "a" prefix @@ -286,18 +287,18 @@ func (s *PrecompileTestSuite) TestDecimals() { }, { name: "pass - valid ibc denom without metadata", - denom: validTraceDenom.IBCDenom(), + denom: validDenom.IBCDenom(), malleate: func(ctx sdk.Context, app *app.EVMD) { - app.TransferKeeper.SetDenomTrace(ctx, validTraceDenom) + app.TransferKeeper.SetDenom(ctx, validDenom) }, expPass: true, expDecimals: 6, }, { name: "pass - valid ibc denom without metadata and 18 decimals", - denom: validAttoTraceDenom.IBCDenom(), + denom: validAttoDenom.IBCDenom(), malleate: func(ctx sdk.Context, app *app.EVMD) { - app.TransferKeeper.SetDenomTrace(ctx, validAttoTraceDenom) + app.TransferKeeper.SetDenom(ctx, validAttoDenom) }, expPass: true, expDecimals: 18, diff --git a/precompiles/ics20/ICS20I.sol b/precompiles/ics20/ICS20I.sol index 80af1db6b..7ee32eb72 100644 --- a/precompiles/ics20/ICS20I.sol +++ b/precompiles/ics20/ICS20I.sol @@ -10,9 +10,9 @@ address constant ICS20_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000 /// @dev The ICS20 contract's instance. ICS20I constant ICS20_CONTRACT = ICS20I(ICS20_PRECOMPILE_ADDRESS); -/// @dev DenomTrace contains the base denomination for ICS20 fungible tokens and the +/// @dev Denom contains the base denomination for ICS20 fungible tokens and the /// source tracing information path. -struct DenomTrace { +struct Denom { // path defines the chain of port/channel identifiers used for tracing the // source of the fungible token. string path; @@ -68,22 +68,22 @@ interface ICS20I is IICS20Authorization { string memory memo ) external returns (uint64 nextSequence); - /// @dev DenomTraces Defines a method for returning all denom traces. + /// @dev denoms Defines a method for returning all denom traces. /// @param pageRequest Defines the pagination parameters to for the request. - function denomTraces( + function denoms( PageRequest memory pageRequest ) external view returns ( - DenomTrace[] memory denomTraces, + Denom[] memory denoms, PageResponse memory pageResponse ); /// @dev DenomTrace defines a method for returning a denom trace. - function denomTrace( + function denom( string memory hash - ) external view returns (DenomTrace memory denomTrace); + ) external view returns (Denom memory denom); /// @dev DenomHash defines a method for returning a hash of the denomination trace info. function denomHash( diff --git a/precompiles/ics20/abi.json b/precompiles/ics20/abi.json index 6f475e6d9..cd002d463 100644 --- a/precompiles/ics20/abi.json +++ b/precompiles/ics20/abi.json @@ -281,25 +281,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "string", - "name": "trace", - "type": "string" - } - ], - "name": "denomHash", - "outputs": [ - { - "internalType": "string", - "name": "hash", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -308,7 +289,7 @@ "type": "string" } ], - "name": "denomTrace", + "name": "denom", "outputs": [ { "components": [ @@ -323,14 +304,33 @@ "type": "string" } ], - "internalType": "struct DenomTrace", - "name": "denomTrace", + "internalType": "struct Denom", + "name": "denom", "type": "tuple" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "string", + "name": "trace", + "type": "string" + } + ], + "name": "denomHash", + "outputs": [ + { + "internalType": "string", + "name": "hash", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -366,7 +366,7 @@ "type": "tuple" } ], - "name": "denomTraces", + "name": "denoms", "outputs": [ { "components": [ @@ -381,8 +381,8 @@ "type": "string" } ], - "internalType": "struct DenomTrace[]", - "name": "denomTraces", + "internalType": "struct Denom[]", + "name": "denoms", "type": "tuple[]" }, { diff --git a/precompiles/ics20/approve_common.go b/precompiles/ics20/approve_common.go index 74b959b60..48b84f043 100644 --- a/precompiles/ics20/approve_common.go +++ b/precompiles/ics20/approve_common.go @@ -9,12 +9,13 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channelkeeper "github.com/cosmos/ibc-go/v10/modules/core/04-channel/keeper" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + "github.com/cosmos/evm/precompiles/authorization" cmn "github.com/cosmos/evm/precompiles/common" "github.com/cosmos/evm/x/vm/core/vm" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" @@ -31,7 +32,7 @@ var TransferMsgURL = sdk.MsgTypeURL(&transfertypes.MsgTransfer{}) func Approve( ctx sdk.Context, authzKeeper authzkeeper.Keeper, - channelKeeper channelkeeper.Keeper, + channelKeeper *channelkeeper.Keeper, precompileAddr, grantee, origin common.Address, approvalExpiration time.Duration, transferAuthz *transfertypes.TransferAuthorization, diff --git a/precompiles/ics20/ics20.go b/precompiles/ics20/ics20.go index fcca248fb..fd15fe906 100644 --- a/precompiles/ics20/ics20.go +++ b/precompiles/ics20/ics20.go @@ -7,13 +7,14 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + channelkeeper "github.com/cosmos/ibc-go/v10/modules/core/04-channel/keeper" + "github.com/cosmos/evm/precompiles/authorization" cmn "github.com/cosmos/evm/precompiles/common" transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" "github.com/cosmos/evm/x/vm/core/vm" evmkeeper "github.com/cosmos/evm/x/vm/keeper" evmtypes "github.com/cosmos/evm/x/vm/types" - channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" storetypes "cosmossdk.io/store/types" @@ -35,7 +36,7 @@ type Precompile struct { cmn.Precompile stakingKeeper stakingkeeper.Keeper transferKeeper transferkeeper.Keeper - channelKeeper channelkeeper.Keeper + channelKeeper *channelkeeper.Keeper evmKeeper *evmkeeper.Keeper } @@ -44,7 +45,7 @@ type Precompile struct { func NewPrecompile( stakingKeeper stakingkeeper.Keeper, transferKeeper transferkeeper.Keeper, - channelKeeper channelkeeper.Keeper, + channelKeeper *channelkeeper.Keeper, authzKeeper authzkeeper.Keeper, evmKeeper *evmkeeper.Keeper, ) (*Precompile, error) { @@ -117,10 +118,10 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ case TransferMethod: bz, err = p.Transfer(ctx, evm.Origin, contract, stateDB, method, args) // ICS20 queries - case DenomTraceMethod: - bz, err = p.DenomTrace(ctx, contract, method, args) - case DenomTracesMethod: - bz, err = p.DenomTraces(ctx, contract, method, args) + case DenomMethod: + bz, err = p.Denom(ctx, contract, method, args) + case DenomsMethod: + bz, err = p.Denoms(ctx, contract, method, args) case DenomHashMethod: bz, err = p.DenomHash(ctx, contract, method, args) case authorization.AllowanceMethod: diff --git a/precompiles/ics20/query.go b/precompiles/ics20/query.go index 6726b492b..85a5a5761 100644 --- a/precompiles/ics20/query.go +++ b/precompiles/ics20/query.go @@ -6,68 +6,69 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + "github.com/cosmos/evm/precompiles/authorization" cmn "github.com/cosmos/evm/precompiles/common" "github.com/cosmos/evm/x/vm/core/vm" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" sdk "github.com/cosmos/cosmos-sdk/types" ) const ( - // DenomTraceMethod defines the ABI method name for the ICS20 DenomTrace + // DenomMethod defines the ABI method name for the ICS20 Denom // query. - DenomTraceMethod = "denomTrace" - // DenomTracesMethod defines the ABI method name for the ICS20 DenomTraces + DenomMethod = "denom" + // DenomsMethod defines the ABI method name for the ICS20 Denoms // query. - DenomTracesMethod = "denomTraces" + DenomsMethod = "denoms" // DenomHashMethod defines the ABI method name for the ICS20 DenomHash // query. DenomHashMethod = "denomHash" ) -// DenomTrace returns the requested denomination trace information. -func (p Precompile) DenomTrace( +// Denom returns the requested denomination trace information. +func (p Precompile) Denom( ctx sdk.Context, _ *vm.Contract, method *abi.Method, args []interface{}, ) ([]byte, error) { - req, err := NewDenomTraceRequest(args) + req, err := NewDenomRequest(args) if err != nil { return nil, err } - res, err := p.transferKeeper.DenomTrace(ctx, req) + res, err := p.transferKeeper.Denom(ctx, req) if err != nil { // if the trace does not exist, return empty array if strings.Contains(err.Error(), ErrTraceNotFound) { - return method.Outputs.Pack(transfertypes.DenomTrace{}) + return method.Outputs.Pack(transfertypes.Denom{}) } return nil, err } - return method.Outputs.Pack(*res.DenomTrace) + return method.Outputs.Pack(*res.Denom) } -// DenomTraces returns the requested denomination traces information. -func (p Precompile) DenomTraces( +// Denoms returns the requested denomination traces information. +func (p Precompile) Denoms( ctx sdk.Context, _ *vm.Contract, method *abi.Method, args []interface{}, ) ([]byte, error) { - req, err := NewDenomTracesRequest(method, args) + req, err := NewDenomsRequest(method, args) if err != nil { return nil, err } - res, err := p.transferKeeper.DenomTraces(ctx, req) + res, err := p.transferKeeper.Denoms(ctx, req) if err != nil { return nil, err } - return method.Outputs.Pack(res.DenomTraces, res.Pagination) + return method.Outputs.Pack(res.Denoms, res.Pagination) } // DenomHash returns the denom hash (in hex format) of the denomination trace information. diff --git a/precompiles/ics20/tx.go b/precompiles/ics20/tx.go index d122c2cc1..a95cbc661 100644 --- a/precompiles/ics20/tx.go +++ b/precompiles/ics20/tx.go @@ -9,8 +9,8 @@ import ( cmn "github.com/cosmos/evm/precompiles/common" "github.com/cosmos/evm/x/vm/core/vm" evmtypes "github.com/cosmos/evm/x/vm/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" errorsmod "cosmossdk.io/errors" diff --git a/precompiles/ics20/types.go b/precompiles/ics20/types.go index edf8d7947..d144d4201 100644 --- a/precompiles/ics20/types.go +++ b/precompiles/ics20/types.go @@ -9,11 +9,12 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + "github.com/cosmos/evm/precompiles/authorization" cmn "github.com/cosmos/evm/precompiles/common" "github.com/cosmos/evm/x/vm/core/vm" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" @@ -56,9 +57,9 @@ type EventTransferAuthorization struct { Allocations []cmn.ICS20Allocation } -// DenomTraceResponse defines the data for the denom trace response. -type DenomTraceResponse struct { - DenomTrace transfertypes.DenomTrace +// DenomResponse defines the data for the denom response. +type DenomResponse struct { + Denom transfertypes.Denom } // PageRequest defines the data for the page request. @@ -66,9 +67,9 @@ type PageRequest struct { PageRequest query.PageRequest } -// DenomTracesResponse defines the data for the denom traces response. -type DenomTracesResponse struct { - DenomTraces []transfertypes.DenomTrace +// DenomsResponse defines the data for the denoms response. +type DenomsResponse struct { + Denoms []transfertypes.Denom PageResponse query.PageResponse } @@ -191,8 +192,8 @@ func CreateAndValidateMsgTransfer( return msg, nil } -// NewDenomTraceRequest returns a new denom trace request from the given arguments. -func NewDenomTraceRequest(args []interface{}) (*transfertypes.QueryDenomTraceRequest, error) { +// NewDenomRequest returns a new denom request from the given arguments. +func NewDenomRequest(args []interface{}) (*transfertypes.QueryDenomRequest, error) { if len(args) != 1 { return nil, fmt.Errorf("invalid input arguments. Expected 1, got %d", len(args)) } @@ -202,15 +203,15 @@ func NewDenomTraceRequest(args []interface{}) (*transfertypes.QueryDenomTraceReq return nil, fmt.Errorf(ErrInvalidHash, args[0]) } - req := &transfertypes.QueryDenomTraceRequest{ + req := &transfertypes.QueryDenomRequest{ Hash: hash, } return req, nil } -// NewDenomTracesRequest returns a new denom traces request from the given arguments. -func NewDenomTracesRequest(method *abi.Method, args []interface{}) (*transfertypes.QueryDenomTracesRequest, error) { +// NewDenomsRequest returns a new denoms request from the given arguments. +func NewDenomsRequest(method *abi.Method, args []interface{}) (*transfertypes.QueryDenomsRequest, error) { if len(args) != 1 { return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 1, len(args)) } @@ -220,7 +221,7 @@ func NewDenomTracesRequest(method *abi.Method, args []interface{}) (*transfertyp return nil, fmt.Errorf("error while unpacking args to PageRequest: %w", err) } - req := &transfertypes.QueryDenomTracesRequest{ + req := &transfertypes.QueryDenomsRequest{ Pagination: &pageRequest.PageRequest, } diff --git a/precompiles/testutil/contracts/InterchainSender.json b/precompiles/testutil/contracts/InterchainSender.json index ba8e5aa8e..9079cc244 100644 --- a/precompiles/testutil/contracts/InterchainSender.json +++ b/precompiles/testutil/contracts/InterchainSender.json @@ -159,25 +159,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "string", - "name": "trace", - "type": "string" - } - ], - "name": "testDenomHash", - "outputs": [ - { - "internalType": "string", - "name": "hash", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -186,7 +167,7 @@ "type": "string" } ], - "name": "testDenomTrace", + "name": "testDenom", "outputs": [ { "components": [ @@ -201,7 +182,7 @@ "type": "string" } ], - "internalType": "struct DenomTrace", + "internalType": "struct Denom", "name": "denomTrace", "type": "tuple" } @@ -209,6 +190,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "string", + "name": "trace", + "type": "string" + } + ], + "name": "testDenomHash", + "outputs": [ + { + "internalType": "string", + "name": "hash", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -244,7 +244,7 @@ "type": "tuple" } ], - "name": "testDenomTraces", + "name": "testDenoms", "outputs": [ { "components": [ @@ -259,8 +259,8 @@ "type": "string" } ], - "internalType": "struct DenomTrace[]", - "name": "denomTraces", + "internalType": "struct Denom[]", + "name": "denoms", "type": "tuple[]" }, { @@ -558,8 +558,8 @@ "type": "function" } ], - "bytecode": "0x608060405234801561001057600080fd5b50613831806100206000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c8063a363df841161008c578063dfa10f3911610066578063dfa10f3914610210578063ee5766d914610241578063f298e7a814610271578063f3675f081461028d576100cf565b8063a363df8414610194578063b9672879146101c4578063c595699a146101e0576100cf565b80631dba685b146100d4578063424af9f6146100f057806361bc221a1461010c5780636fdf23cc1461012a5780637492bdd81461015a5780637a6185e11461018a575b600080fd5b6100ee60048036038101906100e9919061131b565b6102a9565b005b61010a600480360381019061010591906114b5565b61071e565b005b6101146107f8565b604051610121919061159a565b60405180910390f35b610144600480360381019061013f919061164f565b610809565b60405161015191906117a1565b60405180910390f35b610174600480360381019061016f919061164f565b6108a7565b60405161018191906117a1565b60405180910390f35b610192610945565b005b6101ae60048036038101906101a991906117fa565b610a0a565b6040516101bb9190611bdd565b60405180910390f35b6101de60048036038101906101d99190611bff565b610a97565b005b6101fa60048036038101906101f59190611d39565b610d64565b6040516102079190611dcc565b60405180910390f35b61022a60048036038101906102259190611e12565b610dee565b604051610238929190612002565b60405180910390f35b61025b60048036038101906102569190611d39565b610e82565b604051610268919061207d565b60405180910390f35b61028b600480360381019061028691906114b5565b610f12565b005b6102a760048036038101906102a291906120f5565b610fec565b005b82156103ab5760008081819054906101000a900460070b809291906102cd90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008973ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610323906121d2565b60006040518083038185875af1925050503d8060008114610360576040519150601f19603f3d011682016040523d82523d6000602084013e610365565b606091505b50509050806103a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a090612259565b60405180910390fd5b505b60006040518060400160405280606467ffffffffffffffff168152602001606467ffffffffffffffff16815250905061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a60028b61040891906122a8565b8f8b8860006040518963ffffffff1660e01b81526004016104309897969594939291906123d4565b6020604051808303816000875af115801561044f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104739190612498565b5082156105765760008081819054906101000a900460070b8092919061049890612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf0006040516104ee906121d2565b60006040518083038185875af1925050503d806000811461052b576040519150601f19603f3d011682016040523d82523d6000602084013e610530565b606091505b5050905080610574576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056b90612259565b60405180910390fd5b505b61080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a60028b6105a491906122a8565b8f8b8860006040518963ffffffff1660e01b81526004016105cc9897969594939291906123d4565b6020604051808303816000875af11580156105eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060f9190612498565b5081156107125760008081819054906101000a900460070b8092919061063490612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf00060405161068a906121d2565b60006040518083038185875af1925050503d80600081146106c7576040519150601f19603f3d011682016040523d82523d6000602084013e6106cc565b606091505b5050905080610710576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070790612259565b60405180910390fd5b505b50505050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff166354de647b308a8a8a8a8a8a8a6040518963ffffffff1660e01b8152600401610769989796959493929190612501565b6020604051808303816000875af1158015610788573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ac9190612584565b9050806107ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e5906125fd565b60405180910390fd5b5050505050505050565b60008054906101000a900460070b81565b600061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a8a308b8b8b8b6040518a63ffffffff1660e01b81526004016108569998979695949392919061261d565b6020604051808303816000875af1158015610875573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108999190612498565b905098975050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a8a338b8b8b8b6040518a63ffffffff1660e01b81526004016108f49998979695949392919061261d565b6020604051808303816000875af1158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109379190612498565b905098975050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff166374a8f103306040518263ffffffff1660e01b815260040161098291906126ce565b6020604051808303816000875af11580156109a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c59190612584565b905080610a07576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109fe90612735565b60405180910390fd5b50565b606061080273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e84846040518363ffffffff1660e01b8152600401610a49929190612755565b600060405180830381865afa158015610a66573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610a8f9190612c2a565b905092915050565b8115610b995760008081819054906101000a900460070b80929190610abb90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008973ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610b11906121d2565b60006040518083038185875af1925050503d8060008114610b4e576040519150601f19603f3d011682016040523d82523d6000602084013e610b53565b606091505b5050905080610b97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8e90612259565b60405180910390fd5b505b60006040518060400160405280606467ffffffffffffffff168152602001606467ffffffffffffffff16815250905061080273ffffffffffffffffffffffffffffffffffffffff1663632535b9898989898e8a8860006040518963ffffffff1660e01b8152600401610c12989796959493929190612c73565b6020604051808303816000875af1158015610c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c559190612498565b508115610d585760008081819054906101000a900460070b80929190610c7a90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610cd0906121d2565b60006040518083038185875af1925050503d8060008114610d0d576040519150601f19603f3d011682016040523d82523d6000602084013e610d12565b606091505b5050905080610d56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d4d90612259565b60405180910390fd5b505b50505050505050505050565b606061080273ffffffffffffffffffffffffffffffffffffffff1663b5cb6e7d836040518263ffffffff1660e01b8152600401610da19190611dcc565b600060405180830381865afa158015610dbe573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610de79190612d22565b9050919050565b6060610df86110b7565b61080273ffffffffffffffffffffffffffffffffffffffff166322b6fad6846040518263ffffffff1660e01b8152600401610e339190612ee7565b600060405180830381865afa158015610e50573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610e79919061317f565b91509150915091565b610e8a6110db565b61080273ffffffffffffffffffffffffffffffffffffffff1663a815cdd9836040518263ffffffff1660e01b8152600401610ec59190611dcc565b600060405180830381865afa158015610ee2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610f0b91906131f7565b9050919050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663b3f536ec308a8a8a8a8a8a8a6040518963ffffffff1660e01b8152600401610f5d989796959493929190612501565b6020604051808303816000875af1158015610f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa09190612584565b905080610fe2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fd99061328c565b60405180910390fd5b5050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663473c90c73085856040518463ffffffff1660e01b815260040161102d9392919061375d565b6020604051808303816000875af115801561104c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110709190612584565b9050806110b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110a9906137db565b60405180910390fd5b505050565b604051806040016040528060608152602001600067ffffffffffffffff1681525090565b604051806040016040528060608152602001606081525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061113482611109565b9050919050565b61114481611129565b811461114f57600080fd5b50565b6000813590506111618161113b565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6111ba82611171565b810181811067ffffffffffffffff821117156111d9576111d8611182565b5b80604052505050565b60006111ec6110f5565b90506111f882826111b1565b919050565b600067ffffffffffffffff82111561121857611217611182565b5b61122182611171565b9050602081019050919050565b82818337600083830152505050565b600061125061124b846111fd565b6111e2565b90508281526020810184848401111561126c5761126b61116c565b5b61127784828561122e565b509392505050565b600082601f83011261129457611293611167565b5b81356112a484826020860161123d565b91505092915050565b6000819050919050565b6112c0816112ad565b81146112cb57600080fd5b50565b6000813590506112dd816112b7565b92915050565b60008115159050919050565b6112f8816112e3565b811461130357600080fd5b50565b600081359050611315816112ef565b92915050565b60008060008060008060008060006101208a8c03121561133e5761133d6110ff565b5b600061134c8c828d01611152565b99505060208a013567ffffffffffffffff81111561136d5761136c611104565b5b6113798c828d0161127f565b98505060408a013567ffffffffffffffff81111561139a57611399611104565b5b6113a68c828d0161127f565b97505060608a013567ffffffffffffffff8111156113c7576113c6611104565b5b6113d38c828d0161127f565b96505060806113e48c828d016112ce565b95505060a08a013567ffffffffffffffff81111561140557611404611104565b5b6114118c828d0161127f565b94505060c06114228c828d01611306565b93505060e06114338c828d01611306565b9250506101006114458c828d01611306565b9150509295985092959850929598565b600080fd5b600080fd5b60008083601f84011261147557611474611167565b5b8235905067ffffffffffffffff81111561149257611491611455565b5b6020830191508360018202830111156114ae576114ad61145a565b5b9250929050565b60008060008060008060006080888a0312156114d4576114d36110ff565b5b600088013567ffffffffffffffff8111156114f2576114f1611104565b5b6114fe8a828b0161145f565b9750975050602088013567ffffffffffffffff81111561152157611520611104565b5b61152d8a828b0161145f565b9550955050604088013567ffffffffffffffff8111156115505761154f611104565b5b61155c8a828b0161145f565b9350935050606061156f8a828b016112ce565b91505092959891949750929550565b60008160070b9050919050565b6115948161157e565b82525050565b60006020820190506115af600083018461158b565b92915050565b600080fd5b600080fd5b600067ffffffffffffffff82169050919050565b6115dc816115bf565b81146115e757600080fd5b50565b6000813590506115f9816115d3565b92915050565b600060408284031215611615576116146115b5565b5b61161f60406111e2565b9050600061162f848285016115ea565b6000830152506020611643848285016115ea565b60208301525092915050565b600080600080600080600080610120898b0312156116705761166f6110ff565b5b600089013567ffffffffffffffff81111561168e5761168d611104565b5b61169a8b828c0161127f565b985050602089013567ffffffffffffffff8111156116bb576116ba611104565b5b6116c78b828c0161127f565b975050604089013567ffffffffffffffff8111156116e8576116e7611104565b5b6116f48b828c0161127f565b96505060606117058b828c016112ce565b955050608089013567ffffffffffffffff81111561172657611725611104565b5b6117328b828c0161127f565b94505060a06117438b828c016115ff565b93505060e06117548b828c016115ea565b92505061010089013567ffffffffffffffff81111561177657611775611104565b5b6117828b828c0161127f565b9150509295985092959890939650565b61179b816115bf565b82525050565b60006020820190506117b66000830184611792565b92915050565b60006117c782611109565b9050919050565b6117d7816117bc565b81146117e257600080fd5b50565b6000813590506117f4816117ce565b92915050565b60008060408385031215611811576118106110ff565b5b600061181f858286016117e5565b9250506020611830858286016117e5565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b838110156118a0578082015181840152602081019050611885565b60008484015250505050565b60006118b782611866565b6118c18185611871565b93506118d1818560208601611882565b6118da81611171565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61191a816112ad565b82525050565b6000604083016000830151848203600086015261193d82826118ac565b91505060208301516119526020860182611911565b508091505092915050565b60006119698383611920565b905092915050565b6000602082019050919050565b6000611989826118e5565b61199381856118f0565b9350836020820285016119a585611901565b8060005b858110156119e157848403895281516119c2858261195d565b94506119cd83611971565b925060208a019950506001810190506119a9565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000611a2b83836118ac565b905092915050565b6000602082019050919050565b6000611a4b826119f3565b611a5581856119fe565b935083602082028501611a6785611a0f565b8060005b85811015611aa35784840389528151611a848582611a1f565b9450611a8f83611a33565b925060208a01995050600181019050611a6b565b50829750879550505050505092915050565b600060a0830160008301518482036000860152611ad282826118ac565b91505060208301518482036020860152611aec82826118ac565b91505060408301518482036040860152611b06828261197e565b91505060608301518482036060860152611b208282611a40565b91505060808301518482036080860152611b3a8282611a40565b9150508091505092915050565b6000611b538383611ab5565b905092915050565b6000602082019050919050565b6000611b738261183a565b611b7d8185611845565b935083602082028501611b8f85611856565b8060005b85811015611bcb5784840389528151611bac8582611b47565b9450611bb783611b5b565b925060208a01995050600181019050611b93565b50829750879550505050505092915050565b60006020820190508181036000830152611bf78184611b68565b905092915050565b60008060008060008060008060006101208a8c031215611c2257611c216110ff565b5b6000611c308c828d01611152565b9950506020611c418c828d016117e5565b98505060408a013567ffffffffffffffff811115611c6257611c61611104565b5b611c6e8c828d0161127f565b97505060608a013567ffffffffffffffff811115611c8f57611c8e611104565b5b611c9b8c828d0161127f565b96505060808a013567ffffffffffffffff811115611cbc57611cbb611104565b5b611cc88c828d0161127f565b95505060a0611cd98c828d016112ce565b94505060c08a013567ffffffffffffffff811115611cfa57611cf9611104565b5b611d068c828d0161127f565b93505060e0611d178c828d01611306565b925050610100611d298c828d01611306565b9150509295985092959850929598565b600060208284031215611d4f57611d4e6110ff565b5b600082013567ffffffffffffffff811115611d6d57611d6c611104565b5b611d798482850161127f565b91505092915050565b600082825260208201905092915050565b6000611d9e82611866565b611da88185611d82565b9350611db8818560208601611882565b611dc181611171565b840191505092915050565b60006020820190508181036000830152611de68184611d93565b905092915050565b600080fd5b600060a08284031215611e0957611e08611dee565b5b81905092915050565b600060208284031215611e2857611e276110ff565b5b600082013567ffffffffffffffff811115611e4657611e45611104565b5b611e5284828501611df3565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006040830160008301518482036000860152611ea482826118ac565b91505060208301518482036020860152611ebe82826118ac565b9150508091505092915050565b6000611ed78383611e87565b905092915050565b6000602082019050919050565b6000611ef782611e5b565b611f018185611e66565b935083602082028501611f1385611e77565b8060005b85811015611f4f5784840389528151611f308582611ecb565b9450611f3b83611edf565b925060208a01995050600181019050611f17565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b6000611f8882611f61565b611f928185611f6c565b9350611fa2818560208601611882565b611fab81611171565b840191505092915050565b611fbf816115bf565b82525050565b60006040830160008301518482036000860152611fe28282611f7d565b9150506020830151611ff76020860182611fb6565b508091505092915050565b6000604082019050818103600083015261201c8185611eec565b905081810360208301526120308184611fc5565b90509392505050565b6000604083016000830151848203600086015261205682826118ac565b9150506020830151848203602086015261207082826118ac565b9150508091505092915050565b600060208201905081810360008301526120978184612039565b905092915050565b60008083601f8401126120b5576120b4611167565b5b8235905067ffffffffffffffff8111156120d2576120d1611455565b5b6020830191508360208202830111156120ee576120ed61145a565b5b9250929050565b6000806020838503121561210c5761210b6110ff565b5b600083013567ffffffffffffffff81111561212a57612129611104565b5b6121368582860161209f565b92509250509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061217c8261157e565b9150677fffffffffffffff820361219657612195612142565b5b600182019050919050565b600081905092915050565b50565b60006121bc6000836121a1565b91506121c7826121ac565b600082019050919050565b60006121dd826121af565b9150819050919050565b7f4661696c656420746f2073656e6420457468657220746f2064656c656761746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000612243602183611d82565b915061224e826121e7565b604082019050919050565b6000602082019050818103600083015261227281612236565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006122b3826112ad565b91506122be836112ad565b9250826122ce576122cd612279565b5b828204905092915050565b6122e2816112ad565b82525050565b6000819050919050565b600061230d61230861230384611109565b6122e8565b611109565b9050919050565b600061231f826122f2565b9050919050565b600061233182612314565b9050919050565b61234181612326565b82525050565b60408201600082015161235d6000850182611fb6565b5060208201516123706020850182611fb6565b50505050565b6000819050919050565b600061239b61239661239184612376565b6122e8565b6115bf565b9050919050565b6123ab81612380565b82525050565b60006123be600083611d82565b91506123c9826121ac565b600082019050919050565b60006101408201905081810360008301526123ef818b611d93565b90508181036020830152612403818a611d93565b905081810360408301526124178189611d93565b905061242660608301886122d9565b6124336080830187612338565b81810360a08301526124458186611d93565b905061245460c0830185612347565b6124626101008301846123a2565b818103610120830152612474816123b1565b90509998505050505050505050565b600081519050612492816115d3565b92915050565b6000602082840312156124ae576124ad6110ff565b5b60006124bc84828501612483565b91505092915050565b6124ce816117bc565b82525050565b60006124e08385611d82565b93506124ed83858461122e565b6124f683611171565b840190509392505050565b600060a082019050612516600083018b6124c5565b818103602083015261252981898b6124d4565b9050818103604083015261253e8187896124d4565b905081810360608301526125538185876124d4565b905061256260808301846122d9565b9998505050505050505050565b60008151905061257e816112ef565b92915050565b60006020828403121561259a576125996110ff565b5b60006125a88482850161256f565b91505092915050565b7f4661696c656420746f20696e63726561736520616c6c6f77616e636500000000600082015250565b60006125e7601c83611d82565b91506125f2826125b1565b602082019050919050565b60006020820190508181036000830152612616816125da565b9050919050565b6000610140820190508181036000830152612638818c611d93565b9050818103602083015261264c818b611d93565b90508181036040830152612660818a611d93565b905061266f60608301896122d9565b61267c60808301886124c5565b81810360a083015261268e8187611d93565b905061269d60c0830186612347565b6126ab610100830185611792565b8181036101208301526126be8184611d93565b90509a9950505050505050505050565b60006020820190506126e360008301846124c5565b92915050565b7f4661696c656420746f207265766f6b6520617070726f76616c00000000000000600082015250565b600061271f601983611d82565b915061272a826126e9565b602082019050919050565b6000602082019050818103600083015261274e81612712565b9050919050565b600060408201905061276a60008301856124c5565b61277760208301846124c5565b9392505050565b600067ffffffffffffffff82111561279957612798611182565b5b602082029050602081019050919050565b60006127bd6127b8846111fd565b6111e2565b9050828152602081018484840111156127d9576127d861116c565b5b6127e4848285611882565b509392505050565b600082601f83011261280157612800611167565b5b81516128118482602086016127aa565b91505092915050565b600067ffffffffffffffff82111561283557612834611182565b5b602082029050602081019050919050565b600081519050612855816112b7565b92915050565b600060408284031215612871576128706115b5565b5b61287b60406111e2565b9050600082015167ffffffffffffffff81111561289b5761289a6115ba565b5b6128a7848285016127ec565b60008301525060206128bb84828501612846565b60208301525092915050565b60006128da6128d58461281a565b6111e2565b905080838252602082019050602084028301858111156128fd576128fc61145a565b5b835b8181101561294457805167ffffffffffffffff81111561292257612921611167565b5b80860161292f898261285b565b855260208501945050506020810190506128ff565b5050509392505050565b600082601f83011261296357612962611167565b5b81516129738482602086016128c7565b91505092915050565b600067ffffffffffffffff82111561299757612996611182565b5b602082029050602081019050919050565b60006129bb6129b68461297c565b6111e2565b905080838252602082019050602084028301858111156129de576129dd61145a565b5b835b81811015612a2557805167ffffffffffffffff811115612a0357612a02611167565b5b808601612a1089826127ec565b855260208501945050506020810190506129e0565b5050509392505050565b600082601f830112612a4457612a43611167565b5b8151612a548482602086016129a8565b91505092915050565b600060a08284031215612a7357612a726115b5565b5b612a7d60a06111e2565b9050600082015167ffffffffffffffff811115612a9d57612a9c6115ba565b5b612aa9848285016127ec565b600083015250602082015167ffffffffffffffff811115612acd57612acc6115ba565b5b612ad9848285016127ec565b602083015250604082015167ffffffffffffffff811115612afd57612afc6115ba565b5b612b098482850161294e565b604083015250606082015167ffffffffffffffff811115612b2d57612b2c6115ba565b5b612b3984828501612a2f565b606083015250608082015167ffffffffffffffff811115612b5d57612b5c6115ba565b5b612b6984828501612a2f565b60808301525092915050565b6000612b88612b838461277e565b6111e2565b90508083825260208201905060208402830185811115612bab57612baa61145a565b5b835b81811015612bf257805167ffffffffffffffff811115612bd057612bcf611167565b5b808601612bdd8982612a5d565b85526020850194505050602081019050612bad565b5050509392505050565b600082601f830112612c1157612c10611167565b5b8151612c21848260208601612b75565b91505092915050565b600060208284031215612c4057612c3f6110ff565b5b600082015167ffffffffffffffff811115612c5e57612c5d611104565b5b612c6a84828501612bfc565b91505092915050565b6000610140820190508181036000830152612c8e818b611d93565b90508181036020830152612ca2818a611d93565b90508181036040830152612cb68189611d93565b9050612cc560608301886122d9565b612cd260808301876124c5565b81810360a0830152612ce48186611d93565b9050612cf360c0830185612347565b612d016101008301846123a2565b818103610120830152612d13816123b1565b90509998505050505050505050565b600060208284031215612d3857612d376110ff565b5b600082015167ffffffffffffffff811115612d5657612d55611104565b5b612d62848285016127ec565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112612d9757612d96612d75565b5b83810192508235915060208301925067ffffffffffffffff821115612dbf57612dbe612d6b565b5b600182023603831315612dd557612dd4612d70565b5b509250929050565b6000612de98385611f6c565b9350612df683858461122e565b612dff83611171565b840190509392505050565b6000612e1960208401846115ea565b905092915050565b6000612e306020840184611306565b905092915050565b612e41816112e3565b82525050565b600060a08301612e5a6000840184612d7a565b8583036000870152612e6d838284612ddd565b92505050612e7e6020840184612e0a565b612e8b6020860182611fb6565b50612e996040840184612e0a565b612ea66040860182611fb6565b50612eb46060840184612e21565b612ec16060860182612e38565b50612ecf6080840184612e21565b612edc6080860182612e38565b508091505092915050565b60006020820190508181036000830152612f018184612e47565b905092915050565b600067ffffffffffffffff821115612f2457612f23611182565b5b602082029050602081019050919050565b600060408284031215612f4b57612f4a6115b5565b5b612f5560406111e2565b9050600082015167ffffffffffffffff811115612f7557612f746115ba565b5b612f81848285016127ec565b600083015250602082015167ffffffffffffffff811115612fa557612fa46115ba565b5b612fb1848285016127ec565b60208301525092915050565b6000612fd0612fcb84612f09565b6111e2565b90508083825260208201905060208402830185811115612ff357612ff261145a565b5b835b8181101561303a57805167ffffffffffffffff81111561301857613017611167565b5b8086016130258982612f35565b85526020850194505050602081019050612ff5565b5050509392505050565b600082601f83011261305957613058611167565b5b8151613069848260208601612fbd565b91505092915050565b600067ffffffffffffffff82111561308d5761308c611182565b5b61309682611171565b9050602081019050919050565b60006130b66130b184613072565b6111e2565b9050828152602081018484840111156130d2576130d161116c565b5b6130dd848285611882565b509392505050565b600082601f8301126130fa576130f9611167565b5b815161310a8482602086016130a3565b91505092915050565b600060408284031215613129576131286115b5565b5b61313360406111e2565b9050600082015167ffffffffffffffff811115613153576131526115ba565b5b61315f848285016130e5565b600083015250602061317384828501612483565b60208301525092915050565b60008060408385031215613196576131956110ff565b5b600083015167ffffffffffffffff8111156131b4576131b3611104565b5b6131c085828601613044565b925050602083015167ffffffffffffffff8111156131e1576131e0611104565b5b6131ed85828601613113565b9150509250929050565b60006020828403121561320d5761320c6110ff565b5b600082015167ffffffffffffffff81111561322b5761322a611104565b5b61323784828501612f35565b91505092915050565b7f4661696c656420746f20646563726561736520616c6c6f77616e636500000000600082015250565b6000613276601c83611d82565b915061328182613240565b602082019050919050565b600060208201905081810360008301526132a581613269565b9050919050565b6000819050919050565b600080833560016020038436030381126132d3576132d2612d75565b5b83810192508235915060208301925067ffffffffffffffff8211156132fb576132fa612d6b565b5b60018202360383131561331157613310612d70565b5b509250929050565b60006133258385611871565b935061333283858461122e565b61333b83611171565b840190509392505050565b6000808335600160200384360303811261336357613362612d75565b5b83810192508235915060208301925067ffffffffffffffff82111561338b5761338a612d6b565b5b6020820236038313156133a1576133a0612d70565b5b509250929050565b6000819050919050565b60006133c260208401846112ce565b905092915050565b6000604083016133dd60008401846132b6565b85830360008701526133f0838284613319565b9250505061340160208401846133b3565b61340e6020860182611911565b508091505092915050565b600061342583836133ca565b905092915050565b60008235600160400383360303811261344957613448612d75565b5b82810191505092915050565b6000602082019050919050565b600061346e83856118f0565b935083602084028501613480846133a9565b8060005b878110156134c457848403895261349b828461342d565b6134a58582613419565b94506134b083613455565b925060208a01995050600181019050613484565b50829750879450505050509392505050565b600080833560016020038436030381126134f3576134f2612d75565b5b83810192508235915060208301925067ffffffffffffffff82111561351b5761351a612d6b565b5b60208202360383131561353157613530612d70565b5b509250929050565b6000819050919050565b6000613550848484613319565b90509392505050565b6000602082019050919050565b600061357283856119fe565b93508360208402850161358484613539565b8060005b878110156135ca57848403895261359f82846132b6565b6135aa868284613543565b95506135b584613559565b935060208b019a505050600181019050613588565b50829750879450505050509392505050565b600060a083016135ef60008401846132b6565b8583036000870152613602838284613319565b9250505061361360208401846132b6565b8583036020870152613626838284613319565b925050506136376040840184613346565b858303604087015261364a838284613462565b9250505061365b60608401846134d6565b858303606087015261366e838284613566565b9250505061367f60808401846134d6565b8583036080870152613692838284613566565b925050508091505092915050565b60006136ac83836135dc565b905092915050565b60008235600160a0038336030381126136d0576136cf612d75565b5b82810191505092915050565b6000602082019050919050565b60006136f58385611845565b935083602084028501613707846132ac565b8060005b8781101561374b57848403895261372282846136b4565b61372c85826136a0565b9450613737836136dc565b925060208a0199505060018101905061370b565b50829750879450505050509392505050565b600060408201905061377260008301866124c5565b81810360208301526137858184866136e9565b9050949350505050565b7f4661696c656420746f20706572666f726d20617070726f76616c000000000000600082015250565b60006137c5601a83611d82565b91506137d08261378f565b602082019050919050565b600060208201905081810360008301526137f4816137b8565b905091905056fea2646970667358221220ad77753d207f5fa16ed802e3577e3ce385d25445983916e5d53914f0d256891964736f6c63430008140033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100cf5760003560e01c8063a363df841161008c578063dfa10f3911610066578063dfa10f3914610210578063ee5766d914610241578063f298e7a814610271578063f3675f081461028d576100cf565b8063a363df8414610194578063b9672879146101c4578063c595699a146101e0576100cf565b80631dba685b146100d4578063424af9f6146100f057806361bc221a1461010c5780636fdf23cc1461012a5780637492bdd81461015a5780637a6185e11461018a575b600080fd5b6100ee60048036038101906100e9919061131b565b6102a9565b005b61010a600480360381019061010591906114b5565b61071e565b005b6101146107f8565b604051610121919061159a565b60405180910390f35b610144600480360381019061013f919061164f565b610809565b60405161015191906117a1565b60405180910390f35b610174600480360381019061016f919061164f565b6108a7565b60405161018191906117a1565b60405180910390f35b610192610945565b005b6101ae60048036038101906101a991906117fa565b610a0a565b6040516101bb9190611bdd565b60405180910390f35b6101de60048036038101906101d99190611bff565b610a97565b005b6101fa60048036038101906101f59190611d39565b610d64565b6040516102079190611dcc565b60405180910390f35b61022a60048036038101906102259190611e12565b610dee565b604051610238929190612002565b60405180910390f35b61025b60048036038101906102569190611d39565b610e82565b604051610268919061207d565b60405180910390f35b61028b600480360381019061028691906114b5565b610f12565b005b6102a760048036038101906102a291906120f5565b610fec565b005b82156103ab5760008081819054906101000a900460070b809291906102cd90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008973ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610323906121d2565b60006040518083038185875af1925050503d8060008114610360576040519150601f19603f3d011682016040523d82523d6000602084013e610365565b606091505b50509050806103a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a090612259565b60405180910390fd5b505b60006040518060400160405280606467ffffffffffffffff168152602001606467ffffffffffffffff16815250905061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a60028b61040891906122a8565b8f8b8860006040518963ffffffff1660e01b81526004016104309897969594939291906123d4565b6020604051808303816000875af115801561044f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104739190612498565b5082156105765760008081819054906101000a900460070b8092919061049890612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf0006040516104ee906121d2565b60006040518083038185875af1925050503d806000811461052b576040519150601f19603f3d011682016040523d82523d6000602084013e610530565b606091505b5050905080610574576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056b90612259565b60405180910390fd5b505b61080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a60028b6105a491906122a8565b8f8b8860006040518963ffffffff1660e01b81526004016105cc9897969594939291906123d4565b6020604051808303816000875af11580156105eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060f9190612498565b5081156107125760008081819054906101000a900460070b8092919061063490612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf00060405161068a906121d2565b60006040518083038185875af1925050503d80600081146106c7576040519150601f19603f3d011682016040523d82523d6000602084013e6106cc565b606091505b5050905080610710576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070790612259565b60405180910390fd5b505b50505050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff166354de647b308a8a8a8a8a8a8a6040518963ffffffff1660e01b8152600401610769989796959493929190612501565b6020604051808303816000875af1158015610788573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ac9190612584565b9050806107ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e5906125fd565b60405180910390fd5b5050505050505050565b60008054906101000a900460070b81565b600061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a8a308b8b8b8b6040518a63ffffffff1660e01b81526004016108569998979695949392919061261d565b6020604051808303816000875af1158015610875573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108999190612498565b905098975050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a8a338b8b8b8b6040518a63ffffffff1660e01b81526004016108f49998979695949392919061261d565b6020604051808303816000875af1158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109379190612498565b905098975050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff166374a8f103306040518263ffffffff1660e01b815260040161098291906126ce565b6020604051808303816000875af11580156109a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c59190612584565b905080610a07576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109fe90612735565b60405180910390fd5b50565b606061080273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e84846040518363ffffffff1660e01b8152600401610a49929190612755565b600060405180830381865afa158015610a66573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610a8f9190612c2a565b905092915050565b8115610b995760008081819054906101000a900460070b80929190610abb90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008973ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610b11906121d2565b60006040518083038185875af1925050503d8060008114610b4e576040519150601f19603f3d011682016040523d82523d6000602084013e610b53565b606091505b5050905080610b97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8e90612259565b60405180910390fd5b505b60006040518060400160405280606467ffffffffffffffff168152602001606467ffffffffffffffff16815250905061080273ffffffffffffffffffffffffffffffffffffffff1663632535b9898989898e8a8860006040518963ffffffff1660e01b8152600401610c12989796959493929190612c73565b6020604051808303816000875af1158015610c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c559190612498565b508115610d585760008081819054906101000a900460070b80929190610c7a90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610cd0906121d2565b60006040518083038185875af1925050503d8060008114610d0d576040519150601f19603f3d011682016040523d82523d6000602084013e610d12565b606091505b5050905080610d56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d4d90612259565b60405180910390fd5b505b50505050505050505050565b606061080273ffffffffffffffffffffffffffffffffffffffff1663b5cb6e7d836040518263ffffffff1660e01b8152600401610da19190611dcc565b600060405180830381865afa158015610dbe573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610de79190612d22565b9050919050565b6060610df86110b7565b61080273ffffffffffffffffffffffffffffffffffffffff166322b6fad6846040518263ffffffff1660e01b8152600401610e339190612ee7565b600060405180830381865afa158015610e50573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610e79919061317f565b91509150915091565b610e8a6110db565b61080273ffffffffffffffffffffffffffffffffffffffff1663a815cdd9836040518263ffffffff1660e01b8152600401610ec59190611dcc565b600060405180830381865afa158015610ee2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610f0b91906131f7565b9050919050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663b3f536ec308a8a8a8a8a8a8a6040518963ffffffff1660e01b8152600401610f5d989796959493929190612501565b6020604051808303816000875af1158015610f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa09190612584565b905080610fe2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fd99061328c565b60405180910390fd5b5050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663473c90c73085856040518463ffffffff1660e01b815260040161102d9392919061375d565b6020604051808303816000875af115801561104c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110709190612584565b9050806110b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110a9906137db565b60405180910390fd5b505050565b604051806040016040528060608152602001600067ffffffffffffffff1681525090565b604051806040016040528060608152602001606081525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061113482611109565b9050919050565b61114481611129565b811461114f57600080fd5b50565b6000813590506111618161113b565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6111ba82611171565b810181811067ffffffffffffffff821117156111d9576111d8611182565b5b80604052505050565b60006111ec6110f5565b90506111f882826111b1565b919050565b600067ffffffffffffffff82111561121857611217611182565b5b61122182611171565b9050602081019050919050565b82818337600083830152505050565b600061125061124b846111fd565b6111e2565b90508281526020810184848401111561126c5761126b61116c565b5b61127784828561122e565b509392505050565b600082601f83011261129457611293611167565b5b81356112a484826020860161123d565b91505092915050565b6000819050919050565b6112c0816112ad565b81146112cb57600080fd5b50565b6000813590506112dd816112b7565b92915050565b60008115159050919050565b6112f8816112e3565b811461130357600080fd5b50565b600081359050611315816112ef565b92915050565b60008060008060008060008060006101208a8c03121561133e5761133d6110ff565b5b600061134c8c828d01611152565b99505060208a013567ffffffffffffffff81111561136d5761136c611104565b5b6113798c828d0161127f565b98505060408a013567ffffffffffffffff81111561139a57611399611104565b5b6113a68c828d0161127f565b97505060608a013567ffffffffffffffff8111156113c7576113c6611104565b5b6113d38c828d0161127f565b96505060806113e48c828d016112ce565b95505060a08a013567ffffffffffffffff81111561140557611404611104565b5b6114118c828d0161127f565b94505060c06114228c828d01611306565b93505060e06114338c828d01611306565b9250506101006114458c828d01611306565b9150509295985092959850929598565b600080fd5b600080fd5b60008083601f84011261147557611474611167565b5b8235905067ffffffffffffffff81111561149257611491611455565b5b6020830191508360018202830111156114ae576114ad61145a565b5b9250929050565b60008060008060008060006080888a0312156114d4576114d36110ff565b5b600088013567ffffffffffffffff8111156114f2576114f1611104565b5b6114fe8a828b0161145f565b9750975050602088013567ffffffffffffffff81111561152157611520611104565b5b61152d8a828b0161145f565b9550955050604088013567ffffffffffffffff8111156115505761154f611104565b5b61155c8a828b0161145f565b9350935050606061156f8a828b016112ce565b91505092959891949750929550565b60008160070b9050919050565b6115948161157e565b82525050565b60006020820190506115af600083018461158b565b92915050565b600080fd5b600080fd5b600067ffffffffffffffff82169050919050565b6115dc816115bf565b81146115e757600080fd5b50565b6000813590506115f9816115d3565b92915050565b600060408284031215611615576116146115b5565b5b61161f60406111e2565b9050600061162f848285016115ea565b6000830152506020611643848285016115ea565b60208301525092915050565b600080600080600080600080610120898b0312156116705761166f6110ff565b5b600089013567ffffffffffffffff81111561168e5761168d611104565b5b61169a8b828c0161127f565b985050602089013567ffffffffffffffff8111156116bb576116ba611104565b5b6116c78b828c0161127f565b975050604089013567ffffffffffffffff8111156116e8576116e7611104565b5b6116f48b828c0161127f565b96505060606117058b828c016112ce565b955050608089013567ffffffffffffffff81111561172657611725611104565b5b6117328b828c0161127f565b94505060a06117438b828c016115ff565b93505060e06117548b828c016115ea565b92505061010089013567ffffffffffffffff81111561177657611775611104565b5b6117828b828c0161127f565b9150509295985092959890939650565b61179b816115bf565b82525050565b60006020820190506117b66000830184611792565b92915050565b60006117c782611109565b9050919050565b6117d7816117bc565b81146117e257600080fd5b50565b6000813590506117f4816117ce565b92915050565b60008060408385031215611811576118106110ff565b5b600061181f858286016117e5565b9250506020611830858286016117e5565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b838110156118a0578082015181840152602081019050611885565b60008484015250505050565b60006118b782611866565b6118c18185611871565b93506118d1818560208601611882565b6118da81611171565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61191a816112ad565b82525050565b6000604083016000830151848203600086015261193d82826118ac565b91505060208301516119526020860182611911565b508091505092915050565b60006119698383611920565b905092915050565b6000602082019050919050565b6000611989826118e5565b61199381856118f0565b9350836020820285016119a585611901565b8060005b858110156119e157848403895281516119c2858261195d565b94506119cd83611971565b925060208a019950506001810190506119a9565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000611a2b83836118ac565b905092915050565b6000602082019050919050565b6000611a4b826119f3565b611a5581856119fe565b935083602082028501611a6785611a0f565b8060005b85811015611aa35784840389528151611a848582611a1f565b9450611a8f83611a33565b925060208a01995050600181019050611a6b565b50829750879550505050505092915050565b600060a0830160008301518482036000860152611ad282826118ac565b91505060208301518482036020860152611aec82826118ac565b91505060408301518482036040860152611b06828261197e565b91505060608301518482036060860152611b208282611a40565b91505060808301518482036080860152611b3a8282611a40565b9150508091505092915050565b6000611b538383611ab5565b905092915050565b6000602082019050919050565b6000611b738261183a565b611b7d8185611845565b935083602082028501611b8f85611856565b8060005b85811015611bcb5784840389528151611bac8582611b47565b9450611bb783611b5b565b925060208a01995050600181019050611b93565b50829750879550505050505092915050565b60006020820190508181036000830152611bf78184611b68565b905092915050565b60008060008060008060008060006101208a8c031215611c2257611c216110ff565b5b6000611c308c828d01611152565b9950506020611c418c828d016117e5565b98505060408a013567ffffffffffffffff811115611c6257611c61611104565b5b611c6e8c828d0161127f565b97505060608a013567ffffffffffffffff811115611c8f57611c8e611104565b5b611c9b8c828d0161127f565b96505060808a013567ffffffffffffffff811115611cbc57611cbb611104565b5b611cc88c828d0161127f565b95505060a0611cd98c828d016112ce565b94505060c08a013567ffffffffffffffff811115611cfa57611cf9611104565b5b611d068c828d0161127f565b93505060e0611d178c828d01611306565b925050610100611d298c828d01611306565b9150509295985092959850929598565b600060208284031215611d4f57611d4e6110ff565b5b600082013567ffffffffffffffff811115611d6d57611d6c611104565b5b611d798482850161127f565b91505092915050565b600082825260208201905092915050565b6000611d9e82611866565b611da88185611d82565b9350611db8818560208601611882565b611dc181611171565b840191505092915050565b60006020820190508181036000830152611de68184611d93565b905092915050565b600080fd5b600060a08284031215611e0957611e08611dee565b5b81905092915050565b600060208284031215611e2857611e276110ff565b5b600082013567ffffffffffffffff811115611e4657611e45611104565b5b611e5284828501611df3565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006040830160008301518482036000860152611ea482826118ac565b91505060208301518482036020860152611ebe82826118ac565b9150508091505092915050565b6000611ed78383611e87565b905092915050565b6000602082019050919050565b6000611ef782611e5b565b611f018185611e66565b935083602082028501611f1385611e77565b8060005b85811015611f4f5784840389528151611f308582611ecb565b9450611f3b83611edf565b925060208a01995050600181019050611f17565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b6000611f8882611f61565b611f928185611f6c565b9350611fa2818560208601611882565b611fab81611171565b840191505092915050565b611fbf816115bf565b82525050565b60006040830160008301518482036000860152611fe28282611f7d565b9150506020830151611ff76020860182611fb6565b508091505092915050565b6000604082019050818103600083015261201c8185611eec565b905081810360208301526120308184611fc5565b90509392505050565b6000604083016000830151848203600086015261205682826118ac565b9150506020830151848203602086015261207082826118ac565b9150508091505092915050565b600060208201905081810360008301526120978184612039565b905092915050565b60008083601f8401126120b5576120b4611167565b5b8235905067ffffffffffffffff8111156120d2576120d1611455565b5b6020830191508360208202830111156120ee576120ed61145a565b5b9250929050565b6000806020838503121561210c5761210b6110ff565b5b600083013567ffffffffffffffff81111561212a57612129611104565b5b6121368582860161209f565b92509250509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061217c8261157e565b9150677fffffffffffffff820361219657612195612142565b5b600182019050919050565b600081905092915050565b50565b60006121bc6000836121a1565b91506121c7826121ac565b600082019050919050565b60006121dd826121af565b9150819050919050565b7f4661696c656420746f2073656e6420457468657220746f2064656c656761746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000612243602183611d82565b915061224e826121e7565b604082019050919050565b6000602082019050818103600083015261227281612236565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006122b3826112ad565b91506122be836112ad565b9250826122ce576122cd612279565b5b828204905092915050565b6122e2816112ad565b82525050565b6000819050919050565b600061230d61230861230384611109565b6122e8565b611109565b9050919050565b600061231f826122f2565b9050919050565b600061233182612314565b9050919050565b61234181612326565b82525050565b60408201600082015161235d6000850182611fb6565b5060208201516123706020850182611fb6565b50505050565b6000819050919050565b600061239b61239661239184612376565b6122e8565b6115bf565b9050919050565b6123ab81612380565b82525050565b60006123be600083611d82565b91506123c9826121ac565b600082019050919050565b60006101408201905081810360008301526123ef818b611d93565b90508181036020830152612403818a611d93565b905081810360408301526124178189611d93565b905061242660608301886122d9565b6124336080830187612338565b81810360a08301526124458186611d93565b905061245460c0830185612347565b6124626101008301846123a2565b818103610120830152612474816123b1565b90509998505050505050505050565b600081519050612492816115d3565b92915050565b6000602082840312156124ae576124ad6110ff565b5b60006124bc84828501612483565b91505092915050565b6124ce816117bc565b82525050565b60006124e08385611d82565b93506124ed83858461122e565b6124f683611171565b840190509392505050565b600060a082019050612516600083018b6124c5565b818103602083015261252981898b6124d4565b9050818103604083015261253e8187896124d4565b905081810360608301526125538185876124d4565b905061256260808301846122d9565b9998505050505050505050565b60008151905061257e816112ef565b92915050565b60006020828403121561259a576125996110ff565b5b60006125a88482850161256f565b91505092915050565b7f4661696c656420746f20696e63726561736520616c6c6f77616e636500000000600082015250565b60006125e7601c83611d82565b91506125f2826125b1565b602082019050919050565b60006020820190508181036000830152612616816125da565b9050919050565b6000610140820190508181036000830152612638818c611d93565b9050818103602083015261264c818b611d93565b90508181036040830152612660818a611d93565b905061266f60608301896122d9565b61267c60808301886124c5565b81810360a083015261268e8187611d93565b905061269d60c0830186612347565b6126ab610100830185611792565b8181036101208301526126be8184611d93565b90509a9950505050505050505050565b60006020820190506126e360008301846124c5565b92915050565b7f4661696c656420746f207265766f6b6520617070726f76616c00000000000000600082015250565b600061271f601983611d82565b915061272a826126e9565b602082019050919050565b6000602082019050818103600083015261274e81612712565b9050919050565b600060408201905061276a60008301856124c5565b61277760208301846124c5565b9392505050565b600067ffffffffffffffff82111561279957612798611182565b5b602082029050602081019050919050565b60006127bd6127b8846111fd565b6111e2565b9050828152602081018484840111156127d9576127d861116c565b5b6127e4848285611882565b509392505050565b600082601f83011261280157612800611167565b5b81516128118482602086016127aa565b91505092915050565b600067ffffffffffffffff82111561283557612834611182565b5b602082029050602081019050919050565b600081519050612855816112b7565b92915050565b600060408284031215612871576128706115b5565b5b61287b60406111e2565b9050600082015167ffffffffffffffff81111561289b5761289a6115ba565b5b6128a7848285016127ec565b60008301525060206128bb84828501612846565b60208301525092915050565b60006128da6128d58461281a565b6111e2565b905080838252602082019050602084028301858111156128fd576128fc61145a565b5b835b8181101561294457805167ffffffffffffffff81111561292257612921611167565b5b80860161292f898261285b565b855260208501945050506020810190506128ff565b5050509392505050565b600082601f83011261296357612962611167565b5b81516129738482602086016128c7565b91505092915050565b600067ffffffffffffffff82111561299757612996611182565b5b602082029050602081019050919050565b60006129bb6129b68461297c565b6111e2565b905080838252602082019050602084028301858111156129de576129dd61145a565b5b835b81811015612a2557805167ffffffffffffffff811115612a0357612a02611167565b5b808601612a1089826127ec565b855260208501945050506020810190506129e0565b5050509392505050565b600082601f830112612a4457612a43611167565b5b8151612a548482602086016129a8565b91505092915050565b600060a08284031215612a7357612a726115b5565b5b612a7d60a06111e2565b9050600082015167ffffffffffffffff811115612a9d57612a9c6115ba565b5b612aa9848285016127ec565b600083015250602082015167ffffffffffffffff811115612acd57612acc6115ba565b5b612ad9848285016127ec565b602083015250604082015167ffffffffffffffff811115612afd57612afc6115ba565b5b612b098482850161294e565b604083015250606082015167ffffffffffffffff811115612b2d57612b2c6115ba565b5b612b3984828501612a2f565b606083015250608082015167ffffffffffffffff811115612b5d57612b5c6115ba565b5b612b6984828501612a2f565b60808301525092915050565b6000612b88612b838461277e565b6111e2565b90508083825260208201905060208402830185811115612bab57612baa61145a565b5b835b81811015612bf257805167ffffffffffffffff811115612bd057612bcf611167565b5b808601612bdd8982612a5d565b85526020850194505050602081019050612bad565b5050509392505050565b600082601f830112612c1157612c10611167565b5b8151612c21848260208601612b75565b91505092915050565b600060208284031215612c4057612c3f6110ff565b5b600082015167ffffffffffffffff811115612c5e57612c5d611104565b5b612c6a84828501612bfc565b91505092915050565b6000610140820190508181036000830152612c8e818b611d93565b90508181036020830152612ca2818a611d93565b90508181036040830152612cb68189611d93565b9050612cc560608301886122d9565b612cd260808301876124c5565b81810360a0830152612ce48186611d93565b9050612cf360c0830185612347565b612d016101008301846123a2565b818103610120830152612d13816123b1565b90509998505050505050505050565b600060208284031215612d3857612d376110ff565b5b600082015167ffffffffffffffff811115612d5657612d55611104565b5b612d62848285016127ec565b91505092915050565b600080fd5b600080fd5b600080fd5b60008083356001602003843603038112612d9757612d96612d75565b5b83810192508235915060208301925067ffffffffffffffff821115612dbf57612dbe612d6b565b5b600182023603831315612dd557612dd4612d70565b5b509250929050565b6000612de98385611f6c565b9350612df683858461122e565b612dff83611171565b840190509392505050565b6000612e1960208401846115ea565b905092915050565b6000612e306020840184611306565b905092915050565b612e41816112e3565b82525050565b600060a08301612e5a6000840184612d7a565b8583036000870152612e6d838284612ddd565b92505050612e7e6020840184612e0a565b612e8b6020860182611fb6565b50612e996040840184612e0a565b612ea66040860182611fb6565b50612eb46060840184612e21565b612ec16060860182612e38565b50612ecf6080840184612e21565b612edc6080860182612e38565b508091505092915050565b60006020820190508181036000830152612f018184612e47565b905092915050565b600067ffffffffffffffff821115612f2457612f23611182565b5b602082029050602081019050919050565b600060408284031215612f4b57612f4a6115b5565b5b612f5560406111e2565b9050600082015167ffffffffffffffff811115612f7557612f746115ba565b5b612f81848285016127ec565b600083015250602082015167ffffffffffffffff811115612fa557612fa46115ba565b5b612fb1848285016127ec565b60208301525092915050565b6000612fd0612fcb84612f09565b6111e2565b90508083825260208201905060208402830185811115612ff357612ff261145a565b5b835b8181101561303a57805167ffffffffffffffff81111561301857613017611167565b5b8086016130258982612f35565b85526020850194505050602081019050612ff5565b5050509392505050565b600082601f83011261305957613058611167565b5b8151613069848260208601612fbd565b91505092915050565b600067ffffffffffffffff82111561308d5761308c611182565b5b61309682611171565b9050602081019050919050565b60006130b66130b184613072565b6111e2565b9050828152602081018484840111156130d2576130d161116c565b5b6130dd848285611882565b509392505050565b600082601f8301126130fa576130f9611167565b5b815161310a8482602086016130a3565b91505092915050565b600060408284031215613129576131286115b5565b5b61313360406111e2565b9050600082015167ffffffffffffffff811115613153576131526115ba565b5b61315f848285016130e5565b600083015250602061317384828501612483565b60208301525092915050565b60008060408385031215613196576131956110ff565b5b600083015167ffffffffffffffff8111156131b4576131b3611104565b5b6131c085828601613044565b925050602083015167ffffffffffffffff8111156131e1576131e0611104565b5b6131ed85828601613113565b9150509250929050565b60006020828403121561320d5761320c6110ff565b5b600082015167ffffffffffffffff81111561322b5761322a611104565b5b61323784828501612f35565b91505092915050565b7f4661696c656420746f20646563726561736520616c6c6f77616e636500000000600082015250565b6000613276601c83611d82565b915061328182613240565b602082019050919050565b600060208201905081810360008301526132a581613269565b9050919050565b6000819050919050565b600080833560016020038436030381126132d3576132d2612d75565b5b83810192508235915060208301925067ffffffffffffffff8211156132fb576132fa612d6b565b5b60018202360383131561331157613310612d70565b5b509250929050565b60006133258385611871565b935061333283858461122e565b61333b83611171565b840190509392505050565b6000808335600160200384360303811261336357613362612d75565b5b83810192508235915060208301925067ffffffffffffffff82111561338b5761338a612d6b565b5b6020820236038313156133a1576133a0612d70565b5b509250929050565b6000819050919050565b60006133c260208401846112ce565b905092915050565b6000604083016133dd60008401846132b6565b85830360008701526133f0838284613319565b9250505061340160208401846133b3565b61340e6020860182611911565b508091505092915050565b600061342583836133ca565b905092915050565b60008235600160400383360303811261344957613448612d75565b5b82810191505092915050565b6000602082019050919050565b600061346e83856118f0565b935083602084028501613480846133a9565b8060005b878110156134c457848403895261349b828461342d565b6134a58582613419565b94506134b083613455565b925060208a01995050600181019050613484565b50829750879450505050509392505050565b600080833560016020038436030381126134f3576134f2612d75565b5b83810192508235915060208301925067ffffffffffffffff82111561351b5761351a612d6b565b5b60208202360383131561353157613530612d70565b5b509250929050565b6000819050919050565b6000613550848484613319565b90509392505050565b6000602082019050919050565b600061357283856119fe565b93508360208402850161358484613539565b8060005b878110156135ca57848403895261359f82846132b6565b6135aa868284613543565b95506135b584613559565b935060208b019a505050600181019050613588565b50829750879450505050509392505050565b600060a083016135ef60008401846132b6565b8583036000870152613602838284613319565b9250505061361360208401846132b6565b8583036020870152613626838284613319565b925050506136376040840184613346565b858303604087015261364a838284613462565b9250505061365b60608401846134d6565b858303606087015261366e838284613566565b9250505061367f60808401846134d6565b8583036080870152613692838284613566565b925050508091505092915050565b60006136ac83836135dc565b905092915050565b60008235600160a0038336030381126136d0576136cf612d75565b5b82810191505092915050565b6000602082019050919050565b60006136f58385611845565b935083602084028501613707846132ac565b8060005b8781101561374b57848403895261372282846136b4565b61372c85826136a0565b9450613737836136dc565b925060208a0199505060018101905061370b565b50829750879450505050509392505050565b600060408201905061377260008301866124c5565b81810360208301526137858184866136e9565b9050949350505050565b7f4661696c656420746f20706572666f726d20617070726f76616c000000000000600082015250565b60006137c5601a83611d82565b91506137d08261378f565b602082019050919050565b600060208201905081810360008301526137f4816137b8565b905091905056fea2646970667358221220ad77753d207f5fa16ed802e3577e3ce385d25445983916e5d53914f0d256891964736f6c63430008140033", + "bytecode": "0x608060405234801561001057600080fd5b50613831806100206000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80637a6185e11161008c578063b967287911610066578063b967287914610225578063c595699a14610241578063f298e7a814610271578063f3675f081461028d576100cf565b80637a6185e1146101bb578063a363df84146101c5578063accc7b90146101f5576100cf565b80631dba685b146100d4578063424af9f6146100f057806344c286701461010c57806361bc221a1461013d5780636fdf23cc1461015b5780637492bdd81461018b575b600080fd5b6100ee60048036038101906100e9919061131b565b6102a9565b005b61010a600480360381019061010591906114b5565b61071e565b005b610126600480360381019061012191906115a2565b6107f8565b604051610134929190611825565b60405180910390f35b61014561088c565b6040516101529190611878565b60405180910390f35b61017560048036038101906101709190611919565b61089d565b6040516101829190611a6b565b60405180910390f35b6101a560048036038101906101a09190611919565b61093b565b6040516101b29190611a6b565b60405180910390f35b6101c36109d9565b005b6101df60048036038101906101da9190611ac4565b610a9e565b6040516101ec9190611e28565b60405180910390f35b61020f600480360381019061020a9190611e4a565b610b2b565b60405161021c9190611ed7565b60405180910390f35b61023f600480360381019061023a9190611ef9565b610bbb565b005b61025b60048036038101906102569190611e4a565b610e88565b604051610268919061207d565b60405180910390f35b61028b600480360381019061028691906114b5565b610f12565b005b6102a760048036038101906102a291906120f5565b610fec565b005b82156103ab5760008081819054906101000a900460070b809291906102cd90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008973ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610323906121d2565b60006040518083038185875af1925050503d8060008114610360576040519150601f19603f3d011682016040523d82523d6000602084013e610365565b606091505b50509050806103a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a090612259565b60405180910390fd5b505b60006040518060400160405280606467ffffffffffffffff168152602001606467ffffffffffffffff16815250905061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a60028b61040891906122a8565b8f8b8860006040518963ffffffff1660e01b81526004016104309897969594939291906123d4565b6020604051808303816000875af115801561044f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104739190612498565b5082156105765760008081819054906101000a900460070b8092919061049890612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf0006040516104ee906121d2565b60006040518083038185875af1925050503d806000811461052b576040519150601f19603f3d011682016040523d82523d6000602084013e610530565b606091505b5050905080610574576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056b90612259565b60405180910390fd5b505b61080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a60028b6105a491906122a8565b8f8b8860006040518963ffffffff1660e01b81526004016105cc9897969594939291906123d4565b6020604051808303816000875af11580156105eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060f9190612498565b5081156107125760008081819054906101000a900460070b8092919061063490612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf00060405161068a906121d2565b60006040518083038185875af1925050503d80600081146106c7576040519150601f19603f3d011682016040523d82523d6000602084013e6106cc565b606091505b5050905080610710576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070790612259565b60405180910390fd5b505b50505050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff166354de647b308a8a8a8a8a8a8a6040518963ffffffff1660e01b8152600401610769989796959493929190612501565b6020604051808303816000875af1158015610788573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ac9190612584565b9050806107ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e5906125fd565b60405180910390fd5b5050505050505050565b60606108026110b7565b61080273ffffffffffffffffffffffffffffffffffffffff1663c0fab104846040518263ffffffff1660e01b815260040161083d9190612799565b600060405180830381865afa15801561085a573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906108839190612aa1565b91509150915091565b60008054906101000a900460070b81565b600061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a8a308b8b8b8b6040518a63ffffffff1660e01b81526004016108ea99989796959493929190612b19565b6020604051808303816000875af1158015610909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092d9190612498565b905098975050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a8a338b8b8b8b6040518a63ffffffff1660e01b815260040161098899989796959493929190612b19565b6020604051808303816000875af11580156109a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cb9190612498565b905098975050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff166374a8f103306040518263ffffffff1660e01b8152600401610a169190612bca565b6020604051808303816000875af1158015610a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a599190612584565b905080610a9b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9290612c31565b60405180910390fd5b50565b606061080273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e84846040518363ffffffff1660e01b8152600401610add929190612c51565b600060405180830381865afa158015610afa573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610b2391906130b6565b905092915050565b610b336110db565b61080273ffffffffffffffffffffffffffffffffffffffff16635f1f98a2836040518263ffffffff1660e01b8152600401610b6e919061207d565b600060405180830381865afa158015610b8b573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610bb491906130ff565b9050919050565b8115610cbd5760008081819054906101000a900460070b80929190610bdf90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008973ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610c35906121d2565b60006040518083038185875af1925050503d8060008114610c72576040519150601f19603f3d011682016040523d82523d6000602084013e610c77565b606091505b5050905080610cbb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb290612259565b60405180910390fd5b505b60006040518060400160405280606467ffffffffffffffff168152602001606467ffffffffffffffff16815250905061080273ffffffffffffffffffffffffffffffffffffffff1663632535b9898989898e8a8860006040518963ffffffff1660e01b8152600401610d36989796959493929190613148565b6020604051808303816000875af1158015610d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d799190612498565b508115610e7c5760008081819054906101000a900460070b80929190610d9e90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610df4906121d2565b60006040518083038185875af1925050503d8060008114610e31576040519150601f19603f3d011682016040523d82523d6000602084013e610e36565b606091505b5050905080610e7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e7190612259565b60405180910390fd5b505b50505050505050505050565b606061080273ffffffffffffffffffffffffffffffffffffffff1663b5cb6e7d836040518263ffffffff1660e01b8152600401610ec5919061207d565b600060405180830381865afa158015610ee2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610f0b91906131f7565b9050919050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663b3f536ec308a8a8a8a8a8a8a6040518963ffffffff1660e01b8152600401610f5d989796959493929190612501565b6020604051808303816000875af1158015610f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa09190612584565b905080610fe2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fd99061328c565b60405180910390fd5b5050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663473c90c73085856040518463ffffffff1660e01b815260040161102d9392919061375d565b6020604051808303816000875af115801561104c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110709190612584565b9050806110b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110a9906137db565b60405180910390fd5b505050565b604051806040016040528060608152602001600067ffffffffffffffff1681525090565b604051806040016040528060608152602001606081525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061113482611109565b9050919050565b61114481611129565b811461114f57600080fd5b50565b6000813590506111618161113b565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6111ba82611171565b810181811067ffffffffffffffff821117156111d9576111d8611182565b5b80604052505050565b60006111ec6110f5565b90506111f882826111b1565b919050565b600067ffffffffffffffff82111561121857611217611182565b5b61122182611171565b9050602081019050919050565b82818337600083830152505050565b600061125061124b846111fd565b6111e2565b90508281526020810184848401111561126c5761126b61116c565b5b61127784828561122e565b509392505050565b600082601f83011261129457611293611167565b5b81356112a484826020860161123d565b91505092915050565b6000819050919050565b6112c0816112ad565b81146112cb57600080fd5b50565b6000813590506112dd816112b7565b92915050565b60008115159050919050565b6112f8816112e3565b811461130357600080fd5b50565b600081359050611315816112ef565b92915050565b60008060008060008060008060006101208a8c03121561133e5761133d6110ff565b5b600061134c8c828d01611152565b99505060208a013567ffffffffffffffff81111561136d5761136c611104565b5b6113798c828d0161127f565b98505060408a013567ffffffffffffffff81111561139a57611399611104565b5b6113a68c828d0161127f565b97505060608a013567ffffffffffffffff8111156113c7576113c6611104565b5b6113d38c828d0161127f565b96505060806113e48c828d016112ce565b95505060a08a013567ffffffffffffffff81111561140557611404611104565b5b6114118c828d0161127f565b94505060c06114228c828d01611306565b93505060e06114338c828d01611306565b9250506101006114458c828d01611306565b9150509295985092959850929598565b600080fd5b600080fd5b60008083601f84011261147557611474611167565b5b8235905067ffffffffffffffff81111561149257611491611455565b5b6020830191508360018202830111156114ae576114ad61145a565b5b9250929050565b60008060008060008060006080888a0312156114d4576114d36110ff565b5b600088013567ffffffffffffffff8111156114f2576114f1611104565b5b6114fe8a828b0161145f565b9750975050602088013567ffffffffffffffff81111561152157611520611104565b5b61152d8a828b0161145f565b9550955050604088013567ffffffffffffffff8111156115505761154f611104565b5b61155c8a828b0161145f565b9350935050606061156f8a828b016112ce565b91505092959891949750929550565b600080fd5b600060a082840312156115995761159861157e565b5b81905092915050565b6000602082840312156115b8576115b76110ff565b5b600082013567ffffffffffffffff8111156115d6576115d5611104565b5b6115e284828501611583565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611651578082015181840152602081019050611636565b60008484015250505050565b600061166882611617565b6116728185611622565b9350611682818560208601611633565b61168b81611171565b840191505092915050565b600060408301600083015184820360008601526116b3828261165d565b915050602083015184820360208601526116cd828261165d565b9150508091505092915050565b60006116e68383611696565b905092915050565b6000602082019050919050565b6000611706826115eb565b61171081856115f6565b93508360208202850161172285611607565b8060005b8581101561175e578484038952815161173f85826116da565b945061174a836116ee565b925060208a01995050600181019050611726565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b600061179782611770565b6117a1818561177b565b93506117b1818560208601611633565b6117ba81611171565b840191505092915050565b600067ffffffffffffffff82169050919050565b6117e2816117c5565b82525050565b60006040830160008301518482036000860152611805828261178c565b915050602083015161181a60208601826117d9565b508091505092915050565b6000604082019050818103600083015261183f81856116fb565b9050818103602083015261185381846117e8565b90509392505050565b60008160070b9050919050565b6118728161185c565b82525050565b600060208201905061188d6000830184611869565b92915050565b600080fd5b600080fd5b6118a6816117c5565b81146118b157600080fd5b50565b6000813590506118c38161189d565b92915050565b6000604082840312156118df576118de611893565b5b6118e960406111e2565b905060006118f9848285016118b4565b600083015250602061190d848285016118b4565b60208301525092915050565b600080600080600080600080610120898b03121561193a576119396110ff565b5b600089013567ffffffffffffffff81111561195857611957611104565b5b6119648b828c0161127f565b985050602089013567ffffffffffffffff81111561198557611984611104565b5b6119918b828c0161127f565b975050604089013567ffffffffffffffff8111156119b2576119b1611104565b5b6119be8b828c0161127f565b96505060606119cf8b828c016112ce565b955050608089013567ffffffffffffffff8111156119f0576119ef611104565b5b6119fc8b828c0161127f565b94505060a0611a0d8b828c016118c9565b93505060e0611a1e8b828c016118b4565b92505061010089013567ffffffffffffffff811115611a4057611a3f611104565b5b611a4c8b828c0161127f565b9150509295985092959890939650565b611a65816117c5565b82525050565b6000602082019050611a806000830184611a5c565b92915050565b6000611a9182611109565b9050919050565b611aa181611a86565b8114611aac57600080fd5b50565b600081359050611abe81611a98565b92915050565b60008060408385031215611adb57611ada6110ff565b5b6000611ae985828601611aaf565b9250506020611afa85828601611aaf565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b611b65816112ad565b82525050565b60006040830160008301518482036000860152611b88828261165d565b9150506020830151611b9d6020860182611b5c565b508091505092915050565b6000611bb48383611b6b565b905092915050565b6000602082019050919050565b6000611bd482611b30565b611bde8185611b3b565b935083602082028501611bf085611b4c565b8060005b85811015611c2c5784840389528151611c0d8582611ba8565b9450611c1883611bbc565b925060208a01995050600181019050611bf4565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000611c76838361165d565b905092915050565b6000602082019050919050565b6000611c9682611c3e565b611ca08185611c49565b935083602082028501611cb285611c5a565b8060005b85811015611cee5784840389528151611ccf8582611c6a565b9450611cda83611c7e565b925060208a01995050600181019050611cb6565b50829750879550505050505092915050565b600060a0830160008301518482036000860152611d1d828261165d565b91505060208301518482036020860152611d37828261165d565b91505060408301518482036040860152611d518282611bc9565b91505060608301518482036060860152611d6b8282611c8b565b91505060808301518482036080860152611d858282611c8b565b9150508091505092915050565b6000611d9e8383611d00565b905092915050565b6000602082019050919050565b6000611dbe82611b04565b611dc88185611b0f565b935083602082028501611dda85611b20565b8060005b85811015611e165784840389528151611df78582611d92565b9450611e0283611da6565b925060208a01995050600181019050611dde565b50829750879550505050505092915050565b60006020820190508181036000830152611e428184611db3565b905092915050565b600060208284031215611e6057611e5f6110ff565b5b600082013567ffffffffffffffff811115611e7e57611e7d611104565b5b611e8a8482850161127f565b91505092915050565b60006040830160008301518482036000860152611eb0828261165d565b91505060208301518482036020860152611eca828261165d565b9150508091505092915050565b60006020820190508181036000830152611ef18184611e93565b905092915050565b60008060008060008060008060006101208a8c031215611f1c57611f1b6110ff565b5b6000611f2a8c828d01611152565b9950506020611f3b8c828d01611aaf565b98505060408a013567ffffffffffffffff811115611f5c57611f5b611104565b5b611f688c828d0161127f565b97505060608a013567ffffffffffffffff811115611f8957611f88611104565b5b611f958c828d0161127f565b96505060808a013567ffffffffffffffff811115611fb657611fb5611104565b5b611fc28c828d0161127f565b95505060a0611fd38c828d016112ce565b94505060c08a013567ffffffffffffffff811115611ff457611ff3611104565b5b6120008c828d0161127f565b93505060e06120118c828d01611306565b9250506101006120238c828d01611306565b9150509295985092959850929598565b600082825260208201905092915050565b600061204f82611617565b6120598185612033565b9350612069818560208601611633565b61207281611171565b840191505092915050565b600060208201905081810360008301526120978184612044565b905092915050565b60008083601f8401126120b5576120b4611167565b5b8235905067ffffffffffffffff8111156120d2576120d1611455565b5b6020830191508360208202830111156120ee576120ed61145a565b5b9250929050565b6000806020838503121561210c5761210b6110ff565b5b600083013567ffffffffffffffff81111561212a57612129611104565b5b6121368582860161209f565b92509250509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061217c8261185c565b9150677fffffffffffffff820361219657612195612142565b5b600182019050919050565b600081905092915050565b50565b60006121bc6000836121a1565b91506121c7826121ac565b600082019050919050565b60006121dd826121af565b9150819050919050565b7f4661696c656420746f2073656e6420457468657220746f2064656c656761746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000612243602183612033565b915061224e826121e7565b604082019050919050565b6000602082019050818103600083015261227281612236565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006122b3826112ad565b91506122be836112ad565b9250826122ce576122cd612279565b5b828204905092915050565b6122e2816112ad565b82525050565b6000819050919050565b600061230d61230861230384611109565b6122e8565b611109565b9050919050565b600061231f826122f2565b9050919050565b600061233182612314565b9050919050565b61234181612326565b82525050565b60408201600082015161235d60008501826117d9565b50602082015161237060208501826117d9565b50505050565b6000819050919050565b600061239b61239661239184612376565b6122e8565b6117c5565b9050919050565b6123ab81612380565b82525050565b60006123be600083612033565b91506123c9826121ac565b600082019050919050565b60006101408201905081810360008301526123ef818b612044565b90508181036020830152612403818a612044565b905081810360408301526124178189612044565b905061242660608301886122d9565b6124336080830187612338565b81810360a08301526124458186612044565b905061245460c0830185612347565b6124626101008301846123a2565b818103610120830152612474816123b1565b90509998505050505050505050565b6000815190506124928161189d565b92915050565b6000602082840312156124ae576124ad6110ff565b5b60006124bc84828501612483565b91505092915050565b6124ce81611a86565b82525050565b60006124e08385612033565b93506124ed83858461122e565b6124f683611171565b840190509392505050565b600060a082019050612516600083018b6124c5565b818103602083015261252981898b6124d4565b9050818103604083015261253e8187896124d4565b905081810360608301526125538185876124d4565b905061256260808301846122d9565b9998505050505050505050565b60008151905061257e816112ef565b92915050565b60006020828403121561259a576125996110ff565b5b60006125a88482850161256f565b91505092915050565b7f4661696c656420746f20696e63726561736520616c6c6f77616e636500000000600082015250565b60006125e7601c83612033565b91506125f2826125b1565b602082019050919050565b60006020820190508181036000830152612616816125da565b9050919050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261264957612648612627565b5b83810192508235915060208301925067ffffffffffffffff8211156126715761267061261d565b5b60018202360383131561268757612686612622565b5b509250929050565b600061269b838561177b565b93506126a883858461122e565b6126b183611171565b840190509392505050565b60006126cb60208401846118b4565b905092915050565b60006126e26020840184611306565b905092915050565b6126f3816112e3565b82525050565b600060a0830161270c600084018461262c565b858303600087015261271f83828461268f565b9250505061273060208401846126bc565b61273d60208601826117d9565b5061274b60408401846126bc565b61275860408601826117d9565b5061276660608401846126d3565b61277360608601826126ea565b5061278160808401846126d3565b61278e60808601826126ea565b508091505092915050565b600060208201905081810360008301526127b381846126f9565b905092915050565b600067ffffffffffffffff8211156127d6576127d5611182565b5b602082029050602081019050919050565b60006127fa6127f5846111fd565b6111e2565b9050828152602081018484840111156128165761281561116c565b5b612821848285611633565b509392505050565b600082601f83011261283e5761283d611167565b5b815161284e8482602086016127e7565b91505092915050565b60006040828403121561286d5761286c611893565b5b61287760406111e2565b9050600082015167ffffffffffffffff81111561289757612896611898565b5b6128a384828501612829565b600083015250602082015167ffffffffffffffff8111156128c7576128c6611898565b5b6128d384828501612829565b60208301525092915050565b60006128f26128ed846127bb565b6111e2565b905080838252602082019050602084028301858111156129155761291461145a565b5b835b8181101561295c57805167ffffffffffffffff81111561293a57612939611167565b5b8086016129478982612857565b85526020850194505050602081019050612917565b5050509392505050565b600082601f83011261297b5761297a611167565b5b815161298b8482602086016128df565b91505092915050565b600067ffffffffffffffff8211156129af576129ae611182565b5b6129b882611171565b9050602081019050919050565b60006129d86129d384612994565b6111e2565b9050828152602081018484840111156129f4576129f361116c565b5b6129ff848285611633565b509392505050565b600082601f830112612a1c57612a1b611167565b5b8151612a2c8482602086016129c5565b91505092915050565b600060408284031215612a4b57612a4a611893565b5b612a5560406111e2565b9050600082015167ffffffffffffffff811115612a7557612a74611898565b5b612a8184828501612a07565b6000830152506020612a9584828501612483565b60208301525092915050565b60008060408385031215612ab857612ab76110ff565b5b600083015167ffffffffffffffff811115612ad657612ad5611104565b5b612ae285828601612966565b925050602083015167ffffffffffffffff811115612b0357612b02611104565b5b612b0f85828601612a35565b9150509250929050565b6000610140820190508181036000830152612b34818c612044565b90508181036020830152612b48818b612044565b90508181036040830152612b5c818a612044565b9050612b6b60608301896122d9565b612b7860808301886124c5565b81810360a0830152612b8a8187612044565b9050612b9960c0830186612347565b612ba7610100830185611a5c565b818103610120830152612bba8184612044565b90509a9950505050505050505050565b6000602082019050612bdf60008301846124c5565b92915050565b7f4661696c656420746f207265766f6b6520617070726f76616c00000000000000600082015250565b6000612c1b601983612033565b9150612c2682612be5565b602082019050919050565b60006020820190508181036000830152612c4a81612c0e565b9050919050565b6000604082019050612c6660008301856124c5565b612c7360208301846124c5565b9392505050565b600067ffffffffffffffff821115612c9557612c94611182565b5b602082029050602081019050919050565b600067ffffffffffffffff821115612cc157612cc0611182565b5b602082029050602081019050919050565b600081519050612ce1816112b7565b92915050565b600060408284031215612cfd57612cfc611893565b5b612d0760406111e2565b9050600082015167ffffffffffffffff811115612d2757612d26611898565b5b612d3384828501612829565b6000830152506020612d4784828501612cd2565b60208301525092915050565b6000612d66612d6184612ca6565b6111e2565b90508083825260208201905060208402830185811115612d8957612d8861145a565b5b835b81811015612dd057805167ffffffffffffffff811115612dae57612dad611167565b5b808601612dbb8982612ce7565b85526020850194505050602081019050612d8b565b5050509392505050565b600082601f830112612def57612dee611167565b5b8151612dff848260208601612d53565b91505092915050565b600067ffffffffffffffff821115612e2357612e22611182565b5b602082029050602081019050919050565b6000612e47612e4284612e08565b6111e2565b90508083825260208201905060208402830185811115612e6a57612e6961145a565b5b835b81811015612eb157805167ffffffffffffffff811115612e8f57612e8e611167565b5b808601612e9c8982612829565b85526020850194505050602081019050612e6c565b5050509392505050565b600082601f830112612ed057612ecf611167565b5b8151612ee0848260208601612e34565b91505092915050565b600060a08284031215612eff57612efe611893565b5b612f0960a06111e2565b9050600082015167ffffffffffffffff811115612f2957612f28611898565b5b612f3584828501612829565b600083015250602082015167ffffffffffffffff811115612f5957612f58611898565b5b612f6584828501612829565b602083015250604082015167ffffffffffffffff811115612f8957612f88611898565b5b612f9584828501612dda565b604083015250606082015167ffffffffffffffff811115612fb957612fb8611898565b5b612fc584828501612ebb565b606083015250608082015167ffffffffffffffff811115612fe957612fe8611898565b5b612ff584828501612ebb565b60808301525092915050565b600061301461300f84612c7a565b6111e2565b905080838252602082019050602084028301858111156130375761303661145a565b5b835b8181101561307e57805167ffffffffffffffff81111561305c5761305b611167565b5b8086016130698982612ee9565b85526020850194505050602081019050613039565b5050509392505050565b600082601f83011261309d5761309c611167565b5b81516130ad848260208601613001565b91505092915050565b6000602082840312156130cc576130cb6110ff565b5b600082015167ffffffffffffffff8111156130ea576130e9611104565b5b6130f684828501613088565b91505092915050565b600060208284031215613115576131146110ff565b5b600082015167ffffffffffffffff81111561313357613132611104565b5b61313f84828501612857565b91505092915050565b6000610140820190508181036000830152613163818b612044565b90508181036020830152613177818a612044565b9050818103604083015261318b8189612044565b905061319a60608301886122d9565b6131a760808301876124c5565b81810360a08301526131b98186612044565b90506131c860c0830185612347565b6131d66101008301846123a2565b8181036101208301526131e8816123b1565b90509998505050505050505050565b60006020828403121561320d5761320c6110ff565b5b600082015167ffffffffffffffff81111561322b5761322a611104565b5b61323784828501612829565b91505092915050565b7f4661696c656420746f20646563726561736520616c6c6f77616e636500000000600082015250565b6000613276601c83612033565b915061328182613240565b602082019050919050565b600060208201905081810360008301526132a581613269565b9050919050565b6000819050919050565b600080833560016020038436030381126132d3576132d2612627565b5b83810192508235915060208301925067ffffffffffffffff8211156132fb576132fa61261d565b5b60018202360383131561331157613310612622565b5b509250929050565b60006133258385611622565b935061333283858461122e565b61333b83611171565b840190509392505050565b6000808335600160200384360303811261336357613362612627565b5b83810192508235915060208301925067ffffffffffffffff82111561338b5761338a61261d565b5b6020820236038313156133a1576133a0612622565b5b509250929050565b6000819050919050565b60006133c260208401846112ce565b905092915050565b6000604083016133dd60008401846132b6565b85830360008701526133f0838284613319565b9250505061340160208401846133b3565b61340e6020860182611b5c565b508091505092915050565b600061342583836133ca565b905092915050565b60008235600160400383360303811261344957613448612627565b5b82810191505092915050565b6000602082019050919050565b600061346e8385611b3b565b935083602084028501613480846133a9565b8060005b878110156134c457848403895261349b828461342d565b6134a58582613419565b94506134b083613455565b925060208a01995050600181019050613484565b50829750879450505050509392505050565b600080833560016020038436030381126134f3576134f2612627565b5b83810192508235915060208301925067ffffffffffffffff82111561351b5761351a61261d565b5b60208202360383131561353157613530612622565b5b509250929050565b6000819050919050565b6000613550848484613319565b90509392505050565b6000602082019050919050565b60006135728385611c49565b93508360208402850161358484613539565b8060005b878110156135ca57848403895261359f82846132b6565b6135aa868284613543565b95506135b584613559565b935060208b019a505050600181019050613588565b50829750879450505050509392505050565b600060a083016135ef60008401846132b6565b8583036000870152613602838284613319565b9250505061361360208401846132b6565b8583036020870152613626838284613319565b925050506136376040840184613346565b858303604087015261364a838284613462565b9250505061365b60608401846134d6565b858303606087015261366e838284613566565b9250505061367f60808401846134d6565b8583036080870152613692838284613566565b925050508091505092915050565b60006136ac83836135dc565b905092915050565b60008235600160a0038336030381126136d0576136cf612627565b5b82810191505092915050565b6000602082019050919050565b60006136f58385611b0f565b935083602084028501613707846132ac565b8060005b8781101561374b57848403895261372282846136b4565b61372c85826136a0565b9450613737836136dc565b925060208a0199505060018101905061370b565b50829750879450505050509392505050565b600060408201905061377260008301866124c5565b81810360208301526137858184866136e9565b9050949350505050565b7f4661696c656420746f20706572666f726d20617070726f76616c000000000000600082015250565b60006137c5601a83612033565b91506137d08261378f565b602082019050919050565b600060208201905081810360008301526137f4816137b8565b905091905056fea2646970667358221220851e57b5d12bf748509c3f69c33bffdb4e4cfaede7eeb42591bcd0975440103f64736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100cf5760003560e01c80637a6185e11161008c578063b967287911610066578063b967287914610225578063c595699a14610241578063f298e7a814610271578063f3675f081461028d576100cf565b80637a6185e1146101bb578063a363df84146101c5578063accc7b90146101f5576100cf565b80631dba685b146100d4578063424af9f6146100f057806344c286701461010c57806361bc221a1461013d5780636fdf23cc1461015b5780637492bdd81461018b575b600080fd5b6100ee60048036038101906100e9919061131b565b6102a9565b005b61010a600480360381019061010591906114b5565b61071e565b005b610126600480360381019061012191906115a2565b6107f8565b604051610134929190611825565b60405180910390f35b61014561088c565b6040516101529190611878565b60405180910390f35b61017560048036038101906101709190611919565b61089d565b6040516101829190611a6b565b60405180910390f35b6101a560048036038101906101a09190611919565b61093b565b6040516101b29190611a6b565b60405180910390f35b6101c36109d9565b005b6101df60048036038101906101da9190611ac4565b610a9e565b6040516101ec9190611e28565b60405180910390f35b61020f600480360381019061020a9190611e4a565b610b2b565b60405161021c9190611ed7565b60405180910390f35b61023f600480360381019061023a9190611ef9565b610bbb565b005b61025b60048036038101906102569190611e4a565b610e88565b604051610268919061207d565b60405180910390f35b61028b600480360381019061028691906114b5565b610f12565b005b6102a760048036038101906102a291906120f5565b610fec565b005b82156103ab5760008081819054906101000a900460070b809291906102cd90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008973ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610323906121d2565b60006040518083038185875af1925050503d8060008114610360576040519150601f19603f3d011682016040523d82523d6000602084013e610365565b606091505b50509050806103a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a090612259565b60405180910390fd5b505b60006040518060400160405280606467ffffffffffffffff168152602001606467ffffffffffffffff16815250905061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a60028b61040891906122a8565b8f8b8860006040518963ffffffff1660e01b81526004016104309897969594939291906123d4565b6020604051808303816000875af115801561044f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104739190612498565b5082156105765760008081819054906101000a900460070b8092919061049890612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf0006040516104ee906121d2565b60006040518083038185875af1925050503d806000811461052b576040519150601f19603f3d011682016040523d82523d6000602084013e610530565b606091505b5050905080610574576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056b90612259565b60405180910390fd5b505b61080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a60028b6105a491906122a8565b8f8b8860006040518963ffffffff1660e01b81526004016105cc9897969594939291906123d4565b6020604051808303816000875af11580156105eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060f9190612498565b5081156107125760008081819054906101000a900460070b8092919061063490612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf00060405161068a906121d2565b60006040518083038185875af1925050503d80600081146106c7576040519150601f19603f3d011682016040523d82523d6000602084013e6106cc565b606091505b5050905080610710576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161070790612259565b60405180910390fd5b505b50505050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff166354de647b308a8a8a8a8a8a8a6040518963ffffffff1660e01b8152600401610769989796959493929190612501565b6020604051808303816000875af1158015610788573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ac9190612584565b9050806107ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e5906125fd565b60405180910390fd5b5050505050505050565b60606108026110b7565b61080273ffffffffffffffffffffffffffffffffffffffff1663c0fab104846040518263ffffffff1660e01b815260040161083d9190612799565b600060405180830381865afa15801561085a573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906108839190612aa1565b91509150915091565b60008054906101000a900460070b81565b600061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a8a308b8b8b8b6040518a63ffffffff1660e01b81526004016108ea99989796959493929190612b19565b6020604051808303816000875af1158015610909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092d9190612498565b905098975050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663632535b98a8a8a8a338b8b8b8b6040518a63ffffffff1660e01b815260040161098899989796959493929190612b19565b6020604051808303816000875af11580156109a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cb9190612498565b905098975050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff166374a8f103306040518263ffffffff1660e01b8152600401610a169190612bca565b6020604051808303816000875af1158015610a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a599190612584565b905080610a9b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9290612c31565b60405180910390fd5b50565b606061080273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e84846040518363ffffffff1660e01b8152600401610add929190612c51565b600060405180830381865afa158015610afa573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610b2391906130b6565b905092915050565b610b336110db565b61080273ffffffffffffffffffffffffffffffffffffffff16635f1f98a2836040518263ffffffff1660e01b8152600401610b6e919061207d565b600060405180830381865afa158015610b8b573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610bb491906130ff565b9050919050565b8115610cbd5760008081819054906101000a900460070b80929190610bdf90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008973ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610c35906121d2565b60006040518083038185875af1925050503d8060008114610c72576040519150601f19603f3d011682016040523d82523d6000602084013e610c77565b606091505b5050905080610cbb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb290612259565b60405180910390fd5b505b60006040518060400160405280606467ffffffffffffffff168152602001606467ffffffffffffffff16815250905061080273ffffffffffffffffffffffffffffffffffffffff1663632535b9898989898e8a8860006040518963ffffffff1660e01b8152600401610d36989796959493929190613148565b6020604051808303816000875af1158015610d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d799190612498565b508115610e7c5760008081819054906101000a900460070b80929190610d9e90612171565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff1602179055505060008a73ffffffffffffffffffffffffffffffffffffffff16650da475abf000604051610df4906121d2565b60006040518083038185875af1925050503d8060008114610e31576040519150601f19603f3d011682016040523d82523d6000602084013e610e36565b606091505b5050905080610e7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e7190612259565b60405180910390fd5b505b50505050505050505050565b606061080273ffffffffffffffffffffffffffffffffffffffff1663b5cb6e7d836040518263ffffffff1660e01b8152600401610ec5919061207d565b600060405180830381865afa158015610ee2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610f0b91906131f7565b9050919050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663b3f536ec308a8a8a8a8a8a8a6040518963ffffffff1660e01b8152600401610f5d989796959493929190612501565b6020604051808303816000875af1158015610f7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa09190612584565b905080610fe2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fd99061328c565b60405180910390fd5b5050505050505050565b600061080273ffffffffffffffffffffffffffffffffffffffff1663473c90c73085856040518463ffffffff1660e01b815260040161102d9392919061375d565b6020604051808303816000875af115801561104c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110709190612584565b9050806110b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110a9906137db565b60405180910390fd5b505050565b604051806040016040528060608152602001600067ffffffffffffffff1681525090565b604051806040016040528060608152602001606081525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061113482611109565b9050919050565b61114481611129565b811461114f57600080fd5b50565b6000813590506111618161113b565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6111ba82611171565b810181811067ffffffffffffffff821117156111d9576111d8611182565b5b80604052505050565b60006111ec6110f5565b90506111f882826111b1565b919050565b600067ffffffffffffffff82111561121857611217611182565b5b61122182611171565b9050602081019050919050565b82818337600083830152505050565b600061125061124b846111fd565b6111e2565b90508281526020810184848401111561126c5761126b61116c565b5b61127784828561122e565b509392505050565b600082601f83011261129457611293611167565b5b81356112a484826020860161123d565b91505092915050565b6000819050919050565b6112c0816112ad565b81146112cb57600080fd5b50565b6000813590506112dd816112b7565b92915050565b60008115159050919050565b6112f8816112e3565b811461130357600080fd5b50565b600081359050611315816112ef565b92915050565b60008060008060008060008060006101208a8c03121561133e5761133d6110ff565b5b600061134c8c828d01611152565b99505060208a013567ffffffffffffffff81111561136d5761136c611104565b5b6113798c828d0161127f565b98505060408a013567ffffffffffffffff81111561139a57611399611104565b5b6113a68c828d0161127f565b97505060608a013567ffffffffffffffff8111156113c7576113c6611104565b5b6113d38c828d0161127f565b96505060806113e48c828d016112ce565b95505060a08a013567ffffffffffffffff81111561140557611404611104565b5b6114118c828d0161127f565b94505060c06114228c828d01611306565b93505060e06114338c828d01611306565b9250506101006114458c828d01611306565b9150509295985092959850929598565b600080fd5b600080fd5b60008083601f84011261147557611474611167565b5b8235905067ffffffffffffffff81111561149257611491611455565b5b6020830191508360018202830111156114ae576114ad61145a565b5b9250929050565b60008060008060008060006080888a0312156114d4576114d36110ff565b5b600088013567ffffffffffffffff8111156114f2576114f1611104565b5b6114fe8a828b0161145f565b9750975050602088013567ffffffffffffffff81111561152157611520611104565b5b61152d8a828b0161145f565b9550955050604088013567ffffffffffffffff8111156115505761154f611104565b5b61155c8a828b0161145f565b9350935050606061156f8a828b016112ce565b91505092959891949750929550565b600080fd5b600060a082840312156115995761159861157e565b5b81905092915050565b6000602082840312156115b8576115b76110ff565b5b600082013567ffffffffffffffff8111156115d6576115d5611104565b5b6115e284828501611583565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611651578082015181840152602081019050611636565b60008484015250505050565b600061166882611617565b6116728185611622565b9350611682818560208601611633565b61168b81611171565b840191505092915050565b600060408301600083015184820360008601526116b3828261165d565b915050602083015184820360208601526116cd828261165d565b9150508091505092915050565b60006116e68383611696565b905092915050565b6000602082019050919050565b6000611706826115eb565b61171081856115f6565b93508360208202850161172285611607565b8060005b8581101561175e578484038952815161173f85826116da565b945061174a836116ee565b925060208a01995050600181019050611726565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b600061179782611770565b6117a1818561177b565b93506117b1818560208601611633565b6117ba81611171565b840191505092915050565b600067ffffffffffffffff82169050919050565b6117e2816117c5565b82525050565b60006040830160008301518482036000860152611805828261178c565b915050602083015161181a60208601826117d9565b508091505092915050565b6000604082019050818103600083015261183f81856116fb565b9050818103602083015261185381846117e8565b90509392505050565b60008160070b9050919050565b6118728161185c565b82525050565b600060208201905061188d6000830184611869565b92915050565b600080fd5b600080fd5b6118a6816117c5565b81146118b157600080fd5b50565b6000813590506118c38161189d565b92915050565b6000604082840312156118df576118de611893565b5b6118e960406111e2565b905060006118f9848285016118b4565b600083015250602061190d848285016118b4565b60208301525092915050565b600080600080600080600080610120898b03121561193a576119396110ff565b5b600089013567ffffffffffffffff81111561195857611957611104565b5b6119648b828c0161127f565b985050602089013567ffffffffffffffff81111561198557611984611104565b5b6119918b828c0161127f565b975050604089013567ffffffffffffffff8111156119b2576119b1611104565b5b6119be8b828c0161127f565b96505060606119cf8b828c016112ce565b955050608089013567ffffffffffffffff8111156119f0576119ef611104565b5b6119fc8b828c0161127f565b94505060a0611a0d8b828c016118c9565b93505060e0611a1e8b828c016118b4565b92505061010089013567ffffffffffffffff811115611a4057611a3f611104565b5b611a4c8b828c0161127f565b9150509295985092959890939650565b611a65816117c5565b82525050565b6000602082019050611a806000830184611a5c565b92915050565b6000611a9182611109565b9050919050565b611aa181611a86565b8114611aac57600080fd5b50565b600081359050611abe81611a98565b92915050565b60008060408385031215611adb57611ada6110ff565b5b6000611ae985828601611aaf565b9250506020611afa85828601611aaf565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b611b65816112ad565b82525050565b60006040830160008301518482036000860152611b88828261165d565b9150506020830151611b9d6020860182611b5c565b508091505092915050565b6000611bb48383611b6b565b905092915050565b6000602082019050919050565b6000611bd482611b30565b611bde8185611b3b565b935083602082028501611bf085611b4c565b8060005b85811015611c2c5784840389528151611c0d8582611ba8565b9450611c1883611bbc565b925060208a01995050600181019050611bf4565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000611c76838361165d565b905092915050565b6000602082019050919050565b6000611c9682611c3e565b611ca08185611c49565b935083602082028501611cb285611c5a565b8060005b85811015611cee5784840389528151611ccf8582611c6a565b9450611cda83611c7e565b925060208a01995050600181019050611cb6565b50829750879550505050505092915050565b600060a0830160008301518482036000860152611d1d828261165d565b91505060208301518482036020860152611d37828261165d565b91505060408301518482036040860152611d518282611bc9565b91505060608301518482036060860152611d6b8282611c8b565b91505060808301518482036080860152611d858282611c8b565b9150508091505092915050565b6000611d9e8383611d00565b905092915050565b6000602082019050919050565b6000611dbe82611b04565b611dc88185611b0f565b935083602082028501611dda85611b20565b8060005b85811015611e165784840389528151611df78582611d92565b9450611e0283611da6565b925060208a01995050600181019050611dde565b50829750879550505050505092915050565b60006020820190508181036000830152611e428184611db3565b905092915050565b600060208284031215611e6057611e5f6110ff565b5b600082013567ffffffffffffffff811115611e7e57611e7d611104565b5b611e8a8482850161127f565b91505092915050565b60006040830160008301518482036000860152611eb0828261165d565b91505060208301518482036020860152611eca828261165d565b9150508091505092915050565b60006020820190508181036000830152611ef18184611e93565b905092915050565b60008060008060008060008060006101208a8c031215611f1c57611f1b6110ff565b5b6000611f2a8c828d01611152565b9950506020611f3b8c828d01611aaf565b98505060408a013567ffffffffffffffff811115611f5c57611f5b611104565b5b611f688c828d0161127f565b97505060608a013567ffffffffffffffff811115611f8957611f88611104565b5b611f958c828d0161127f565b96505060808a013567ffffffffffffffff811115611fb657611fb5611104565b5b611fc28c828d0161127f565b95505060a0611fd38c828d016112ce565b94505060c08a013567ffffffffffffffff811115611ff457611ff3611104565b5b6120008c828d0161127f565b93505060e06120118c828d01611306565b9250506101006120238c828d01611306565b9150509295985092959850929598565b600082825260208201905092915050565b600061204f82611617565b6120598185612033565b9350612069818560208601611633565b61207281611171565b840191505092915050565b600060208201905081810360008301526120978184612044565b905092915050565b60008083601f8401126120b5576120b4611167565b5b8235905067ffffffffffffffff8111156120d2576120d1611455565b5b6020830191508360208202830111156120ee576120ed61145a565b5b9250929050565b6000806020838503121561210c5761210b6110ff565b5b600083013567ffffffffffffffff81111561212a57612129611104565b5b6121368582860161209f565b92509250509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061217c8261185c565b9150677fffffffffffffff820361219657612195612142565b5b600182019050919050565b600081905092915050565b50565b60006121bc6000836121a1565b91506121c7826121ac565b600082019050919050565b60006121dd826121af565b9150819050919050565b7f4661696c656420746f2073656e6420457468657220746f2064656c656761746f60008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000612243602183612033565b915061224e826121e7565b604082019050919050565b6000602082019050818103600083015261227281612236565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006122b3826112ad565b91506122be836112ad565b9250826122ce576122cd612279565b5b828204905092915050565b6122e2816112ad565b82525050565b6000819050919050565b600061230d61230861230384611109565b6122e8565b611109565b9050919050565b600061231f826122f2565b9050919050565b600061233182612314565b9050919050565b61234181612326565b82525050565b60408201600082015161235d60008501826117d9565b50602082015161237060208501826117d9565b50505050565b6000819050919050565b600061239b61239661239184612376565b6122e8565b6117c5565b9050919050565b6123ab81612380565b82525050565b60006123be600083612033565b91506123c9826121ac565b600082019050919050565b60006101408201905081810360008301526123ef818b612044565b90508181036020830152612403818a612044565b905081810360408301526124178189612044565b905061242660608301886122d9565b6124336080830187612338565b81810360a08301526124458186612044565b905061245460c0830185612347565b6124626101008301846123a2565b818103610120830152612474816123b1565b90509998505050505050505050565b6000815190506124928161189d565b92915050565b6000602082840312156124ae576124ad6110ff565b5b60006124bc84828501612483565b91505092915050565b6124ce81611a86565b82525050565b60006124e08385612033565b93506124ed83858461122e565b6124f683611171565b840190509392505050565b600060a082019050612516600083018b6124c5565b818103602083015261252981898b6124d4565b9050818103604083015261253e8187896124d4565b905081810360608301526125538185876124d4565b905061256260808301846122d9565b9998505050505050505050565b60008151905061257e816112ef565b92915050565b60006020828403121561259a576125996110ff565b5b60006125a88482850161256f565b91505092915050565b7f4661696c656420746f20696e63726561736520616c6c6f77616e636500000000600082015250565b60006125e7601c83612033565b91506125f2826125b1565b602082019050919050565b60006020820190508181036000830152612616816125da565b9050919050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261264957612648612627565b5b83810192508235915060208301925067ffffffffffffffff8211156126715761267061261d565b5b60018202360383131561268757612686612622565b5b509250929050565b600061269b838561177b565b93506126a883858461122e565b6126b183611171565b840190509392505050565b60006126cb60208401846118b4565b905092915050565b60006126e26020840184611306565b905092915050565b6126f3816112e3565b82525050565b600060a0830161270c600084018461262c565b858303600087015261271f83828461268f565b9250505061273060208401846126bc565b61273d60208601826117d9565b5061274b60408401846126bc565b61275860408601826117d9565b5061276660608401846126d3565b61277360608601826126ea565b5061278160808401846126d3565b61278e60808601826126ea565b508091505092915050565b600060208201905081810360008301526127b381846126f9565b905092915050565b600067ffffffffffffffff8211156127d6576127d5611182565b5b602082029050602081019050919050565b60006127fa6127f5846111fd565b6111e2565b9050828152602081018484840111156128165761281561116c565b5b612821848285611633565b509392505050565b600082601f83011261283e5761283d611167565b5b815161284e8482602086016127e7565b91505092915050565b60006040828403121561286d5761286c611893565b5b61287760406111e2565b9050600082015167ffffffffffffffff81111561289757612896611898565b5b6128a384828501612829565b600083015250602082015167ffffffffffffffff8111156128c7576128c6611898565b5b6128d384828501612829565b60208301525092915050565b60006128f26128ed846127bb565b6111e2565b905080838252602082019050602084028301858111156129155761291461145a565b5b835b8181101561295c57805167ffffffffffffffff81111561293a57612939611167565b5b8086016129478982612857565b85526020850194505050602081019050612917565b5050509392505050565b600082601f83011261297b5761297a611167565b5b815161298b8482602086016128df565b91505092915050565b600067ffffffffffffffff8211156129af576129ae611182565b5b6129b882611171565b9050602081019050919050565b60006129d86129d384612994565b6111e2565b9050828152602081018484840111156129f4576129f361116c565b5b6129ff848285611633565b509392505050565b600082601f830112612a1c57612a1b611167565b5b8151612a2c8482602086016129c5565b91505092915050565b600060408284031215612a4b57612a4a611893565b5b612a5560406111e2565b9050600082015167ffffffffffffffff811115612a7557612a74611898565b5b612a8184828501612a07565b6000830152506020612a9584828501612483565b60208301525092915050565b60008060408385031215612ab857612ab76110ff565b5b600083015167ffffffffffffffff811115612ad657612ad5611104565b5b612ae285828601612966565b925050602083015167ffffffffffffffff811115612b0357612b02611104565b5b612b0f85828601612a35565b9150509250929050565b6000610140820190508181036000830152612b34818c612044565b90508181036020830152612b48818b612044565b90508181036040830152612b5c818a612044565b9050612b6b60608301896122d9565b612b7860808301886124c5565b81810360a0830152612b8a8187612044565b9050612b9960c0830186612347565b612ba7610100830185611a5c565b818103610120830152612bba8184612044565b90509a9950505050505050505050565b6000602082019050612bdf60008301846124c5565b92915050565b7f4661696c656420746f207265766f6b6520617070726f76616c00000000000000600082015250565b6000612c1b601983612033565b9150612c2682612be5565b602082019050919050565b60006020820190508181036000830152612c4a81612c0e565b9050919050565b6000604082019050612c6660008301856124c5565b612c7360208301846124c5565b9392505050565b600067ffffffffffffffff821115612c9557612c94611182565b5b602082029050602081019050919050565b600067ffffffffffffffff821115612cc157612cc0611182565b5b602082029050602081019050919050565b600081519050612ce1816112b7565b92915050565b600060408284031215612cfd57612cfc611893565b5b612d0760406111e2565b9050600082015167ffffffffffffffff811115612d2757612d26611898565b5b612d3384828501612829565b6000830152506020612d4784828501612cd2565b60208301525092915050565b6000612d66612d6184612ca6565b6111e2565b90508083825260208201905060208402830185811115612d8957612d8861145a565b5b835b81811015612dd057805167ffffffffffffffff811115612dae57612dad611167565b5b808601612dbb8982612ce7565b85526020850194505050602081019050612d8b565b5050509392505050565b600082601f830112612def57612dee611167565b5b8151612dff848260208601612d53565b91505092915050565b600067ffffffffffffffff821115612e2357612e22611182565b5b602082029050602081019050919050565b6000612e47612e4284612e08565b6111e2565b90508083825260208201905060208402830185811115612e6a57612e6961145a565b5b835b81811015612eb157805167ffffffffffffffff811115612e8f57612e8e611167565b5b808601612e9c8982612829565b85526020850194505050602081019050612e6c565b5050509392505050565b600082601f830112612ed057612ecf611167565b5b8151612ee0848260208601612e34565b91505092915050565b600060a08284031215612eff57612efe611893565b5b612f0960a06111e2565b9050600082015167ffffffffffffffff811115612f2957612f28611898565b5b612f3584828501612829565b600083015250602082015167ffffffffffffffff811115612f5957612f58611898565b5b612f6584828501612829565b602083015250604082015167ffffffffffffffff811115612f8957612f88611898565b5b612f9584828501612dda565b604083015250606082015167ffffffffffffffff811115612fb957612fb8611898565b5b612fc584828501612ebb565b606083015250608082015167ffffffffffffffff811115612fe957612fe8611898565b5b612ff584828501612ebb565b60808301525092915050565b600061301461300f84612c7a565b6111e2565b905080838252602082019050602084028301858111156130375761303661145a565b5b835b8181101561307e57805167ffffffffffffffff81111561305c5761305b611167565b5b8086016130698982612ee9565b85526020850194505050602081019050613039565b5050509392505050565b600082601f83011261309d5761309c611167565b5b81516130ad848260208601613001565b91505092915050565b6000602082840312156130cc576130cb6110ff565b5b600082015167ffffffffffffffff8111156130ea576130e9611104565b5b6130f684828501613088565b91505092915050565b600060208284031215613115576131146110ff565b5b600082015167ffffffffffffffff81111561313357613132611104565b5b61313f84828501612857565b91505092915050565b6000610140820190508181036000830152613163818b612044565b90508181036020830152613177818a612044565b9050818103604083015261318b8189612044565b905061319a60608301886122d9565b6131a760808301876124c5565b81810360a08301526131b98186612044565b90506131c860c0830185612347565b6131d66101008301846123a2565b8181036101208301526131e8816123b1565b90509998505050505050505050565b60006020828403121561320d5761320c6110ff565b5b600082015167ffffffffffffffff81111561322b5761322a611104565b5b61323784828501612829565b91505092915050565b7f4661696c656420746f20646563726561736520616c6c6f77616e636500000000600082015250565b6000613276601c83612033565b915061328182613240565b602082019050919050565b600060208201905081810360008301526132a581613269565b9050919050565b6000819050919050565b600080833560016020038436030381126132d3576132d2612627565b5b83810192508235915060208301925067ffffffffffffffff8211156132fb576132fa61261d565b5b60018202360383131561331157613310612622565b5b509250929050565b60006133258385611622565b935061333283858461122e565b61333b83611171565b840190509392505050565b6000808335600160200384360303811261336357613362612627565b5b83810192508235915060208301925067ffffffffffffffff82111561338b5761338a61261d565b5b6020820236038313156133a1576133a0612622565b5b509250929050565b6000819050919050565b60006133c260208401846112ce565b905092915050565b6000604083016133dd60008401846132b6565b85830360008701526133f0838284613319565b9250505061340160208401846133b3565b61340e6020860182611b5c565b508091505092915050565b600061342583836133ca565b905092915050565b60008235600160400383360303811261344957613448612627565b5b82810191505092915050565b6000602082019050919050565b600061346e8385611b3b565b935083602084028501613480846133a9565b8060005b878110156134c457848403895261349b828461342d565b6134a58582613419565b94506134b083613455565b925060208a01995050600181019050613484565b50829750879450505050509392505050565b600080833560016020038436030381126134f3576134f2612627565b5b83810192508235915060208301925067ffffffffffffffff82111561351b5761351a61261d565b5b60208202360383131561353157613530612622565b5b509250929050565b6000819050919050565b6000613550848484613319565b90509392505050565b6000602082019050919050565b60006135728385611c49565b93508360208402850161358484613539565b8060005b878110156135ca57848403895261359f82846132b6565b6135aa868284613543565b95506135b584613559565b935060208b019a505050600181019050613588565b50829750879450505050509392505050565b600060a083016135ef60008401846132b6565b8583036000870152613602838284613319565b9250505061361360208401846132b6565b8583036020870152613626838284613319565b925050506136376040840184613346565b858303604087015261364a838284613462565b9250505061365b60608401846134d6565b858303606087015261366e838284613566565b9250505061367f60808401846134d6565b8583036080870152613692838284613566565b925050508091505092915050565b60006136ac83836135dc565b905092915050565b60008235600160a0038336030381126136d0576136cf612627565b5b82810191505092915050565b6000602082019050919050565b60006136f58385611b0f565b935083602084028501613707846132ac565b8060005b8781101561374b57848403895261372282846136b4565b61372c85826136a0565b9450613737836136dc565b925060208a0199505060018101905061370b565b50829750879450505050509392505050565b600060408201905061377260008301866124c5565b81810360208301526137858184866136e9565b9050949350505050565b7f4661696c656420746f20706572666f726d20617070726f76616c000000000000600082015250565b60006137c5601a83612033565b91506137d08261378f565b602082019050919050565b600060208201905081810360008301526137f4816137b8565b905091905056fea2646970667358221220851e57b5d12bf748509c3f69c33bffdb4e4cfaede7eeb42591bcd0975440103f64736f6c63430008140033", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/precompiles/testutil/contracts/InterchainSender.sol b/precompiles/testutil/contracts/InterchainSender.sol index 581d032f6..286ba5fe5 100644 --- a/precompiles/testutil/contracts/InterchainSender.sol +++ b/precompiles/testutil/contracts/InterchainSender.sol @@ -199,23 +199,23 @@ contract InterchainSender { } // QUERIES - function testDenomTraces( + function testDenoms( PageRequest calldata pageRequest ) public view returns ( - DenomTrace[] memory denomTraces, + Denom[] memory denoms, PageResponse memory pageResponse ) { - return ICS20_CONTRACT.denomTraces(pageRequest); + return ICS20_CONTRACT.denoms(pageRequest); } - function testDenomTrace( + function testDenom( string memory hash - ) public view returns (DenomTrace memory denomTrace) { - return ICS20_CONTRACT.denomTrace(hash); + ) public view returns (Denom memory denomTrace) { + return ICS20_CONTRACT.denom(hash); } function testDenomHash( diff --git a/precompiles/testutil/contracts/InterchainSenderCaller.json b/precompiles/testutil/contracts/InterchainSenderCaller.json index 09e328886..2f8f7d8aa 100644 --- a/precompiles/testutil/contracts/InterchainSenderCaller.json +++ b/precompiles/testutil/contracts/InterchainSenderCaller.json @@ -180,8 +180,8 @@ "type": "function" } ], - "bytecode": "0x6080604052604051610c04380380610c04833981810160405281019061002591906100cf565b80600060086101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506100fc565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061009c82610071565b9050919050565b6100ac81610091565b81146100b757600080fd5b50565b6000815190506100c9816100a3565b92915050565b6000602082840312156100e5576100e461006c565b5b60006100f3848285016100ba565b91505092915050565b610af98061010b6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063073989ff1461005c578063427c1cb61461007857806361bc221a1461009457806369a98b2b146100b2578063ec3c5a14146100ce575b600080fd5b61007660048036038101906100719190610752565b6100ea565b005b610092600480360381019061008d9190610752565b6101f1565b005b61009c61030d565b6040516100a9919061086b565b60405180910390f35b6100cc60048036038101906100c79190610752565b61031e565b005b6100e860048036038101906100e39190610752565b6104c4565b005b60008081819054906101000a900460070b80929190610108906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff160217905550503073ffffffffffffffffffffffffffffffffffffffff1663427c1cb68787878787876040518763ffffffff1660e01b815260040161017596959493929190610982565b600060405180830381600087803b15801561018f57600080fd5b505af19250505080156101a0575060015b5060008081819054906101000a900460070b809291906101bf906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050505050505050565b600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b815260040161025e99989796959493929190610a1a565b600060405180830381600087803b15801561027857600080fd5b505af115801561028c573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff1663ec3c5a148787878787876040518763ffffffff1660e01b81526004016102d396959493929190610982565b600060405180830381600087803b1580156102ed57600080fd5b505af1158015610301573d6000803e3d6000fd5b50505050505050505050565b60008054906101000a900460070b81565b60008081819054906101000a900460070b8092919061033c906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b81526004016103d399989796959493929190610a1a565b600060405180830381600087803b1580156103ed57600080fd5b505af1158015610401573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff1663ec3c5a148787878787876040518763ffffffff1660e01b815260040161044896959493929190610982565b600060405180830381600087803b15801561046257600080fd5b505af1925050508015610473575060015b5060008081819054906101000a900460070b80929190610492906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050505050505050565b600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b815260040161053199989796959493929190610a1a565b600060405180830381600087803b15801561054b57600080fd5b505af115801561055f573d6000803e3d6000fd5b600080fd5b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a382610578565b9050919050565b6105b381610598565b81146105be57600080fd5b50565b6000813590506105d0816105aa565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610629826105e0565b810181811067ffffffffffffffff82111715610648576106476105f1565b5b80604052505050565b600061065b610564565b90506106678282610620565b919050565b600067ffffffffffffffff821115610687576106866105f1565b5b610690826105e0565b9050602081019050919050565b82818337600083830152505050565b60006106bf6106ba8461066c565b610651565b9050828152602081018484840111156106db576106da6105db565b5b6106e684828561069d565b509392505050565b600082601f830112610703576107026105d6565b5b81356107138482602086016106ac565b91505092915050565b6000819050919050565b61072f8161071c565b811461073a57600080fd5b50565b60008135905061074c81610726565b92915050565b60008060008060008060c0878903121561076f5761076e61056e565b5b600061077d89828a016105c1565b965050602087013567ffffffffffffffff81111561079e5761079d610573565b5b6107aa89828a016106ee565b955050604087013567ffffffffffffffff8111156107cb576107ca610573565b5b6107d789828a016106ee565b945050606087013567ffffffffffffffff8111156107f8576107f7610573565b5b61080489828a016106ee565b935050608061081589828a0161073d565b92505060a087013567ffffffffffffffff81111561083657610835610573565b5b61084289828a016106ee565b9150509295509295509295565b60008160070b9050919050565b6108658161084f565b82525050565b6000602082019050610880600083018461085c565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006108c08261084f565b9150677fffffffffffffff82036108da576108d9610886565b5b600182019050919050565b6108ee81610598565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561092e578082015181840152602081019050610913565b60008484015250505050565b6000610945826108f4565b61094f81856108ff565b935061095f818560208601610910565b610968816105e0565b840191505092915050565b61097c8161071c565b82525050565b600060c08201905061099760008301896108e5565b81810360208301526109a9818861093a565b905081810360408301526109bd818761093a565b905081810360608301526109d1818661093a565b90506109e06080830185610973565b81810360a08301526109f2818461093a565b9050979650505050505050565b60008115159050919050565b610a14816109ff565b82525050565b600061012082019050610a30600083018c6108e5565b8181036020830152610a42818b61093a565b90508181036040830152610a56818a61093a565b90508181036060830152610a6a818961093a565b9050610a796080830188610973565b81810360a0830152610a8b818761093a565b9050610a9a60c0830186610a0b565b610aa760e0830185610a0b565b610ab5610100830184610a0b565b9a995050505050505050505056fea26469706673582212208d9ac6bb34cf465f323f24873e5ecdfed0aee3ab51a2385e500175826995e5c364736f6c63430008140033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100575760003560e01c8063073989ff1461005c578063427c1cb61461007857806361bc221a1461009457806369a98b2b146100b2578063ec3c5a14146100ce575b600080fd5b61007660048036038101906100719190610752565b6100ea565b005b610092600480360381019061008d9190610752565b6101f1565b005b61009c61030d565b6040516100a9919061086b565b60405180910390f35b6100cc60048036038101906100c79190610752565b61031e565b005b6100e860048036038101906100e39190610752565b6104c4565b005b60008081819054906101000a900460070b80929190610108906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff160217905550503073ffffffffffffffffffffffffffffffffffffffff1663427c1cb68787878787876040518763ffffffff1660e01b815260040161017596959493929190610982565b600060405180830381600087803b15801561018f57600080fd5b505af19250505080156101a0575060015b5060008081819054906101000a900460070b809291906101bf906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050505050505050565b600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b815260040161025e99989796959493929190610a1a565b600060405180830381600087803b15801561027857600080fd5b505af115801561028c573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff1663ec3c5a148787878787876040518763ffffffff1660e01b81526004016102d396959493929190610982565b600060405180830381600087803b1580156102ed57600080fd5b505af1158015610301573d6000803e3d6000fd5b50505050505050505050565b60008054906101000a900460070b81565b60008081819054906101000a900460070b8092919061033c906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b81526004016103d399989796959493929190610a1a565b600060405180830381600087803b1580156103ed57600080fd5b505af1158015610401573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff1663ec3c5a148787878787876040518763ffffffff1660e01b815260040161044896959493929190610982565b600060405180830381600087803b15801561046257600080fd5b505af1925050508015610473575060015b5060008081819054906101000a900460070b80929190610492906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050505050505050565b600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b815260040161053199989796959493929190610a1a565b600060405180830381600087803b15801561054b57600080fd5b505af115801561055f573d6000803e3d6000fd5b600080fd5b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a382610578565b9050919050565b6105b381610598565b81146105be57600080fd5b50565b6000813590506105d0816105aa565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610629826105e0565b810181811067ffffffffffffffff82111715610648576106476105f1565b5b80604052505050565b600061065b610564565b90506106678282610620565b919050565b600067ffffffffffffffff821115610687576106866105f1565b5b610690826105e0565b9050602081019050919050565b82818337600083830152505050565b60006106bf6106ba8461066c565b610651565b9050828152602081018484840111156106db576106da6105db565b5b6106e684828561069d565b509392505050565b600082601f830112610703576107026105d6565b5b81356107138482602086016106ac565b91505092915050565b6000819050919050565b61072f8161071c565b811461073a57600080fd5b50565b60008135905061074c81610726565b92915050565b60008060008060008060c0878903121561076f5761076e61056e565b5b600061077d89828a016105c1565b965050602087013567ffffffffffffffff81111561079e5761079d610573565b5b6107aa89828a016106ee565b955050604087013567ffffffffffffffff8111156107cb576107ca610573565b5b6107d789828a016106ee565b945050606087013567ffffffffffffffff8111156107f8576107f7610573565b5b61080489828a016106ee565b935050608061081589828a0161073d565b92505060a087013567ffffffffffffffff81111561083657610835610573565b5b61084289828a016106ee565b9150509295509295509295565b60008160070b9050919050565b6108658161084f565b82525050565b6000602082019050610880600083018461085c565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006108c08261084f565b9150677fffffffffffffff82036108da576108d9610886565b5b600182019050919050565b6108ee81610598565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561092e578082015181840152602081019050610913565b60008484015250505050565b6000610945826108f4565b61094f81856108ff565b935061095f818560208601610910565b610968816105e0565b840191505092915050565b61097c8161071c565b82525050565b600060c08201905061099760008301896108e5565b81810360208301526109a9818861093a565b905081810360408301526109bd818761093a565b905081810360608301526109d1818661093a565b90506109e06080830185610973565b81810360a08301526109f2818461093a565b9050979650505050505050565b60008115159050919050565b610a14816109ff565b82525050565b600061012082019050610a30600083018c6108e5565b8181036020830152610a42818b61093a565b90508181036040830152610a56818a61093a565b90508181036060830152610a6a818961093a565b9050610a796080830188610973565b81810360a0830152610a8b818761093a565b9050610a9a60c0830186610a0b565b610aa760e0830185610a0b565b610ab5610100830184610a0b565b9a995050505050505050505056fea26469706673582212208d9ac6bb34cf465f323f24873e5ecdfed0aee3ab51a2385e500175826995e5c364736f6c63430008140033", + "bytecode": "0x6080604052604051610c04380380610c04833981810160405281019061002591906100cf565b80600060086101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506100fc565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061009c82610071565b9050919050565b6100ac81610091565b81146100b757600080fd5b50565b6000815190506100c9816100a3565b92915050565b6000602082840312156100e5576100e461006c565b5b60006100f3848285016100ba565b91505092915050565b610af98061010b6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063073989ff1461005c578063427c1cb61461007857806361bc221a1461009457806369a98b2b146100b2578063ec3c5a14146100ce575b600080fd5b61007660048036038101906100719190610752565b6100ea565b005b610092600480360381019061008d9190610752565b6101f1565b005b61009c61030d565b6040516100a9919061086b565b60405180910390f35b6100cc60048036038101906100c79190610752565b61031e565b005b6100e860048036038101906100e39190610752565b6104c4565b005b60008081819054906101000a900460070b80929190610108906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff160217905550503073ffffffffffffffffffffffffffffffffffffffff1663427c1cb68787878787876040518763ffffffff1660e01b815260040161017596959493929190610982565b600060405180830381600087803b15801561018f57600080fd5b505af19250505080156101a0575060015b5060008081819054906101000a900460070b809291906101bf906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050505050505050565b600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b815260040161025e99989796959493929190610a1a565b600060405180830381600087803b15801561027857600080fd5b505af115801561028c573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff1663ec3c5a148787878787876040518763ffffffff1660e01b81526004016102d396959493929190610982565b600060405180830381600087803b1580156102ed57600080fd5b505af1158015610301573d6000803e3d6000fd5b50505050505050505050565b60008054906101000a900460070b81565b60008081819054906101000a900460070b8092919061033c906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b81526004016103d399989796959493929190610a1a565b600060405180830381600087803b1580156103ed57600080fd5b505af1158015610401573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff1663ec3c5a148787878787876040518763ffffffff1660e01b815260040161044896959493929190610982565b600060405180830381600087803b15801561046257600080fd5b505af1925050508015610473575060015b5060008081819054906101000a900460070b80929190610492906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050505050505050565b600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b815260040161053199989796959493929190610a1a565b600060405180830381600087803b15801561054b57600080fd5b505af115801561055f573d6000803e3d6000fd5b600080fd5b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a382610578565b9050919050565b6105b381610598565b81146105be57600080fd5b50565b6000813590506105d0816105aa565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610629826105e0565b810181811067ffffffffffffffff82111715610648576106476105f1565b5b80604052505050565b600061065b610564565b90506106678282610620565b919050565b600067ffffffffffffffff821115610687576106866105f1565b5b610690826105e0565b9050602081019050919050565b82818337600083830152505050565b60006106bf6106ba8461066c565b610651565b9050828152602081018484840111156106db576106da6105db565b5b6106e684828561069d565b509392505050565b600082601f830112610703576107026105d6565b5b81356107138482602086016106ac565b91505092915050565b6000819050919050565b61072f8161071c565b811461073a57600080fd5b50565b60008135905061074c81610726565b92915050565b60008060008060008060c0878903121561076f5761076e61056e565b5b600061077d89828a016105c1565b965050602087013567ffffffffffffffff81111561079e5761079d610573565b5b6107aa89828a016106ee565b955050604087013567ffffffffffffffff8111156107cb576107ca610573565b5b6107d789828a016106ee565b945050606087013567ffffffffffffffff8111156107f8576107f7610573565b5b61080489828a016106ee565b935050608061081589828a0161073d565b92505060a087013567ffffffffffffffff81111561083657610835610573565b5b61084289828a016106ee565b9150509295509295509295565b60008160070b9050919050565b6108658161084f565b82525050565b6000602082019050610880600083018461085c565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006108c08261084f565b9150677fffffffffffffff82036108da576108d9610886565b5b600182019050919050565b6108ee81610598565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561092e578082015181840152602081019050610913565b60008484015250505050565b6000610945826108f4565b61094f81856108ff565b935061095f818560208601610910565b610968816105e0565b840191505092915050565b61097c8161071c565b82525050565b600060c08201905061099760008301896108e5565b81810360208301526109a9818861093a565b905081810360408301526109bd818761093a565b905081810360608301526109d1818661093a565b90506109e06080830185610973565b81810360a08301526109f2818461093a565b9050979650505050505050565b60008115159050919050565b610a14816109ff565b82525050565b600061012082019050610a30600083018c6108e5565b8181036020830152610a42818b61093a565b90508181036040830152610a56818a61093a565b90508181036060830152610a6a818961093a565b9050610a796080830188610973565b81810360a0830152610a8b818761093a565b9050610a9a60c0830186610a0b565b610aa760e0830185610a0b565b610ab5610100830184610a0b565b9a995050505050505050505056fea2646970667358221220ddf0bed02f795411df99fe6e0dd811224f53b272e99041c0cc731b293aef526264736f6c63430008140033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100575760003560e01c8063073989ff1461005c578063427c1cb61461007857806361bc221a1461009457806369a98b2b146100b2578063ec3c5a14146100ce575b600080fd5b61007660048036038101906100719190610752565b6100ea565b005b610092600480360381019061008d9190610752565b6101f1565b005b61009c61030d565b6040516100a9919061086b565b60405180910390f35b6100cc60048036038101906100c79190610752565b61031e565b005b6100e860048036038101906100e39190610752565b6104c4565b005b60008081819054906101000a900460070b80929190610108906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff160217905550503073ffffffffffffffffffffffffffffffffffffffff1663427c1cb68787878787876040518763ffffffff1660e01b815260040161017596959493929190610982565b600060405180830381600087803b15801561018f57600080fd5b505af19250505080156101a0575060015b5060008081819054906101000a900460070b809291906101bf906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050505050505050565b600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b815260040161025e99989796959493929190610a1a565b600060405180830381600087803b15801561027857600080fd5b505af115801561028c573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff1663ec3c5a148787878787876040518763ffffffff1660e01b81526004016102d396959493929190610982565b600060405180830381600087803b1580156102ed57600080fd5b505af1158015610301573d6000803e3d6000fd5b50505050505050505050565b60008054906101000a900460070b81565b60008081819054906101000a900460070b8092919061033c906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b81526004016103d399989796959493929190610a1a565b600060405180830381600087803b1580156103ed57600080fd5b505af1158015610401573d6000803e3d6000fd5b505050503073ffffffffffffffffffffffffffffffffffffffff1663ec3c5a148787878787876040518763ffffffff1660e01b815260040161044896959493929190610982565b600060405180830381600087803b15801561046257600080fd5b505af1925050508015610473575060015b5060008081819054906101000a900460070b80929190610492906108b5565b91906101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555050505050505050565b600060089054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631dba685b87878787878760018060016040518a63ffffffff1660e01b815260040161053199989796959493929190610a1a565b600060405180830381600087803b15801561054b57600080fd5b505af115801561055f573d6000803e3d6000fd5b600080fd5b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a382610578565b9050919050565b6105b381610598565b81146105be57600080fd5b50565b6000813590506105d0816105aa565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610629826105e0565b810181811067ffffffffffffffff82111715610648576106476105f1565b5b80604052505050565b600061065b610564565b90506106678282610620565b919050565b600067ffffffffffffffff821115610687576106866105f1565b5b610690826105e0565b9050602081019050919050565b82818337600083830152505050565b60006106bf6106ba8461066c565b610651565b9050828152602081018484840111156106db576106da6105db565b5b6106e684828561069d565b509392505050565b600082601f830112610703576107026105d6565b5b81356107138482602086016106ac565b91505092915050565b6000819050919050565b61072f8161071c565b811461073a57600080fd5b50565b60008135905061074c81610726565b92915050565b60008060008060008060c0878903121561076f5761076e61056e565b5b600061077d89828a016105c1565b965050602087013567ffffffffffffffff81111561079e5761079d610573565b5b6107aa89828a016106ee565b955050604087013567ffffffffffffffff8111156107cb576107ca610573565b5b6107d789828a016106ee565b945050606087013567ffffffffffffffff8111156107f8576107f7610573565b5b61080489828a016106ee565b935050608061081589828a0161073d565b92505060a087013567ffffffffffffffff81111561083657610835610573565b5b61084289828a016106ee565b9150509295509295509295565b60008160070b9050919050565b6108658161084f565b82525050565b6000602082019050610880600083018461085c565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006108c08261084f565b9150677fffffffffffffff82036108da576108d9610886565b5b600182019050919050565b6108ee81610598565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561092e578082015181840152602081019050610913565b60008484015250505050565b6000610945826108f4565b61094f81856108ff565b935061095f818560208601610910565b610968816105e0565b840191505092915050565b61097c8161071c565b82525050565b600060c08201905061099760008301896108e5565b81810360208301526109a9818861093a565b905081810360408301526109bd818761093a565b905081810360608301526109d1818661093a565b90506109e06080830185610973565b81810360a08301526109f2818461093a565b9050979650505050505050565b60008115159050919050565b610a14816109ff565b82525050565b600061012082019050610a30600083018c6108e5565b8181036020830152610a42818b61093a565b90508181036040830152610a56818a61093a565b90508181036060830152610a6a818961093a565b9050610a796080830188610973565b81810360a0830152610a8b818761093a565b9050610a9a60c0830186610a0b565b610aa760e0830185610a0b565b610ab5610100830184610a0b565b9a995050505050505050505056fea2646970667358221220ddf0bed02f795411df99fe6e0dd811224f53b272e99041c0cc731b293aef526264736f6c63430008140033", "linkReferences": {}, "deployedLinkReferences": {} } diff --git a/precompiles/testutil/ibc.go b/precompiles/testutil/ibc.go index 77f153f71..476de91f4 100644 --- a/precompiles/testutil/ibc.go +++ b/precompiles/testutil/ibc.go @@ -1,37 +1,26 @@ package testutil import ( - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" ) var ( - UosmoDenomtrace = transfertypes.DenomTrace{ - Path: "transfer/channel-0", - BaseDenom: "uosmo", - } - UosmoIbcdenom = UosmoDenomtrace.IBCDenom() + UosmoDenom = transfertypes.NewDenom("uosmo", transfertypes.NewHop(transfertypes.PortID, "channel-0")) + UosmoIbcDenom = UosmoDenom.IBCDenom() - UatomDenomtrace = transfertypes.DenomTrace{ - Path: "transfer/channel-1", - BaseDenom: "uatom", - } - UatomIbcdenom = UatomDenomtrace.IBCDenom() + UatomDenom = transfertypes.NewDenom("uatom", transfertypes.NewHop(transfertypes.PortID, "channel-1")) + UatomIbcDenom = UatomDenom.IBCDenom() - UAtomDenomtrace = transfertypes.DenomTrace{ - Path: "transfer/channel-0", - BaseDenom: "aatom", - } - UAtomIbcdenom = UAtomDenomtrace.IBCDenom() + UAtomDenom = transfertypes.NewDenom("aatom", transfertypes.NewHop(transfertypes.PortID, "channel-0")) + UAtomIbcDenom = UatomDenom.IBCDenom() - UatomOsmoDenomtrace = transfertypes.DenomTrace{ - Path: "transfer/channel-0/transfer/channel-1", - BaseDenom: "uatom", - } - UatomOsmoIbcdenom = UatomOsmoDenomtrace.IBCDenom() + UatomOsmoDenom = transfertypes.NewDenom( + "uatom", + transfertypes.NewHop(transfertypes.PortID, "channel-0"), + transfertypes.NewHop(transfertypes.PortID, "channel-1"), + ) + UatomOsmoIbcDenom = UatomOsmoDenom.IBCDenom() - AAtomDenomtrace = transfertypes.DenomTrace{ - Path: "transfer/channel-0", - BaseDenom: "aatom", - } - AAtomIbcdenom = AAtomDenomtrace.IBCDenom() + AatomDenom = transfertypes.NewDenom("aatom", transfertypes.NewHop(transfertypes.PortID, "channel-0")) + AatomIbcDenom = AatomDenom.IBCDenom() ) diff --git a/tests/ibc/transfer_test.go b/tests/ibc/transfer_test.go new file mode 100644 index 000000000..9abab0c60 --- /dev/null +++ b/tests/ibc/transfer_test.go @@ -0,0 +1,265 @@ +// Copied from https://github.com/cosmos/ibc-go/blob/7325bd2b00fd5e33d895770ec31b5be2f497d37a/modules/apps/transfer/transfer_test.go +// Why was this copied? +// This test suite was imported to validate that ExampleChain (an EVM-based chain) +// correctly supports IBC v1 token transfers using ibc-go’s Transfer module logic. +// The test ensures that multi-hop transfers (A → B → C → B) behave as expected across channels. +package ibc + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/evm/evmd" + evmibctesting "github.com/cosmos/evm/ibc/testing" +) + +type TransferTestSuite struct { + suite.Suite + + coordinator *evmibctesting.Coordinator + + // testing chains used for convenience and readability + evmChainA *evmibctesting.TestChain + chainB *evmibctesting.TestChain + chainC *evmibctesting.TestChain +} + +func (suite *TransferTestSuite) SetupTest() { + suite.coordinator = evmibctesting.NewCoordinator(suite.T(), 1, 2) + suite.evmChainA = suite.coordinator.GetChain(evmibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(evmibctesting.GetChainID(2)) + suite.chainC = suite.coordinator.GetChain(evmibctesting.GetChainID(3)) +} + +// Constructs the following sends based on the established channels/connections +// 1 - from evmChainA to chainB +// 2 - from chainB to chainC +// 3 - from chainC to chainB +func (suite *TransferTestSuite) TestHandleMsgTransfer() { + var ( + sourceDenomToTransfer string + msgAmount sdkmath.Int + err error + ) + + testCases := []struct { + name string + malleate func() + }{ + { + "transfer single denom", + func() {}, + }, + { + "transfer amount larger than int64", + func() { + var ok bool + msgAmount, ok = sdkmath.NewIntFromString("9223372036854775808") // 2^63 (one above int64) + suite.Require().True(ok) + }, + }, + { + "transfer entire balance", + func() { + msgAmount = types.UnboundedSpendLimit() + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + // setup between evmChainA and chainB + // NOTE: + // pathAToB.EndpointA = endpoint on evmChainA + // pathAToB.EndpointB = endpoint on chainB + pathAToB := evmibctesting.NewTransferPath(suite.evmChainA, suite.chainB) + pathAToB.Setup() + traceAToB := types.NewHop(pathAToB.EndpointB.ChannelConfig.PortID, pathAToB.EndpointB.ChannelID) + + tc.malleate() + + evmApp := suite.evmChainA.App.(*evmd.EVMD) + sourceDenomToTransfer, err = evmApp.StakingKeeper.BondDenom(suite.evmChainA.GetContext()) + suite.Require().NoError(err) + msgAmount = evmibctesting.DefaultCoinAmount + originalBalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + suite.evmChainA.SenderAccount.GetAddress(), + sourceDenomToTransfer, + ) + + timeoutHeight := clienttypes.NewHeight(1, 110) + + originalCoin := sdk.NewCoin(sourceDenomToTransfer, msgAmount) + + // send from evmChainA to chainB + msg := types.NewMsgTransfer( + pathAToB.EndpointA.ChannelConfig.PortID, + pathAToB.EndpointA.ChannelID, + originalCoin, + suite.evmChainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + timeoutHeight, 0, "", + ) + res, err := suite.evmChainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + packet, err := evmibctesting.ParsePacketFromEvents(res.Events) + suite.Require().NoError(err) + + // Get the packet data to determine the amount of tokens being transferred (needed for sending entire balance) + packetData, err := types.UnmarshalPacketData(packet.GetData(), pathAToB.EndpointA.GetChannel().Version, "") + suite.Require().NoError(err) + transferAmount, ok := sdkmath.NewIntFromString(packetData.Token.Amount) + suite.Require().True(ok) + + // relay send + err = pathAToB.RelayPacket(packet) + suite.Require().NoError(err) // relay committed + + escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel()) + // check that the balance for evmChainA is updated + chainABalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + suite.evmChainA.SenderAccount.GetAddress(), + originalCoin.Denom, + ) + suite.Require().True(originalBalance.Amount.Sub(transferAmount).Equal(chainABalance.Amount)) + + // check that module account escrow address has locked the tokens + chainAEscrowBalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + escrowAddress, + originalCoin.Denom, + ) + suite.Require().True(transferAmount.Equal(chainAEscrowBalance.Amount)) + + // check that voucher exists on chain B + chainBApp := suite.chainB.GetSimApp() + chainBDenom := types.NewDenom(originalCoin.Denom, traceAToB) + chainBBalance := chainBApp.BankKeeper.GetBalance( + suite.chainB.GetContext(), + suite.chainB.SenderAccount.GetAddress(), + chainBDenom.IBCDenom(), + ) + coinSentFromAToB := sdk.NewCoin(chainBDenom.IBCDenom(), transferAmount) + suite.Require().Equal(coinSentFromAToB, chainBBalance) + + // setup between chainB to chainC + // NOTE: + // pathBToC.EndpointA = endpoint on chainB + // pathBToC.EndpointB = endpoint on chainC + pathBToC := evmibctesting.NewTransferPath(suite.chainB, suite.chainC) + pathBToC.Setup() + traceBToC := types.NewHop(pathBToC.EndpointB.ChannelConfig.PortID, pathBToC.EndpointB.ChannelID) + + // send from chainB to chainC + msg = types.NewMsgTransfer( + pathBToC.EndpointA.ChannelConfig.PortID, + pathBToC.EndpointA.ChannelID, + coinSentFromAToB, + suite.chainB.SenderAccount.GetAddress().String(), + suite.chainC.SenderAccount.GetAddress().String(), + timeoutHeight, 0, "", + ) + res, err = suite.chainB.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + packet, err = evmibctesting.ParsePacketFromEvents(res.Events) + suite.Require().NoError(err) + + err = pathBToC.RelayPacket(packet) + suite.Require().NoError(err) // relay committed + + coinsSentFromBToC := sdk.NewCoins() + // check balances for chainB and chainC after transfer from chainB to chainC + // NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment + chainCDenom := types.NewDenom(originalCoin.Denom, traceBToC, traceAToB) + + // check that the balance is updated on chainC + chainCApp := suite.chainC.GetSimApp() + coinSentFromBToC := sdk.NewCoin(chainCDenom.IBCDenom(), transferAmount) + chainCBalance := chainCApp.BankKeeper.GetBalance( + suite.chainC.GetContext(), + suite.chainC.SenderAccount.GetAddress(), + coinSentFromBToC.Denom, + ) + suite.Require().Equal(coinSentFromBToC, chainCBalance) + + // check that balance on chain B is empty + chainBBalance = chainBApp.BankKeeper.GetBalance( + suite.chainB.GetContext(), + suite.chainB.SenderAccount.GetAddress(), + coinSentFromBToC.Denom, + ) + suite.Require().Zero(chainBBalance.Amount.Int64()) + + // send from chainC back to chainB + msg = types.NewMsgTransfer( + pathBToC.EndpointB.ChannelConfig.PortID, + pathBToC.EndpointB.ChannelID, coinSentFromBToC, + suite.chainC.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + timeoutHeight, 0, "", + ) + res, err = suite.chainC.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + packet, err = evmibctesting.ParsePacketFromEvents(res.Events) + suite.Require().NoError(err) + + err = pathBToC.RelayPacket(packet) + suite.Require().NoError(err) // relay committed + + // check balances for chainC are empty after transfer from chainC to chainB + for _, coin := range coinsSentFromBToC { + // check that balance on chain C is empty + chainCBalance := chainCApp.BankKeeper.GetBalance( + suite.chainC.GetContext(), + suite.chainC.SenderAccount.GetAddress(), + coin.Denom, + ) + suite.Require().Zero(chainCBalance.Amount.Int64()) + } + + // check balances for chainB after transfer from chainC to chainB + // check that balance on chain B has the transferred amount + chainBBalance = chainBApp.BankKeeper.GetBalance( + suite.chainB.GetContext(), + suite.chainB.SenderAccount.GetAddress(), + coinSentFromAToB.Denom, + ) + suite.Require().Equal(coinSentFromAToB, chainBBalance) + + // check that module account escrow address is empty + escrowAddress = types.GetEscrowAddress(traceBToC.PortId, traceBToC.ChannelId) + chainBEscrowBalance := chainBApp.BankKeeper.GetBalance( + suite.chainB.GetContext(), + escrowAddress, + coinSentFromAToB.Denom, + ) + suite.Require().Zero(chainBEscrowBalance.Amount.Int64()) + + // check balances for evmChainA after transfer from chainC to chainB + // check that the balance is unchanged + chainABalance = evmApp.BankKeeper.GetBalance(suite.evmChainA.GetContext(), suite.evmChainA.SenderAccount.GetAddress(), originalCoin.Denom) + suite.Require().True(originalBalance.Amount.Sub(transferAmount).Equal(chainABalance.Amount)) + + // check that module account escrow address is unchanged + escrowAddress = types.GetEscrowAddress(pathAToB.EndpointA.ChannelConfig.PortID, pathAToB.EndpointA.ChannelID) + chainAEscrowBalance = evmApp.BankKeeper.GetBalance(suite.evmChainA.GetContext(), escrowAddress, originalCoin.Denom) + suite.Require().True(transferAmount.Equal(chainAEscrowBalance.Amount)) + }) + } +} + +func TestTransferTestSuite(t *testing.T) { + suite.Run(t, new(TransferTestSuite)) +} diff --git a/tests/ibc/v2_transfer_test.go b/tests/ibc/v2_transfer_test.go new file mode 100644 index 000000000..1eda86b97 --- /dev/null +++ b/tests/ibc/v2_transfer_test.go @@ -0,0 +1,566 @@ +// Copied from https://github.com/cosmos/ibc-go/blob/e5baeaea3e549f64055f0a60f2617a3404ea777d/modules/apps/transfer/v2/ibc_module_test.go +// +// Why was this copied? +// This test suite was copied to verify that ExampleChain (EVM-based chain) +// correctly implements IBC v2 packet handling logic, including send, receive, +// acknowledgement, and timeout flows. +// Additionally, we made slight modifications to confirm ExampleChain's behavior +// as a receiving chain (see TestOnRecvPacket), ensuring that the EVM-based chain +// correctly mints/burns/escrows tokens according to ICS-20 standards. +package ibc + +import ( + "crypto/sha256" + "fmt" + "testing" + "time" + + testifysuite "github.com/stretchr/testify/suite" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + channeltypesv2 "github.com/cosmos/ibc-go/v10/modules/core/04-channel/v2/types" + + "github.com/cosmos/evm/evmd" + evmibctesting "github.com/cosmos/evm/ibc/testing" +) + +const testclientid = "testclientid" + +type TransferTestSuiteV2 struct { + testifysuite.Suite + + coordinator *evmibctesting.Coordinator + + // testing chains used for convenience and readability + evmChainA *evmibctesting.TestChain + chainB *evmibctesting.TestChain + chainC *evmibctesting.TestChain + + pathAToB *evmibctesting.Path + pathBToC *evmibctesting.Path + + // chainB to evmChainA for testing OnRecvPacket, OnAckPacket, and OnTimeoutPacket + pathBToA *evmibctesting.Path +} + +const invalidPortID = "invalidportid" + +func (suite *TransferTestSuiteV2) SetupTest() { + suite.coordinator = evmibctesting.NewCoordinator(suite.T(), 1, 2) + suite.evmChainA = suite.coordinator.GetChain(evmibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(evmibctesting.GetChainID(2)) + suite.chainC = suite.coordinator.GetChain(evmibctesting.GetChainID(3)) + + // setup between evmChainA and chainB + // NOTE: + // pathAToB.EndpointA = endpoint on evmChainA + // pathAToB.EndpointB = endpoint on chainB + suite.pathAToB = evmibctesting.NewPath(suite.evmChainA, suite.chainB) + + // setup between chainB and chainC + // pathBToC.EndpointA = endpoint on chainB + // pathBToC.EndpointB = endpoint on chainC + suite.pathBToC = evmibctesting.NewPath(suite.chainB, suite.chainC) + + // setup between chainB and evmChainA + // pathBToA.EndpointA = endpoint on chainB + // pathBToA.EndpointB = endpoint on evmChainA + suite.pathBToA = evmibctesting.NewPath(suite.chainB, suite.evmChainA) + + // setup IBC v2 paths between the chains + suite.pathAToB.SetupV2() + suite.pathBToC.SetupV2() + suite.pathBToA.SetupV2() +} + +func TestTransferTestSuiteV2(t *testing.T) { + testifysuite.Run(t, new(TransferTestSuiteV2)) +} + +// TestOnSendPacket tests ExampleChain's implementation of the OnSendPacket callback. +func (suite *TransferTestSuiteV2) TestOnSendPacket() { + var payload channeltypesv2.Payload + testCases := []struct { + name string + sourceDenomToTransfer string + malleate func() + expError error + }{ + { + "transfer single denom", + sdk.DefaultBondDenom, + func() {}, + nil, + }, + { + "transfer with invalid source port", + sdk.DefaultBondDenom, + func() { + payload.SourcePort = invalidPortID + }, + channeltypesv2.ErrInvalidPacket, + }, + { + "transfer with invalid destination port", + sdk.DefaultBondDenom, + func() { + payload.DestinationPort = invalidPortID + }, + channeltypesv2.ErrInvalidPacket, + }, + { + "transfer with invalid source client", + sdk.DefaultBondDenom, + func() { + suite.pathAToB.EndpointA.ClientID = testclientid + }, + channeltypesv2.ErrInvalidPacket, + }, + { + "transfer with invalid destination client", + sdk.DefaultBondDenom, + func() { + suite.pathAToB.EndpointB.ClientID = testclientid + }, + channeltypesv2.ErrInvalidPacket, + }, + { + "transfer with slashes in base denom", + "base/coin", + func() {}, + types.ErrInvalidDenomForTransfer, + }, + { + "transfer with slashes in ibc denom", + fmt.Sprintf("ibc/%x", sha256.Sum256([]byte("coin"))), + func() {}, + types.ErrInvalidDenomForTransfer, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + evmApp := suite.evmChainA.App.(*evmd.EVMD) + originalBalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + suite.evmChainA.SenderAccount.GetAddress(), + tc.sourceDenomToTransfer, + ) + + amount, ok := sdkmath.NewIntFromString("9223372036854775808") // 2^63 (one above int64) + suite.Require().True(ok) + originalCoin := sdk.NewCoin(tc.sourceDenomToTransfer, amount) + + token := types.Token{ + Denom: types.Denom{Base: originalCoin.Denom}, + Amount: originalCoin.Amount.String(), + } + + transferData := types.NewFungibleTokenPacketData( + token.Denom.Path(), + token.Amount, + suite.evmChainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + "", + ) + bz := suite.evmChainA.Codec.MustMarshal(&transferData) + payload = channeltypesv2.NewPayload( + types.PortID, types.PortID, types.V1, + types.EncodingProtobuf, bz, + ) + + // malleate payload + tc.malleate() + + ctx := suite.evmChainA.GetContext() + cbs := suite.evmChainA.App.GetIBCKeeper().ChannelKeeperV2.Router.Route(evmibctesting.TransferPort) + + err := cbs.OnSendPacket( + ctx, + suite.pathAToB.EndpointA.ClientID, + suite.pathAToB.EndpointB.ClientID, + 1, + payload, + suite.evmChainA.SenderAccount.GetAddress(), + ) + + if tc.expError != nil { + suite.Require().Contains(err.Error(), tc.expError.Error()) + } else { + suite.Require().NoError(err) + + escrowAddress := types.GetEscrowAddress(types.PortID, suite.pathAToB.EndpointA.ClientID) + // check that the balance for evmChainA is updated + chainABalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + suite.evmChainA.SenderAccount.GetAddress(), + originalCoin.Denom, + ) + suite.Require().Equal(originalBalance.Amount.Sub(amount).Int64(), chainABalance.Amount.Int64()) + + // check that module account escrow address has locked the tokens + chainAEscrowBalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + escrowAddress, + originalCoin.Denom, + ) + suite.Require().Equal(originalCoin, chainAEscrowBalance) + } + }) + } +} + +// TestOnRecvPacket tests ExampleChain's implementation of the OnRecvPacket callback. +func (suite *TransferTestSuiteV2) TestOnRecvPacket() { + var payload channeltypesv2.Payload + testCases := []struct { + name string + sourceDenomToTransfer string + malleate func() + expErr bool + }{ + { + "transfer single denom", + sdk.DefaultBondDenom, + func() {}, + false, + }, + { + "transfer with invalid source port", + sdk.DefaultBondDenom, + func() { + payload.SourcePort = invalidPortID + }, + true, + }, + { + "transfer with invalid dest port", + sdk.DefaultBondDenom, + func() { + payload.DestinationPort = invalidPortID + }, + true, + }, + { + "transfer with invalid source client", + sdk.DefaultBondDenom, + func() { + suite.pathBToA.EndpointB.ClientID = testclientid + }, + true, + }, + { + "transfer with invalid destination client", + sdk.DefaultBondDenom, + func() { + suite.pathBToA.EndpointA.ClientID = testclientid + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + simAppB := suite.chainB.GetSimApp() + originalBalance := simAppB.BankKeeper.GetBalance( + suite.chainB.GetContext(), + suite.chainB.SenderAccount.GetAddress(), + tc.sourceDenomToTransfer, + ) + + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().Add(time.Hour).Unix()) + + amount, ok := sdkmath.NewIntFromString("9223372036854775808") // 2^63 (one above int64) + suite.Require().True(ok) + originalCoin := sdk.NewCoin(tc.sourceDenomToTransfer, amount) + + msg := types.NewMsgTransferWithEncoding( + types.PortID, suite.pathBToA.EndpointB.ClientID, + originalCoin, suite.chainB.SenderAccount.GetAddress().String(), + suite.evmChainA.SenderAccount.GetAddress().String(), clienttypes.Height{}, + timeoutTimestamp, "", types.EncodingProtobuf, + ) + _, err := suite.chainB.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + token, err := simAppB.TransferKeeper.TokenFromCoin(suite.chainB.GetContext(), originalCoin) + suite.Require().NoError(err) + + transferData := types.NewFungibleTokenPacketData( + token.Denom.Path(), + token.Amount, + suite.chainB.SenderAccount.GetAddress().String(), + suite.evmChainA.SenderAccount.GetAddress().String(), + "", + ) + bz := suite.chainB.Codec.MustMarshal(&transferData) + payload = channeltypesv2.NewPayload( + types.PortID, types.PortID, types.V1, + types.EncodingProtobuf, bz, + ) + + ctx := suite.evmChainA.GetContext() + evmApp := suite.evmChainA.App.(*evmd.EVMD) + cbs := evmApp.GetIBCKeeper().ChannelKeeperV2.Router.Route(evmibctesting.TransferPort) + + // malleate payload after it has been sent but before OnRecvPacket callback is called + tc.malleate() + + recvResult := cbs.OnRecvPacket( + ctx, suite.pathBToA.EndpointB.ClientID, suite.pathBToA.EndpointA.ClientID, + 1, payload, suite.evmChainA.SenderAccount.GetAddress(), + ) + + if !tc.expErr { + + suite.Require().Equal(channeltypesv2.PacketStatus_Success, recvResult.Status) + suite.Require().Equal(channeltypes.NewResultAcknowledgement([]byte{byte(1)}).Acknowledgement(), recvResult.Acknowledgement) + + escrowAddress := types.GetEscrowAddress(types.PortID, suite.pathBToA.EndpointB.ClientID) + // check that the balance for evmChainA is updated + chainBBalance := simAppB.BankKeeper.GetBalance( + suite.chainB.GetContext(), + suite.chainB.SenderAccount.GetAddress(), + originalCoin.Denom, + ) + suite.Require().Equal(originalBalance.Amount.Sub(amount).Int64(), chainBBalance.Amount.Int64()) + + // check that module account escrow address has locked the tokens + chainBEscrowBalance := simAppB.BankKeeper.GetBalance( + suite.chainB.GetContext(), + escrowAddress, + originalCoin.Denom, + ) + suite.Require().Equal(originalCoin, chainBEscrowBalance) + + traceBToA := types.NewHop(types.PortID, suite.pathBToA.EndpointA.ClientID) + + // check that voucher exists on chain B + chainADenom := types.NewDenom(originalCoin.Denom, traceBToA) + chainABalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + suite.evmChainA.SenderAccount.GetAddress(), + chainADenom.IBCDenom(), + ) + coinSentFromBToA := sdk.NewCoin(chainADenom.IBCDenom(), amount) + suite.Require().Equal(coinSentFromBToA, chainABalance) + } else { + suite.Require().Equal(channeltypesv2.PacketStatus_Failure, recvResult.Status) + } + }) + } +} + +// TestOnAckPacket tests ExampleChain's implementation of the OnAckPacket callback. +func (suite *TransferTestSuiteV2) TestOnAckPacket() { + testCases := []struct { + name string + sourceDenomToTransfer string + }{ + { + "transfer single denom", + sdk.DefaultBondDenom, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + evmApp := suite.evmChainA.App.(*evmd.EVMD) + originalBalance := evmApp.BankKeeper.GetBalance(suite.evmChainA.GetContext(), suite.evmChainA.SenderAccount.GetAddress(), tc.sourceDenomToTransfer) + + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().Add(time.Hour).Unix()) + + amount, ok := sdkmath.NewIntFromString("9223372036854775808") // 2^63 (one above int64) + suite.Require().True(ok) + originalCoin := sdk.NewCoin(tc.sourceDenomToTransfer, amount) + + msg := types.NewMsgTransferWithEncoding( + types.PortID, suite.pathAToB.EndpointA.ClientID, + originalCoin, suite.evmChainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), clienttypes.Height{}, + timeoutTimestamp, "", types.EncodingProtobuf, + ) + _, err := suite.evmChainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + token, err := evmApp.TransferKeeper.TokenFromCoin(suite.evmChainA.GetContext(), originalCoin) + suite.Require().NoError(err) + + transferData := types.NewFungibleTokenPacketData( + token.Denom.Path(), + token.Amount, + suite.evmChainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + "", + ) + bz := suite.evmChainA.Codec.MustMarshal(&transferData) + payload := channeltypesv2.NewPayload( + types.PortID, types.PortID, types.V1, + types.EncodingProtobuf, bz, + ) + + ctx := suite.evmChainA.GetContext() + cbs := evmApp.GetIBCKeeper().ChannelKeeperV2.Router.Route(evmibctesting.TransferPort) + + ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + + err = cbs.OnAcknowledgementPacket( + ctx, suite.pathAToB.EndpointA.ClientID, suite.pathAToB.EndpointB.ClientID, + 1, ack.Acknowledgement(), payload, suite.evmChainA.SenderAccount.GetAddress(), + ) + suite.Require().NoError(err) + + // on successful ack, the tokens sent in packets should still be in escrow + escrowAddress := types.GetEscrowAddress(types.PortID, suite.pathAToB.EndpointA.ClientID) + // check that the balance for evmChainA is updated + chainABalance := evmApp.BankKeeper.GetBalance(suite.evmChainA.GetContext(), suite.evmChainA.SenderAccount.GetAddress(), originalCoin.Denom) + suite.Require().Equal(originalBalance.Amount.Sub(amount).Int64(), chainABalance.Amount.Int64()) + + // check that module account escrow address has locked the tokens + chainAEscrowBalance := evmApp.BankKeeper.GetBalance(suite.evmChainA.GetContext(), escrowAddress, originalCoin.Denom) + suite.Require().Equal(originalCoin, chainAEscrowBalance) + + // create a custom error ack and replay the callback to ensure it fails with IBC v2 callbacks + errAck := channeltypes.NewErrorAcknowledgement(types.ErrInvalidAmount) + err = cbs.OnAcknowledgementPacket( + ctx, suite.pathAToB.EndpointA.ClientID, suite.pathAToB.EndpointB.ClientID, + 1, errAck.Acknowledgement(), payload, suite.evmChainA.SenderAccount.GetAddress(), + ) + suite.Require().Error(err) + + // create the sentinel error ack and replay the callback to ensure the tokens are correctly refunded + // we can replay the callback here because the replay protection is handled in the IBC handler + err = cbs.OnAcknowledgementPacket( + ctx, suite.pathAToB.EndpointA.ClientID, suite.pathAToB.EndpointB.ClientID, + 1, channeltypesv2.ErrorAcknowledgement[:], payload, suite.evmChainA.SenderAccount.GetAddress(), + ) + suite.Require().NoError(err) + + // on error ack, the tokens sent in packets should be returned to sender + // check that the balance for evmChainA is refunded + chainABalance = evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + suite.evmChainA.SenderAccount.GetAddress(), + originalCoin.Denom, + ) + suite.Require().Equal(originalBalance.Amount, chainABalance.Amount) + + // check that module account escrow address has no tokens + chainAEscrowBalance = evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + escrowAddress, + originalCoin.Denom, + ) + suite.Require().Equal(sdk.NewCoin(originalCoin.Denom, sdkmath.ZeroInt()), chainAEscrowBalance) + }) + } +} + +// TestOnTimeoutPacket tests ExampleChain's implementation of the OnTimeoutPacket callback. +func (suite *TransferTestSuiteV2) TestOnTimeoutPacket() { + testCases := []struct { + name string + sourceDenomToTransfer string + }{ + { + "transfer single denom", + sdk.DefaultBondDenom, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + evmApp := suite.evmChainA.App.(*evmd.EVMD) + originalBalance := evmApp.BankKeeper.GetBalance(suite.evmChainA.GetContext(), suite.evmChainA.SenderAccount.GetAddress(), tc.sourceDenomToTransfer) + + timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().Add(time.Hour).Unix()) + + amount, ok := sdkmath.NewIntFromString("9223372036854775808") // 2^63 (one above int64) + suite.Require().True(ok) + originalCoin := sdk.NewCoin(tc.sourceDenomToTransfer, amount) + + msg := types.NewMsgTransferWithEncoding( + types.PortID, suite.pathAToB.EndpointA.ClientID, + originalCoin, suite.evmChainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), clienttypes.Height{}, + timeoutTimestamp, "", types.EncodingProtobuf, + ) + _, err := suite.evmChainA.SendMsgs(msg) + suite.Require().NoError(err) // message committed + + token, err := evmApp.TransferKeeper.TokenFromCoin(suite.evmChainA.GetContext(), originalCoin) + suite.Require().NoError(err) + + transferData := types.NewFungibleTokenPacketData( + token.Denom.Path(), + token.Amount, + suite.evmChainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + "", + ) + bz := suite.evmChainA.Codec.MustMarshal(&transferData) + payload := channeltypesv2.NewPayload( + types.PortID, types.PortID, types.V1, + types.EncodingProtobuf, bz, + ) + + // on successful send, the tokens sent in packets should be in escrow + escrowAddress := types.GetEscrowAddress(types.PortID, suite.pathAToB.EndpointA.ClientID) + // check that the balance for evmChainA is updated + chainABalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + suite.evmChainA.SenderAccount.GetAddress(), + originalCoin.Denom, + ) + suite.Require().Equal(originalBalance.Amount.Sub(amount).Int64(), chainABalance.Amount.Int64()) + + // check that module account escrow address has locked the tokens + chainAEscrowBalance := evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + escrowAddress, + originalCoin.Denom, + ) + suite.Require().Equal(originalCoin, chainAEscrowBalance) + + ctx := suite.evmChainA.GetContext() + cbs := suite.evmChainA.App.GetIBCKeeper().ChannelKeeperV2.Router.Route(evmibctesting.TransferPort) + + err = cbs.OnTimeoutPacket( + ctx, suite.pathAToB.EndpointA.ClientID, suite.pathAToB.EndpointB.ClientID, + 1, payload, suite.evmChainA.SenderAccount.GetAddress(), + ) + suite.Require().NoError(err) + + // on timeout, the tokens sent in packets should be returned to sender + // check that the balance for evmChainA is refunded + chainABalance = evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + suite.evmChainA.SenderAccount.GetAddress(), + originalCoin.Denom, + ) + suite.Require().Equal(originalBalance.Amount, chainABalance.Amount) + + // check that module account escrow address has no tokens + chainAEscrowBalance = evmApp.BankKeeper.GetBalance( + suite.evmChainA.GetContext(), + escrowAddress, + originalCoin.Denom, + ) + suite.Require().Equal(sdk.NewCoin(originalCoin.Denom, sdkmath.ZeroInt()), chainAEscrowBalance) + }) + } +} diff --git a/testutil/integration/common/network/network.go b/testutil/integration/common/network/network.go index c65b0c296..c03a3642d 100644 --- a/testutil/integration/common/network/network.go +++ b/testutil/integration/common/network/network.go @@ -6,7 +6,7 @@ import ( abcitypes "github.com/cometbft/cometbft/abci/types" - ibctesting "github.com/cosmos/ibc-go/v8/testing" + ibctesting "github.com/cosmos/ibc-go/v10/testing" sdktypes "github.com/cosmos/cosmos-sdk/types" sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" diff --git a/testutil/integration/ibc/chain/chain.go b/testutil/integration/ibc/chain/chain.go deleted file mode 100644 index b72d6191a..000000000 --- a/testutil/integration/ibc/chain/chain.go +++ /dev/null @@ -1,81 +0,0 @@ -package chain - -import ( - "time" - - cmttypes "github.com/cometbft/cometbft/types" - - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - // For now, we'll keep this. Pending to review if we can remove it. - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" - ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" - ibctesting "github.com/cosmos/ibc-go/v8/testing" - "github.com/cosmos/ibc-go/v8/testing/simapp" - - sdktypes "github.com/cosmos/cosmos-sdk/types" -) - -// Chain defines the required methods needed for a testing IBC chain that complies -// with the ibctesting chain struct. -type Chain interface { - // GetContext returns the current context for the application. - GetContext() sdktypes.Context - // GetSimApp returns the SimApp to allow usage of non-interface fields. - GetSimApp() *simapp.SimApp - // QueryProof performs an abci query with the given key and returns the proto encoded merkle proof - // for the query and the height at which the proof will succeed on a tendermint verifier. - QueryProof(key []byte) ([]byte, clienttypes.Height) - // QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof - // for the query and the height at which the proof will succeed on a tendermint verifier. Only the IBC - // store is supported - QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) - // QueryProofForStore performs an abci query with the given key and returns the proto encoded merkle proof - // for the query and the height at which the proof will succeed on a tendermint verifier. - QueryProofForStore(storeKey string, key []byte, height int64) ([]byte, clienttypes.Height) - // QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof - // for the query and the height at which the proof will succeed on a tendermint verifier. - QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) - // QueryConsensusStateProof performs an abci query for a consensus state - // stored on the given clientID. The proof and consensusHeight are returned. - QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) - // NextBlock sets the last header to the current header and increments the current header to be - // at the next block height. It does not update the time as that is handled by the Coordinator. - // It will call Endblock and Commit and apply the validator set changes to the next validators - // of the next block being created. This follows the Tendermint protocol of applying valset changes - // returned on block `n` to the validators of block `n+2`. - // It calls BeginBlock with the new block created before returning. - NextBlock() - // GetClientState retrieves the client state for the provided clientID. The client is - // expected to exist otherwise testing will fail. - GetClientState(clientID string) exported.ClientState - // GetConsensusState retrieves the consensus state for the provided clientID and height. - // It will return a success boolean depending on if consensus state exists or not. - GetConsensusState(clientID string, height exported.Height) (exported.ConsensusState, bool) - // GetValsAtHeight will return the trusted validator set of the chain for the given trusted height. It will return - // a success boolean depending on if the validator set exists or not at that height. - GetValsAtHeight(trustedHeight int64) (*cmttypes.ValidatorSet, bool) - // GetAcknowledgement retrieves an acknowledgement for the provided packet. If the - // acknowledgement does not exist then testing will fail. - GetAcknowledgement(packet exported.PacketI) []byte - // GetPrefix returns the prefix for used by a chain in connection creation - GetPrefix() commitmenttypes.MerklePrefix - // ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the - // light client on the source chain. - ConstructUpdateTMClientHeader(counterparty *ibctesting.TestChain, clientID string) (*ibctm.Header, error) - // ConstructUpdateTMClientHeaderWithTrustedHeight will construct a valid 07-tendermint Header to update the - ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty *ibctesting.TestChain, clientID string, trustedHeight clienttypes.Height) (*ibctm.Header, error) // light client on the source chain. - // ExpireClient fast forwards the chain's block time by the provided amount of time which will - // expire any clients with a trusting period less than or equal to this amount of time. - ExpireClient(amount time.Duration) - // CurrentTMClientHeader creates a TM header using the current header parameters - // on the chain. The trusted fields in the header are set to nil. - CurrentTMClientHeader() *ibctm.Header - // GetChannelCapability returns the channel capability for the given portID and channelID. - // The capability must exist, otherwise testing will fail. - GetChannelCapability(portID, channelID string) *capabilitytypes.Capability - // GetTimeoutHeight is a convenience function which returns an IBC packet timeout height - // to be used for testing. It returns the current IBC height + 100 blocks - GetTimeoutHeight() clienttypes.Height -} diff --git a/testutil/integration/ibc/coordinator/coordinator.go b/testutil/integration/ibc/coordinator/coordinator.go deleted file mode 100644 index 3707c9983..000000000 --- a/testutil/integration/ibc/coordinator/coordinator.go +++ /dev/null @@ -1,168 +0,0 @@ -package coordinator - -import ( - "testing" - "time" - - cosmosevmibc "github.com/cosmos/evm/ibc/testing" - "github.com/cosmos/evm/testutil/integration/common/network" - ibcchain "github.com/cosmos/evm/testutil/integration/ibc/chain" - ibctesting "github.com/cosmos/ibc-go/v8/testing" - - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// Coordinator is the interface that defines the methods that are used to -// coordinate the execution of the IBC relayer. -type Coordinator interface { - // IncrementTime iterates through all the TestChain's and increments their current header time - // by 5 seconds. - IncrementTime() - // UpdateTime updates all clocks for the TestChains to the current global time. - UpdateTime() - // UpdateTimeForChain updates the clock for a specific chain. - UpdateTimeForChain(chainID string) - // GetChain returns the TestChain for a given chainID. - GetChain(chainID string) ibcchain.Chain - // GetDummyChainsIDs returns the chainIDs for all dummy chains. - GetDummyChainsIDs() []string - // GetPath returns the transfer path for the chain ids 'a' and 'b' - GetPath(a, b string) *cosmosevmibc.Path - // GetChainSenderAcc returns the sender account for the specified chain - GetChainSenderAcc(chainID string) sdk.AccountI - // SetDefaultSignerForChain sets the default signer for the chain with the given chainID. - SetDefaultSignerForChain(chainID string, priv cryptotypes.PrivKey, acc sdk.AccountI) - // Setup constructs a TM client, connection, and channel on both chains provided. It will - // fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned - // for both chains. The channels created are connected to the ibc-transfer application. - Setup(src, dst string) IBCConnection - // CommitNBlocks commits n blocks on the chain with the given chainID. - CommitNBlocks(chainID string, n uint64) error - // CommitAll commits 1 blocks on all chains within the coordinator. - CommitAll() error -} - -var AmountOfDummyChains = 2 - -var _ Coordinator = (*IntegrationCoordinator)(nil) - -// IntegrationCoordinator is a testing struct which contains N TestChain's. It handles keeping all chains -// in sync with regards to time. -// NOTE: When using the coordinator, it is important to commit blocks through the coordinator and not -// through the network interface directly. This is because the coordinator does not keep the context in -// sync with the network interface. -type IntegrationCoordinator struct { - coord *ibctesting.Coordinator - dummyChainsIDs []string -} - -// NewIntegrationCoordinator returns a new IntegrationCoordinator with N TestChain's. -func NewIntegrationCoordinator(t *testing.T, preConfiguredChains []network.Network) *IntegrationCoordinator { - t.Helper() - coord := &ibctesting.Coordinator{ - T: t, - CurrentTime: time.Now(), - } - ibcChains := getIBCChains(t, coord, preConfiguredChains) - dummyChains, dummyChainsIDs := generateDummyChains(t, coord, AmountOfDummyChains) - totalChains := mergeMaps(ibcChains, dummyChains) - coord.Chains = totalChains - return &IntegrationCoordinator{ - coord: coord, - dummyChainsIDs: dummyChainsIDs, - } -} - -// GetChain returns the TestChain for a given chainID but abstracted to our internal chain interface. -func (c *IntegrationCoordinator) GetChain(chainID string) ibcchain.Chain { - return c.coord.Chains[chainID] -} - -// GetTestChain returns the TestChain for a given chainID. -func (c *IntegrationCoordinator) GetTestChain(chainID string) *ibctesting.TestChain { - return c.coord.GetChain(chainID) -} - -// GetDummyChainsIDs returns the chainIDs for all dummy chains. -func (c *IntegrationCoordinator) GetDummyChainsIDs() []string { - return c.dummyChainsIDs -} - -// GetPath returns the transfer path for the chain ids 'a' and 'b' -func (c *IntegrationCoordinator) GetPath(a, b string) *cosmosevmibc.Path { - chainA := c.coord.GetChain(a) - chainB := c.coord.GetChain(b) - - return cosmosevmibc.NewTransferPath(chainA, chainB) -} - -// GetChain returns the TestChain for a given chainID. -func (c *IntegrationCoordinator) GetChainSenderAcc(chainID string) sdk.AccountI { - return c.coord.Chains[chainID].SenderAccount -} - -// IncrementTime iterates through all the TestChain's and increments their current header time -// by 5 seconds. -func (c *IntegrationCoordinator) IncrementTime() { - c.coord.IncrementTime() -} - -// UpdateTime updates all clocks for the TestChains to the current global time. -func (c *IntegrationCoordinator) UpdateTime() { - c.coord.UpdateTime() -} - -// UpdateTimeForChain updates the clock for a specific chain. -func (c *IntegrationCoordinator) UpdateTimeForChain(chainID string) { - chain := c.coord.GetChain(chainID) - c.coord.UpdateTimeForChain(chain) -} - -// SetDefaultSignerForChain sets the default signer for the chain with the given chainID. -func (c *IntegrationCoordinator) SetDefaultSignerForChain(chainID string, priv cryptotypes.PrivKey, acc sdk.AccountI) { - chain := c.coord.GetChain(chainID) - chain.SenderPrivKey = priv - chain.SenderAccount = acc - chain.SenderAccounts = []ibctesting.SenderAccount{{SenderPrivKey: priv, SenderAccount: acc}} -} - -// Setup constructs a TM client, connection, and channel on both chains provided. It will -// fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned -// for both chains. The channels created are connected to the ibc-transfer application. -func (c *IntegrationCoordinator) Setup(a, b string) IBCConnection { - path := c.GetPath(a, b) - cosmosevmibc.SetupPath(c.coord, path) - - return IBCConnection{ - EndpointA: Endpoint{ - ChainID: a, - ClientID: path.EndpointA.ClientID, - ConnectionID: path.EndpointA.ConnectionID, - ChannelID: path.EndpointA.ChannelID, - PortID: path.EndpointA.ChannelConfig.PortID, - }, - EndpointB: Endpoint{ - ChainID: b, - ClientID: path.EndpointB.ClientID, - ConnectionID: path.EndpointB.ConnectionID, - ChannelID: path.EndpointB.ChannelID, - PortID: path.EndpointB.ChannelConfig.PortID, - }, - } -} - -// CommitNBlocks commits n blocks on the chain with the given chainID. -func (c *IntegrationCoordinator) CommitNBlocks(chainID string, n uint64) error { - chain := c.coord.GetChain(chainID) - c.coord.CommitNBlocks(chain, n) - return nil -} - -// CommitAll commits n blocks on the chain with the given chainID. -func (c *IntegrationCoordinator) CommitAll() error { - for _, chain := range c.coord.Chains { - c.coord.CommitNBlocks(chain, 1) - } - return nil -} diff --git a/testutil/integration/ibc/coordinator/types.go b/testutil/integration/ibc/coordinator/types.go deleted file mode 100644 index 193463435..000000000 --- a/testutil/integration/ibc/coordinator/types.go +++ /dev/null @@ -1,16 +0,0 @@ -package coordinator - -// Endpoint defines the identifiers for a chain's client, connection, and channel. -type Endpoint struct { - ChainID string - ClientID string - ConnectionID string - ChannelID string - PortID string -} - -// IBCConnection defines the connection between two chains. -type IBCConnection struct { - EndpointA Endpoint - EndpointB Endpoint -} diff --git a/testutil/integration/ibc/coordinator/utils.go b/testutil/integration/ibc/coordinator/utils.go deleted file mode 100644 index f564a4d2b..000000000 --- a/testutil/integration/ibc/coordinator/utils.go +++ /dev/null @@ -1,53 +0,0 @@ -package coordinator - -import ( - "strconv" - "testing" - - "github.com/cosmos/evm/testutil/integration/common/network" - ibctesting "github.com/cosmos/ibc-go/v8/testing" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// getIBCChains returns a map of TestChain's for the given network interface. -func getIBCChains(t *testing.T, coord *ibctesting.Coordinator, chains []network.Network) map[string]*ibctesting.TestChain { - t.Helper() - ibcChains := make(map[string]*ibctesting.TestChain) - for _, chain := range chains { - ibcChains[chain.GetChainID()] = chain.GetIBCChain(t, coord) - } - return ibcChains -} - -// generateDummyChains returns a map of dummy chains to complement IBC connections for integration tests. -func generateDummyChains(t *testing.T, coord *ibctesting.Coordinator, numberOfChains int) (map[string]*ibctesting.TestChain, []string) { - t.Helper() - ibcChains := make(map[string]*ibctesting.TestChain) - ids := make([]string, numberOfChains) - // dummy chains use the ibc testing chain setup - // that uses the default sdk address prefix ('cosmos') - // Update the prefix configs to use that prefix - cfg := sdk.GetConfig() - cfg.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub) - cfg.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub) - cfg.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub) - // Also need to disable address cache to avoid using modules - // accounts with 'evmos' addresses (because Cosmos EVM chain setup is first) - sdk.SetAddrCacheEnabled(false) - for i := 1; i <= numberOfChains; i++ { - chainID := "dummychain-" + strconv.Itoa(i) - ids[i-1] = chainID - ibcChains[chainID] = ibctesting.NewTestChain(t, coord, chainID) - } - - return ibcChains, ids -} - -// mergeMaps merges two maps of TestChain's. -func mergeMaps(m1, m2 map[string]*ibctesting.TestChain) map[string]*ibctesting.TestChain { - for k, v := range m2 { - m1[k] = v - } - return m1 -} diff --git a/testutil/integration/os/network/ibc.go b/testutil/integration/os/network/ibc.go index 71dea12c4..90d9a6519 100644 --- a/testutil/integration/os/network/ibc.go +++ b/testutil/integration/os/network/ibc.go @@ -3,7 +3,7 @@ package network import ( "testing" - ibctesting "github.com/cosmos/ibc-go/v8/testing" + ibctesting "github.com/cosmos/ibc-go/v10/testing" ) // GetIBCChain returns a TestChain instance for the given network. @@ -12,16 +12,14 @@ import ( func (n *IntegrationNetwork) GetIBCChain(t *testing.T, coord *ibctesting.Coordinator) *ibctesting.TestChain { t.Helper() return &ibctesting.TestChain{ - TB: t, - Coordinator: coord, - ChainID: n.GetChainID(), - App: n.app, - CurrentHeader: n.ctx.BlockHeader(), - QueryServer: n.app.GetIBCKeeper(), - TxConfig: n.app.GetTxConfig(), - Codec: n.app.AppCodec(), - Vals: n.valSet, - NextVals: n.valSet, - Signers: n.valSigners, + TB: t, + Coordinator: coord, + ChainID: n.GetChainID(), + App: n.app, + TxConfig: n.app.GetTxConfig(), + Codec: n.app.AppCodec(), + Vals: n.valSet, + NextVals: n.valSet, + Signers: n.valSigners, } } diff --git a/testutil/integration/os/utils/unit.go b/testutil/integration/os/utils/unit.go index 11ac135b1..58a2fe80f 100644 --- a/testutil/integration/os/utils/unit.go +++ b/testutil/integration/os/utils/unit.go @@ -7,9 +7,10 @@ package utils import ( "fmt" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + "github.com/cosmos/evm/testutil/integration/os/network" erc20types "github.com/cosmos/evm/x/erc20/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" "cosmossdk.io/math" @@ -82,10 +83,10 @@ func RegisterEvmosERC20Coins( func RegisterIBCERC20Coins( network *network.UnitTestNetwork, tokenReceiver sdk.AccAddress, - denomTrace transfertypes.DenomTrace, + denom transfertypes.Denom, ) (erc20types.TokenPair, error) { - ibcDenom := denomTrace.IBCDenom() - network.App.TransferKeeper.SetDenomTrace(network.GetContext(), denomTrace) + ibcDenom := denom.IBCDenom() + network.App.TransferKeeper.SetDenom(network.GetContext(), denom) ibcMetadata := banktypes.Metadata{ Name: "Generic IBC name", Symbol: "IBC", @@ -132,7 +133,7 @@ func RegisterIBCERC20Coins( ibcDenomID := network.App.Erc20Keeper.GetDenomMap( network.GetContext(), - denomTrace.IBCDenom(), + denom.IBCDenom(), ) tokenPair, ok := network.App.Erc20Keeper.GetTokenPair(network.GetContext(), ibcDenomID) if !ok { diff --git a/utils/utils.go b/utils/utils.go index b0489e245..10619ccdb 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -8,8 +8,9 @@ import ( "github.com/ethereum/go-ethereum/common" "golang.org/x/exp/constraints" + ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + "github.com/cosmos/evm/crypto/ethsecp256k1" - ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" errorsmod "cosmossdk.io/errors" @@ -119,7 +120,7 @@ func CreateAccAddressFromBech32(address string, bech32prefix string) (addr sdk.A return sdk.AccAddress(bz), nil } -// GetIBCDenomAddress returns the address from the hash of the ICS20's DenomTrace Path. +// GetIBCDenomAddress returns the address from the hash of the ICS20's Denom Path. func GetIBCDenomAddress(denom string) (common.Address, error) { if !strings.HasPrefix(denom, "ibc/") { return common.Address{}, ibctransfertypes.ErrInvalidDenomForTransfer.Wrapf("coin %s does not have 'ibc/' prefix", denom) @@ -129,7 +130,7 @@ func GetIBCDenomAddress(denom string) (common.Address, error) { return common.Address{}, ibctransfertypes.ErrInvalidDenomForTransfer.Wrapf("coin %s is not a valid IBC voucher hash", denom) } - // Get the address from the hash of the ICS20's DenomTrace Path + // Get the address from the hash of the ICS20's Denom Path bz, err := ibctransfertypes.ParseHexHash(denom[4:]) if err != nil { return common.Address{}, ibctransfertypes.ErrInvalidDenomForTransfer.Wrap(err.Error()) @@ -138,29 +139,6 @@ func GetIBCDenomAddress(denom string) (common.Address, error) { return common.BytesToAddress(bz), nil } -// ComputeIBCDenomTrace compute the ibc voucher denom trace associated with -// the portID, channelID, and the given a token denomination. -func ComputeIBCDenomTrace( - portID, channelID, - denom string, -) ibctransfertypes.DenomTrace { - denomTrace := ibctransfertypes.DenomTrace{ - Path: fmt.Sprintf("%s/%s", portID, channelID), - BaseDenom: denom, - } - - return denomTrace -} - -// ComputeIBCDenom compute the ibc voucher denom associated to -// the portID, channelID, and the given a token denomination. -func ComputeIBCDenom( - portID, channelID, - denom string, -) string { - return ComputeIBCDenomTrace(portID, channelID, denom).IBCDenom() -} - // SortSlice sorts a slice of any ordered type. func SortSlice[T constraints.Ordered](slice []T) { sort.Slice(slice, func(i, j int) bool { diff --git a/x/erc20/genesis_test.go b/x/erc20/genesis_test.go index c93ca56f4..6ac93e4ca 100644 --- a/x/erc20/genesis_test.go +++ b/x/erc20/genesis_test.go @@ -11,13 +11,14 @@ import ( tmversion "github.com/cometbft/cometbft/proto/tendermint/version" "github.com/cometbft/cometbft/version" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + exampleapp "github.com/cosmos/evm/evmd" "github.com/cosmos/evm/testutil/constants" "github.com/cosmos/evm/testutil/integration/os/network" utiltx "github.com/cosmos/evm/testutil/tx" "github.com/cosmos/evm/x/erc20" "github.com/cosmos/evm/x/erc20/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -31,10 +32,7 @@ type GenesisTestSuite struct { const osmoERC20ContractAddr = "0x5dCA2483280D9727c80b5518faC4556617fb19ZZ" -var osmoDenomTrace = transfertypes.DenomTrace{ - BaseDenom: "uosmo", - Path: "transfer/channel-0", -} +var osmoDenom = transfertypes.NewDenom("uosmo", transfertypes.NewHop(transfertypes.PortID, "channel-0")) func TestGenesisTestSuite(t *testing.T) { suite.Run(t, new(GenesisTestSuite)) @@ -94,7 +92,7 @@ func (suite *GenesisTestSuite) TestERC20InitGenesis() { []types.TokenPair{ { Erc20Address: osmoERC20ContractAddr, - Denom: osmoDenomTrace.IBCDenom(), + Denom: osmoDenom.IBCDenom(), Enabled: true, ContractOwner: types.OWNER_MODULE, }, @@ -143,7 +141,7 @@ func (suite *GenesisTestSuite) TestErc20ExportGenesis() { []types.TokenPair{ { Erc20Address: osmoERC20ContractAddr, - Denom: osmoDenomTrace.IBCDenom(), + Denom: osmoDenom.IBCDenom(), Enabled: true, ContractOwner: types.OWNER_MODULE, }, diff --git a/x/erc20/ibc_middleware.go b/x/erc20/ibc_middleware.go index 4d383ca5c..ca166b643 100644 --- a/x/erc20/ibc_middleware.go +++ b/x/erc20/ibc_middleware.go @@ -1,12 +1,15 @@ package erc20 import ( + "errors" + + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v10/modules/core/exported" + "github.com/cosmos/evm/ibc" - "github.com/cosmos/evm/x/erc20/keeper" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" + erc20types "github.com/cosmos/evm/x/erc20/types" errorsmod "cosmossdk.io/errors" @@ -20,11 +23,18 @@ var _ porttypes.IBCModule = &IBCMiddleware{} // the erc20 keeper and the underlying application. type IBCMiddleware struct { *ibc.Module - keeper keeper.Keeper + keeper erc20types.ERC20Keeper } // NewIBCMiddleware creates a new IBCMiddleware given the keeper and underlying application -func NewIBCMiddleware(k keeper.Keeper, app porttypes.IBCModule) IBCMiddleware { +func NewIBCMiddleware(k erc20types.ERC20Keeper, app porttypes.IBCModule) IBCMiddleware { + if app == nil { + panic(errors.New("underlying application cannot be nil")) + } + if k == nil { + panic(errors.New("erc20 keeper cannot be nil")) + } + return IBCMiddleware{ Module: ibc.NewModule(app), keeper: k, @@ -39,10 +49,11 @@ func NewIBCMiddleware(k keeper.Keeper, app porttypes.IBCModule) IBCMiddleware { // packet callback. func (im IBCMiddleware) OnRecvPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) exported.Acknowledgement { - ack := im.Module.OnRecvPacket(ctx, packet, relayer) + ack := im.Module.OnRecvPacket(ctx, channelVersion, packet, relayer) // return if the acknowledgement is an error ACK if !ack.Success() { @@ -57,6 +68,7 @@ func (im IBCMiddleware) OnRecvPacket( // Cosmos Coin to their ERC20 token representation. func (im IBCMiddleware) OnAcknowledgementPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, @@ -71,7 +83,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return errorsmod.Wrapf(errortypes.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) } - if err := im.Module.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer); err != nil { + if err := im.Module.OnAcknowledgementPacket(ctx, channelVersion, packet, acknowledgement, relayer); err != nil { return err } @@ -83,6 +95,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( // Cosmos Coin to their ERC20 token representation. func (im IBCMiddleware) OnTimeoutPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) error { @@ -91,7 +104,7 @@ func (im IBCMiddleware) OnTimeoutPacket( return errorsmod.Wrapf(errortypes.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) } - if err := im.Module.OnTimeoutPacket(ctx, packet, relayer); err != nil { + if err := im.Module.OnTimeoutPacket(ctx, channelVersion, packet, relayer); err != nil { return err } diff --git a/x/erc20/keeper/ibc_callbacks.go b/x/erc20/keeper/ibc_callbacks.go index 1b0d15b6e..f351a0148 100644 --- a/x/erc20/keeper/ibc_callbacks.go +++ b/x/erc20/keeper/ibc_callbacks.go @@ -8,9 +8,9 @@ import ( "github.com/cosmos/evm/ibc" "github.com/cosmos/evm/x/erc20/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v10/modules/core/exported" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" diff --git a/x/erc20/keeper/ibc_callbacks_test.go b/x/erc20/keeper/ibc_callbacks_test.go index 1f78917c2..c0dc1418a 100644 --- a/x/erc20/keeper/ibc_callbacks_test.go +++ b/x/erc20/keeper/ibc_callbacks_test.go @@ -7,17 +7,18 @@ import ( "github.com/ethereum/go-ethereum/common" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + ibcgotesting "github.com/cosmos/ibc-go/v10/testing" + ibcmock "github.com/cosmos/ibc-go/v10/testing/mock" + "github.com/cosmos/evm/contracts" "github.com/cosmos/evm/crypto/ethsecp256k1" "github.com/cosmos/evm/testutil" "github.com/cosmos/evm/x/erc20/keeper" "github.com/cosmos/evm/x/erc20/types" evmtypes "github.com/cosmos/evm/x/vm/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - ibcgotesting "github.com/cosmos/ibc-go/v8/testing" - ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" "cosmossdk.io/math" @@ -46,7 +47,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // Setup Cosmos <=> Cosmos EVM IBC relayer sourceChannel := "channel-292" cosmosEVMChannel := "channel-3" - path := fmt.Sprintf("%s/%s", transfertypes.PortID, cosmosEVMChannel) + hop := transfertypes.NewHop(transfertypes.PortID, cosmosEVMChannel) timeoutHeight := clienttypes.NewHeight(0, 100) disabledTimeoutTimestamp := uint64(0) @@ -233,12 +234,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // get updated context after registering ERC20 pair ctx = suite.network.GetContext() - // Set Denom Trace - denomTrace := transfertypes.DenomTrace{ - Path: path, - BaseDenom: registeredDenom, - } - suite.network.App.TransferKeeper.SetDenomTrace(ctx, denomTrace) + // Set Denom + denom := transfertypes.NewDenom(registeredDenom, hop) + suite.network.App.TransferKeeper.SetDenom(ctx, denom) // Set Cosmos Channel channel := channeltypes.Channel{ diff --git a/x/erc20/keeper/token_pairs.go b/x/erc20/keeper/token_pairs.go index 32e1fb48e..6815ddbde 100644 --- a/x/erc20/keeper/token_pairs.go +++ b/x/erc20/keeper/token_pairs.go @@ -164,7 +164,7 @@ func (k Keeper) IsDenomRegistered(ctx sdk.Context, denom string) bool { // GetCoinAddress returns the corresponding ERC-20 contract address for the // given denom. // If the denom is not registered and its an IBC voucher, it returns the address -// from the hash of the ICS20's DenomTrace Path. +// from the hash of the ICS20's Denom Path. func (k Keeper) GetCoinAddress(ctx sdk.Context, denom string) (common.Address, error) { id := k.GetDenomMap(ctx, denom) if len(id) == 0 { diff --git a/x/erc20/types/interfaces.go b/x/erc20/types/interfaces.go index d3f550cfa..24da67cd0 100644 --- a/x/erc20/types/interfaces.go +++ b/x/erc20/types/interfaces.go @@ -3,6 +3,10 @@ package types import ( "context" + "cosmossdk.io/log" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v10/modules/core/exported" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -47,6 +51,13 @@ type EVMKeeper interface { GetAccount(ctx sdk.Context, address common.Address) *statedb.Account } +type ERC20Keeper interface { + OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, ack exported.Acknowledgement) exported.Acknowledgement + OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data transfertypes.FungibleTokenPacketData, ack channeltypes.Acknowledgement) error + OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data transfertypes.FungibleTokenPacketData) error + Logger(ctx sdk.Context) log.Logger +} + type ( LegacyParams = paramtypes.ParamSet // Subspace defines an interface that implements the legacy Cosmos SDK x/params Subspace type. diff --git a/x/erc20/v2/ibc_middleware.go b/x/erc20/v2/ibc_middleware.go new file mode 100644 index 000000000..aa7b8262d --- /dev/null +++ b/x/erc20/v2/ibc_middleware.go @@ -0,0 +1,191 @@ +package v2 + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + channeltypesv2 "github.com/cosmos/ibc-go/v10/modules/core/04-channel/v2/types" + ibcapi "github.com/cosmos/ibc-go/v10/modules/core/api" + + erc20types "github.com/cosmos/evm/x/erc20/types" +) + +var _ ibcapi.IBCModule = &IBCMiddleware{} + +// IBCMiddleware implements the ICS26 callbacks for the transfer middleware given +// the erc20 keeper and the underlying application. +// The logics are same as the IBCMiddleware, but this is a v2 version of the middleware +type IBCMiddleware struct { + app ibcapi.IBCModule + keeper erc20types.ERC20Keeper +} + +// NewIBCMiddleware creates a new IBCMiddleware given the keeper and underlying application +func NewIBCMiddleware( + app ibcapi.IBCModule, + k erc20types.ERC20Keeper, +) IBCMiddleware { + if app == nil { + panic(errors.New("underlying application cannot be nil")) + } + if k == nil { + panic(errors.New("erc20 keeper cannot be nil")) + } + + return IBCMiddleware{ + app: app, + keeper: k, + } +} + +// OnSendPacket doesn't do anything in the erc20 middleware. +func (im IBCMiddleware) OnSendPacket( + ctx sdk.Context, + sourceClient string, + destinationClient string, + sequence uint64, + payload channeltypesv2.Payload, + signer sdk.AccAddress, +) error { + return im.app.OnSendPacket(ctx, sourceClient, destinationClient, sequence, payload, signer) +} + +// OnRecvPacket implements the IBCModule interface. +// It receives the tokens through the default ICS20 OnRecvPacket callback logic +// and then automatically converts the Cosmos Coin to their ERC20 token +// representation. +// If the acknowledgement fails, this callback will default to the ibc-core +// packet callback. +func (im IBCMiddleware) OnRecvPacket( + ctx sdk.Context, + sourceClient string, + destinationClient string, + sequence uint64, + payload channeltypesv2.Payload, + relayer sdk.AccAddress, +) channeltypesv2.RecvPacketResult { + recvResult := im.app.OnRecvPacket(ctx, sourceClient, destinationClient, sequence, payload, relayer) + if recvResult.Status == channeltypesv2.PacketStatus_Failure { + return recvResult + } + packet, err := v2ToV1Packet(payload, sourceClient, destinationClient, sequence) + if err != nil { + return channeltypesv2.RecvPacketResult{ + Status: channeltypesv2.PacketStatus_Failure, + } + } + var ack channeltypes.Acknowledgement + if err := transfertypes.ModuleCdc.UnmarshalJSON(recvResult.Acknowledgement, &ack); err != nil { + return channeltypesv2.RecvPacketResult{ + Status: channeltypesv2.PacketStatus_Failure, + } + } + im.keeper.OnRecvPacket(ctx, packet, ack) + return recvResult +} + +// OnAcknowledgementPacket implements the IBCModule interface. +// It refunds the token transferred and then automatically converts the +// Cosmos Coin to their ERC20 token representation. +func (im IBCMiddleware) OnAcknowledgementPacket( + ctx sdk.Context, + sourceClient string, + destinationClient string, + sequence uint64, + acknowledgement []byte, + payload channeltypesv2.Payload, + relayer sdk.AccAddress, +) error { + if err := im.app.OnAcknowledgementPacket(ctx, sourceClient, destinationClient, sequence, acknowledgement, payload, relayer); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("erc20 middleware OnAckPacket failed to call underlying app: %s", err.Error())) + return err + } + + packet, err := v2ToV1Packet(payload, sourceClient, destinationClient, sequence) + if err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("erc20 middleware OnAckPacketfailed failed to convert v2 packet to v1 packet: %s", err.Error())) + return err + } + var data transfertypes.FungibleTokenPacketData + if err = transfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("erc20 middleware OnAckPacket failed to unmarshal packet data: %s", err.Error())) + return err + } + var ack channeltypes.Acknowledgement + if bytes.Equal(acknowledgement, channeltypesv2.ErrorAcknowledgement[:]) { + ack = channeltypes.NewErrorAcknowledgement(transfertypes.ErrReceiveFailed) + } else { + if err = transfertypes.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("erc20 middleware OnAckPacket failed to unmarshal acknowledgement: %s", err.Error())) + return err + } + } + return im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack) +} + +// OnTimeoutPacket implements the IBCModule interface. +// It refunds the token transferred and then automatically converts the +// Cosmos Coin to their ERC20 token representation. +func (im IBCMiddleware) OnTimeoutPacket( + ctx sdk.Context, + sourceClient string, + destinationClient string, + sequence uint64, + payload channeltypesv2.Payload, + relayer sdk.AccAddress, +) error { + packet, err := v2ToV1Packet(payload, sourceClient, destinationClient, sequence) + if err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("erc20 middleware OnTimeoutPacketfailed failed to convert v2 packet to v1 packet: %s", err.Error())) + return err + } + var data transfertypes.FungibleTokenPacketData + if err = transfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("erc20 middleware OnTimeoutPacket failed to unmarshal packet data: %s", err.Error())) + return err + } + + if err = im.app.OnTimeoutPacket(ctx, sourceClient, destinationClient, sequence, payload, relayer); err != nil { + im.keeper.Logger(ctx).Error(fmt.Sprintf("erc20 middleware OnTimeoutPacket failed to call underlying app: %s", err.Error())) + return err + } + + return im.keeper.OnTimeoutPacket(ctx, packet, data) +} + +func v2ToV1Packet(payload channeltypesv2.Payload, sourceClient, destinationClient string, sequence uint64) (channeltypes.Packet, error) { + transferRepresentation, err := transfertypes.UnmarshalPacketData(payload.Value, payload.Version, payload.Encoding) + if err != nil { + return channeltypes.Packet{}, err + } + + packetData := transfertypes.FungibleTokenPacketData{ + Denom: transferRepresentation.Token.Denom.Path(), + Amount: transferRepresentation.Token.Amount, + Sender: transferRepresentation.Sender, + Receiver: transferRepresentation.Receiver, + Memo: transferRepresentation.Memo, + } + + packetDataBz, err := json.Marshal(packetData) + if err != nil { + return channeltypes.Packet{}, err + } + + return channeltypes.Packet{ + Sequence: sequence, + SourcePort: payload.SourcePort, + SourceChannel: sourceClient, + DestinationPort: payload.DestinationPort, + DestinationChannel: destinationClient, + Data: packetDataBz, + TimeoutHeight: clienttypes.Height{}, + TimeoutTimestamp: 0, + }, nil +} diff --git a/x/ibc/transfer/ibc_module.go b/x/ibc/transfer/ibc_module.go index 10d0f092c..1d5a4a6c6 100644 --- a/x/ibc/transfer/ibc_module.go +++ b/x/ibc/transfer/ibc_module.go @@ -2,8 +2,8 @@ package transfer import ( "github.com/cosmos/evm/x/ibc/transfer/keeper" - ibctransfer "github.com/cosmos/ibc-go/v8/modules/apps/transfer" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" + ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" + porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" ) var _ porttypes.IBCModule = IBCModule{} diff --git a/x/ibc/transfer/keeper/keeper.go b/x/ibc/transfer/keeper/keeper.go index b6136af8b..bec720685 100644 --- a/x/ibc/transfer/keeper/keeper.go +++ b/x/ibc/transfer/keeper/keeper.go @@ -1,13 +1,11 @@ package keeper import ( + corestore "cosmossdk.io/core/store" "github.com/cosmos/evm/x/ibc/transfer/types" - capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - - storetypes "cosmossdk.io/store/types" + "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" "github.com/cosmos/cosmos-sdk/codec" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -26,30 +24,28 @@ type Keeper struct { // NewKeeper creates a new IBC transfer Keeper instance func NewKeeper( cdc codec.BinaryCodec, - storeKey storetypes.StoreKey, + storeService corestore.KVStoreService, paramSpace paramtypes.Subspace, ics4Wrapper porttypes.ICS4Wrapper, channelKeeper transfertypes.ChannelKeeper, - portKeeper transfertypes.PortKeeper, - accountKeeper types.AccountKeeper, + msgRouter transfertypes.MessageRouter, + authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, - scopedKeeper capabilitykeeper.ScopedKeeper, erc20Keeper types.ERC20Keeper, authority string, ) Keeper { // create the original IBC transfer keeper for embedding transferKeeper := keeper.NewKeeper( - cdc, storeKey, paramSpace, - ics4Wrapper, channelKeeper, portKeeper, - accountKeeper, bankKeeper, scopedKeeper, - authority, + cdc, storeService, paramSpace, + ics4Wrapper, channelKeeper, msgRouter, + authKeeper, bankKeeper, authority, ) return Keeper{ Keeper: &transferKeeper, bankKeeper: bankKeeper, erc20Keeper: erc20Keeper, - accountKeeper: accountKeeper, + accountKeeper: authKeeper, } } diff --git a/x/ibc/transfer/keeper/keeper_test.go b/x/ibc/transfer/keeper/keeper_test.go index 732e41d38..e23bb0b0e 100644 --- a/x/ibc/transfer/keeper/keeper_test.go +++ b/x/ibc/transfer/keeper/keeper_test.go @@ -4,12 +4,14 @@ import ( "math/big" "testing" + "cosmossdk.io/math" + abcitypes "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" - abcitypes "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/evm/contracts" cmnfactory "github.com/cosmos/evm/testutil/integration/common/factory" "github.com/cosmos/evm/testutil/integration/os/factory" @@ -18,16 +20,12 @@ import ( "github.com/cosmos/evm/testutil/integration/os/network" erc20types "github.com/cosmos/evm/x/erc20/types" evm "github.com/cosmos/evm/x/vm/types" - 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" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" - - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v10/modules/core/exported" ) type KeeperTestSuite struct { @@ -52,31 +50,8 @@ func (suite *KeeperTestSuite) SetupTest() { keys := keyring.New(2) suite.otherDenom = "xmpl" - // Set custom genesis with capability record customGenesis := network.CustomGenesisState{} - capParams := capabilitytypes.DefaultGenesis() - capParams.Index = 2 - capParams.Owners = []capabilitytypes.GenesisOwners{ - { - Index: 1, - IndexOwners: capabilitytypes.CapabilityOwners{ - Owners: []capabilitytypes.Owner{ - { - Module: "ibc", - Name: "capabilities/ports/transfer/channels/channel-0", - }, - { - Module: "transfer", - Name: "capabilities/ports/transfer/channels/channel-0", - }, - }, - }, - }, - } - - customGenesis[capabilitytypes.ModuleName] = capParams - nw := network.NewUnitTestNetwork( network.WithPreFundedAccounts(keys.GetAllAccAddrs()...), network.WithOtherDenoms([]string{suite.otherDenom}), @@ -97,16 +72,24 @@ type MockChannelKeeper struct { mock.Mock } +//nolint:revive // allow unused parameters to indicate expected signature func (b *MockChannelKeeper) GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { args := b.Called(mock.Anything, mock.Anything, mock.Anything) return args.Get(0).(channeltypes.Channel), true } +func (b *MockChannelKeeper) HasChannel(ctx sdk.Context, srcPort, srcChan string) bool { + _ = b.Called(mock.Anything, mock.Anything, mock.Anything) + return true +} + +//nolint:revive // allow unused parameters to indicate expected signature func (b *MockChannelKeeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) { _ = b.Called(mock.Anything, mock.Anything, mock.Anything) return 1, true } +//nolint:revive // allow unused parameters to indicate expected signature func (b *MockChannelKeeper) GetAllChannelsWithPortPrefix(ctx sdk.Context, portPrefix string) []channeltypes.IdentifiedChannel { return []channeltypes.IdentifiedChannel{} } @@ -117,17 +100,18 @@ type MockICS4Wrapper struct { mock.Mock } -func (b *MockICS4Wrapper) WriteAcknowledgement(_ sdk.Context, _ *capabilitytypes.Capability, _ exported.PacketI, _ exported.Acknowledgement) error { +func (b *MockICS4Wrapper) WriteAcknowledgement(_ sdk.Context, _ exported.PacketI, _ exported.Acknowledgement) error { return nil } +//nolint:revive // allow unused parameters to indicate expected signature func (b *MockICS4Wrapper) GetAppVersion(ctx sdk.Context, portID string, channelID string) (string, bool) { return "", false } +//nolint:revive // allow unused parameters to indicate expected signature func (b *MockICS4Wrapper) SendPacket( ctx sdk.Context, - channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, diff --git a/x/ibc/transfer/keeper/msg_server.go b/x/ibc/transfer/keeper/msg_server.go index 9801a3f10..cae24b9b1 100644 --- a/x/ibc/transfer/keeper/msg_server.go +++ b/x/ibc/transfer/keeper/msg_server.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/go-metrics" erc20types "github.com/cosmos/evm/x/erc20/types" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" storetypes "cosmossdk.io/store/types" diff --git a/x/ibc/transfer/keeper/msg_server_test.go b/x/ibc/transfer/keeper/msg_server_test.go index 40724e606..2bcba06ab 100644 --- a/x/ibc/transfer/keeper/msg_server_test.go +++ b/x/ibc/transfer/keeper/msg_server_test.go @@ -3,21 +3,23 @@ package keeper_test import ( "fmt" + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" "github.com/stretchr/testify/mock" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + "github.com/cosmos/evm/testutil/integration/os/keyring" testutils "github.com/cosmos/evm/testutil/integration/os/utils" "github.com/cosmos/evm/x/ibc/transfer/keeper" evmtypes "github.com/cosmos/evm/x/vm/types" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - - "cosmossdk.io/math" - - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) func (suite *KeeperTestSuite) TestTransfer() { @@ -31,6 +33,8 @@ func (suite *KeeperTestSuite) TestTransfer() { mockChannelKeeper.On("GetChannel", mock.Anything, mock.Anything, mock.Anything).Return(channeltypes.Channel{Counterparty: channeltypes.NewCounterparty("transfer", "channel-1")}, true) mockICS4Wrapper.On("SendPacket", mock.Anything, mock.Anything, mock.Anything).Return(nil) authAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() + receiver := sdk.AccAddress([]byte("reciever")) + chan0 := "channel-0" testCases := []struct { name string @@ -40,7 +44,7 @@ func (suite *KeeperTestSuite) TestTransfer() { { "pass - no token pair", func() *types.MsgTransfer { - transferMsg := types.NewMsgTransfer("transfer", "channel-0", sdk.NewCoin(evmtypes.GetEVMCoinDenom(), math.NewInt(10)), sender.AccAddr.String(), "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, sdk.NewCoin(evmtypes.GetEVMCoinDenom(), math.NewInt(10)), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, true, @@ -52,7 +56,7 @@ func (suite *KeeperTestSuite) TestTransfer() { contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) suite.Require().NoError(err) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", sdk.NewCoin("erc20/"+contractAddr.String(), math.NewInt(10)), addr, "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, sdk.NewCoin("erc20/"+contractAddr.String(), math.NewInt(10)), addr, receiver.String(), timeoutHeight, 0, "") return transferMsg }, false, @@ -90,7 +94,7 @@ func (suite *KeeperTestSuite) TestTransfer() { suite.Require().NoError(err) coin := sdk.NewCoin(pair[0].Denom, amt) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", coin, sender.AccAddr.String(), "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, coin, sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, @@ -113,6 +117,8 @@ func (suite *KeeperTestSuite) TestTransfer() { _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) suite.Require().NoError(err) + // No conversion to IBC coin, so the balance is insufficient + params := suite.network.App.Erc20Keeper.GetParams(ctx) params.EnableErc20 = false err = testutils.UpdateERC20Params(testutils.UpdateParamsInput{ @@ -123,7 +129,8 @@ func (suite *KeeperTestSuite) TestTransfer() { }) suite.Require().NoError(err) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", sdk.NewCoin(pair[0].Denom, amt), sender.AccAddr.String(), "", timeoutHeight, 0, "") + coin := sdk.NewCoin(pair[0].Denom, amt) + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, coin, sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, @@ -133,7 +140,7 @@ func (suite *KeeperTestSuite) TestTransfer() { "no-op - pair not registered", func() *types.MsgTransfer { coin := sdk.NewCoin(suite.otherDenom, math.NewInt(10)) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", coin, sender.AccAddr.String(), "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, coin, sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, true, @@ -164,7 +171,7 @@ func (suite *KeeperTestSuite) TestTransfer() { suite.Require().NoError(err) coin := sdk.NewCoin(pair[0].Denom, math.NewInt(10)) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", coin, sender.AccAddr.String(), "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, coin, sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, @@ -189,7 +196,7 @@ func (suite *KeeperTestSuite) TestTransfer() { _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) suite.Require().NoError(err) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", sdk.NewCoin(pair.Denom, amt), sender.AccAddr.String(), "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, sdk.NewCoin(pair.Denom, amt), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, @@ -214,11 +221,10 @@ func (suite *KeeperTestSuite) TestTransfer() { suite.Require().NoError(err) // convert all to IBC coins - sender := suite.keyring.GetKey(0) err = suite.ConvertERC20(sender, contractAddr, amt) suite.Require().NoError(err) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", sdk.NewCoin(pair[0].Denom, amt), sender.AccAddr.String(), "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, sdk.NewCoin(pair[0].Denom, amt), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, @@ -237,7 +243,7 @@ func (suite *KeeperTestSuite) TestTransfer() { suite.Require().NoError(err) suite.Require().True(len(pair) == 1) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", sdk.NewCoin(pair[0].Denom, math.NewInt(10)), sender.AccAddr.String(), "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, sdk.NewCoin(pair[0].Denom, math.NewInt(10)), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, false, @@ -276,7 +282,7 @@ func (suite *KeeperTestSuite) TestTransfer() { suite.Require().Equal(pair.Denom, denom) suite.Require().NoError(err) - transferMsg := types.NewMsgTransfer("transfer", "channel-0", coin, senderAcc.String(), "", timeoutHeight, 0, "") + transferMsg := types.NewMsgTransfer(transfertypes.PortID, chan0, coin, senderAcc.String(), receiver.String(), timeoutHeight, 0, "") return transferMsg }, @@ -290,10 +296,14 @@ func (suite *KeeperTestSuite) TestTransfer() { ctx = suite.network.GetContext() suite.network.App.TransferKeeper = keeper.NewKeeper( - suite.network.App.AppCodec(), suite.network.App.GetKey(types.StoreKey), suite.network.App.GetSubspace(types.ModuleName), + suite.network.App.AppCodec(), + runtime.NewKVStoreService(suite.network.App.GetKey(types.StoreKey)), + suite.network.App.GetSubspace(types.ModuleName), &MockICS4Wrapper{}, // ICS4 Wrapper - mockChannelKeeper, suite.network.App.IBCKeeper.PortKeeper, - suite.network.App.AccountKeeper, suite.network.App.BankKeeper, suite.network.App.ScopedTransferKeeper, + mockChannelKeeper, + suite.network.App.MsgServiceRouter(), + suite.network.App.AccountKeeper, + suite.network.App.BankKeeper, suite.network.App.Erc20Keeper, // Add ERC20 Keeper for ERC20 transfers authAddr, ) diff --git a/x/ibc/transfer/module.go b/x/ibc/transfer/module.go index 79260d022..75cd489a1 100644 --- a/x/ibc/transfer/module.go +++ b/x/ibc/transfer/module.go @@ -3,10 +3,11 @@ package transfer import ( "fmt" + ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" + "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + "github.com/cosmos/evm/x/ibc/transfer/keeper" - ibctransfer "github.com/cosmos/ibc-go/v8/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" "github.com/cosmos/cosmos-sdk/types/module" ) @@ -43,9 +44,6 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterQueryServer(cfg.QueryServer(), am.keeper) m := ibctransferkeeper.NewMigrator(*am.keeper.Keeper) - if err := cfg.RegisterMigration(types.ModuleName, 1, m.MigrateTraces); err != nil { - panic(fmt.Sprintf("failed to migrate transfer app from version 1 to 2: %v", err)) - } if err := cfg.RegisterMigration(types.ModuleName, 2, m.MigrateTotalEscrowForDenom); err != nil { panic(fmt.Sprintf("failed to migrate transfer app from version 2 to 3: %v", err)) diff --git a/x/ibc/transfer/types/interfaces.go b/x/ibc/transfer/types/interfaces.go index df34d9af7..fa5d349f6 100644 --- a/x/ibc/transfer/types/interfaces.go +++ b/x/ibc/transfer/types/interfaces.go @@ -4,7 +4,7 @@ import ( "context" erc20types "github.com/cosmos/evm/x/erc20/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/ibc/transfer/v2/ibc_module.go b/x/ibc/transfer/v2/ibc_module.go new file mode 100644 index 000000000..64f35e133 --- /dev/null +++ b/x/ibc/transfer/v2/ibc_module.go @@ -0,0 +1,23 @@ +package v2 + +import ( + v2 "github.com/cosmos/ibc-go/v10/modules/apps/transfer/v2" + ibcapi "github.com/cosmos/ibc-go/v10/modules/core/api" + + "github.com/cosmos/evm/x/ibc/transfer/keeper" +) + +var _ ibcapi.IBCModule = IBCModule{} + +// IBCModule implements the ICS26 interface for transfer given the transfer keeper. +type IBCModule struct { + *v2.IBCModule +} + +// NewIBCModule creates a new IBCModule given the keeper +func NewIBCModule(k keeper.Keeper) IBCModule { + transferModule := v2.NewIBCModule(*k.Keeper) + return IBCModule{ + IBCModule: transferModule, + } +} diff --git a/x/vm/types/params.go b/x/vm/types/params.go index cade0ee01..890a47c3d 100644 --- a/x/vm/types/params.go +++ b/x/vm/types/params.go @@ -10,8 +10,8 @@ import ( "github.com/cosmos/evm/types" "github.com/cosmos/evm/x/vm/core/vm" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v10/modules/core/24-host" errorsmod "cosmossdk.io/errors" )