diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml index dee6db05edc..ba93985263b 100644 --- a/.github/workflows/contracts.yml +++ b/.github/workflows/contracts.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - contract: [{workdir: ./x/ibc-rate-limit/, output: bytecode/rate_limiter.wasm, build: artifacts/rate_limiter-x86_64.wasm, name: rate_limiter}] + contract: [{workdir: ./x/ibc-rate-limit/, output: bytecode/rate_limiter.wasm, build: artifacts/rate_limiter.wasm, name: rate_limiter}] steps: - name: Checkout sources @@ -45,30 +45,13 @@ jobs: cargo test if: env.GIT_DIFF - - name: Set latest cw-optimizoor version - run: > - echo "CW_OPTIMIZOOR_VERSION=0.8.0" >> $GITHUB_ENV - - - name: Cache cw-optimizoor - id: cache-cw-optimizoor - uses: actions/cache@v3 - env: - cache-name: cache-cw-optimizoor - with: - # cargo bin files are stored in `~/.cargo/bin/` on Linux/macOS - path: ~/.cargo/bin/cargo-cw-optimizoor - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ env.CW_OPTIMIZOOR_VERSION }} - - - if: ${{ steps.cache-cw-optimizoor.outputs.cache-hit != 'true' }} - name: Install cw-optimizoor - continue-on-error: true - run: > - cargo install cw-optimizoor - - name: Optimize working-directory: ${{ matrix.contract.workdir }} run: > - cargo cw-optimizoor + docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/workspace-optimizer:0.12.10 if: env.GIT_DIFF - name: 'Upload optimized contract artifact' @@ -79,6 +62,21 @@ jobs: retention-days: 1 if: env.GIT_DIFF + - name: 'Upload Cargo.lock artifact' + uses: actions/upload-artifact@v3 + with: + name: Cargo.lock + path: ${{ matrix.contract.workdir }}Cargo.lock + retention-days: 1 + if: env.GIT_DIFF + + - name: 'Upload Cargo.lock artifact' + uses: actions/upload-artifact@v3 + with: + name: Cargo.lock + path: ${{ matrix.contract.workdir }}Cargo.lock + retention-days: 1 + - name: Check Test Data working-directory: ${{ matrix.contract.workdir }} if: env.GIT_DIFF diff --git a/.gitignore b/.gitignore index 9298d99de92..fc3ab4bb663 100644 --- a/.gitignore +++ b/.gitignore @@ -216,10 +216,6 @@ target/ # Generated by rust-optimizer artifacts/ -# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries -# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -Cargo.lock - # These are backup files generated by rustfmt **/*.rs.bk # Don't commit lock files for test utils diff --git a/CHANGELOG.md b/CHANGELOG.md index 02d07de0017..f15597c5a7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,54 +42,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -### Misc Improvements - -* [#3677](https://github.com/osmosis-labs/osmosis/pull/3677) Add methods for cloning and mutative multiplication on osmomath.BigDec. -* [#3676](https://github.com/osmosis-labs/osmosis/pull/3676) implement `PowerInteger` function on `osmomath.BigDec` -* [#3678](https://github.com/osmosis-labs/osmosis/pull/3678) implement mutative `PowerIntegerMut` function on `osmomath.BigDec`. - -### Features - -### Bug fixes +* [#3731](https://github.com/osmosis-labs/osmosis/pull/3731) BigDec Power functions with decimal exponent. +* [#3817](https://github.com/osmosis-labs/osmosis/pull/3817) Move osmoassert from `app/apptesting/osmoassert` to `osmoutils/osmoassert`. -## v13.1.2 +### API breaks ### Bug fixes -* Fix state export -* Update swagger files for v13 - -## v13.1.1 - -* Add a check in the makefile for using go v1.18 - -## v13.1.0 - -* Correctly apply DragonBerry IBC patch - -### API breaks - -* [#3763](https://github.com/osmosis-labs/osmosis/pull/3763) Move binary search and error tolerance code from `osmoutils` into `osmomath` -* [#3817](https://github.com/osmosis-labs/osmosis/pull/3817) Move osmoassert from `app/apptesting/osmoassert` to `osmoutils/osmoassert`. -* [#3771](https://github.com/osmosis-labs/osmosis/pull/3771) Move osmomath into its own go.mod -* [#3827](https://github.com/osmosis-labs/osmosis/pull/3827) Move osmoutils into its own go.mod +### Misc Improvements +* [#3611](https://github.com/osmosis-labs/osmosis/pull/3611),[#3647](https://github.com/osmosis-labs/osmosis/pull/3647) Introduce osmocli, to automate thousands of lines of CLI boilerplate +* [#3634](https://github.com/osmosis-labs/osmosis/pull/3634) (Makefile) Ensure correct golang version in make build and make install. (Thank you @jhernandezb ) +* [#3712](https://github.com/osmosis-labs/osmosis/pull/3712) replace `osmomath.BigDec` `Power` with `PowerInteger` +* [#3711](https://github.com/osmosis-labs/osmosis/pull/3711) Use Dec instead of Int for additive `ErrTolerace` in `osmoutils`. +## v14.0.0 +### Features +* [#3609](https://github.com/osmosis-labs/osmosis/pull/3609) Add Downtime-detection module. +* [#2788](https://github.com/osmosis-labs/osmosis/pull/2788) Add logarithm base 2 implementation. +* [#3693](https://github.com/osmosis-labs/osmosis/pull/3693) Add `EstimateSwapExactAmountOut` query to stargate whitelist +* [#3852](https://github.com/osmosis-labs/osmosis/pull/3852) GeometricTwap and GeometricTwapToNow queries added to Stargate whitelist. +* [#3812](https://github.com/osmosis-labs/osmosis/pull/3812) Add geometric option to TWAP cli. +* IBC features + * [#3838](https://github.com/osmosis-labs/osmosis/pull/3838)Upgrade to IBC v4.2.0 +* Cosmwasm + * Upgrade to wasmd v0.30.x ### Bug fixes - * [#3608](https://github.com/osmosis-labs/osmosis/pull/3608) Make it possible to state export from any directory. ### Misc Improvements - -* [#3611](https://github.com/osmosis-labs/osmosis/pull/3611),[#3647](https://github.com/osmosis-labs/osmosis/pull/3647) Introduce osmocli, to automate thousands of lines of CLI boilerplate -* [#3634](https://github.com/osmosis-labs/osmosis/pull/3634) (Makefile) Ensure correct golang version in make build and make install. (Thank you @jhernandezb ) -<<<<<<< HEAD -* [#3712](https://github.com/osmosis-labs/osmosis/pull/3712) replace `osmomath.BigDec` `Power` with `PowerInteger` - -======= -* [#3711](https://github.com/osmosis-labs/osmosis/pull/3711) Use Dec instead of Int for additive `ErrTolerace` in `osmoutils`. ->>>>>>> 5ab7ebf6 (refactor(osmoutils): use Dec for additive tolerance instead of Int (#3711)) +* [#3678](https://github.com/osmosis-labs/osmosis/pull/3678) Add methods for cloning and mutative multiplication on osmomath.BigDec. +* [#3899](https://github.com/osmosis-labs/osmosis/pull/3899) Fixed osmoutils so its importable by chains that don't use the osmosis CosmosSDK fork +* [#3676](https://github.com/osmosis-labs/osmosis/pull/3676) Implement `PowerInteger` function on `osmomath.BigDec` +* [#3678](https://github.com/osmosis-labs/osmosis/pull/3678) Implement mutative `PowerIntegerMut` function on `osmomath.BigDec`. +* [#3708](https://github.com/osmosis-labs/osmosis/pull/3708) `Exp2` function to compute 2^decimal. +* [#3763](https://github.com/osmosis-labs/osmosis/pull/3763) Move binary search and error tolerance code from `osmoutils` into `osmomath` +* [#3771](https://github.com/osmosis-labs/osmosis/pull/3771) Move osmomath into its own go.mod +* [#3827](https://github.com/osmosis-labs/osmosis/pull/3827) Move osmoutils into its own go.mod ## v13.0.0 diff --git a/Makefile b/Makefile index 2792b5bceed..d60e5033a3a 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ SDK_PACK := $(shell go list -m github.com/cosmos/cosmos-sdk | sed 's/ /\@/g') GO_VERSION := $(shell cat go.mod | grep -E 'go [0-9].[0-9]+' | cut -d ' ' -f 2) DOCKER := $(shell which docker) BUILDDIR ?= $(CURDIR)/build -E2E_UPGRADE_VERSION := "v13" +E2E_UPGRADE_VERSION := "v14" GO_MAJOR_VERSION = $(shell go version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1) diff --git a/app/ante.go b/app/ante.go index 5d8964104c8..7d5338bb82c 100644 --- a/app/ante.go +++ b/app/ante.go @@ -3,8 +3,8 @@ package app import ( wasm "github.com/CosmWasm/wasmd/x/wasm" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - ibcante "github.com/cosmos/ibc-go/v3/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" + ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/app/app.go b/app/app.go index 2f7ce2ed6f7..82a58967eaa 100644 --- a/app/app.go +++ b/app/app.go @@ -6,8 +6,13 @@ import ( "net/http" "os" "path/filepath" + "reflect" "strings" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + + "github.com/osmosis-labs/osmosis/osmoutils" + "github.com/CosmWasm/wasmd/x/wasm" "github.com/gorilla/mux" "github.com/rakyll/statik/fs" @@ -45,6 +50,7 @@ import ( v11 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v11" v12 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v12" v13 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v13" + v14 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v14" v3 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v3" v4 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v4" v5 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v5" @@ -53,7 +59,7 @@ import ( v8 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v8" v9 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v9" _ "github.com/osmosis-labs/osmosis/v13/client/docs/statik" - ibc_hooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks" + ibc_hooks "github.com/osmosis-labs/osmosis/x/ibc-hooks" ) const appName = "OsmosisApp" @@ -91,7 +97,7 @@ var ( // _ sdksimapp.App = (*OsmosisApp)(nil) - Upgrades = []upgrades.Upgrade{v4.Upgrade, v5.Upgrade, v7.Upgrade, v9.Upgrade, v11.Upgrade, v12.Upgrade, v13.Upgrade} + Upgrades = []upgrades.Upgrade{v4.Upgrade, v5.Upgrade, v7.Upgrade, v9.Upgrade, v11.Upgrade, v12.Upgrade, v13.Upgrade, v14.Upgrade} Forks = []upgrades.Fork{v3.Fork, v6.Fork, v8.Fork, v10.Fork} ) @@ -143,6 +149,16 @@ func init() { DefaultNodeHome = filepath.Join(userHomeDir, ".osmosisd") } +// initReusablePackageInjections injects data available within osmosis into the reusable packages. +// This is done to ensure they can be built without depending on at compilation time and thus imported by other chains +// This should always be called before any other function to avoid inconsistent data +func initReusablePackageInjections() { + // Inject ClawbackVestingAccount account type into osmoutils + osmoutils.OsmoUtilsExtraAccountTypes = map[reflect.Type]struct{}{ + reflect.TypeOf(&vestingtypes.ClawbackVestingAccount{}): {}, + } +} + // NewOsmosisApp returns a reference to an initialized Osmosis. func NewOsmosisApp( logger log.Logger, @@ -157,6 +173,7 @@ func NewOsmosisApp( wasmOpts []wasm.Option, baseAppOptions ...func(*baseapp.BaseApp), ) *OsmosisApp { + initReusablePackageInjections() // This should run before anything else to make sure the variables are properly initialized encodingConfig := GetEncodingConfig() appCodec := encodingConfig.Marshaler cdc := encodingConfig.Amino diff --git a/app/apptesting/test_suite.go b/app/apptesting/test_suite.go index c52ebae6f13..2599879edcb 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -364,7 +364,7 @@ func (s *KeeperTestHelper) BuildTx( // StateNotAltered validates that app state is not altered. Fails if it is. func (s *KeeperTestHelper) StateNotAltered() { oldState := s.App.ExportState(s.Ctx) - s.Commit() + s.App.Commit() newState := s.App.ExportState(s.Ctx) s.Require().Equal(oldState, newState) } diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index a21aa893a41..b760b4e42a1 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -34,23 +34,27 @@ import ( upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - ibchooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks" + downtimedetector "github.com/osmosis-labs/osmosis/v13/x/downtime-detector" + downtimetypes "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" ibcratelimit "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit" ibcratelimittypes "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/types" - - icahost "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host" - icahostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" - icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" - ibcclienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" + ibchooks "github.com/osmosis-labs/osmosis/x/ibc-hooks" + ibchookskeeper "github.com/osmosis-labs/osmosis/x/ibc-hooks/keeper" + ibchookstypes "github.com/osmosis-labs/osmosis/x/ibc-hooks/types" + + icahost "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" + ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" // IBC Transfer: Defines the "transfer" IBC port - transfer "github.com/cosmos/ibc-go/v3/modules/apps/transfer" + transfer "github.com/cosmos/ibc-go/v4/modules/apps/transfer" _ "github.com/osmosis-labs/osmosis/v13/client/docs/statik" owasm "github.com/osmosis-labs/osmosis/v13/wasmbinding" @@ -99,8 +103,10 @@ type AppKeepers struct { AuthzKeeper *authzkeeper.Keeper StakingKeeper *stakingkeeper.Keeper DistrKeeper *distrkeeper.Keeper + DowntimeKeeper *downtimedetector.Keeper SlashingKeeper *slashingkeeper.Keeper IBCKeeper *ibckeeper.Keeper + IBCHooksKeeper *ibchookskeeper.Keeper ICAHostKeeper *icahostkeeper.Keeper TransferKeeper *ibctransferkeeper.Keeper EvidenceKeeper *evidencekeeper.Keeper @@ -188,6 +194,10 @@ func (appKeepers *AppKeepers) InitNormalKeepers( ) appKeepers.DistrKeeper = &distrKeeper + appKeepers.DowntimeKeeper = downtimedetector.NewKeeper( + appKeepers.keys[downtimetypes.StoreKey], + ) + slashingKeeper := slashingkeeper.NewKeeper( appCodec, appKeepers.keys[slashingtypes.StoreKey], @@ -206,7 +216,13 @@ func (appKeepers *AppKeepers) InitNormalKeepers( appKeepers.ScopedIBCKeeper, ) - appKeepers.WireICS20PreWasmKeeper(appCodec, bApp) + // Configure the hooks keeper + hooksKeeper := ibchookskeeper.NewKeeper( + appKeepers.keys[ibchookstypes.StoreKey], + ) + appKeepers.IBCHooksKeeper = &hooksKeeper + + appKeepers.WireICS20PreWasmKeeper(appCodec, bApp, appKeepers.IBCHooksKeeper) icaHostKeeper := icahostkeeper.NewKeeper( appCodec, appKeepers.keys[icahosttypes.StoreKey], @@ -349,7 +365,7 @@ func (appKeepers *AppKeepers) InitNormalKeepers( appKeepers.Ics20WasmHooks.ContractKeeper = appKeepers.ContractKeeper // wire up x/wasm to IBC - ibcRouter.AddRoute(wasm.ModuleName, wasm.NewIBCHandler(appKeepers.WasmKeeper, appKeepers.IBCKeeper.ChannelKeeper)) + ibcRouter.AddRoute(wasm.ModuleName, wasm.NewIBCHandler(appKeepers.WasmKeeper, appKeepers.IBCKeeper.ChannelKeeper, appKeepers.IBCKeeper.ChannelKeeper)) appKeepers.IBCKeeper.SetRouter(ibcRouter) // register the proposal types @@ -387,9 +403,10 @@ func (appKeepers *AppKeepers) InitNormalKeepers( // appkeepers.WasmHooks AND appKeepers.RateLimitingICS4Wrapper func (appKeepers *AppKeepers) WireICS20PreWasmKeeper( appCodec codec.Codec, - bApp *baseapp.BaseApp) { + bApp *baseapp.BaseApp, + hooksKeeper *ibchookskeeper.Keeper) { // Setup the ICS4Wrapper used by the hooks middleware - wasmHooks := ibchooks.NewWasmHooks(nil) // The contract keeper needs to be set later + wasmHooks := ibchooks.NewWasmHooks(hooksKeeper, nil) // The contract keeper needs to be set later appKeepers.Ics20WasmHooks = &wasmHooks appKeepers.HooksICS4Wrapper = ibchooks.NewICS4Middleware( appKeepers.IBCKeeper.ChannelKeeper, @@ -572,6 +589,7 @@ func KVStoreKeys() []string { stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, + downtimetypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, @@ -592,5 +610,6 @@ func KVStoreKeys() []string { superfluidtypes.StoreKey, wasm.StoreKey, tokenfactorytypes.StoreKey, + ibchookstypes.StoreKey, } } diff --git a/app/keepers/modules.go b/app/keepers/modules.go index de9643c0f20..18c4aa39bca 100644 --- a/app/keepers/modules.go +++ b/app/keepers/modules.go @@ -3,9 +3,9 @@ package keepers import ( "github.com/CosmWasm/wasmd/x/wasm" wasmclient "github.com/CosmWasm/wasmd/x/wasm/client" - transfer "github.com/cosmos/ibc-go/v3/modules/apps/transfer" - ibc "github.com/cosmos/ibc-go/v3/modules/core" - ibcclientclient "github.com/cosmos/ibc-go/v3/modules/core/02-client/client" + transfer "github.com/cosmos/ibc-go/v4/modules/apps/transfer" + ibc "github.com/cosmos/ibc-go/v4/modules/core" + ibcclientclient "github.com/cosmos/ibc-go/v4/modules/core/02-client/client" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" @@ -25,12 +25,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/upgrade" upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" - ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" _ "github.com/osmosis-labs/osmosis/v13/client/docs/statik" + downtimemodule "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/module" "github.com/osmosis-labs/osmosis/v13/x/epochs" "github.com/osmosis-labs/osmosis/v13/x/gamm" - ibc_hooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks" ibc_rate_limit "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit" "github.com/osmosis-labs/osmosis/v13/x/incentives" "github.com/osmosis-labs/osmosis/v13/x/lockup" @@ -42,6 +42,7 @@ import ( "github.com/osmosis-labs/osmosis/v13/x/tokenfactory" "github.com/osmosis-labs/osmosis/v13/x/twap/twapmodule" "github.com/osmosis-labs/osmosis/v13/x/txfees" + ibc_hooks "github.com/osmosis-labs/osmosis/x/ibc-hooks" ) // AppModuleBasics returns ModuleBasics for the module BasicManager. @@ -52,6 +53,7 @@ var AppModuleBasics = []module.AppModuleBasic{ capability.AppModuleBasic{}, staking.AppModuleBasic{}, mint.AppModuleBasic{}, + downtimemodule.AppModuleBasic{}, distr.AppModuleBasic{}, gov.NewAppModuleBasic( append( diff --git a/app/modules.go b/app/modules.go index ffe86946713..bbbc7bebc53 100644 --- a/app/modules.go +++ b/app/modules.go @@ -5,15 +5,20 @@ import ( "github.com/cosmos/cosmos-sdk/client" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v3/modules/core" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" - ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v4/modules/core" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" - ibc_hooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks" + ibchookstypes "github.com/osmosis-labs/osmosis/x/ibc-hooks/types" + + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + + downtimemodule "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/module" + downtimetypes "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" + ibc_hooks "github.com/osmosis-labs/osmosis/x/ibc-hooks" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" @@ -76,7 +81,7 @@ import ( var moduleAccountPermissions = map[string][]string{ authtypes.FeeCollectorName: nil, distrtypes.ModuleName: nil, - ibc_hooks.ModuleName: nil, + ibchookstypes.ModuleName: nil, icatypes.ModuleName: nil, minttypes.ModuleName: {authtypes.Minter, authtypes.Burner}, minttypes.DeveloperVestingModuleAcctName: nil, @@ -119,6 +124,7 @@ func appModules( mint.NewAppModule(appCodec, *app.MintKeeper, app.AccountKeeper, app.BankKeeper), slashing.NewAppModule(appCodec, *app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper), distr.NewAppModule(appCodec, *app.DistrKeeper, app.AccountKeeper, app.BankKeeper, *app.StakingKeeper), + downtimemodule.NewAppModule(*app.DowntimeKeeper), staking.NewAppModule(appCodec, *app.StakingKeeper, app.AccountKeeper, app.BankKeeper), upgrade.NewAppModule(*app.UpgradeKeeper), wasm.NewAppModule(appCodec, app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), @@ -167,6 +173,7 @@ func orderBeginBlockers(allModuleNames []string) []string { // IBChost came after staking, before superfluid. // TODO: Come back and delete this line after testing the base change. ord.Sequence(stakingtypes.ModuleName, ibchost.ModuleName, superfluidtypes.ModuleName) + // We leave downtime-detector un-constrained. // every remaining module's begin block is a no-op. return ord.TotalOrdering() } @@ -196,6 +203,7 @@ func OrderInitGenesis(allModuleNames []string) []string { authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, + downtimetypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName, @@ -222,7 +230,7 @@ func OrderInitGenesis(allModuleNames []string) []string { // wasm after ibc transfer wasm.ModuleName, // ibc_hooks after auth keeper - ibc_hooks.ModuleName, + ibchookstypes.ModuleName, } } diff --git a/app/upgrades/v12/upgrades.go b/app/upgrades/v12/upgrades.go index 37679efe698..45f8e20e8ec 100644 --- a/app/upgrades/v12/upgrades.go +++ b/app/upgrades/v12/upgrades.go @@ -8,8 +8,8 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" gammtypes "github.com/osmosis-labs/osmosis/v13/x/gamm/types" superfluidtypes "github.com/osmosis-labs/osmosis/v13/x/superfluid/types" diff --git a/app/upgrades/v13/upgrade_test.go b/app/upgrades/v13/upgrade_test.go index 137566eb6e7..492393e9865 100644 --- a/app/upgrades/v13/upgrade_test.go +++ b/app/upgrades/v13/upgrade_test.go @@ -4,6 +4,8 @@ import ( "fmt" "testing" + ibchookstypes "github.com/osmosis-labs/osmosis/x/ibc-hooks/types" + ibcratelimittypes "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/types" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -12,7 +14,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/osmosis-labs/osmosis/v13/app/apptesting" - ibc_hooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks" + ibc_hooks "github.com/osmosis-labs/osmosis/x/ibc-hooks" ) type UpgradeTestSuite struct { @@ -65,7 +67,7 @@ func (suite *UpgradeTestSuite) TestUpgrade() { upgradeStoreKey := suite.App.AppKeepers.GetKey(upgradetypes.StoreKey) store := suite.Ctx.KVStore(upgradeStoreKey) versionStore := prefix.NewStore(store, []byte{upgradetypes.VersionMapByte}) - versionStore.Delete([]byte(ibc_hooks.ModuleName)) + versionStore.Delete([]byte(ibchookstypes.ModuleName)) hasAcc := suite.App.AccountKeeper.HasAccount(suite.Ctx, ibc_hooks.WasmHookModuleAccountAddr) suite.Require().False(hasAcc) diff --git a/app/upgrades/v13/upgrades.go b/app/upgrades/v13/upgrades.go index 8fe71a4c518..8642f0d7025 100644 --- a/app/upgrades/v13/upgrades.go +++ b/app/upgrades/v13/upgrades.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" "github.com/osmosis-labs/osmosis/v13/app/keepers" "github.com/osmosis-labs/osmosis/v13/app/upgrades" diff --git a/app/upgrades/v14/constants.go b/app/upgrades/v14/constants.go new file mode 100644 index 00000000000..fe3f9cb3b87 --- /dev/null +++ b/app/upgrades/v14/constants.go @@ -0,0 +1,22 @@ +package v14 + +import ( + store "github.com/cosmos/cosmos-sdk/store/types" + + ibchookstypes "github.com/osmosis-labs/osmosis/x/ibc-hooks/types" + + "github.com/osmosis-labs/osmosis/v13/app/upgrades" + downtimetypes "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +// UpgradeName defines the on-chain upgrade name for the Osmosis v14 upgrade. +const UpgradeName = "v14" + +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateUpgradeHandler, + StoreUpgrades: store.StoreUpgrades{ + Added: []string{downtimetypes.StoreKey, ibchookstypes.StoreKey}, + Deleted: []string{}, + }, +} diff --git a/app/upgrades/v14/upgrades.go b/app/upgrades/v14/upgrades.go new file mode 100644 index 00000000000..81a72d8f4a9 --- /dev/null +++ b/app/upgrades/v14/upgrades.go @@ -0,0 +1,21 @@ +package v14 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + "github.com/osmosis-labs/osmosis/v13/app/keepers" + "github.com/osmosis-labs/osmosis/v13/app/upgrades" +) + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + bpm upgrades.BaseAppParamManager, + keepers *keepers.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + return mm.RunMigrations(ctx, configurator, vm) + } +} diff --git a/app/upgrades/v5/upgrades.go b/app/upgrades/v5/upgrades.go index 8fb22147740..cce699f08d8 100644 --- a/app/upgrades/v5/upgrades.go +++ b/app/upgrades/v5/upgrades.go @@ -1,7 +1,7 @@ package v5 import ( - ibcconnectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + ibcconnectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" // bech32ibctypes "github.com/osmosis-labs/bech32-ibc/x/bech32ibc/types" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/app/upgrades/v9/constants.go b/app/upgrades/v9/constants.go index 922fb7936a4..0228f3288cf 100644 --- a/app/upgrades/v9/constants.go +++ b/app/upgrades/v9/constants.go @@ -5,7 +5,7 @@ import ( store "github.com/cosmos/cosmos-sdk/store/types" - icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" tokenfactorytypes "github.com/osmosis-labs/osmosis/v13/x/tokenfactory/types" ) diff --git a/app/upgrades/v9/msg_filter_ante.go b/app/upgrades/v9/msg_filter_ante.go index b6035b35976..0d803d20b56 100644 --- a/app/upgrades/v9/msg_filter_ante.go +++ b/app/upgrades/v9/msg_filter_ante.go @@ -4,7 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - ibcchanneltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibcchanneltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // MsgFilterDecorator defines an AnteHandler decorator for the v9 upgrade that diff --git a/app/upgrades/v9/msg_filter_ante_test.go b/app/upgrades/v9/msg_filter_ante_test.go index 531887f1cc1..e66522c3873 100644 --- a/app/upgrades/v9/msg_filter_ante_test.go +++ b/app/upgrades/v9/msg_filter_ante_test.go @@ -7,7 +7,7 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/require" - ibcchanneltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibcchanneltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/osmosis-labs/osmosis/v13/app" v8 "github.com/osmosis-labs/osmosis/v13/app/upgrades/v8" diff --git a/app/upgrades/v9/upgrades.go b/app/upgrades/v9/upgrades.go index 6fe0dc15613..377012e3ee6 100644 --- a/app/upgrades/v9/upgrades.go +++ b/app/upgrades/v9/upgrades.go @@ -12,10 +12,10 @@ import ( gammtypes "github.com/osmosis-labs/osmosis/v13/x/gamm/types" - ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" - icacontrollertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" + icacontrollertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" "github.com/osmosis-labs/osmosis/v13/app/keepers" "github.com/osmosis-labs/osmosis/v13/app/upgrades" diff --git a/go.mod b/go.mod index 5c367df20bf..963de50825a 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,11 @@ module github.com/osmosis-labs/osmosis/v13 go 1.18 require ( - github.com/CosmWasm/wasmd v0.29.2-osmo-v13 + github.com/CosmWasm/wasmd v0.30.0 github.com/cosmos/cosmos-proto v1.0.0-alpha8 github.com/cosmos/cosmos-sdk v0.46.7 github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/ibc-go/v3 v3.4.0 + github.com/cosmos/ibc-go/v4 v4.2.0 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 @@ -18,7 +18,8 @@ require ( github.com/ory/dockertest/v3 v3.9.1 github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 github.com/osmosis-labs/osmosis/osmomath v0.0.2 - github.com/osmosis-labs/osmosis/osmoutils v0.0.1 + github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230101095308-fa4e70e17dbf + github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.0-20230101095308-fa4e70e17dbf github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 github.com/spf13/cast v1.5.0 @@ -28,6 +29,7 @@ require ( github.com/stretchr/testify v1.8.1 github.com/tendermint/tendermint v0.34.24 github.com/tendermint/tm-db v0.6.8-0.20220506192307-f628bb5dc95b + github.com/tidwall/btree v1.6.0 go.uber.org/multierr v1.9.0 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e @@ -40,10 +42,11 @@ require ( github.com/Abirdcfly/dupword v0.0.7 // indirect github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect github.com/alingse/asasalint v0.0.11 // indirect - github.com/cosmos/gogoproto v1.4.2 // indirect + github.com/cosmos/gogoproto v1.4.3 // indirect github.com/cosmos/iavl v0.19.4 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/google/btree v1.1.2 // indirect github.com/kkHAIKE/contextcheck v1.1.3 // indirect @@ -297,7 +300,8 @@ require ( replace ( // osmosis-patched wasmd - github.com/CosmWasm/wasmd => github.com/osmosis-labs/wasmd v0.29.2-osmo-v13 + // ToDo: replace the commit hash with v0.30.0-osmo-v14 once the version is tagged + github.com/CosmWasm/wasmd => github.com/osmosis-labs/wasmd v0.29.2-0.20221222131554-7c8ea36a6e30 // dragonberry github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 // Our cosmos-sdk branch is: https://github.com/osmosis-labs/cosmos-sdk, current branch: v13.x. Direct commit link: https://github.com/osmosis-labs/cosmos-sdk/commit/8757a61551aa1ea993c85a523e18094ab555b1d7 diff --git a/go.sum b/go.sum index cf321861ac9..331132926c0 100644 --- a/go.sum +++ b/go.sum @@ -221,15 +221,15 @@ github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpF github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= -github.com/cosmos/gogoproto v1.4.2 h1:UeGRcmFW41l0G0MiefWhkPEVEwvu78SZsHBvI78dAYw= -github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= +github.com/cosmos/gogoproto v1.4.3 h1:RP3yyVREh9snv/lsOvmsAPQt8f44LgL281X0IOIhhcI= +github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok= github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= -github.com/cosmos/ibc-go/v3 v3.4.0 h1:ha3cqEG36pqMWqA1D+kxDWBTZXpeFMd/aZIQF7I0xro= -github.com/cosmos/ibc-go/v3 v3.4.0/go.mod h1:VwB/vWu4ysT5DN2aF78d17LYmx3omSAdq6gpKvM7XRA= -github.com/cosmos/interchain-accounts v0.1.0 h1:QmuwNsf1Hxl3P5GSGt7Z+JeuHPiZw4Z34R/038P5T6s= +github.com/cosmos/ibc-go/v4 v4.2.0 h1:Fx/kKq/uvawrAxk6ZrQ6sEIgffLRU5Cs/AUnvpPBrHI= +github.com/cosmos/ibc-go/v4 v4.2.0/go.mod h1:57qWScDtfCx3FOMLYmBIKPbOLE6xiVhrgxHAQmbWYXM= +github.com/cosmos/interchain-accounts v0.2.4 h1:7UrroFQsCRSp17980mk6anx4YteveIJVkU+a0wlsHQI= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= @@ -277,6 +277,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M= github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.19+incompatible h1:lzEmjivyNHFHMNAFLXORMBXyGIhw/UP4DvJwvyKYq64= github.com/docker/docker v20.10.19+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= @@ -853,10 +855,12 @@ github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 h1:Ylmch github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3/go.mod h1:lV6KnqXYD/ayTe7310MHtM3I2q8Z6bBfMAi+bhwPYtI= github.com/osmosis-labs/osmosis/osmomath v0.0.2 h1:8vTobkYfoRTCJCie+jE7gzXvqUUfoPI4NSvTskoci50= github.com/osmosis-labs/osmosis/osmomath v0.0.2/go.mod h1:IpoXO7lvmfsBFfQzaqovs541hpqtrnM+GJSZDi/TZtc= -github.com/osmosis-labs/osmosis/osmoutils v0.0.1 h1:iANKdKa6cCgX1NJAldzfedwUPmeaKNrMu/atBCWtGg8= -github.com/osmosis-labs/osmosis/osmoutils v0.0.1/go.mod h1:T7CCZKYhKWASnv5mRE8u3m0gst3NZ/sU16Brjmv4UPw= -github.com/osmosis-labs/wasmd v0.29.2-osmo-v13 h1:HvxAks1ctB3nBx1cXqcmfA0g0BKe7Og77OA2j2rxaJk= -github.com/osmosis-labs/wasmd v0.29.2-osmo-v13/go.mod h1:UlLBU5vuHncwQUM9W8lw+2mEptEMFxxfVWupZ6sXtn4= +github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230101095308-fa4e70e17dbf h1:FZOlrTSaf/YWokt3+tSSZpcu6zu3dXLhsvhJWkHeBxU= +github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230101095308-fa4e70e17dbf/go.mod h1:T7CCZKYhKWASnv5mRE8u3m0gst3NZ/sU16Brjmv4UPw= +github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.0-20230101095308-fa4e70e17dbf h1:qcDUVsM6BNuGJ3dfGs3onOPzR0donLgXznqv60HRk+8= +github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.0-20230101095308-fa4e70e17dbf/go.mod h1:5zNisZDypMTW32EABSuWI/EacHC48590PpSO9QwFzCg= +github.com/osmosis-labs/wasmd v0.29.2-0.20221222131554-7c8ea36a6e30 h1:6uMi7HhPSwvKKU7j5NqljseFTEz4I7qHr+IPnnn42Ck= +github.com/osmosis-labs/wasmd v0.29.2-0.20221222131554-7c8ea36a6e30/go.mod h1:5fDYJyMXBq6u2iuHqqOTYiZ5NitIOeIW5k7qEXqbwJE= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -1095,6 +1099,8 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpR github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= +github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= +github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= diff --git a/go.work b/go.work index b4ddea0fe2f..d0323029630 100644 --- a/go.work +++ b/go.work @@ -2,4 +2,5 @@ go 1.18 use ./osmomath use ./osmoutils +use ./x/ibc-hooks use . diff --git a/go.work.sum b/go.work.sum index cc948aa93a8..160f89cd4bd 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,7 +1,546 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= +cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.8.0/go.mod h1:r3KB8cAdRIe8znzoPWLw8S6gpDVd9treohhn8b09424= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/adlio/schema v1.1.13/go.mod h1:L5Z7tw+7lRK1Fnpi/LT/ooCP1elkXn0krMWBQHUhEDE= +github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.3.11/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/bufbuild/buf v1.9.0/go.mod h1:1Q+rMHiMVcfgScEF/GOldxmu4o9TrQ2sQQh58K6MscE= +github.com/bufbuild/connect-go v1.0.0/go.mod h1:9iNvh/NOsfhNBUH5CtvXeVUskQO1xsrEviH7ZArwZ3I= +github.com/bufbuild/protocompile v0.1.0/go.mod h1:ix/MMMdsT3fzxfw91dvbfzKW3fRRnuPCP47kpAm5m/4= +github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0= +github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= +github.com/cosmos/interchain-accounts v0.2.4/go.mod h1:jeiJEb0zg609G0oCrCG0r6Guhb7YbA1uFiwww/1YgZE= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.8/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= +github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/informalsystems/tm-load-test v1.0.0/go.mod h1:WVaSKaQdfZK3v0C74EMzn7//+3aeCZF8wkIKBz2/M74= +github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= +github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= +github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= +github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= +github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= +github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= +github.com/jhump/protoreflect v1.13.1-0.20220928232736-101791cb1b4c/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/buildkit v0.10.4/go.mod h1:Yajz9vt1Zw5q9Pp4pdb3TCSUXJBIroIQGQ3TTs/sLug= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= +github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= +github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= +github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= +github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI= +github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI= +github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= +github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.8.0/go.mod h1:TmKwZAo97S4Fy4sfMH/HX/cQP5D+ijra2NyLpNNmttY= +github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/tendermint/tendermint v0.34.14/go.mod h1:FrwVm3TvsVicI9Z7FlucHV6Znfd5KBc/Lpp69cCwtk0= +github.com/tendermint/tendermint v0.34.21/go.mod h1:XDvfg6U7grcFTDx7VkzxnhazQ/bspGJAn4DZ6DcLLjQ= +github.com/tendermint/tendermint v0.34.23/go.mod h1:rXVrl4OYzmIa1I91av3iLv2HS0fGSiucyW9J4aMTpKI= +github.com/tendermint/tm-db v0.6.4/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw= +github.com/tendermint/tm-db v0.6.6/go.mod h1:wP8d49A85B7/erz/r4YbKssKw6ylsO/hKtFk7E1aWZI= +github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/vektra/mockery/v2 v2.14.0/go.mod h1:bnD1T8tExSgPD1ripLkDbr60JA9VtQeu12P3wgLZd7M= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3/go.mod h1:Dts42MGkzZne2yCru741+bFiTMWkIj/LLRizad7b9tw= +go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk= +go.opentelemetry.io/otel/metric v0.32.3/go.mod h1:pgiGmKohxHyTPHGOff+vrtIH39/R9fiO/WoenUQ3kcc= +go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220726230323-06994584191e/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/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-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/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-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220727055044-e65921a090b8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211101144312-62acf1d99145/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +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= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/osmomath/exp2.go b/osmomath/exp2.go new file mode 100644 index 00000000000..39b2333ebd3 --- /dev/null +++ b/osmomath/exp2.go @@ -0,0 +1,101 @@ +package osmomath + +import "fmt" + +var ( + // Truncated at precision end. + // See scripts/approximations/main.py exponent_approximation_choice function for details. + numeratorCoefficients13Param = []BigDec{ + MustNewDecFromStr("1.000000000000000000000044212244679434"), + MustNewDecFromStr("0.352032455817400196452603772766844426"), + MustNewDecFromStr("0.056507868883666405413116800969512484"), + MustNewDecFromStr("0.005343900728213034434757419480319916"), + MustNewDecFromStr("0.000317708814342353603087543715930732"), + MustNewDecFromStr("0.000011429747507407623028722262874632"), + MustNewDecFromStr("0.000000198381965651614980168744540366"), + } + + // Rounded up at precision end. + // See scripts/approximations/main.py exponent_approximation_choice function for details. + denominatorCoefficients13Param = []BigDec{ + OneDec(), + MustNewDecFromStr("0.341114724742545112949699755780593311").Neg(), + MustNewDecFromStr("0.052724071627342653404436933178482287"), + MustNewDecFromStr("0.004760950735524957576233524801866342").Neg(), + MustNewDecFromStr("0.000267168475410566529819971616894193"), + MustNewDecFromStr("0.000008923715368802211181557353097439").Neg(), + MustNewDecFromStr("0.000000140277233177373698516010555916"), + } + + // maxSupportedExponent = 2^10. The value is chosen by benchmarking + // when the underlying internal functions overflow. + // If needed in the future, Exp2 can be reimplemented to allow for greater exponents. + maxSupportedExponent = MustNewDecFromStr("2").PowerInteger(9) +) + +// Exp2 takes 2 to the power of a given non-negative decimal exponent +// and returns the result. +// The computation is performed by using th following property: +// 2^decimal_exp = 2^{integer_exp + fractional_exp} = 2^integer_exp * 2^fractional_exp +// The max supported exponent is defined by the global maxSupportedExponent. +// If a greater exponent is given, the function panics. +// Panics if the exponent is negative. +// The answer is correct up to a factor of 10^-18. +// Meaning, result = result * k for k in [1 - 10^(-18), 1 + 10^(-18)] +// Note: our Python script plots show accuracy up to a factor of 10^22. +// However, in Go tests we only test up to 10^18. Therefore, this is the guarantee. +func Exp2(exponent BigDec) BigDec { + if exponent.Abs().GT(maxSupportedExponent) { + panic(fmt.Sprintf("integer exponent %s is too large, max (%s)", exponent, maxSupportedExponent)) + } + if exponent.IsNegative() { + panic(fmt.Sprintf("negative exponent %s is not supported", exponent)) + } + + integerExponent := exponent.TruncateDec() + + fractionalExponent := exponent.Sub(integerExponent) + fractionalResult := exp2ChebyshevRationalApprox(fractionalExponent) + + // Left bit shift is equivalent to multiplying by 2^integerExponent. + fractionalResult.i = fractionalResult.i.Lsh(fractionalResult.i, uint(integerExponent.TruncateInt().Uint64())) + + return fractionalResult +} + +// exp2ChebyshevRationalApprox takes 2 to the power of a given decimal exponent. +// The result is approximated by a 13 parameter Chebyshev rational approximation. +// f(x) = h(x) / p(x) (7, 7) terms. We set the first term of p(x) to 1. +// As a result, this ends up being 7 + 6 = 13 parameters. +// The numerator coefficients are truncated at precision end. The denominator +// coefficients are rounded up at precision end. +// See scripts/approximations/README.md for details of the scripts used +// to compute the coefficients. +// CONTRACT: exponent must be in the range [0, 1], panics if not. +// The answer is correct up to a factor of 10^-18. +// Meaning, result = result * k for k in [1 - 10^(-18), 1 + 10^(-18)] +// Note: our Python script plots show accuracy up to a factor of 10^22. +// However, in Go tests we only test up to 10^18. Therefore, this is the guarantee. +func exp2ChebyshevRationalApprox(x BigDec) BigDec { + if x.LT(ZeroDec()) || x.GT(OneDec()) { + panic(fmt.Sprintf("exponent must be in the range [0, 1], got %s", x)) + } + if x.IsZero() { + return OneDec() + } + if x.Equal(OneDec()) { + return twoBigDec + } + + h_x := numeratorCoefficients13Param[0].Clone() + p_x := denominatorCoefficients13Param[0].Clone() + x_exp_i := OneDec() + for i := 1; i < len(numeratorCoefficients13Param); i++ { + x_exp_i.MulMut(x) + + h_x.AddMut(numeratorCoefficients13Param[i].Mul(x_exp_i)) + p_x.AddMut(denominatorCoefficients13Param[i].Mul(x_exp_i)) + } + + return h_x.QuoMut(p_x) +} diff --git a/osmomath/exp2_test.go b/osmomath/exp2_test.go new file mode 100644 index 00000000000..0d62bcb3a73 --- /dev/null +++ b/osmomath/exp2_test.go @@ -0,0 +1,300 @@ +package osmomath_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + + "github.com/osmosis-labs/osmosis/osmomath" +) + +var ( + // minDecTolerance minimum tolerance for sdk.Dec, given its precision of 18. + minDecTolerance = sdk.MustNewDecFromStr("0.000000000000000001") +) + +func TestExp2ChebyshevRationalApprox(t *testing.T) { + // These values are used to test the approximated results close + // to 0 and 1 boundaries. + // With other types of approximations, there is a high likelyhood + // of larger errors clsoer to the boundaries. This is known as Runge's phenomenon. + // https://en.wikipedia.org/wiki/Runge%27s_phenomenon + // + // Chebyshev approximation should be able to handle this better. + // Tests at the boundaries help to validate there is no Runge's phenomenon. + smallValue := osmomath.MustNewDecFromStr("0.00001") + smallerValue := osmomath.MustNewDecFromStr("0.00000000000000000001") + + tests := map[string]struct { + exponent osmomath.BigDec + expectedResult osmomath.BigDec + errTolerance osmomath.ErrTolerance + expectPanic bool + }{ + "exp2(0.5)": { + exponent: osmomath.MustNewDecFromStr("0.5"), + // https://www.wolframalpha.com/input?i=2%5E0.5+37+digits + expectedResult: osmomath.MustNewDecFromStr("1.414213562373095048801688724209698079"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: minDecTolerance, + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundDown, + }, + }, + "exp2(0)": { + exponent: osmomath.ZeroDec(), + expectedResult: osmomath.OneDec(), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.ZeroDec(), + MultiplicativeTolerance: sdk.ZeroDec(), + RoundingDir: osmomath.RoundDown, + }, + }, + "exp2(1)": { + exponent: osmomath.OneDec(), + expectedResult: osmomath.MustNewDecFromStr("2"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.ZeroDec(), + MultiplicativeTolerance: sdk.ZeroDec(), + RoundingDir: osmomath.RoundDown, + }, + }, + "exp2(0.00001)": { + exponent: smallValue, + // https://www.wolframalpha.com/input?i=2%5E0.00001+37+digits + expectedResult: osmomath.MustNewDecFromStr("1.000006931495828305653209089800561681"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: minDecTolerance, + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(0.99999)": { + exponent: osmomath.OneDec().Sub(smallValue), + // https://www.wolframalpha.com/input?i=2%5E0.99999+37+digits + expectedResult: osmomath.MustNewDecFromStr("1.999986137104433991477606830496602898"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("0.00000000000000007"), + MultiplicativeTolerance: minDecTolerance.Mul(sdk.NewDec(100)), + RoundingDir: osmomath.RoundDown, + }, + }, + "exp2(0.99999...)": { + exponent: osmomath.OneDec().Sub(smallerValue), + // https://www.wolframalpha.com/input?i=2%5E%281+-+0.00000000000000000001%29+37+digits + expectedResult: osmomath.MustNewDecFromStr("1.999999999999999999986137056388801094"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: minDecTolerance, + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundDown, + }, + }, + "exp2(0.0000...1)": { + exponent: osmomath.ZeroDec().Add(smallerValue), + // https://www.wolframalpha.com/input?i=2%5E0.00000000000000000001+37+digits + expectedResult: osmomath.MustNewDecFromStr("1.000000000000000000006931471805599453"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: minDecTolerance, + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(0.3334567)": { + exponent: osmomath.MustNewDecFromStr("0.3334567"), + // https://www.wolframalpha.com/input?i=2%5E0.3334567+37+digits + expectedResult: osmomath.MustNewDecFromStr("1.260028791934303989065848870753742298"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("0.00000000000000007"), + MultiplicativeTolerance: minDecTolerance.Mul(sdk.NewDec(10)), + RoundingDir: osmomath.RoundDown, + }, + }, + "exp2(0.84864288)": { + exponent: osmomath.MustNewDecFromStr("0.84864288"), + // https://www.wolframalpha.com/input?i=2%5E0.84864288+37+digits + expectedResult: osmomath.MustNewDecFromStr("1.800806138872630518880998772777747572"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("0.00000000000000002"), + MultiplicativeTolerance: minDecTolerance.Mul(sdk.NewDec(10)), + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(0.999999999999999999999999999999999956)": { + exponent: osmomath.MustNewDecFromStr("0.999999999999999999999999999999999956"), + // https://www.wolframalpha.com/input?i=2%5E0.999999999999999999999999999999999956+37+digits + expectedResult: osmomath.MustNewDecFromStr("1.999999999999999999999999999999999939"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: minDecTolerance, + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundDown, + }, + }, + // out of bounds. + "exponent < 0 - panic": { + exponent: osmomath.ZeroDec().Sub(smallValue), + expectPanic: true, + }, + "exponent > 1 - panic": { + exponent: osmomath.OneDec().Add(smallValue), + expectPanic: true, + }, + } + + for name, tc := range tests { + tc := tc + t.Run(name, func(t *testing.T) { + osmomath.ConditionalPanic(t, tc.expectPanic, func() { + // System under test. + result := osmomath.Exp2ChebyshevRationalApprox(tc.exponent) + + // Reuse the same test cases for exp2 that is a wrapper around Exp2ChebyshevRationalApprox. + // This is done to reduce boilerplate from duplicating test cases. + resultExp2 := osmomath.Exp2(tc.exponent) + require.Equal(t, result, resultExp2) + + require.Equal(t, 0, tc.errTolerance.CompareBigDec(tc.expectedResult, result)) + }) + }) + } +} + +func TestExp2(t *testing.T) { + tests := map[string]struct { + exponent osmomath.BigDec + expectedResult osmomath.BigDec + errTolerance osmomath.ErrTolerance + expectPanic bool + }{ + "exp2(28.5)": { + exponent: osmomath.MustNewDecFromStr("28.5"), + // https://www.wolframalpha.com/input?i=2%5E%2828.5%29+45+digits + expectedResult: osmomath.MustNewDecFromStr("379625062.497006211556423566253288543343173698"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: minDecTolerance, + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(63.84864288)": { + exponent: osmomath.MustNewDecFromStr("63.84864288"), + // https://www.wolframalpha.com/input?i=2%5E%2863.84864288%29+56+digits + expectedResult: osmomath.MustNewDecFromStr("16609504985074238416.013387053450559984846024066925604094"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("0.00042"), + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(64.5)": { + exponent: osmomath.MustNewDecFromStr("64.5"), + // https://www.wolframalpha.com/input?i=2%5E%2864.5%29+56+digits + expectedResult: osmomath.MustNewDecFromStr("26087635650665564424.699143612505016737766552579185717157"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("0.000000000000000008"), + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(80.5)": { + exponent: osmomath.MustNewDecFromStr("80.5"), + // https://www.wolframalpha.com/input?i=2%5E%2880.5%29+61+digits + expectedResult: osmomath.MustNewDecFromStr("1709679290002018430137083.075789128776926268789829515159631571"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("0.0000000000006"), + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(100.5)": { + exponent: osmomath.MustNewDecFromStr("100.5"), + // https://www.wolframalpha.com/input?i=2%5E%28100.5%29+67+digits + expectedResult: osmomath.MustNewDecFromStr("1792728671193156477399422023278.661496394239222564273688025833797661"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("0.0000006"), + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(128.5)": { + exponent: osmomath.MustNewDecFromStr("128.5"), + // https://www.wolframalpha.com/input?i=2%5E%28128.5%29+75+digits + expectedResult: osmomath.MustNewDecFromStr("481231938336009023090067544955250113854.229961482126296754016435255422777776"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("146.5"), + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "exp2(127.999999999999999999999999999999999999)": { + exponent: osmomath.MustNewDecFromStr("127.999999999999999999999999999999999999"), + // https://www.wolframalpha.com/input?i=2%5E%28127.999999999999999999999999999999999999%29+75+digits + expectedResult: osmomath.MustNewDecFromStr("340282366920938463463374607431768211220.134236774486705862055857235845515682"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("15044647266406936"), + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundDown, + }, + }, + "exp2(127.84864288)": { + exponent: osmomath.MustNewDecFromStr("127.84864288"), + // https://www.wolframalpha.com/input?i=2%5E%28127.84864288%29+75+digits + expectedResult: osmomath.MustNewDecFromStr("306391287650667462068703337664945630660.398687487527674545778353588077174571"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: sdk.MustNewDecFromStr("7707157415597963"), + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundUnconstrained, + }, + }, + "panic, too large - positive": { + exponent: osmomath.MaxSupportedExponent.Add(osmomath.OneDec()), + expectPanic: true, + }, + "panic - negative exponent": { + exponent: osmomath.OneDec().Neg(), + expectPanic: true, + }, + "at exponent boundary - positive": { + exponent: osmomath.MaxSupportedExponent, + // https://www.wolframalpha.com/input?i=2%5E%282%5E9%29 + expectedResult: osmomath.MustNewDecFromStr("13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096"), + + errTolerance: osmomath.ErrTolerance{ + AdditiveTolerance: minDecTolerance, + MultiplicativeTolerance: minDecTolerance, + RoundingDir: osmomath.RoundDown, + }, + }, + } + + for name, tc := range tests { + tc := tc + t.Run(name, func(t *testing.T) { + osmomath.ConditionalPanic(t, tc.expectPanic, func() { + + // System under test. + result := osmomath.Exp2(tc.exponent) + + require.Equal(t, 0, tc.errTolerance.CompareBigDec(tc.expectedResult, result)) + }) + }) + } +} diff --git a/osmomath/export_test.go b/osmomath/export_test.go index bdb6c71f959..d723e106095 100644 --- a/osmomath/export_test.go +++ b/osmomath/export_test.go @@ -8,8 +8,9 @@ import ( ) var ( - EulersNumber = eulersNumber - TwoBigDec = twoBigDec + MaxSupportedExponent = maxSupportedExponent + EulersNumber = eulersNumber + TwoBigDec = twoBigDec ) // 2^128 - 1, needs to be the same as gammtypes.MaxSpotPrice @@ -28,3 +29,7 @@ func ConditionalPanic(t *testing.T, expectPanic bool, sut func()) { } require.NotPanics(t, sut) } + +func Exp2ChebyshevRationalApprox(exponent BigDec) BigDec { + return exp2ChebyshevRationalApprox(exponent) +} diff --git a/osmomath/sigfig_round_test.go b/osmomath/sigfig_round_test.go index 71cbb96ac6f..eca712b0096 100644 --- a/osmomath/sigfig_round_test.go +++ b/osmomath/sigfig_round_test.go @@ -70,6 +70,13 @@ func TestSigFigRound(t *testing.T) { tenToSigFig: sdk.NewInt(100), expectedResult: sdk.MustNewDecFromStr("0.087"), }, + + { + name: "minimum decimal is still kept", + decimal: sdk.NewDecWithPrec(1, 18), + tenToSigFig: sdk.NewInt(10), + expectedResult: sdk.NewDecWithPrec(1, 18), + }, } for i, tc := range testCases { diff --git a/osmoutils/ibc.go b/osmoutils/ibc.go index 67f5864463c..84f08b85bc9 100644 --- a/osmoutils/ibc.go +++ b/osmoutils/ibc.go @@ -3,11 +3,25 @@ package osmoutils import ( "encoding/json" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) +// NewStringErrorAcknowledgement returns a new instance of Acknowledgement using an Acknowledgement_Error +// type in the Response field. These errors differ from the IBC errors in that we use custom error strings. +// NOTE: Acknowledgements are written into state and thus, changes made to error strings included in packet acknowledgements +// risk an app hash divergence when nodes in a network are running different patch versions of software. +func NewStringErrorAcknowledgement(err string) channeltypes.Acknowledgement { + // ToDo: Do we want to do this or do we want to use the IBC errors and emit the string? + + return channeltypes.Acknowledgement{ + Response: &channeltypes.Acknowledgement_Error{ + Error: err, + }, + } +} + // MustExtractDenomFromPacketOnRecv takes a packet with a valid ICS20 token data in the Data field and returns the // denom as represented in the local chain. // If the data cannot be unmarshalled this function will panic diff --git a/osmoutils/module_account.go b/osmoutils/module_account.go index 20c57704cb5..4b87582bd6f 100644 --- a/osmoutils/module_account.go +++ b/osmoutils/module_account.go @@ -10,6 +10,11 @@ import ( vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" ) +// OsmoUtilsExtraAccountTypes is a map of extra account types that can be overridden. +// This is defined as a global variable so it can be modified in the chain's app.go and used here without +// having to import the chain. Specifically, this is used for compatibility with Osmosis' Cosmos SDK fork +var OsmoUtilsExtraAccountTypes map[reflect.Type]struct{} + type AccountKeeper interface { NewAccount(sdk.Context, authtypes.AccountI) authtypes.AccountI @@ -48,8 +53,11 @@ func CanCreateModuleAccountAtAddr(ctx sdk.Context, ak AccountKeeper, addr sdk.Ac reflect.TypeOf(&vestingtypes.BaseVestingAccount{}): {}, reflect.TypeOf(&vestingtypes.PeriodicVestingAccount{}): {}, reflect.TypeOf(&vestingtypes.PermanentLockedAccount{}): {}, - reflect.TypeOf(&vestingtypes.ClawbackVestingAccount{}): {}, } + for extraAccountType := range OsmoUtilsExtraAccountTypes { + overrideAccountTypes[extraAccountType] = struct{}{} + } + if _, clear := overrideAccountTypes[reflect.TypeOf(existingAcct)]; clear { return nil } diff --git a/osmoutils/osmocli/parsers.go b/osmoutils/osmocli/parsers.go index e8da7f14c57..1b051c6ac7c 100644 --- a/osmoutils/osmocli/parsers.go +++ b/osmoutils/osmocli/parsers.go @@ -166,6 +166,14 @@ func parseFieldFromDirectlySetFlag(fVal reflect.Value, fType reflect.StructField } func ParseFieldFromArg(fVal reflect.Value, fType reflect.StructField, arg string) error { + // We cant pass in a negative number due to the way pflags works... + // This is an (extraordinarily ridiculous) workaround that checks if a negative int is encapsulated in square brackets, + // and if so, trims the square brackets + if strings.HasPrefix(arg, "[") && strings.HasSuffix(arg, "]") && arg[1] == '-' { + arg = strings.TrimPrefix(arg, "[") + arg = strings.TrimSuffix(arg, "]") + } + switch fType.Type.Kind() { // SetUint allows anyof type u8, u16, u32, u64, and uint case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: diff --git a/osmoutils/sumtree/tree.pb.go b/osmoutils/sumtree/tree.pb.go index df4790f1cfa..4f007610f28 100644 --- a/osmoutils/sumtree/tree.pb.go +++ b/osmoutils/sumtree/tree.pb.go @@ -169,26 +169,26 @@ func init() { } var fileDescriptor_31a1c5f55b935f78 = []byte{ - // 304 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0x41, 0x4b, 0xc3, 0x30, - 0x1c, 0xc5, 0x1b, 0xdd, 0x44, 0xe3, 0x4e, 0x65, 0xc2, 0x18, 0x92, 0x95, 0x1e, 0xa4, 0x97, 0x25, - 0xd6, 0x21, 0xec, 0x28, 0xf3, 0x24, 0x88, 0x42, 0x8f, 0xde, 0xd2, 0x34, 0xeb, 0x82, 0x6d, 0x33, - 0x9b, 0x74, 0xe8, 0xb7, 0xf0, 0x63, 0xed, 0xb8, 0xa3, 0x78, 0x18, 0xd2, 0x7e, 0x11, 0x69, 0x5a, - 0xa7, 0x82, 0xe0, 0x29, 0xff, 0x97, 0xfc, 0x78, 0xef, 0x91, 0x3f, 0x74, 0xa5, 0x4a, 0xa5, 0x12, - 0x8a, 0xa8, 0x22, 0xd5, 0x39, 0xe7, 0x64, 0xe5, 0x87, 0x5c, 0x53, 0x9f, 0xd4, 0x02, 0x2f, 0x73, - 0xa9, 0xa5, 0x7d, 0xd2, 0x32, 0x58, 0x69, 0x99, 0x73, 0xdc, 0x12, 0xc3, 0x7e, 0x2c, 0x63, 0x69, - 0x08, 0x52, 0x4f, 0x0d, 0x3c, 0x44, 0xcc, 0xd0, 0x24, 0xa4, 0xea, 0xdb, 0x8c, 0x49, 0x91, 0x35, - 0xef, 0xee, 0x15, 0xec, 0xdc, 0xc9, 0x88, 0xdb, 0x53, 0x78, 0xc8, 0x16, 0x22, 0x89, 0x72, 0x9e, - 0x0d, 0x80, 0xb3, 0xef, 0x1d, 0x5f, 0x9c, 0xe2, 0x3f, 0x73, 0xf0, 0x75, 0x8d, 0x05, 0x3b, 0xda, - 0x7d, 0x82, 0x5d, 0x73, 0x65, 0xf7, 0x61, 0x57, 0x64, 0x11, 0x7f, 0x1e, 0x00, 0x07, 0x78, 0xbd, - 0xa0, 0x11, 0x76, 0x00, 0x7b, 0x94, 0xb1, 0x22, 0x2d, 0x12, 0xaa, 0x85, 0xcc, 0x06, 0x7b, 0x0e, - 0xf0, 0x8e, 0x66, 0x78, 0xbd, 0x1d, 0x59, 0xef, 0xdb, 0xd1, 0x59, 0x2c, 0xf4, 0xa2, 0x08, 0x31, - 0x93, 0x29, 0x69, 0x9b, 0x36, 0xc7, 0x58, 0x45, 0x8f, 0x44, 0xbf, 0x2c, 0xb9, 0xc2, 0x37, 0x99, - 0x0e, 0x7e, 0x79, 0xb8, 0x53, 0xd8, 0xb9, 0xe5, 0x74, 0x6e, 0x9f, 0xc3, 0x4e, 0xc2, 0xe9, 0xdc, - 0x04, 0xfe, 0x57, 0xd8, 0x90, 0xb3, 0xfb, 0x75, 0x89, 0xc0, 0xa6, 0x44, 0xe0, 0xa3, 0x44, 0xe0, - 0xb5, 0x42, 0xd6, 0xa6, 0x42, 0xd6, 0x5b, 0x85, 0xac, 0x87, 0xcb, 0x1f, 0x4d, 0x5a, 0x9f, 0x71, - 0x42, 0x43, 0xf5, 0x25, 0xc8, 0xca, 0x9f, 0x98, 0xb9, 0xd0, 0x22, 0xd9, 0xed, 0x27, 0x3c, 0x30, - 0xdf, 0x38, 0xf9, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x09, 0x06, 0x72, 0xc1, 0xb9, 0x01, 0x00, 0x00, + // 302 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0xb1, 0x4e, 0xeb, 0x30, + 0x18, 0x85, 0xe3, 0x7b, 0x53, 0x04, 0xa6, 0x53, 0x54, 0xa4, 0xa8, 0x42, 0x6e, 0x94, 0x01, 0x65, + 0xa9, 0x4d, 0x60, 0xe9, 0x88, 0xca, 0x84, 0x40, 0x0c, 0x19, 0xd9, 0x1c, 0xc7, 0x4d, 0x2d, 0x92, + 0xb8, 0xc4, 0x0e, 0x82, 0xb7, 0xe0, 0xb1, 0x3a, 0x76, 0x44, 0x0c, 0x15, 0x4a, 0x5e, 0x04, 0xc5, + 0x09, 0x05, 0x24, 0x24, 0xa6, 0xdf, 0xc7, 0xfe, 0x74, 0xce, 0x91, 0x7f, 0xe8, 0x4b, 0x95, 0x4b, + 0x25, 0x14, 0x51, 0x55, 0xae, 0x4b, 0xce, 0xc9, 0x63, 0x18, 0x73, 0x4d, 0x43, 0xd2, 0x0a, 0xbc, + 0x2a, 0xa5, 0x96, 0xce, 0x51, 0xcf, 0x60, 0xa5, 0x65, 0xc9, 0x71, 0x4f, 0x8c, 0x47, 0xa9, 0x4c, + 0xa5, 0x21, 0x48, 0x7b, 0xea, 0xe0, 0x31, 0x62, 0x86, 0x26, 0x31, 0x55, 0x5f, 0x66, 0x4c, 0x8a, + 0xa2, 0x7b, 0xf7, 0x2f, 0xa0, 0x7d, 0x2b, 0x13, 0xee, 0xcc, 0xe0, 0x3e, 0x5b, 0x8a, 0x2c, 0x29, + 0x79, 0xe1, 0x02, 0xef, 0x7f, 0x70, 0x78, 0x76, 0x8c, 0x7f, 0xcd, 0xc1, 0x97, 0x2d, 0x16, 0xed, + 0x68, 0xff, 0x01, 0x0e, 0xcc, 0x95, 0x33, 0x82, 0x03, 0x51, 0x24, 0xfc, 0xc9, 0x05, 0x1e, 0x08, + 0x86, 0x51, 0x27, 0x9c, 0x08, 0x0e, 0x29, 0x63, 0x55, 0x5e, 0x65, 0x54, 0x0b, 0x59, 0xb8, 0xff, + 0x3c, 0x10, 0x1c, 0xcc, 0xf1, 0x7a, 0x3b, 0xb1, 0xde, 0xb6, 0x93, 0x93, 0x54, 0xe8, 0x65, 0x15, + 0x63, 0x26, 0x73, 0xd2, 0x37, 0xed, 0xc6, 0x54, 0x25, 0xf7, 0x44, 0x3f, 0xaf, 0xb8, 0xc2, 0x57, + 0x85, 0x8e, 0x7e, 0x78, 0xf8, 0x33, 0x68, 0xdf, 0x70, 0xba, 0x70, 0x4e, 0xa1, 0x9d, 0x71, 0xba, + 0x30, 0x81, 0x7f, 0x15, 0x36, 0xe4, 0xfc, 0x7a, 0x5d, 0x23, 0xb0, 0xa9, 0x11, 0x78, 0xaf, 0x11, + 0x78, 0x69, 0x90, 0xb5, 0x69, 0x90, 0xf5, 0xda, 0x20, 0xeb, 0x2e, 0xfc, 0xd6, 0xa4, 0xf7, 0x99, + 0x66, 0x34, 0x56, 0x9f, 0xc2, 0xcc, 0x4a, 0x8b, 0x6c, 0xb7, 0x9b, 0x78, 0xcf, 0x7c, 0xe1, 0xf9, + 0x47, 0x00, 0x00, 0x00, 0xff, 0xff, 0x30, 0x34, 0x4b, 0x32, 0xb5, 0x01, 0x00, 0x00, } func (m *Node) Marshal() (dAtA []byte, err error) { diff --git a/proto/osmosis/downtime-detector/v1beta1/downtime_duration.proto b/proto/osmosis/downtime-detector/v1beta1/downtime_duration.proto new file mode 100644 index 00000000000..39b13561bb6 --- /dev/null +++ b/proto/osmosis/downtime-detector/v1beta1/downtime_duration.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; +package osmosis.downtimedetector.v1beta1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types"; + +enum Downtime { + DURATION_30S = 0; + DURATION_1M = 1; + DURATION_2M = 2; + DURATION_3M = 3; + DURATION_4M = 4; + DURATION_5M = 5; + DURATION_10M = 6; + DURATION_20M = 7; + DURATION_30M = 8; + DURATION_40M = 9; + DURATION_50M = 10; + DURATION_1H = 11; + DURATION_1_5H = 12; + DURATION_2H = 13; + DURATION_2_5H = 14; + DURATION_3H = 15; + DURATION_4H = 16; + DURATION_5H = 17; + DURATION_6H = 18; + DURATION_9H = 19; + DURATION_12H = 20; + DURATION_18H = 21; + DURATION_24H = 22; + DURATION_36H = 23; + DURATION_48H = 24; +} diff --git a/proto/osmosis/downtime-detector/v1beta1/genesis.proto b/proto/osmosis/downtime-detector/v1beta1/genesis.proto new file mode 100644 index 00000000000..3e4f3c105fc --- /dev/null +++ b/proto/osmosis/downtime-detector/v1beta1/genesis.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +package osmosis.downtimedetector.v1beta1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "osmosis/downtime-detector/v1beta1/downtime_duration.proto"; + +option go_package = "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types"; + +message GenesisDowntimeEntry { + Downtime duration = 1 [ (gogoproto.moretags) = "yaml:\"duration\"" ]; + google.protobuf.Timestamp last_downtime = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"last_downtime\"" + ]; +} + +// GenesisState defines the twap module's genesis state. +message GenesisState { + repeated GenesisDowntimeEntry downtimes = 1 [ (gogoproto.nullable) = false ]; + + google.protobuf.Timestamp last_block_time = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"last_block_time\"" + ]; +} diff --git a/proto/osmosis/downtime-detector/v1beta1/query.proto b/proto/osmosis/downtime-detector/v1beta1/query.proto new file mode 100644 index 00000000000..7c435de52a3 --- /dev/null +++ b/proto/osmosis/downtime-detector/v1beta1/query.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; +package osmosis.downtimedetector.v1beta1; + +import "gogoproto/gogo.proto"; +import "osmosis/downtime-detector/v1beta1/genesis.proto"; +import "osmosis/downtime-detector/v1beta1/downtime_duration.proto"; + +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "google/api/annotations.proto"; +import "google/protobuf/any.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto"; + +service Query { + rpc RecoveredSinceDowntimeOfLength(RecoveredSinceDowntimeOfLengthRequest) + returns (RecoveredSinceDowntimeOfLengthResponse) { + option (google.api.http).get = + "/osmosis/downtime-detector/v1beta1/RecoveredSinceDowntimeOfLength"; + } +} + +// Query for has it been at least $RECOVERY_DURATION units of time, +// since the chain has been down for $DOWNTIME_DURATION. +message RecoveredSinceDowntimeOfLengthRequest { + Downtime downtime = 1 [ (gogoproto.moretags) = "yaml:\"downtime\"" ]; + google.protobuf.Duration recovery = 2 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true, + (gogoproto.moretags) = "yaml:\"recovery_duration\"" + ]; +} + +message RecoveredSinceDowntimeOfLengthResponse { + bool succesfully_recovered = 1; +} diff --git a/proto/osmosis/downtime-detector/v1beta1/query.yml b/proto/osmosis/downtime-detector/v1beta1/query.yml new file mode 100644 index 00000000000..178b70ea7b4 --- /dev/null +++ b/proto/osmosis/downtime-detector/v1beta1/query.yml @@ -0,0 +1,8 @@ +keeper: + path: "github.com/osmosis-labs/osmosis/v13/x/downtime-detector" + struct: "Keeper" +client_path: "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client" +queries: + RecoveredSinceDowntimeOfLength: + proto_wrapper: + query_func: "k.RecoveredSinceDowntimeOfLength" \ No newline at end of file diff --git a/proto/osmosis/twap/v1beta1/query.proto b/proto/osmosis/twap/v1beta1/query.proto index 95374ece07c..f8ab108d2f4 100644 --- a/proto/osmosis/twap/v1beta1/query.proto +++ b/proto/osmosis/twap/v1beta1/query.proto @@ -23,9 +23,15 @@ service Query { } rpc ArithmeticTwapToNow(ArithmeticTwapToNowRequest) returns (ArithmeticTwapToNowResponse) { - option deprecated = true; option (google.api.http).get = "/osmosis/twap/v1beta1/ArithmeticTwapToNow"; } + rpc GeometricTwap(GeometricTwapRequest) returns (GeometricTwapResponse) { + option (google.api.http).get = "/osmosis/twap/v1beta1/GeometricTwap"; + } + rpc GeometricTwapToNow(GeometricTwapToNowRequest) + returns (GeometricTwapToNowResponse) { + option (google.api.http).get = "/osmosis/twap/v1beta1/GeometricTwapToNow"; + } } message ArithmeticTwapRequest { @@ -69,5 +75,46 @@ message ArithmeticTwapToNowResponse { ]; } +message GeometricTwapRequest { + uint64 pool_id = 1; + string base_asset = 2; + string quote_asset = 3; + google.protobuf.Timestamp start_time = 4 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"start_time\"" + ]; + google.protobuf.Timestamp end_time = 5 [ + (gogoproto.nullable) = true, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"end_time\"" + ]; +} +message GeometricTwapResponse { + string geometric_twap = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.moretags) = "yaml:\"geometric_twap\"", + (gogoproto.nullable) = false + ]; +} + +message GeometricTwapToNowRequest { + uint64 pool_id = 1; + string base_asset = 2; + string quote_asset = 3; + google.protobuf.Timestamp start_time = 4 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"start_time\"" + ]; +} +message GeometricTwapToNowResponse { + string geometric_twap = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.moretags) = "yaml:\"geometric_twap\"", + (gogoproto.nullable) = false + ]; +} + message ParamsRequest {} message ParamsResponse { Params params = 1 [ (gogoproto.nullable) = false ]; } diff --git a/proto/osmosis/twap/v1beta1/query.yml b/proto/osmosis/twap/v1beta1/query.yml index 6763392aaaf..514bb092e9d 100644 --- a/proto/osmosis/twap/v1beta1/query.yml +++ b/proto/osmosis/twap/v1beta1/query.yml @@ -15,6 +15,18 @@ queries: query_func: "k.GetArithmeticTwapToNow" cli: cmd: "ArithmeticTwapToNow" + GeometricTwap: + proto_wrapper: + default_values: + Req.end_time: "ctx.BlockTime()" + query_func: "k.GetGeometricTwap" + cli: + cmd: "ArithmeticTwap" + GeometricTwapToNow: + proto_wrapper: + query_func: "k.GetGeometricTwapToNow" + cli: + cmd: "GeometricTwapToNow" Params: proto_wrapper: query_func: "k.GetParams" diff --git a/proto/osmosis/twap/v1beta1/twap_record.proto b/proto/osmosis/twap/v1beta1/twap_record.proto index d040b318eb0..a57ae9678f1 100644 --- a/proto/osmosis/twap/v1beta1/twap_record.proto +++ b/proto/osmosis/twap/v1beta1/twap_record.proto @@ -54,9 +54,11 @@ message TwapRecord { (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; - // string geometric_twap_accumulator = 7 [(gogoproto.customtype) = - // "github.com/cosmos/cosmos-sdk/types.Dec", - // (gogoproto.nullable) = false]; + + string geometric_twap_accumulator = 10 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; // This field contains the time in which the last spot price error occured. // It is used to alert the caller if they are getting a potentially erroneous diff --git a/scripts/approximations/approximations.py b/scripts/approximations/approximations.py index 19849698088..1a434509667 100644 --- a/scripts/approximations/approximations.py +++ b/scripts/approximations/approximations.py @@ -84,9 +84,9 @@ def compute_max_error(y_approximation, y_actual) -> sp.Float: max = sp.Max(max, cur_abs) return max -def compute_error_range(y_approximation: list, y_actual: list) -> list[sp.Float]: +def compute_absolute_error_range(y_approximation: list, y_actual: list) -> list[sp.Float]: """ Given an approximated list of y values and actual y values, computes and returns - error deltas between them. + absolute error between them, computed as | y_approximation[i] - y_actual[i] |. CONTRACT: - y_approximation and y_actual must be the same length @@ -101,6 +101,29 @@ def compute_error_range(y_approximation: list, y_actual: list) -> list[sp.Float] result.append(cur_abs) return result +def compute_relative_error_range(y_approximation: list, y_actual: list) -> list[sp.Float]: + """ Given an approximated list of y values and actual y values, computes and returns + relative error between them, computed as | y_approximation[i] - y_actual[i] | / y_actual[i]. + + For y_actual[i] = 0, relative error is defined as 0. + + CONTRACT: + - y_approximation and y_actual must be the same length + - for every i in range(len(y_approximation)), y_approximation[i] and y_actual[i] must correspond to the + same x coordinate + """ + result = [] + for i in range(len(y_approximation)): + if y_actual[i] == 0: + result.append(0) + continue + + cur_relative_error = sp.Abs(y_approximation[i] - y_actual[i]) / y_actual[i] + if cur_relative_error is sp.nan: + raise ValueError(F"cur_abs is nan. y_approximation[i] ({y_approximation[i]}) and y_actual[i] ({y_actual[i]})") + result.append(cur_relative_error) + return result + def equispaced_poly_approx(fn, x_start: sp.Float, x_end: sp.Float, num_terms: int): """ Returns the coefficients for an equispaced polynomial between x_start and x_end with num_terms terms. diff --git a/scripts/approximations/main.py b/scripts/approximations/main.py index b91433855c9..47875ed7b24 100644 --- a/scripts/approximations/main.py +++ b/scripts/approximations/main.py @@ -20,10 +20,10 @@ num_parameters_errors = 30 # number of (x,y) coordinates used to plot the resulting approximation. -num_points_plot = 100000 +num_points_plot = 10000 # function to approximate -approximated_fn = lambda x: sp.Pow(sp.E, x) +approximated_fn = lambda x: sp.Pow(2, x) # fixed point precision used in Osmosis `osmomath` package. osmomath_precision = 36 @@ -48,16 +48,23 @@ # Plots if true. shouldPlotMaxError = True -def plot_error_range(x_coordinates, y_approximation, y_actual): +def plot_error_range(x_coordinates, y_approximation, y_actual, is_absolute: bool): """ Given x coordinates that correspond to approximated y coordinates and actual y coordinates, - compute the deltas between y approximated and y actual and plot them in log scale on y. + computes the error between y approximated and y actual and plot them in log scale on y. + + If is_absolute, plots the absolute error. Otherwise, plots the relative error. """ - error_deltas = approximations.compute_error_range(y_approximation, y_actual) + if is_absolute: + error_kind_str = "Absolute" + error_deltas = approximations.compute_absolute_error_range(y_approximation, y_actual) + else: + error_kind_str = "Relative" + error_deltas = approximations.compute_relative_error_range(y_approximation, y_actual) plt.semilogy(x_coordinates, error_deltas) plt.grid(True) - plt.title(f"Chebyshev Rational e^x Errors on [{x_start}, {x_end}]. {num_parameters} params, {num_points_plot} points") + plt.title(f"Chebyshev Rational e^x {error_kind_str} Errors on [{x_start}, {x_end}]. {num_parameters} params, {num_points_plot} points") plt.show() # This script does the following: @@ -171,14 +178,41 @@ def main(): def exponent_approximation_choice(): # Equispaced x coordinates to be used for plotting every approximation. x_coordinates = approximations.linspace(x_start, x_end, num_points_plot) - x_coordinates = [sp.Float(sp.N(coef, osmomath_precision + 1), osmomath_precision + 1) for coef in x_coordinates] + x_coordinates = [sp.N(sp.Float(coef, osmomath_precision), n=osmomath_precision) for coef in x_coordinates] - # Chebyshev Rational Approximation to get the coefficients. - coef_numerator, coef_denominator = approximations.chebyshev_rational_approx(approximated_fn, x_start, x_end, num_parameters) + print(x_coordinates) - # Truncate the coefficients to osmomath precision. - coef_numerator = [sp.Float(sp.N(coef, osmomath_precision + 1), osmomath_precision + 1) for coef in coef_numerator] - coef_denominator = [sp.Float(sp.N(coef, osmomath_precision + 1), osmomath_precision + 1) for coef in coef_denominator] + # Chebyshev Rational Approximation to get the coefficients. + # coef_numerator, coef_denominator = approximations.chebyshev_rational_approx(approximated_fn, x_start, x_end, num_parameters) + # coef_numerator = [sp.N(coef, osmomath_precision + 2) for coef in coef_numerator] + # coef_denominator = [sp.N(coef, osmomath_precision + 2) for coef in coef_denominator] + + # Hard code and round up numerator coefficientst that are to be used in production + # Hard code and round down numerator coefficientst that are to be used in production + # Both of these are calculated us=ing the above commented out code. + + coef_numerator = [ + sp.N(sp.Float("1.000000000000000000000044212244679434", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.352032455817400196452603772766844426", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.056507868883666405413116800969512484", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.005343900728213034434757419480319916", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.000317708814342353603087543715930732", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.000011429747507407623028722262874632", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.000000198381965651614980168744540366", osmomath_precision), n=osmomath_precision), + ] + + coef_denominator = [ + sp.N(sp.Float("1.0000000000000000000000000000000000000", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("-0.341114724742545112949699755780593311", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.052724071627342653404436933178482287", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("-0.004760950735524957576233524801866342", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.000267168475410566529819971616894193", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("-0.000008923715368802211181557353097439", osmomath_precision), n=osmomath_precision), + sp.N(sp.Float("0.000000140277233177373698516010555916", osmomath_precision), n=osmomath_precision), + ] + + print(coef_numerator) + print(coef_denominator) # Evaluate approximation. y_chebyshev_rational = rational.evaluate(x_coordinates, coef_numerator, coef_denominator) @@ -186,7 +220,7 @@ def exponent_approximation_choice(): # Compute Actual Values y_actual = approximations.get_y_actual(approximated_fn, x_coordinates) - plot_error_range(x_coordinates, y_chebyshev_rational, y_actual) + plot_error_range(x_coordinates, y_chebyshev_rational, y_actual, True) if __name__ == "__main__": # Uncomment to run the main script. diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 9b17c63409e..00f593bc924 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -25,6 +25,7 @@ cd .. # # Note: Proto files are suffixed with the current binary version. cp -r github.com/osmosis-labs/osmosis/v13/* ./ +cp -r github.com/osmosis-labs/osmosis/osmoutils ./ rm -rf github.com go mod tidy -compat=1.18 diff --git a/tests/e2e/configurer/chain/queries.go b/tests/e2e/configurer/chain/queries.go index 1b53ca5a31f..5a7bc1f2123 100644 --- a/tests/e2e/configurer/chain/queries.go +++ b/tests/e2e/configurer/chain/queries.go @@ -187,7 +187,6 @@ func (n *NodeConfig) QueryArithmeticTwapToNow(poolId uint64, baseAsset, quoteAss return sdk.Dec{}, err } - // nolint: staticcheck var response twapqueryproto.ArithmeticTwapToNowResponse err = util.Cdc.UnmarshalJSON(bz, &response) require.NoError(n.t, err) // this error should not happen @@ -209,13 +208,53 @@ func (n *NodeConfig) QueryArithmeticTwap(poolId uint64, baseAsset, quoteAsset st return sdk.Dec{}, err } - // nolint: staticcheck var response twapqueryproto.ArithmeticTwapResponse err = util.Cdc.UnmarshalJSON(bz, &response) require.NoError(n.t, err) // this error should not happen return response.ArithmeticTwap, nil } +func (n *NodeConfig) QueryGeometricTwapToNow(poolId uint64, baseAsset, quoteAsset string, startTime time.Time) (sdk.Dec, error) { + path := "osmosis/twap/v1beta1/GeometricTwapToNow" + + bz, err := n.QueryGRPCGateway( + path, + "pool_id", strconv.FormatInt(int64(poolId), 10), + "base_asset", baseAsset, + "quote_asset", quoteAsset, + "start_time", startTime.Format(time.RFC3339Nano), + ) + if err != nil { + return sdk.Dec{}, err + } + + var response twapqueryproto.GeometricTwapToNowResponse + err = util.Cdc.UnmarshalJSON(bz, &response) + require.NoError(n.t, err) + return response.GeometricTwap, nil +} + +func (n *NodeConfig) QueryGeometricTwap(poolId uint64, baseAsset, quoteAsset string, startTime time.Time, endTime time.Time) (sdk.Dec, error) { + path := "osmosis/twap/v1beta1/GeometricTwap" + + bz, err := n.QueryGRPCGateway( + path, + "pool_id", strconv.FormatInt(int64(poolId), 10), + "base_asset", baseAsset, + "quote_asset", quoteAsset, + "start_time", startTime.Format(time.RFC3339Nano), + "end_time", endTime.Format(time.RFC3339Nano), + ) + if err != nil { + return sdk.Dec{}, err + } + + var response twapqueryproto.GeometricTwapResponse + err = util.Cdc.UnmarshalJSON(bz, &response) + require.NoError(n.t, err) + return response.GeometricTwap, nil +} + // QueryHashFromBlock gets block hash at a specific height. Otherwise, error. func (n *NodeConfig) QueryHashFromBlock(height int64) (string, error) { block, err := n.rpcClient.Block(context.Background(), &height) diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index bf59468d30a..0ee4cff4f10 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -161,10 +161,9 @@ func (s *IntegrationTestSuite) TestIBCTokenTransferRateLimiting() { fmt.Println(wd, projectDir) err = copyFile(projectDir+"/x/ibc-rate-limit/bytecode/rate_limiter.wasm", wd+"/scripts/rate_limiter.wasm") s.NoError(err) - // set LatestCodeId to 1 since we upload a contract in the upgrade handler for v13 - chainA.LatestCodeId = 1 + node.StoreWasmCode("rate_limiter.wasm", initialization.ValidatorWalletName) - chainA.LatestCodeId += 1 + chainA.LatestCodeId = 1 node.InstantiateWasmContract( strconv.Itoa(chainA.LatestCodeId), fmt.Sprintf(`{"gov_module": "%s", "ibc_module": "%s", "paths": [{"channel_id": "channel-0", "denom": "%s", "quotas": [{"name":"testQuota", "duration": 86400, "send_recv": [1, 1]}] } ] }`, node.PublicAddress, node.PublicAddress, initialization.OsmoToken.Denom), @@ -263,16 +262,16 @@ func (s *IntegrationTestSuite) TestAddToExistingLock() { chainA.LockAndAddToExistingLock(sdk.NewInt(1000000000000000000), fmt.Sprintf("gamm/pool/%d", poolId), lockupWalletAddr, lockupWalletSuperfluidAddr) } -// TestTWAP tests TWAP by creating a pool, performing a swap. +// TestArithmeticTWAP tests TWAP by creating a pool, performing a swap. // These two operations should create TWAP records. // Then, we wait until the epoch for the records to be pruned. // The records are guranteed to be pruned at the next epoch // because twap keep time = epoch time / 4 and we use a timer // to wait for at least the twap keep time. -func (s *IntegrationTestSuite) TestTWAP() { +func (s *IntegrationTestSuite) TestArithmeticTWAP() { const ( poolFile = "nativeDenomThreeAssetPool.json" - walletName = "swap-exact-amount-in-wallet" + walletName = "arithmetic-twap-wallet" denomA = "stake" denomB = "uion" @@ -570,3 +569,94 @@ func (s *IntegrationTestSuite) TestExpeditedProposals() { s.T().Logf("expeditedVotingPeriodDuration within two seconds of expected time: %v", timeDelta) close(totalTimeChan) } + +// TestGeometricTWAP tests geometric twap. +// It does the following: creates a pool, queries twap, performs a swap , and queries twap again. +// Twap is expected to change after the swap. +// The pool is created with 1_000_000 uosmo and 2_000_000 stake and equal weights. +// Assuming base asset is uosmo, the initial twap is 2 +// Upon swapping 1_000_000 uosmo for stake, supply changes, making uosmo less expensive. +// As a result of the swap, twap changes to 0.5. +func (s *IntegrationTestSuite) TestGeometricTWAP() { + const ( + // This pool contains 1_000_000 uosmo and 2_000_000 stake. + // Equals weights. + poolFile = "geometricPool.json" + walletName = "geometric-twap-wallet" + + denomA = "uosmo" // 1_000_000 uosmo + denomB = "stake" // 2_000_000 stake + + minAmountOut = "1" + + epochIdentifier = "day" + ) + + chainA := s.configurer.GetChainConfig(0) + chainANode, err := chainA.GetDefaultNode() + s.NoError(err) + + // Triggers the creation of TWAP records. + poolId := chainANode.CreatePool(poolFile, initialization.ValidatorWalletName) + swapWalletAddr := chainANode.CreateWallet(walletName) + + // We add 5 ms to avoid landing directly on block time in twap. If block time + // is provided as start time, the latest spot price is used. Otherwise + // interpolation is done. + timeBeforeSwapPlus5ms := chainANode.QueryLatestBlockTime().Add(5 * time.Millisecond) + // Wait for the next height so that the requested twap + // start time (timeBeforeSwap) is not equal to the block time. + chainA.WaitForNumHeights(1) + + s.T().Log("querying for the first geometric TWAP to now (before swap)") + // Assume base = uosmo, quote = stake + // At pool creation time, the twap should be: + // quote assset supply / base asset supply = 2_000_000 / 1_000_000 = 2 + initialTwapBOverA, err := chainANode.QueryGeometricTwapToNow(poolId, denomA, denomB, timeBeforeSwapPlus5ms) + s.Require().NoError(err) + s.Require().Equal(sdk.NewDec(2), initialTwapBOverA) + + // Assume base = stake, quote = uosmo + // At pool creation time, the twap should be: + // quote assset supply / base asset supply = 1_000_000 / 2_000_000 = 0.5 + initialTwapAOverB, err := chainANode.QueryGeometricTwapToNow(poolId, denomB, denomA, timeBeforeSwapPlus5ms) + s.Require().NoError(err) + s.Require().Equal(sdk.NewDecWithPrec(5, 1), initialTwapAOverB) + + coinAIn := fmt.Sprintf("1000000%s", denomA) + chainANode.BankSend(coinAIn, chainA.NodeConfigs[0].PublicAddress, swapWalletAddr) + + s.T().Logf("performing swap of %s for %s", coinAIn, denomB) + + // stake out = stake supply * (1 - (uosmo supply before / uosmo supply after)^(uosmo weight / stake weight)) + // = 2_000_000 * (1 - (1_000_000 / 2_000_000)^1) + // = 2_000_000 * 0.5 + // = 1_000_000 + chainANode.SwapExactAmountIn(coinAIn, minAmountOut, fmt.Sprintf("%d", poolId), denomB, swapWalletAddr) + + // New supply post swap: + // stake = 2_000_000 - 1_000_000 - 1_000_000 + // uosmo = 1_000_000 + 1_000_000 = 2_000_000 + + timeAfterSwap := chainANode.QueryLatestBlockTime() + chainA.WaitForNumHeights(1) + timeAfterSwapPlus1Height := chainANode.QueryLatestBlockTime() + + s.T().Log("querying for the TWAP from after swap to now") + afterSwapTwapBOverA, err := chainANode.QueryGeometricTwap(poolId, denomA, denomB, timeAfterSwap, timeAfterSwapPlus1Height) + s.Require().NoError(err) + + // We swap uosmo so uosmo's supply will increase and stake will decrease. + // The the price after will be smaller than the previous one. + s.Require().True(initialTwapBOverA.GT(afterSwapTwapBOverA)) + + // Assume base = uosmo, quote = stake + // At pool creation, we had: + // quote assset supply / base asset supply = 2_000_000 / 1_000_000 = 2 + // Next, we swapped 1_000_000 uosmo for stake. + // Now, we roughly have + // uatom = 1_000_000 + // uosmo = 2_000_000 + // quote assset supply / base asset supply = 1_000_000 / 2_000_000 = 0.5 + osmoassert.DecApproxEq(s.T(), sdk.NewDecWithPrec(5, 1), afterSwapTwapBOverA, sdk.NewDecWithPrec(1, 2)) +} diff --git a/tests/e2e/scripts/geometricPool.json b/tests/e2e/scripts/geometricPool.json new file mode 100644 index 00000000000..8c60b25e5cf --- /dev/null +++ b/tests/e2e/scripts/geometricPool.json @@ -0,0 +1,7 @@ +{ + "weights": "1uosmo,1stake", + "initial-deposit": "1000000uosmo,2000000stake", + "swap-fee": "0", + "exit-fee": "0", + "future-governor": "" +} diff --git a/tests/ibc-hooks/bytecode/counter.wasm b/tests/ibc-hooks/bytecode/counter.wasm new file mode 100644 index 00000000000..2e4d8b7ccf9 Binary files /dev/null and b/tests/ibc-hooks/bytecode/counter.wasm differ diff --git a/tests/ibc-hooks/bytecode/crosschain_swaps.wasm b/tests/ibc-hooks/bytecode/crosschain_swaps.wasm new file mode 100644 index 00000000000..10c587e8db2 Binary files /dev/null and b/tests/ibc-hooks/bytecode/crosschain_swaps.wasm differ diff --git a/tests/ibc-hooks/bytecode/echo.wasm b/tests/ibc-hooks/bytecode/echo.wasm new file mode 100644 index 00000000000..4feb4554e7c Binary files /dev/null and b/tests/ibc-hooks/bytecode/echo.wasm differ diff --git a/tests/ibc-hooks/bytecode/swaprouter.wasm b/tests/ibc-hooks/bytecode/swaprouter.wasm new file mode 100644 index 00000000000..d6cdcd989bc Binary files /dev/null and b/tests/ibc-hooks/bytecode/swaprouter.wasm differ diff --git a/tests/ibc-hooks/ibc_middleware_test.go b/tests/ibc-hooks/ibc_middleware_test.go new file mode 100644 index 00000000000..0bc35313625 --- /dev/null +++ b/tests/ibc-hooks/ibc_middleware_test.go @@ -0,0 +1,930 @@ +package ibc_hooks_test + +import ( + "encoding/json" + "fmt" + "testing" + "time" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + + "github.com/osmosis-labs/osmosis/v13/x/gamm/pool-models/balancer" + gammtypes "github.com/osmosis-labs/osmosis/v13/x/gamm/types" + minttypes "github.com/osmosis-labs/osmosis/v13/x/mint/types" + ibchooks "github.com/osmosis-labs/osmosis/x/ibc-hooks" + + "github.com/osmosis-labs/osmosis/osmoutils" + + "github.com/osmosis-labs/osmosis/v13/app/apptesting" + + "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + + osmosisibctesting "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/testutil" + + "github.com/osmosis-labs/osmosis/v13/tests/ibc-hooks/testutils" +) + +type HooksTestSuite struct { + apptesting.KeeperTestHelper + + coordinator *ibctesting.Coordinator + + chainA *osmosisibctesting.TestChain + chainB *osmosisibctesting.TestChain + + path *ibctesting.Path +} + +func (suite *HooksTestSuite) SetupTest() { + suite.Setup() + ibctesting.DefaultTestingAppInit = osmosisibctesting.SetupTestingApp + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + suite.chainA = &osmosisibctesting.TestChain{ + TestChain: suite.coordinator.GetChain(ibctesting.GetChainID(1)), + } + suite.chainB = &osmosisibctesting.TestChain{ + TestChain: suite.coordinator.GetChain(ibctesting.GetChainID(2)), + } + err := suite.chainA.MoveEpochsToTheFuture() + suite.Require().NoError(err) + err = suite.chainB.MoveEpochsToTheFuture() + suite.Require().NoError(err) + suite.path = NewTransferPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(suite.path) +} + +func TestIBCHooksTestSuite(t *testing.T) { + suite.Run(t, new(HooksTestSuite)) +} + +// ToDo: Move this to osmosistesting to avoid repetition +func NewTransferPath(chainA, chainB *osmosisibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA.TestChain, chainB.TestChain) + path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + path.EndpointA.ChannelConfig.Version = transfertypes.Version + path.EndpointB.ChannelConfig.Version = transfertypes.Version + + return path +} + +func (suite *HooksTestSuite) TestOnRecvPacketHooks() { + var ( + trace transfertypes.DenomTrace + amount sdk.Int + receiver string + status testutils.Status + ) + + testCases := []struct { + msg string + malleate func(*testutils.Status) + expPass bool + }{ + {"override", func(status *testutils.Status) { + suite.chainB.GetOsmosisApp().TransferStack. + ICS4Middleware.Hooks = testutils.TestRecvOverrideHooks{Status: status} + }, true}, + {"before and after", func(status *testutils.Status) { + suite.chainB.GetOsmosisApp().TransferStack. + ICS4Middleware.Hooks = testutils.TestRecvBeforeAfterHooks{Status: status} + }, true}, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.msg, func() { + suite.SetupTest() // reset + + path := NewTransferPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + receiver = suite.chainB.SenderAccount.GetAddress().String() // must be explicitly changed in malleate + status = testutils.Status{} + + amount = sdk.NewInt(100) // must be explicitly changed in malleate + seq := uint64(1) + + trace = transfertypes.ParseDenomTrace(sdk.DefaultBondDenom) + + // send coin from chainA to chainB + transferMsg := transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoin(trace.IBCDenom(), amount), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0) + _, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + tc.malleate(&status) + + data := transfertypes.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), suite.chainA.SenderAccount.GetAddress().String(), receiver) + packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) + + ack := suite.chainB.GetOsmosisApp().TransferStack. + OnRecvPacket(suite.chainB.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) + + if tc.expPass { + suite.Require().True(ack.Success()) + } else { + suite.Require().False(ack.Success()) + } + + if _, ok := suite.chainB.GetOsmosisApp().TransferStack. + ICS4Middleware.Hooks.(testutils.TestRecvOverrideHooks); ok { + suite.Require().True(status.OverrideRan) + suite.Require().False(status.BeforeRan) + suite.Require().False(status.AfterRan) + } + + if _, ok := suite.chainB.GetOsmosisApp().TransferStack. + ICS4Middleware.Hooks.(testutils.TestRecvBeforeAfterHooks); ok { + suite.Require().False(status.OverrideRan) + suite.Require().True(status.BeforeRan) + suite.Require().True(status.AfterRan) + } + }) + } +} + +func (suite *HooksTestSuite) makeMockPacket(receiver, memo string, prevSequence uint64) channeltypes.Packet { + packetData := transfertypes.FungibleTokenPacketData{ + Denom: sdk.DefaultBondDenom, + Amount: "1", + Sender: suite.chainB.SenderAccount.GetAddress().String(), + Receiver: receiver, + Memo: memo, + } + + return channeltypes.NewPacket( + packetData.GetBytes(), + prevSequence+1, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) +} + +func (suite *HooksTestSuite) receivePacket(receiver, memo string) []byte { + return suite.receivePacketWithSequence(receiver, memo, 0) +} + +func (suite *HooksTestSuite) receivePacketWithSequence(receiver, memo string, prevSequence uint64) []byte { + channelCap := suite.chainB.GetChannelCapability( + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID) + + packet := suite.makeMockPacket(receiver, memo, prevSequence) + + err := suite.chainB.GetOsmosisApp().HooksICS4Wrapper.SendPacket( + suite.chainB.GetContext(), channelCap, packet) + suite.Require().NoError(err, "IBC send failed. Expected success. %s", err) + + // Update both clients + err = suite.path.EndpointB.UpdateClient() + suite.Require().NoError(err) + err = suite.path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + // recv in chain a + res, err := suite.path.EndpointA.RecvPacketWithResult(packet) + + // get the ack from the chain a's response + ack, err := ibctesting.ParseAckFromEvents(res.GetEvents()) + suite.Require().NoError(err) + + // manually send the acknowledgement to chain b + err = suite.path.EndpointA.AcknowledgePacket(packet, ack) + suite.Require().NoError(err) + return ack +} + +func (suite *HooksTestSuite) TestRecvTransferWithMetadata() { + // Setup contract + suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/echo.wasm") + addr := suite.chainA.InstantiateContract(&suite.Suite, "{}", 1) + + ackBytes := suite.receivePacket(addr.String(), fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"echo": {"msg": "test"} } } }`, addr)) + ackStr := string(ackBytes) + fmt.Println(ackStr) + var ack map[string]string // This can't be unmarshalled to Acknowledgement because it's fetched from the events + err := json.Unmarshal(ackBytes, &ack) + suite.Require().NoError(err) + suite.Require().NotContains(ack, "error") + suite.Require().Equal(ack["result"], "eyJjb250cmFjdF9yZXN1bHQiOiJkR2hwY3lCemFHOTFiR1FnWldOb2J3PT0iLCJpYmNfYWNrIjoiZXlKeVpYTjFiSFFpT2lKQlVUMDlJbjA9In0=") +} + +// After successfully executing a wasm call, the contract should have the funds sent via IBC +func (suite *HooksTestSuite) TestFundsAreTransferredToTheContract() { + // Setup contract + suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/echo.wasm") + addr := suite.chainA.InstantiateContract(&suite.Suite, "{}", 1) + + // Check that the contract has no funds + localDenom := osmoutils.MustExtractDenomFromPacketOnRecv(suite.makeMockPacket("", "", 0)) + balance := suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) + suite.Require().Equal(sdk.NewInt(0), balance.Amount) + + // Execute the contract via IBC + ackBytes := suite.receivePacket(addr.String(), fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"echo": {"msg": "test"} } } }`, addr)) + ackStr := string(ackBytes) + fmt.Println(ackStr) + var ack map[string]string // This can't be unmarshalled to Acknowledgement because it's fetched from the events + err := json.Unmarshal(ackBytes, &ack) + suite.Require().NoError(err) + suite.Require().NotContains(ack, "error") + suite.Require().Equal(ack["result"], "eyJjb250cmFjdF9yZXN1bHQiOiJkR2hwY3lCemFHOTFiR1FnWldOb2J3PT0iLCJpYmNfYWNrIjoiZXlKeVpYTjFiSFFpT2lKQlVUMDlJbjA9In0=") + + // Check that the token has now been transferred to the contract + balance = suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) + suite.Require().Equal(sdk.NewInt(1), balance.Amount) +} + +// If the wasm call wails, the contract acknowledgement should be an error and the funds returned +func (suite *HooksTestSuite) TestFundsAreReturnedOnFailedContractExec() { + // Setup contract + suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/echo.wasm") + addr := suite.chainA.InstantiateContract(&suite.Suite, "{}", 1) + + // Check that the contract has no funds + localDenom := osmoutils.MustExtractDenomFromPacketOnRecv(suite.makeMockPacket("", "", 0)) + balance := suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) + suite.Require().Equal(sdk.NewInt(0), balance.Amount) + + // Execute the contract via IBC with a message that the contract will reject + ackBytes := suite.receivePacket(addr.String(), fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"not_echo": {"msg": "test"} } } }`, addr)) + ackStr := string(ackBytes) + fmt.Println(ackStr) + var ack map[string]string // This can't be unmarshalled to Acknowledgement because it's fetched from the events + err := json.Unmarshal(ackBytes, &ack) + suite.Require().NoError(err) + suite.Require().Contains(ack, "error") + + // Check that the token has now been transferred to the contract + balance = suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) + fmt.Println(balance) + suite.Require().Equal(sdk.NewInt(0), balance.Amount) +} + +func (suite *HooksTestSuite) TestPacketsThatShouldBeSkipped() { + var sequence uint64 + receiver := suite.chainB.SenderAccount.GetAddress().String() + + testCases := []struct { + memo string + expPassthrough bool + }{ + {"", true}, + {"{01]", true}, // bad json + {"{}", true}, + {`{"something": ""}`, true}, + {`{"wasm": "test"}`, false}, + {`{"wasm": []`, true}, // invalid top level JSON + {`{"wasm": {}`, true}, // invalid top level JSON + {`{"wasm": []}`, false}, + {`{"wasm": {}}`, false}, + {`{"wasm": {"contract": "something"}}`, false}, + {`{"wasm": {"contract": "osmo1clpqr4nrk4khgkxj78fcwwh6dl3uw4epasmvnj"}}`, false}, + {`{"wasm": {"msg": "something"}}`, false}, + // invalid receiver + {`{"wasm": {"contract": "osmo1clpqr4nrk4khgkxj78fcwwh6dl3uw4epasmvnj", "msg": {}}}`, false}, + // msg not an object + {fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": 1}}`, receiver), false}, + } + + for _, tc := range testCases { + ackBytes := suite.receivePacketWithSequence(receiver, tc.memo, sequence) + ackStr := string(ackBytes) + fmt.Println(ackStr) + var ack map[string]string // This can't be unmarshalled to Acknowledgement because it's fetched from the events + err := json.Unmarshal(ackBytes, &ack) + suite.Require().NoError(err) + if tc.expPassthrough { + suite.Require().Equal("AQ==", ack["result"], tc.memo) + } else { + suite.Require().Contains(ackStr, "error", tc.memo) + } + sequence += 1 + } +} + +// After successfully executing a wasm call, the contract should have the funds sent via IBC +func (suite *HooksTestSuite) TestFundTracking() { + // Setup contract + suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/counter.wasm") + addr := suite.chainA.InstantiateContract(&suite.Suite, `{"count": 0}`, 1) + + // Check that the contract has no funds + localDenom := osmoutils.MustExtractDenomFromPacketOnRecv(suite.makeMockPacket("", "", 0)) + balance := suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) + suite.Require().Equal(sdk.NewInt(0), balance.Amount) + + // Execute the contract via IBC + suite.receivePacket( + addr.String(), + fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"increment": {} } } }`, addr)) + + state := suite.chainA.QueryContract( + &suite.Suite, addr, + []byte(fmt.Sprintf(`{"get_count": {"addr": "%s"}}`, ibchooks.WasmHookModuleAccountAddr))) + suite.Require().Equal(`{"count":0}`, state) + + state = suite.chainA.QueryContract( + &suite.Suite, addr, + []byte(fmt.Sprintf(`{"get_total_funds": {"addr": "%s"}}`, ibchooks.WasmHookModuleAccountAddr))) + suite.Require().Equal(`{"total_funds":[{"denom":"ibc/C053D637CCA2A2BA030E2C5EE1B28A16F71CCB0E45E8BE52766DC1B241B77878","amount":"1"}]}`, state) + + suite.receivePacketWithSequence( + addr.String(), + fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"increment": {} } } }`, addr), 1) + + state = suite.chainA.QueryContract( + &suite.Suite, addr, + []byte(fmt.Sprintf(`{"get_count": {"addr": "%s"}}`, ibchooks.WasmHookModuleAccountAddr))) + suite.Require().Equal(`{"count":1}`, state) + + state = suite.chainA.QueryContract( + &suite.Suite, addr, + []byte(fmt.Sprintf(`{"get_total_funds": {"addr": "%s"}}`, ibchooks.WasmHookModuleAccountAddr))) + suite.Require().Equal(`{"total_funds":[{"denom":"ibc/C053D637CCA2A2BA030E2C5EE1B28A16F71CCB0E45E8BE52766DC1B241B77878","amount":"2"}]}`, state) + + // Check that the token has now been transferred to the contract + balance = suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) + suite.Require().Equal(sdk.NewInt(2), balance.Amount) +} + +// custom MsgTransfer constructor that supports Memo +func NewMsgTransfer( + token sdk.Coin, sender, receiver string, memo string, +) *transfertypes.MsgTransfer { + return &transfertypes.MsgTransfer{ + SourcePort: "transfer", + SourceChannel: "channel-0", + Token: token, + Sender: sender, + Receiver: receiver, + TimeoutHeight: clienttypes.NewHeight(0, 100), + TimeoutTimestamp: 0, + Memo: memo, + } +} + +type Direction int64 + +const ( + AtoB Direction = iota + BtoA +) + +func (suite *HooksTestSuite) GetEndpoints(direction Direction) (sender *ibctesting.Endpoint, receiver *ibctesting.Endpoint) { + switch direction { + case AtoB: + sender = suite.path.EndpointA + receiver = suite.path.EndpointB + case BtoA: + sender = suite.path.EndpointB + receiver = suite.path.EndpointA + } + return sender, receiver +} + +func (suite *HooksTestSuite) RelayPacket(packet channeltypes.Packet, direction Direction) (*sdk.Result, []byte) { + sender, receiver := suite.GetEndpoints(direction) + + err := receiver.UpdateClient() + suite.Require().NoError(err) + + // receiver Receives + receiveResult, err := receiver.RecvPacketWithResult(packet) + suite.Require().NoError(err) + + ack, err := ibctesting.ParseAckFromEvents(receiveResult.GetEvents()) + suite.Require().NoError(err) + + // sender Acknowledges + err = sender.AcknowledgePacket(packet, ack) + suite.Require().NoError(err) + + err = sender.UpdateClient() + suite.Require().NoError(err) + err = receiver.UpdateClient() + suite.Require().NoError(err) + + return receiveResult, ack +} + +func (suite *HooksTestSuite) FullSend(msg sdk.Msg, direction Direction) (*sdk.Result, *sdk.Result, string, error) { + var sender *osmosisibctesting.TestChain + switch direction { + case AtoB: + sender = suite.chainA + case BtoA: + sender = suite.chainB + } + sendResult, err := sender.SendMsgsNoCheck(msg) + suite.Require().NoError(err) + + packet, err := ibctesting.ParsePacketFromEvents(sendResult.GetEvents()) + suite.Require().NoError(err) + + receiveResult, ack := suite.RelayPacket(packet, direction) + + return sendResult, receiveResult, string(ack), err +} + +func (suite *HooksTestSuite) TestAcks() { + suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/counter.wasm") + addr := suite.chainA.InstantiateContract(&suite.Suite, `{"count": 0}`, 1) + + // Generate swap instructions for the contract + callbackMemo := fmt.Sprintf(`{"ibc_callback":"%s"}`, addr) + // Send IBC transfer with the memo with crosschain-swap instructions + transferMsg := NewMsgTransfer(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)), suite.chainA.SenderAccount.GetAddress().String(), addr.String(), callbackMemo) + suite.FullSend(transferMsg, AtoB) + + // The test contract will increment the counter for itself every time it receives an ack + state := suite.chainA.QueryContract( + &suite.Suite, addr, + []byte(fmt.Sprintf(`{"get_count": {"addr": "%s"}}`, addr))) + suite.Require().Equal(`{"count":1}`, state) + + suite.FullSend(transferMsg, AtoB) + state = suite.chainA.QueryContract( + &suite.Suite, addr, + []byte(fmt.Sprintf(`{"get_count": {"addr": "%s"}}`, addr))) + suite.Require().Equal(`{"count":2}`, state) + +} + +func (suite *HooksTestSuite) TestTimeouts() { + suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/counter.wasm") + addr := suite.chainA.InstantiateContract(&suite.Suite, `{"count": 0}`, 1) + + // Generate swap instructions for the contract + callbackMemo := fmt.Sprintf(`{"ibc_callback":"%s"}`, addr) + // Send IBC transfer with the memo with crosschain-swap instructions + transferMsg := NewMsgTransfer(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)), suite.chainA.SenderAccount.GetAddress().String(), addr.String(), callbackMemo) + transferMsg.TimeoutTimestamp = uint64(suite.coordinator.CurrentTime.Add(time.Minute).UnixNano()) + sendResult, err := suite.chainA.SendMsgsNoCheck(transferMsg) + suite.Require().NoError(err) + + packet, err := ibctesting.ParsePacketFromEvents(sendResult.GetEvents()) + suite.Require().NoError(err) + + // Move chainB forward one block + suite.chainB.NextBlock() + // One month later + suite.coordinator.IncrementTimeBy(time.Hour) + err = suite.path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + err = suite.path.EndpointA.TimeoutPacket(packet) + suite.Require().NoError(err) + + // The test contract will increment the counter for itself by 10 when a packet times out + state := suite.chainA.QueryContract( + &suite.Suite, addr, + []byte(fmt.Sprintf(`{"get_count": {"addr": "%s"}}`, addr))) + suite.Require().Equal(`{"count":10}`, state) + +} + +func (suite *HooksTestSuite) TestSendWithoutMemo() { + // Sending a packet without memo to ensure that the ibc_callback middleware doesn't interfere with a regular send + transferMsg := NewMsgTransfer(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000)), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "") + _, _, ack, err := suite.FullSend(transferMsg, AtoB) + suite.Require().NoError(err) + suite.Require().Contains(ack, "result") +} + +type Chain int64 + +const ( + ChainA Chain = iota + ChainB +) + +// This is a copy of the SetupGammPoolsWithBondDenomMultiplier from the test helpers, but using chainA instead of the default +func (suite *HooksTestSuite) SetupPools(chainName Chain, multipliers []sdk.Dec) []gammtypes.PoolI { + chain := suite.GetChain(chainName) + acc1 := chain.SenderAccount.GetAddress() + bondDenom := chain.GetOsmosisApp().StakingKeeper.BondDenom(chain.GetContext()) + + pools := []gammtypes.PoolI{} + for index, multiplier := range multipliers { + token := fmt.Sprintf("token%d", index) + uosmoAmount := gammtypes.InitPoolSharesSupply.ToDec().Mul(multiplier).RoundInt() + + var ( + defaultFutureGovernor = "" + + // pool assets + defaultFooAsset = balancer.PoolAsset{ + Weight: sdk.NewInt(100), + Token: sdk.NewCoin(bondDenom, uosmoAmount), + } + defaultBarAsset = balancer.PoolAsset{ + Weight: sdk.NewInt(100), + Token: sdk.NewCoin(token, sdk.NewInt(10000)), + } + + poolAssets = []balancer.PoolAsset{defaultFooAsset, defaultBarAsset} + ) + + poolParams := balancer.PoolParams{ + SwapFee: sdk.NewDecWithPrec(1, 2), + ExitFee: sdk.NewDecWithPrec(1, 2), + } + msg := balancer.NewMsgCreateBalancerPool(acc1, poolParams, poolAssets, defaultFutureGovernor) + + poolId, err := chain.GetOsmosisApp().GAMMKeeper.CreatePool(chain.GetContext(), msg) + suite.Require().NoError(err) + + pool, err := chain.GetOsmosisApp().GAMMKeeper.GetPoolAndPoke(chain.GetContext(), poolId) + suite.Require().NoError(err) + + pools = append(pools, pool) + } + + return pools +} + +func (suite *HooksTestSuite) SetupCrosschainSwaps(chainName Chain, withAckTracking bool) (sdk.AccAddress, sdk.AccAddress) { + chain := suite.GetChain(chainName) + owner := chain.SenderAccount.GetAddress() + + // Fund the account with some uosmo and some stake + bankKeeper := chain.GetOsmosisApp().BankKeeper + i, ok := sdk.NewIntFromString("20000000000000000000000") + suite.Require().True(ok) + amounts := sdk.NewCoins(sdk.NewCoin("uosmo", i), sdk.NewCoin("stake", i), sdk.NewCoin("token0", i), sdk.NewCoin("token1", i)) + err := bankKeeper.MintCoins(chain.GetContext(), minttypes.ModuleName, amounts) + suite.Require().NoError(err) + err = bankKeeper.SendCoinsFromModuleToAccount(chain.GetContext(), minttypes.ModuleName, owner, amounts) + suite.Require().NoError(err) + + suite.SetupPools(chainName, []sdk.Dec{sdk.NewDec(20), sdk.NewDec(20)}) + + // Setup contract + chain.StoreContractCode(&suite.Suite, "./bytecode/swaprouter.wasm") + swaprouterAddr := chain.InstantiateContract(&suite.Suite, + fmt.Sprintf(`{"owner": "%s"}`, owner), 1) + chain.StoreContractCode(&suite.Suite, "./bytecode/crosschain_swaps.wasm") + trackAcks := "false" + if withAckTracking { + trackAcks = "true" + } + // Configuring two prefixes for the same channel here. This is so that we can test bad acks when the receiver can't handle the receiving addr + channels := `[["osmo", "channel-0"],["juno", "channel-0"]]` + crosschainAddr := chain.InstantiateContract(&suite.Suite, + fmt.Sprintf(`{"swap_contract": "%s", "track_ibc_sends": %s, "channels": %s}`, swaprouterAddr, trackAcks, channels), 2) + + osmosisApp := chain.GetOsmosisApp() + contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(osmosisApp.WasmKeeper) + + ctx := chain.GetContext() + + // ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins + msg := `{"set_route":{"input_denom":"token0","output_denom":"token1","pool_route":[{"pool_id":"1","token_out_denom":"stake"},{"pool_id":"2","token_out_denom":"token1"}]}}` + _, err = contractKeeper.Execute(ctx, swaprouterAddr, owner, []byte(msg), sdk.NewCoins()) + suite.Require().NoError(err) + + // Move forward one block + chain.NextBlock() + chain.Coordinator.IncrementTime() + + // Update both clients + err = suite.path.EndpointA.UpdateClient() + suite.Require().NoError(err) + err = suite.path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + return swaprouterAddr, crosschainAddr +} + +func (suite *HooksTestSuite) TestCrosschainSwaps() { + owner := suite.chainA.SenderAccount.GetAddress() + _, crosschainAddr := suite.SetupCrosschainSwaps(ChainA, true) + osmosisApp := suite.chainA.GetOsmosisApp() + contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(osmosisApp.WasmKeeper) + + balanceSender := osmosisApp.BankKeeper.GetBalance(suite.chainA.GetContext(), owner, "token0") + + ctx := suite.chainA.GetContext() + + msg := fmt.Sprintf(`{"osmosis_swap":{"input_coin":{"denom":"token0","amount":"1000"},"output_denom":"token1","slippage":{"max_slippage_percentage":"20"},"receiver":"%s"}}`, + suite.chainB.SenderAccount.GetAddress(), + ) + res, err := contractKeeper.Execute(ctx, crosschainAddr, owner, []byte(msg), sdk.NewCoins(sdk.NewCoin("token0", sdk.NewInt(1000)))) + suite.Require().NoError(err) + suite.Require().Contains(string(res), "Sent") + suite.Require().Contains(string(res), "token1") + suite.Require().Contains(string(res), fmt.Sprintf("to channel-0/%s", suite.chainB.SenderAccount.GetAddress())) + + balanceSender2 := osmosisApp.BankKeeper.GetBalance(suite.chainA.GetContext(), owner, "token0") + suite.Require().Equal(int64(1000), balanceSender.Amount.Sub(balanceSender2.Amount).Int64()) +} + +// Crosschain swaps should successfully work with and without ack tracking. Only BadAcks depend on ack tracking. +func (suite *HooksTestSuite) TestCrosschainSwapsViaIBCWithoutAckTracking() { + suite.CrosschainSwapsViaIBCTest(false) +} +func (suite *HooksTestSuite) TestCrosschainSwapsViaIBCWithAckTracking() { + suite.CrosschainSwapsViaIBCTest(true) +} + +func (suite *HooksTestSuite) CrosschainSwapsViaIBCTest(withAckTracking bool) { + initializer := suite.chainB.SenderAccount.GetAddress() + _, crosschainAddr := suite.SetupCrosschainSwaps(ChainA, withAckTracking) + // Send some token0 tokens to B so that there are ibc tokens to send to A and crosschain-swap + transferMsg := NewMsgTransfer(sdk.NewCoin("token0", sdk.NewInt(2000)), suite.chainA.SenderAccount.GetAddress().String(), initializer.String(), "") + suite.FullSend(transferMsg, AtoB) + + // Calculate the names of the tokens when swapped via IBC + denomTrace0 := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", "channel-0", "token0")) + token0IBC := denomTrace0.IBCDenom() + denomTrace1 := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", "channel-0", "token1")) + token1IBC := denomTrace1.IBCDenom() + + osmosisAppB := suite.chainB.GetOsmosisApp() + balanceToken0 := osmosisAppB.BankKeeper.GetBalance(suite.chainB.GetContext(), initializer, token0IBC) + receiver := initializer + balanceToken1 := osmosisAppB.BankKeeper.GetBalance(suite.chainB.GetContext(), receiver, token1IBC) + + suite.Require().Equal(int64(0), balanceToken1.Amount.Int64()) + + // Generate swap instructions for the contract + swapMsg := fmt.Sprintf(`{"osmosis_swap":{"input_coin":{"denom":"token0","amount":"1000"},"output_denom":"token1","slippage":{"max_slippage_percentage":"20"},"receiver":"%s"}}`, + receiver, + ) + // Generate full memo + msg := fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": %s } }`, crosschainAddr, swapMsg) + // Send IBC transfer with the memo with crosschain-swap instructions + transferMsg = NewMsgTransfer(sdk.NewCoin(token0IBC, sdk.NewInt(1000)), suite.chainB.SenderAccount.GetAddress().String(), crosschainAddr.String(), msg) + _, receiveResult, _, err := suite.FullSend(transferMsg, BtoA) + + // We use the receive result here because the receive adds another packet to be sent back + suite.Require().NoError(err) + suite.Require().NotNil(receiveResult) + + // "Relay the packet" by executing the receive on chain B + packet, err := ibctesting.ParsePacketFromEvents(receiveResult.GetEvents()) + suite.Require().NoError(err) + suite.RelayPacket(packet, AtoB) + + balanceToken0After := osmosisAppB.BankKeeper.GetBalance(suite.chainB.GetContext(), initializer, token0IBC) + suite.Require().Equal(int64(1000), balanceToken0.Amount.Sub(balanceToken0After.Amount).Int64()) + + balanceToken1After := osmosisAppB.BankKeeper.GetBalance(suite.chainB.GetContext(), receiver, token1IBC) + suite.Require().Greater(balanceToken1After.Amount.Int64(), int64(0)) +} + +// This is a copy of the above to test bad acks. Lots of repetition here could be abstracted, but keeping as-is for +// now to avoid complexity +// The main difference between this test and the above one is that the receiver specified in the memo does not +// exist on chain B +func (suite *HooksTestSuite) TestCrosschainSwapsViaIBCBadAck() { + initializer := suite.chainB.SenderAccount.GetAddress() + _, crosschainAddr := suite.SetupCrosschainSwaps(ChainA, true) + // Send some token0 tokens to B so that there are ibc tokens to send to A and crosschain-swap + transferMsg := NewMsgTransfer(sdk.NewCoin("token0", sdk.NewInt(2000)), suite.chainA.SenderAccount.GetAddress().String(), initializer.String(), "") + suite.FullSend(transferMsg, AtoB) + + // Calculate the names of the tokens when swapped via IBC + denomTrace0 := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", "channel-0", "token0")) + token0IBC := denomTrace0.IBCDenom() + + osmosisAppB := suite.chainB.GetOsmosisApp() + balanceToken0 := osmosisAppB.BankKeeper.GetBalance(suite.chainB.GetContext(), initializer, token0IBC) + receiver := "juno1ka8v934kgrw6679fs9cuu0kesyl0ljjy4tmycx" // Will not exist on chainB + + // Generate swap instructions for the contract. This will send correctly on chainA, but fail to be received on chainB + recoverAddr := suite.chainA.SenderAccounts[8].SenderAccount.GetAddress() + swapMsg := fmt.Sprintf(`{"osmosis_swap":{"input_coin":{"denom":"token0","amount":"1000"},"output_denom":"token1","slippage":{"max_slippage_percentage":"20"},"receiver":"%s","failed_delivery": {"recovery_addr": "%s"}}}`, + receiver, // Note that this is the chain A account, which does not exist on chain B + recoverAddr, + ) + // Generate full memo + msg := fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": %s } }`, crosschainAddr, swapMsg) + // Send IBC transfer with the memo with crosschain-swap instructions + transferMsg = NewMsgTransfer(sdk.NewCoin(token0IBC, sdk.NewInt(1000)), suite.chainB.SenderAccount.GetAddress().String(), crosschainAddr.String(), msg) + _, receiveResult, _, err := suite.FullSend(transferMsg, BtoA) + + // We use the receive result here because the receive adds another packet to be sent back + suite.Require().NoError(err) + suite.Require().NotNil(receiveResult) + + // "Relay the packet" by executing the receive on chain B + packet, err := ibctesting.ParsePacketFromEvents(receiveResult.GetEvents()) + suite.Require().NoError(err) + _, ack2 := suite.RelayPacket(packet, AtoB) + fmt.Println(string(ack2)) + + balanceToken0After := osmosisAppB.BankKeeper.GetBalance(suite.chainB.GetContext(), initializer, token0IBC) + suite.Require().Equal(int64(1000), balanceToken0.Amount.Sub(balanceToken0After.Amount).Int64()) + + // The balance is stuck in the contract + osmosisAppA := suite.chainA.GetOsmosisApp() + balanceContract := osmosisAppA.BankKeeper.GetBalance(suite.chainA.GetContext(), crosschainAddr, "token1") + suite.Require().Greater(balanceContract.Amount.Int64(), int64(0)) + + // check that the contract knows this + state := suite.chainA.QueryContract( + &suite.Suite, crosschainAddr, + []byte(fmt.Sprintf(`{"recoverable": {"addr": "%s"}}`, recoverAddr))) + suite.Require().Contains(state, "token1") + suite.Require().Contains(state, `"sequence":2`) + + // Recover the stuck amount + recoverMsg := `{"recover": {}}` + contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(osmosisAppA.WasmKeeper) + _, err = contractKeeper.Execute(suite.chainA.GetContext(), crosschainAddr, recoverAddr, []byte(recoverMsg), sdk.NewCoins()) + suite.Require().NoError(err) + + balanceRecovery := osmosisAppA.BankKeeper.GetBalance(suite.chainA.GetContext(), recoverAddr, "token1") + suite.Require().Greater(balanceRecovery.Amount.Int64(), int64(0)) +} + +func (suite *HooksTestSuite) TestBadCrosschainSwapsNextMemoMessages() { + initializer := suite.chainB.SenderAccount.GetAddress() + _, crosschainAddr := suite.SetupCrosschainSwaps(ChainA, true) + // Send some token0 tokens to B so that there are ibc tokens to send to A and crosschain-swap + transferMsg := NewMsgTransfer(sdk.NewCoin("token0", sdk.NewInt(20000)), suite.chainA.SenderAccount.GetAddress().String(), initializer.String(), "") + suite.FullSend(transferMsg, AtoB) + + // Calculate the names of the tokens when swapped via IBC + denomTrace0 := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", "channel-0", "token0")) + token0IBC := denomTrace0.IBCDenom() + + recoverAddr := suite.chainA.SenderAccounts[8].SenderAccount.GetAddress() + receiver := initializer + + innerMsg := fmt.Sprintf(`{"osmosis_swap":{"input_coin":{"denom":"token0","amount":"1000"},"output_denom":"token1","slippage":{"max_slippage_percentage":"20"},"receiver":"%s","failed_delivery": {"recovery_addr": "%s"},"next_memo":%%s}}`, + receiver, // Note that this is the chain A account, which does not exist on chain B + recoverAddr) + + testCases := []struct { + memo string + expPass bool + }{ + {fmt.Sprintf(innerMsg, `1`), false}, + {fmt.Sprintf(innerMsg, `""`), false}, + {fmt.Sprintf(innerMsg, `null`), true}, + {fmt.Sprintf(innerMsg, `"{\"ibc_callback\": \"something\"}"`), false}, + {fmt.Sprintf(innerMsg, `"{\"myKey\": \"myValue\"}"`), true}, + {fmt.Sprintf(innerMsg, `"{}""`), true}, + } + + for _, tc := range testCases { + // Generate swap instructions for the contract. This will send correctly on chainA, but fail to be received on chainB + // Generate full memo + msg := fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": %s } }`, crosschainAddr, tc.memo) + // Send IBC transfer with the memo with crosschain-swap instructions + transferMsg = NewMsgTransfer(sdk.NewCoin(token0IBC, sdk.NewInt(1000)), suite.chainB.SenderAccount.GetAddress().String(), crosschainAddr.String(), msg) + _, _, ack, _ := suite.FullSend(transferMsg, BtoA) + if tc.expPass { + fmt.Println(ack) + suite.Require().Contains(ack, "result", tc.memo) + } else { + suite.Require().Contains(ack, "error", tc.memo) + } + } +} + +func (suite *HooksTestSuite) CreateIBCPoolOnChainB() { + chain := suite.GetChain(ChainB) + acc1 := chain.SenderAccount.GetAddress() + bondDenom := chain.GetOsmosisApp().StakingKeeper.BondDenom(chain.GetContext()) + + multiplier := sdk.NewDec(20) + denomTrace1 := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", "channel-0", "token1")) + token1IBC := denomTrace1.IBCDenom() + + uosmoAmount := gammtypes.InitPoolSharesSupply.ToDec().Mul(multiplier).RoundInt() + + defaultFutureGovernor := "" + + // pool assets + defaultFooAsset := balancer.PoolAsset{ + Weight: sdk.NewInt(100), + Token: sdk.NewCoin(bondDenom, uosmoAmount), + } + defaultBarAsset := balancer.PoolAsset{ + Weight: sdk.NewInt(100), + Token: sdk.NewCoin(token1IBC, sdk.NewInt(10000)), + } + + poolAssets := []balancer.PoolAsset{defaultFooAsset, defaultBarAsset} + + poolParams := balancer.PoolParams{ + SwapFee: sdk.NewDecWithPrec(1, 2), + ExitFee: sdk.NewDecWithPrec(1, 2), + } + msg := balancer.NewMsgCreateBalancerPool(acc1, poolParams, poolAssets, defaultFutureGovernor) + + poolId, err := chain.GetOsmosisApp().GAMMKeeper.CreatePool(chain.GetContext(), msg) + suite.Require().NoError(err) + + _, err = chain.GetOsmosisApp().GAMMKeeper.GetPoolAndPoke(chain.GetContext(), poolId) + suite.Require().NoError(err) + +} + +func (suite *HooksTestSuite) SetupIBCRouteOnChainB(swaprouterAddr, owner sdk.AccAddress) { + chain := suite.GetChain(ChainB) + denomTrace1 := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", "channel-0", "token1")) + token1IBC := denomTrace1.IBCDenom() + + msg := fmt.Sprintf(`{"set_route":{"input_denom":"%s","output_denom":"token0","pool_route":[{"pool_id":"3","token_out_denom":"stake"},{"pool_id":"1","token_out_denom":"token0"}]}}`, + token1IBC) + osmosisApp := chain.GetOsmosisApp() + contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(osmosisApp.WasmKeeper) + _, err := contractKeeper.Execute(chain.GetContext(), swaprouterAddr, owner, []byte(msg), sdk.NewCoins()) + suite.Require().NoError(err) + + // Move forward one block + chain.NextBlock() + chain.Coordinator.IncrementTime() + + // Update both clients + err = suite.path.EndpointA.UpdateClient() + suite.Require().NoError(err) + err = suite.path.EndpointB.UpdateClient() + suite.Require().NoError(err) + +} + +func (suite *HooksTestSuite) TestCrosschainForwardWithMemo() { + initializer := suite.chainB.SenderAccount.GetAddress() + receiver := suite.chainA.SenderAccount.GetAddress() + + _, crosschainAddrA := suite.SetupCrosschainSwaps(ChainA, true) + swapRouterAddrB, crosschainAddrB := suite.SetupCrosschainSwaps(ChainB, true) + // Send some token0 and token1 tokens to B so that there are ibc token0 to send to A and crosschain-swap, and token1 to create the pool + transferMsg := NewMsgTransfer(sdk.NewCoin("token0", sdk.NewInt(500000)), suite.chainA.SenderAccount.GetAddress().String(), initializer.String(), "") + suite.FullSend(transferMsg, AtoB) + transferMsg1 := NewMsgTransfer(sdk.NewCoin("token1", sdk.NewInt(500000)), suite.chainA.SenderAccount.GetAddress().String(), initializer.String(), "") + suite.FullSend(transferMsg1, AtoB) + suite.CreateIBCPoolOnChainB() + suite.SetupIBCRouteOnChainB(swapRouterAddrB, suite.chainB.SenderAccount.GetAddress()) + + // Calculate the names of the tokens when swapped via IBC + denomTrace0 := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", "channel-0", "token0")) + token0IBC := denomTrace0.IBCDenom() + denomTrace1 := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", "channel-0", "token1")) + token1IBC := denomTrace1.IBCDenom() + + balanceToken0IBCBefore := suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), receiver, token0IBC) + fmt.Println("receiver now has: ", balanceToken0IBCBefore) + suite.Require().Equal(int64(0), balanceToken0IBCBefore.Amount.Int64()) + + //suite.Require().Equal(int64(0), balanceToken1.Amount.Int64()) + + // Generate swap instructions for the contract + nextMemo := fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"osmosis_swap":{"input_coin":{"denom":"%s","amount":"800"},"output_denom":"token0","slippage":{"max_slippage_percentage":"20"},"receiver":"%s"}}}}`, + crosschainAddrB, + token1IBC, + receiver, + ) + swapMsg := fmt.Sprintf(`{"osmosis_swap":{"input_coin":{"denom":"token0","amount":"1000"},"output_denom":"token1","slippage":{"max_slippage_percentage":"20"},"receiver":"%s", "next_memo": %#v}}`, + crosschainAddrB, + nextMemo, + ) + fmt.Println(swapMsg) + // Generate full memo + msg := fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": %s } }`, crosschainAddrA, swapMsg) + // Send IBC transfer with the memo with crosschain-swap instructions + transferMsg = NewMsgTransfer(sdk.NewCoin(token0IBC, sdk.NewInt(1000)), suite.chainB.SenderAccount.GetAddress().String(), crosschainAddrA.String(), msg) + _, receiveResult, _, err := suite.FullSend(transferMsg, BtoA) + + // We use the receive result here because the receive adds another packet to be sent back + suite.Require().NoError(err) + suite.Require().NotNil(receiveResult) + + // "Relay the packet" by executing the receive on chain B + packet, err := ibctesting.ParsePacketFromEvents(receiveResult.GetEvents()) + suite.Require().NoError(err) + relayResult, _ := suite.RelayPacket(packet, AtoB) + + // Now that chain B has processed it, it should be sending a message to chain A. Relay the response + packet2, err := ibctesting.ParsePacketFromEvents(relayResult.GetEvents()) + suite.Require().NoError(err) + suite.RelayPacket(packet2, BtoA) + + balanceToken0IBCAfter := suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), receiver, token0IBC) + fmt.Println("receiver now has: ", balanceToken0IBCAfter) + suite.Require().Greater(balanceToken0IBCAfter.Amount.Int64(), int64(0)) +} + +func (suite *HooksTestSuite) GetChain(name Chain) *osmosisibctesting.TestChain { + if name == ChainA { + return suite.chainA + } else { + return suite.chainB + } +} diff --git a/x/ibc-hooks/testutils/Cargo.toml b/tests/ibc-hooks/testutils/Cargo.toml similarity index 100% rename from x/ibc-hooks/testutils/Cargo.toml rename to tests/ibc-hooks/testutils/Cargo.toml diff --git a/x/ibc-hooks/testutils/contracts/counter/Cargo.toml b/tests/ibc-hooks/testutils/contracts/counter/Cargo.toml similarity index 100% rename from x/ibc-hooks/testutils/contracts/counter/Cargo.toml rename to tests/ibc-hooks/testutils/contracts/counter/Cargo.toml diff --git a/x/ibc-hooks/testutils/contracts/counter/README.md b/tests/ibc-hooks/testutils/contracts/counter/README.md similarity index 100% rename from x/ibc-hooks/testutils/contracts/counter/README.md rename to tests/ibc-hooks/testutils/contracts/counter/README.md diff --git a/x/ibc-hooks/testutils/contracts/counter/src/contract.rs b/tests/ibc-hooks/testutils/contracts/counter/src/contract.rs similarity index 62% rename from x/ibc-hooks/testutils/contracts/counter/src/contract.rs rename to tests/ibc-hooks/testutils/contracts/counter/src/contract.rs index be67b59302b..963973a92a8 100644 --- a/x/ibc-hooks/testutils/contracts/counter/src/contract.rs +++ b/tests/ibc-hooks/testutils/contracts/counter/src/contract.rs @@ -36,6 +36,40 @@ pub fn instantiate( .add_attribute("count", msg.count.to_string())) } +pub mod utils { + use cosmwasm_std::Addr; + + use super::*; + + pub fn update_counter( + deps: DepsMut, + sender: Addr, + update_counter: &dyn Fn(&Option) -> i32, + update_funds: &dyn Fn(&Option) -> Vec, + ) -> Result { + COUNTERS + .update( + deps.storage, + sender.clone(), + |state| -> Result<_, ContractError> { + match state { + None => Ok(Counter { + count: update_counter(&None), + total_funds: update_funds(&None), + owner: sender, + }), + Some(counter) => Ok(Counter { + count: update_counter(&Some(counter.clone())), + total_funds: update_funds(&Some(counter)), + owner: sender, + }), + } + }, + ) + .map(|_r| true) + } +} + #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( deps: DepsMut, @@ -53,47 +87,76 @@ pub mod execute { use super::*; pub fn increment(deps: DepsMut, info: MessageInfo) -> Result { - COUNTERS.update( - deps.storage, - info.sender.clone(), - |state| -> Result<_, ContractError> { - match state { - None => Ok(Counter { - count: 0, - total_funds: vec![], - owner: info.sender.clone(), - }), - Some(counter) => Ok(Counter { - count: counter.count + 1, - total_funds: naive_add_coins(&info.funds, &counter.total_funds), - owner: info.sender.clone(), - }), - } + utils::update_counter( + deps, + info.sender, + &|counter| match counter { + None => 0, + Some(counter) => counter.count + 1, + }, + &|counter| match counter { + None => info.funds.clone(), + Some(counter) => naive_add_coins(&info.funds, &counter.total_funds), }, )?; - Ok(Response::new().add_attribute("action", "increment")) } pub fn reset(deps: DepsMut, info: MessageInfo, count: i32) -> Result { - COUNTERS.update( - deps.storage, - info.sender.clone(), - |state| -> Result<_, ContractError> { - match state { - None => Err(ContractError::Unauthorized {}), - Some(state) if state.owner != info.sender.clone() => { - Err(ContractError::Unauthorized {}) - } - _ => Ok(Counter { - count, - total_funds: vec![], - owner: info.sender.clone(), - }), - } + utils::update_counter(deps, info.sender, &|_counter| count, &|_counter| vec![])?; + Ok(Response::new().add_attribute("action", "reset")) + } +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result { + match msg { + SudoMsg::ReceiveAck { + channel: _, + sequence: _, + ack: _, + success, + } => sudo::receive_ack(deps, env.contract.address, success), + SudoMsg::IBCTimeout { + channel: _, + sequence: _, + } => sudo::ibc_timeout(deps, env.contract.address), + } +} + +pub mod sudo { + use cosmwasm_std::Addr; + + use super::*; + + pub fn receive_ack( + deps: DepsMut, + contract: Addr, + _success: bool, + ) -> Result { + utils::update_counter( + deps, + contract, + &|counter| match counter { + None => 1, + Some(counter) => counter.count + 1, }, + &|_counter| vec![], )?; - Ok(Response::new().add_attribute("action", "reset")) + Ok(Response::new().add_attribute("action", "ack")) + } + + pub(crate) fn ibc_timeout(deps: DepsMut, contract: Addr) -> Result { + utils::update_counter( + deps, + contract, + &|counter| match counter { + None => 10, + Some(counter) => counter.count + 10, + }, + &|_counter| vec![], + )?; + Ok(Response::new().add_attribute("action", "timeout")) } } @@ -106,7 +169,6 @@ pub fn naive_add_coins(lhs: &Vec, rhs: &Vec) -> Vec { coins.insert(coin.denom.clone(), coin.amount); } - for coin in rhs { coins .entry(coin.denom.clone()) @@ -260,12 +322,20 @@ mod tests { // beneficiary can release it let unauth_info = mock_info("anyone", &coins(2, "token")); - let msg = ExecuteMsg::Reset { count: 5 }; - let res = execute(deps.as_mut(), mock_env(), unauth_info, msg); - match res { - Err(ContractError::Unauthorized {}) => {} - _ => panic!("Must return unauthorized error"), - } + let msg = ExecuteMsg::Reset { count: 7 }; + let _res = execute(deps.as_mut(), mock_env(), unauth_info, msg); + + // should be 7 + let res = query( + deps.as_ref(), + mock_env(), + QueryMsg::GetCount { + addr: Addr::unchecked("anyone"), + }, + ) + .unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(7, value.count); // only the original creator can reset the counter let auth_info = mock_info("creator", &coins(2, "token")); @@ -284,4 +354,42 @@ mod tests { let value: GetCountResponse = from_binary(&res).unwrap(); assert_eq!(5, value.count); } + + #[test] + fn acks() { + let mut deps = mock_dependencies(); + let env = mock_env(); + let get_msg = QueryMsg::GetCount { + addr: Addr::unchecked(env.clone().contract.address), + }; + + // No acks + query(deps.as_ref(), env.clone(), get_msg.clone()).unwrap_err(); + + let msg = SudoMsg::ReceiveAck { + channel: format!("channel-0"), + sequence: 1, + ack: String::new(), + success: true, + }; + let _res = sudo(deps.as_mut(), env.clone(), msg).unwrap(); + + // should increase counter by 1 + let res = query(deps.as_ref(), env.clone(), get_msg.clone()).unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(1, value.count); + + let msg = SudoMsg::ReceiveAck { + channel: format!("channel-0"), + sequence: 1, + ack: String::new(), + success: true, + }; + let _res = sudo(deps.as_mut(), env.clone(), msg).unwrap(); + + // should increase counter by 1 + let res = query(deps.as_ref(), env, get_msg).unwrap(); + let value: GetCountResponse = from_binary(&res).unwrap(); + assert_eq!(2, value.count); + } } diff --git a/x/ibc-hooks/testutils/contracts/counter/src/error.rs b/tests/ibc-hooks/testutils/contracts/counter/src/error.rs similarity index 100% rename from x/ibc-hooks/testutils/contracts/counter/src/error.rs rename to tests/ibc-hooks/testutils/contracts/counter/src/error.rs diff --git a/x/ibc-hooks/testutils/contracts/counter/src/helpers.rs b/tests/ibc-hooks/testutils/contracts/counter/src/helpers.rs similarity index 100% rename from x/ibc-hooks/testutils/contracts/counter/src/helpers.rs rename to tests/ibc-hooks/testutils/contracts/counter/src/helpers.rs diff --git a/x/ibc-hooks/testutils/contracts/counter/src/integration_tests.rs b/tests/ibc-hooks/testutils/contracts/counter/src/integration_tests.rs similarity index 100% rename from x/ibc-hooks/testutils/contracts/counter/src/integration_tests.rs rename to tests/ibc-hooks/testutils/contracts/counter/src/integration_tests.rs diff --git a/x/ibc-hooks/testutils/contracts/counter/src/lib.rs b/tests/ibc-hooks/testutils/contracts/counter/src/lib.rs similarity index 100% rename from x/ibc-hooks/testutils/contracts/counter/src/lib.rs rename to tests/ibc-hooks/testutils/contracts/counter/src/lib.rs diff --git a/x/ibc-hooks/testutils/contracts/counter/src/msg.rs b/tests/ibc-hooks/testutils/contracts/counter/src/msg.rs similarity index 74% rename from x/ibc-hooks/testutils/contracts/counter/src/msg.rs rename to tests/ibc-hooks/testutils/contracts/counter/src/msg.rs index 6c29fdf2508..db85e9ad4e5 100644 --- a/x/ibc-hooks/testutils/contracts/counter/src/msg.rs +++ b/tests/ibc-hooks/testutils/contracts/counter/src/msg.rs @@ -32,3 +32,15 @@ pub struct GetCountResponse { pub struct GetTotalFundsResponse { pub total_funds: Vec, } + +#[cw_serde] +pub enum SudoMsg { + ReceiveAck { + channel: String, + sequence: u64, + ack: String, + success: bool, + }, + #[serde(rename = "ibc_timeout")] + IBCTimeout { channel: String, sequence: u64 }, +} diff --git a/x/ibc-hooks/testutils/contracts/counter/src/state.rs b/tests/ibc-hooks/testutils/contracts/counter/src/state.rs similarity index 100% rename from x/ibc-hooks/testutils/contracts/counter/src/state.rs rename to tests/ibc-hooks/testutils/contracts/counter/src/state.rs diff --git a/x/ibc-hooks/testutils/contracts/echo/Cargo.toml b/tests/ibc-hooks/testutils/contracts/echo/Cargo.toml similarity index 100% rename from x/ibc-hooks/testutils/contracts/echo/Cargo.toml rename to tests/ibc-hooks/testutils/contracts/echo/Cargo.toml diff --git a/x/ibc-hooks/testutils/contracts/echo/src/lib.rs b/tests/ibc-hooks/testutils/contracts/echo/src/lib.rs similarity index 100% rename from x/ibc-hooks/testutils/contracts/echo/src/lib.rs rename to tests/ibc-hooks/testutils/contracts/echo/src/lib.rs diff --git a/x/ibc-hooks/testutils/testing_hooks.go b/tests/ibc-hooks/testutils/testing_hooks.go similarity index 84% rename from x/ibc-hooks/testutils/testing_hooks.go rename to tests/ibc-hooks/testutils/testing_hooks.go index 3b9671c03fc..cce68c627f2 100644 --- a/x/ibc-hooks/testutils/testing_hooks.go +++ b/tests/ibc-hooks/testutils/testing_hooks.go @@ -5,10 +5,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" // ibc-go - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibchooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks" + ibchooks "github.com/osmosis-labs/osmosis/x/ibc-hooks" ) var ( diff --git a/wasmbinding/stargate_whitelist.go b/wasmbinding/stargate_whitelist.go index e3fd3fae74e..f1527345f0f 100644 --- a/wasmbinding/stargate_whitelist.go +++ b/wasmbinding/stargate_whitelist.go @@ -13,6 +13,7 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + downtimequerytypes "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto" epochtypes "github.com/osmosis-labs/osmosis/v13/x/epochs/types" gammtypes "github.com/osmosis-labs/osmosis/v13/x/gamm/types" gammv2types "github.com/osmosis-labs/osmosis/v13/x/gamm/v2types" @@ -84,6 +85,7 @@ func init() { setWhitelistedQuery("/osmosis.gamm.v1beta1.Query/PoolType", &gammtypes.QueryPoolTypeResponse{}) setWhitelistedQuery("/osmosis.gamm.v2.Query/SpotPrice", &gammv2types.QuerySpotPriceResponse{}) setWhitelistedQuery("/osmosis.gamm.v1beta1.Query/EstimateSwapExactAmountIn", &gammtypes.QuerySwapExactAmountInResponse{}) + setWhitelistedQuery("/osmosis.gamm.v1beta1.Query/EstimateSwapExactAmountOut", &gammtypes.QuerySwapExactAmountOutResponse{}) // incentives setWhitelistedQuery("/osmosis.incentives.Query/ModuleToDistributeCoins", &incentivestypes.ModuleToDistributeCoinsResponse{}) @@ -123,7 +125,12 @@ func init() { // twap setWhitelistedQuery("/osmosis.twap.v1beta1.Query/ArithmeticTwap", &twapquerytypes.ArithmeticTwapResponse{}) setWhitelistedQuery("/osmosis.twap.v1beta1.Query/ArithmeticTwapToNow", &twapquerytypes.ArithmeticTwapToNowResponse{}) + setWhitelistedQuery("/osmosis.twap.v1beta1.Query/GeometricTwap", &twapquerytypes.GeometricTwapResponse{}) + setWhitelistedQuery("/osmosis.twap.v1beta1.Query/GeometricTwapToNow", &twapquerytypes.GeometricTwapToNowResponse{}) setWhitelistedQuery("/osmosis.twap.v1beta1.Query/Params", &twapquerytypes.ParamsResponse{}) + + // downtime-detector + setWhitelistedQuery("/osmosis.downtimedetector.v1beta1.Query/RecoveredSinceDowntimeOfLength", &downtimequerytypes.RecoveredSinceDowntimeOfLengthResponse{}) } // GetWhitelistedQuery returns the whitelisted query at the provided path. diff --git a/wasmbinding/test/custom_query_test.go b/wasmbinding/test/custom_query_test.go index 639889f03cb..cb015fc9edd 100644 --- a/wasmbinding/test/custom_query_test.go +++ b/wasmbinding/test/custom_query_test.go @@ -1,6 +1,7 @@ package wasmbinding import ( + "crypto/sha256" "encoding/json" "fmt" "os" @@ -305,6 +306,8 @@ func storeReflectCode(t *testing.T, ctx sdk.Context, osmosis *app.OsmosisApp, ad src := wasmtypes.StoreCodeProposalFixture(func(p *wasmtypes.StoreCodeProposal) { p.RunAs = addr.String() p.WASMByteCode = wasmCode + checksum := sha256.Sum256(wasmCode) + p.CodeHash = checksum[:] }) // when stored diff --git a/wasmbinding/test/store_run_test.go b/wasmbinding/test/store_run_test.go index 6f276149818..8fca6baf600 100644 --- a/wasmbinding/test/store_run_test.go +++ b/wasmbinding/test/store_run_test.go @@ -1,6 +1,7 @@ package wasmbinding import ( + "crypto/sha256" "encoding/json" "os" "testing" @@ -41,6 +42,8 @@ func storeCodeViaProposal(t *testing.T, ctx sdk.Context, osmosis *app.OsmosisApp src := types.StoreCodeProposalFixture(func(p *types.StoreCodeProposal) { p.RunAs = addr.String() p.WASMByteCode = wasmCode + checksum := sha256.Sum256(wasmCode) + p.CodeHash = checksum[:] }) // when stored diff --git a/x/downtime-detector/README.md b/x/downtime-detector/README.md new file mode 100644 index 00000000000..938354186de --- /dev/null +++ b/x/downtime-detector/README.md @@ -0,0 +1,30 @@ +# Downtime-detector + +For several use cases, we need a module that can detect when the chain is recovering from downtime. We want to be able to efficiently know "Has it been $RECOVERY_PERIOD minutes since the chain has been down for $DOWNTIME_PERIOD", and expose this as a query to contracts. + +So for instance, you'd want to know if it has been at least 10 minutes, since the chain was down for > 30 minutes. Since you assume in such an event that it may take ~10 minutes for price oracles to be arb'd to correct. +Suggested Design + +Theres a couple designs, such as: + +* Iterating over block times from the last N blocks (with a heuristic filter based on average block time) + * Implies bounds on recovery time + * Linear iteration if heuristic is met + * Requires encoding expected block time +* Restricting downtime period, and storing a state entry for last time a downtime of length $D occurred + +Because this will be in important txs for contracts, we need to go with the approach that has minimal query compute, which is the latter. So we explain that in more depth. + +We restrict the $DOWNTIME_PERIOD options that you can query, to be: 30seconds, 1 min, 2 min, 3 min, 4 min, 5 min, 10 min, 20 min, 30 min, 40 min, 50 min, 1 hr, 1.5hr, 2 hr, 2.5 hr, 3 hr, 4 hr, 5 hr, 6 hr, 9hr, 12hr, 18hr, 24hr, 36hr, 48hr. + +In the downtime detector module, we store state entries for: + +* Last blocks timestamp +* For each period, last time there was downtime + +Then in every begin block: + +* Store last blocks timestamp +* if time since last block timestamp >= 30 seconds, iterate through all $DOWNTIME_PERIODS less than the downtime, and in each add a state entry for the current block time + +Then our query for has it been $RECOVERY_PERIOD since $DOWNTIME_PERIOD, simply reads the state entry for that $DOWNTIME_PERIOD, and then checks if time difference between now and that block is > RECOVERY_PERIOD. \ No newline at end of file diff --git a/x/downtime-detector/abci.go b/x/downtime-detector/abci.go new file mode 100644 index 00000000000..43803817652 --- /dev/null +++ b/x/downtime-detector/abci.go @@ -0,0 +1,37 @@ +package downtimedetector + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +func (k *Keeper) BeginBlock(ctx sdk.Context) { + curTime := ctx.BlockTime() + lastBlockTime, err := k.GetLastBlockTime(ctx) + if err != nil { + ctx.Logger().Error("Downtime-detector, could not get last block time, did initialization happen correctly. " + err.Error()) + } + downtime := curTime.Sub(lastBlockTime) + k.saveDowntimeUpdates(ctx, downtime) + k.StoreLastBlockTime(ctx, curTime) +} + +// saveDowntimeUpdates saves the current block time as the +// last time the chain was down for all downtime lengths that are LTE the provided downtime. +func (k *Keeper) saveDowntimeUpdates(ctx sdk.Context, downtime time.Duration) { + // minimum stored downtime is 30S, so if downtime is less than that, don't update anything. + if downtime < 30*time.Second { + return + } + types.DowntimeToDuration.Ascend(0, func(downType types.Downtime, duration time.Duration) bool { + // if downtime < duration of this entry, stop iterating further, don't update this entry. + if downtime < duration { + return false + } + k.StoreLastDowntimeOfLength(ctx, downType, ctx.BlockTime()) + return true + }) +} diff --git a/x/downtime-detector/client/cli/query.go b/x/downtime-detector/client/cli/query.go new file mode 100644 index 00000000000..e10262d8732 --- /dev/null +++ b/x/downtime-detector/client/cli/query.go @@ -0,0 +1,40 @@ +package cli + +import ( + "time" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + + "github.com/osmosis-labs/osmosis/osmoutils/osmocli" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +func GetQueryCmd() *cobra.Command { + cmd := osmocli.QueryIndexCmd(types.ModuleName) + osmocli.AddQueryCmd(cmd, queryproto.NewQueryClient, RecoveredSinceQueryCmd) + + return cmd +} + +func RecoveredSinceQueryCmd() (*osmocli.QueryDescriptor, *queryproto.RecoveredSinceDowntimeOfLengthRequest) { + return &osmocli.QueryDescriptor{ + Use: "recovered-since downtime-duration recovery-duration", + Short: "Queries if it has been at least since the chain was down for ", + Long: `{{.Short}} +downtime-duration is a duration, but is restricted to a smaller set. Heres a few from the set: 30s, 1m, 5m, 10m, 30m, 1h, 3 h, 6h, 12h, 24h, 36h, 48h] +{{.ExampleHeader}} +{{.CommandPrefix}} recovered-since 24h 30m`, + CustomFieldParsers: map[string]osmocli.CustomFieldParserFn{"Downtime": parseDowntimeDuration}, + }, &queryproto.RecoveredSinceDowntimeOfLengthRequest{} +} + +func parseDowntimeDuration(arg string, _ *pflag.FlagSet) (any, osmocli.FieldReadLocation, error) { + dur, err := time.ParseDuration(arg) + if err != nil { + return nil, osmocli.UsedArg, err + } + downtime, err := types.DowntimeByDuration(dur) + return downtime, osmocli.UsedArg, err +} diff --git a/x/downtime-detector/client/cli/query_test.go b/x/downtime-detector/client/cli/query_test.go new file mode 100644 index 00000000000..a9b7d6205f5 --- /dev/null +++ b/x/downtime-detector/client/cli/query_test.go @@ -0,0 +1,50 @@ +package cli_test + +import ( + "testing" + "time" + + "github.com/osmosis-labs/osmosis/osmoutils/osmocli" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/cli" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +// We test the custom duration parser via this +func TestRecoveredSinceQueryCmd(t *testing.T) { + desc, _ := cli.RecoveredSinceQueryCmd() + tcs := map[string]osmocli.QueryCliTestCase[*queryproto.RecoveredSinceDowntimeOfLengthRequest]{ + "basic test": { + Cmd: "30s 10m", + ExpectedQuery: &queryproto.RecoveredSinceDowntimeOfLengthRequest{ + Downtime: types.Downtime_DURATION_30S, + Recovery: time.Minute * 10}, + }, + "invalid duration": { + Cmd: "31s 10m", + ExpectedQuery: &queryproto.RecoveredSinceDowntimeOfLengthRequest{ + Downtime: types.Downtime_DURATION_30S, + Recovery: time.Minute * 10}, + ExpectedErr: true, + }, + "90m": { + Cmd: "90m 10m", + ExpectedQuery: &queryproto.RecoveredSinceDowntimeOfLengthRequest{ + Downtime: types.Downtime_DURATION_1_5H, + Recovery: time.Minute * 10}, + }, + "1.5h": { + Cmd: "1.5h 10m", + ExpectedQuery: &queryproto.RecoveredSinceDowntimeOfLengthRequest{ + Downtime: types.Downtime_DURATION_1_5H, + Recovery: time.Minute * 10}, + }, + "1h30m": { + Cmd: "1h30m 10m", + ExpectedQuery: &queryproto.RecoveredSinceDowntimeOfLengthRequest{ + Downtime: types.Downtime_DURATION_1_5H, + Recovery: time.Minute * 10}, + }, + } + osmocli.RunQueryTestCases(t, desc, tcs) +} diff --git a/x/downtime-detector/client/grpc/grpc_query.go b/x/downtime-detector/client/grpc/grpc_query.go new file mode 100644 index 00000000000..f304afd87ab --- /dev/null +++ b/x/downtime-detector/client/grpc/grpc_query.go @@ -0,0 +1,32 @@ +package grpc + +// THIS FILE IS GENERATED CODE, DO NOT EDIT +// SOURCE AT `proto/osmosis/downtime-detector/v1beta1/query.yml` + +import ( + context "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto" +) + +type Querier struct { + Q client.Querier +} + +var _ queryproto.QueryServer = Querier{} + +func (q Querier) RecoveredSinceDowntimeOfLength(grpcCtx context.Context, + req *queryproto.RecoveredSinceDowntimeOfLengthRequest, +) (*queryproto.RecoveredSinceDowntimeOfLengthResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(grpcCtx) + return q.Q.RecoveredSinceDowntimeOfLength(ctx, *req) +} + diff --git a/x/downtime-detector/client/query_proto_wrap.go b/x/downtime-detector/client/query_proto_wrap.go new file mode 100644 index 00000000000..35feb27c1eb --- /dev/null +++ b/x/downtime-detector/client/query_proto_wrap.go @@ -0,0 +1,22 @@ +package client + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + downtimedetector "github.com/osmosis-labs/osmosis/v13/x/downtime-detector" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto" +) + +type Querier struct { + K downtimedetector.Keeper +} + +func (querier *Querier) RecoveredSinceDowntimeOfLength(ctx sdk.Context, req queryproto.RecoveredSinceDowntimeOfLengthRequest) (*queryproto.RecoveredSinceDowntimeOfLengthResponse, error) { + val, err := querier.K.RecoveredSinceDowntimeOfLength(ctx, req.Downtime, req.Recovery) + if err != nil { + return nil, err + } + return &queryproto.RecoveredSinceDowntimeOfLengthResponse{ + SuccesfullyRecovered: val, + }, nil +} diff --git a/x/downtime-detector/client/queryproto/query.pb.go b/x/downtime-detector/client/queryproto/query.pb.go new file mode 100644 index 00000000000..0007c7010ee --- /dev/null +++ b/x/downtime-detector/client/queryproto/query.pb.go @@ -0,0 +1,632 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/downtime-detector/v1beta1/query.proto + +package queryproto + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + types "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Query for has it been at least $RECOVERY_DURATION units of time, +// since the chain has been down for $DOWNTIME_DURATION. +type RecoveredSinceDowntimeOfLengthRequest struct { + Downtime types.Downtime `protobuf:"varint,1,opt,name=downtime,proto3,enum=osmosis.downtimedetector.v1beta1.Downtime" json:"downtime,omitempty" yaml:"downtime"` + Recovery time.Duration `protobuf:"bytes,2,opt,name=recovery,proto3,stdduration" json:"recovery" yaml:"recovery_duration"` +} + +func (m *RecoveredSinceDowntimeOfLengthRequest) Reset() { *m = RecoveredSinceDowntimeOfLengthRequest{} } +func (m *RecoveredSinceDowntimeOfLengthRequest) String() string { return proto.CompactTextString(m) } +func (*RecoveredSinceDowntimeOfLengthRequest) ProtoMessage() {} +func (*RecoveredSinceDowntimeOfLengthRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_b748b3d07fa8b8cb, []int{0} +} +func (m *RecoveredSinceDowntimeOfLengthRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RecoveredSinceDowntimeOfLengthRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RecoveredSinceDowntimeOfLengthRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RecoveredSinceDowntimeOfLengthRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RecoveredSinceDowntimeOfLengthRequest.Merge(m, src) +} +func (m *RecoveredSinceDowntimeOfLengthRequest) XXX_Size() int { + return m.Size() +} +func (m *RecoveredSinceDowntimeOfLengthRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RecoveredSinceDowntimeOfLengthRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RecoveredSinceDowntimeOfLengthRequest proto.InternalMessageInfo + +func (m *RecoveredSinceDowntimeOfLengthRequest) GetDowntime() types.Downtime { + if m != nil { + return m.Downtime + } + return types.Downtime_DURATION_30S +} + +func (m *RecoveredSinceDowntimeOfLengthRequest) GetRecovery() time.Duration { + if m != nil { + return m.Recovery + } + return 0 +} + +type RecoveredSinceDowntimeOfLengthResponse struct { + SuccesfullyRecovered bool `protobuf:"varint,1,opt,name=succesfully_recovered,json=succesfullyRecovered,proto3" json:"succesfully_recovered,omitempty"` +} + +func (m *RecoveredSinceDowntimeOfLengthResponse) Reset() { + *m = RecoveredSinceDowntimeOfLengthResponse{} +} +func (m *RecoveredSinceDowntimeOfLengthResponse) String() string { return proto.CompactTextString(m) } +func (*RecoveredSinceDowntimeOfLengthResponse) ProtoMessage() {} +func (*RecoveredSinceDowntimeOfLengthResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_b748b3d07fa8b8cb, []int{1} +} +func (m *RecoveredSinceDowntimeOfLengthResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RecoveredSinceDowntimeOfLengthResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RecoveredSinceDowntimeOfLengthResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RecoveredSinceDowntimeOfLengthResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RecoveredSinceDowntimeOfLengthResponse.Merge(m, src) +} +func (m *RecoveredSinceDowntimeOfLengthResponse) XXX_Size() int { + return m.Size() +} +func (m *RecoveredSinceDowntimeOfLengthResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RecoveredSinceDowntimeOfLengthResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RecoveredSinceDowntimeOfLengthResponse proto.InternalMessageInfo + +func (m *RecoveredSinceDowntimeOfLengthResponse) GetSuccesfullyRecovered() bool { + if m != nil { + return m.SuccesfullyRecovered + } + return false +} + +func init() { + proto.RegisterType((*RecoveredSinceDowntimeOfLengthRequest)(nil), "osmosis.downtimedetector.v1beta1.RecoveredSinceDowntimeOfLengthRequest") + proto.RegisterType((*RecoveredSinceDowntimeOfLengthResponse)(nil), "osmosis.downtimedetector.v1beta1.RecoveredSinceDowntimeOfLengthResponse") +} + +func init() { + proto.RegisterFile("osmosis/downtime-detector/v1beta1/query.proto", fileDescriptor_b748b3d07fa8b8cb) +} + +var fileDescriptor_b748b3d07fa8b8cb = []byte{ + // 484 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x53, 0xcf, 0x8b, 0xd3, 0x4e, + 0x14, 0x6f, 0x0a, 0xdf, 0x2f, 0x4b, 0x04, 0x85, 0xb8, 0x42, 0xb7, 0x48, 0x52, 0x82, 0xca, 0xb2, + 0xd0, 0x19, 0xda, 0x9e, 0xf4, 0x66, 0x5d, 0xd0, 0x05, 0x41, 0x8c, 0x37, 0x45, 0xca, 0x64, 0xfa, + 0x9a, 0x1d, 0x48, 0x66, 0xb2, 0x99, 0x49, 0x35, 0x57, 0x4f, 0x1e, 0x05, 0x2f, 0xfe, 0x49, 0x7b, + 0x5c, 0xf0, 0xe2, 0xa9, 0x6a, 0xeb, 0x5f, 0xb0, 0x7f, 0x80, 0x48, 0x32, 0x99, 0x50, 0x8a, 0x6c, + 0x16, 0x3c, 0x25, 0xc3, 0xe7, 0xc7, 0x7b, 0x9f, 0xf7, 0x66, 0xec, 0xa1, 0x90, 0x89, 0x90, 0x4c, + 0xe2, 0xb9, 0x78, 0xc7, 0x15, 0x4b, 0x60, 0x38, 0x07, 0x05, 0x54, 0x89, 0x0c, 0x2f, 0x47, 0x21, + 0x28, 0x32, 0xc2, 0x67, 0x39, 0x64, 0x05, 0x4a, 0x33, 0xa1, 0x84, 0x33, 0xa8, 0xe9, 0xc8, 0xd0, + 0x0d, 0x1b, 0xd5, 0xec, 0xfe, 0x7e, 0x24, 0x22, 0x51, 0x91, 0x71, 0xf9, 0xa7, 0x75, 0x7d, 0xdc, + 0x5e, 0x26, 0x02, 0x0e, 0xa5, 0xb3, 0x16, 0x3c, 0x6c, 0x17, 0x18, 0x64, 0x36, 0xcf, 0x33, 0xa2, + 0x98, 0xe0, 0xb5, 0xd4, 0xa5, 0x95, 0x16, 0x87, 0x44, 0x42, 0x43, 0xa6, 0x82, 0x19, 0xfc, 0x68, + 0x1b, 0xaf, 0xc2, 0x35, 0xac, 0x94, 0x44, 0x8c, 0x6f, 0x7b, 0xdd, 0x8d, 0x84, 0x88, 0x62, 0xc0, + 0x24, 0x65, 0x98, 0x70, 0x2e, 0x54, 0x05, 0x9a, 0x26, 0x0f, 0x6a, 0xb4, 0x3a, 0x85, 0xf9, 0x02, + 0x13, 0x5e, 0x18, 0x48, 0x17, 0x99, 0xe9, 0x49, 0xe8, 0x83, 0xe9, 0x6f, 0x57, 0xb5, 0xd3, 0xbf, + 0xb7, 0x8b, 0x97, 0x21, 0xa5, 0x22, 0x49, 0xaa, 0x09, 0xfe, 0x4f, 0xcb, 0xbe, 0x1f, 0x00, 0x15, + 0x4b, 0xc8, 0x60, 0xfe, 0x8a, 0x71, 0x0a, 0xc7, 0xf5, 0x28, 0x5e, 0x2c, 0x9e, 0x03, 0x8f, 0xd4, + 0x69, 0x00, 0x67, 0x39, 0x48, 0xe5, 0xbc, 0xb1, 0xf7, 0xcc, 0x94, 0x7a, 0xd6, 0xc0, 0x3a, 0xbc, + 0x39, 0x3e, 0x42, 0x6d, 0x1b, 0x44, 0xc6, 0x6c, 0x7a, 0xfb, 0x72, 0xe5, 0xdd, 0x2a, 0x48, 0x12, + 0x3f, 0xf2, 0x0d, 0xd9, 0x0f, 0x1a, 0xc3, 0xd2, 0x3c, 0xd3, 0x5d, 0x14, 0xbd, 0xee, 0xc0, 0x3a, + 0xbc, 0x31, 0x3e, 0x40, 0xba, 0x75, 0x64, 0x5a, 0x47, 0xc7, 0x75, 0xb4, 0xe9, 0xbd, 0xf3, 0x95, + 0xd7, 0xb9, 0x5c, 0x79, 0x3d, 0xed, 0x67, 0x84, 0xcd, 0xee, 0xfc, 0x2f, 0xdf, 0x3d, 0x2b, 0x68, + 0x0c, 0xfd, 0xb7, 0xf6, 0x83, 0xb6, 0x88, 0x32, 0x15, 0x5c, 0x82, 0x33, 0xb1, 0xef, 0xc8, 0x9c, + 0x52, 0x90, 0x8b, 0x3c, 0x8e, 0x8b, 0x59, 0x66, 0x54, 0x55, 0xe0, 0xbd, 0x60, 0x7f, 0x0b, 0x6c, + 0x1c, 0xc7, 0x1f, 0xbb, 0xf6, 0x7f, 0x2f, 0xcb, 0xd5, 0x3b, 0xbf, 0x2d, 0xdb, 0xbd, 0xba, 0x92, + 0xf3, 0xb4, 0x7d, 0x66, 0xd7, 0x5a, 0x47, 0xff, 0xd9, 0xbf, 0x1b, 0xe9, 0xd0, 0xfe, 0xc9, 0x87, + 0xaf, 0xbf, 0x3e, 0x77, 0x9f, 0x38, 0x8f, 0xaf, 0xf1, 0xb0, 0xae, 0xb6, 0x9c, 0xd2, 0xf3, 0xb5, + 0x6b, 0x5d, 0xac, 0x5d, 0xeb, 0xc7, 0xda, 0xb5, 0x3e, 0x6d, 0xdc, 0xce, 0xc5, 0xc6, 0xed, 0x7c, + 0xdb, 0xb8, 0x9d, 0xd7, 0x27, 0x11, 0x53, 0xa7, 0x79, 0x88, 0xa8, 0x48, 0x4c, 0x99, 0x61, 0x4c, + 0x42, 0xd9, 0xd4, 0x5c, 0x8e, 0x26, 0xf8, 0xfd, 0x5f, 0x2a, 0xd3, 0x98, 0x01, 0x57, 0xfa, 0x6d, + 0xe9, 0xab, 0xf0, 0x7f, 0xf5, 0x99, 0xfc, 0x09, 0x00, 0x00, 0xff, 0xff, 0x28, 0x46, 0xbb, 0x35, + 0x6f, 0x04, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + RecoveredSinceDowntimeOfLength(ctx context.Context, in *RecoveredSinceDowntimeOfLengthRequest, opts ...grpc.CallOption) (*RecoveredSinceDowntimeOfLengthResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) RecoveredSinceDowntimeOfLength(ctx context.Context, in *RecoveredSinceDowntimeOfLengthRequest, opts ...grpc.CallOption) (*RecoveredSinceDowntimeOfLengthResponse, error) { + out := new(RecoveredSinceDowntimeOfLengthResponse) + err := c.cc.Invoke(ctx, "/osmosis.downtimedetector.v1beta1.Query/RecoveredSinceDowntimeOfLength", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + RecoveredSinceDowntimeOfLength(context.Context, *RecoveredSinceDowntimeOfLengthRequest) (*RecoveredSinceDowntimeOfLengthResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) RecoveredSinceDowntimeOfLength(ctx context.Context, req *RecoveredSinceDowntimeOfLengthRequest) (*RecoveredSinceDowntimeOfLengthResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RecoveredSinceDowntimeOfLength not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_RecoveredSinceDowntimeOfLength_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RecoveredSinceDowntimeOfLengthRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RecoveredSinceDowntimeOfLength(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.downtimedetector.v1beta1.Query/RecoveredSinceDowntimeOfLength", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RecoveredSinceDowntimeOfLength(ctx, req.(*RecoveredSinceDowntimeOfLengthRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "osmosis.downtimedetector.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "RecoveredSinceDowntimeOfLength", + Handler: _Query_RecoveredSinceDowntimeOfLength_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "osmosis/downtime-detector/v1beta1/query.proto", +} + +func (m *RecoveredSinceDowntimeOfLengthRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RecoveredSinceDowntimeOfLengthRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RecoveredSinceDowntimeOfLengthRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n1, err1 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.Recovery, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.Recovery):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintQuery(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x12 + if m.Downtime != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Downtime)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *RecoveredSinceDowntimeOfLengthResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RecoveredSinceDowntimeOfLengthResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RecoveredSinceDowntimeOfLengthResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.SuccesfullyRecovered { + i-- + if m.SuccesfullyRecovered { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *RecoveredSinceDowntimeOfLengthRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Downtime != 0 { + n += 1 + sovQuery(uint64(m.Downtime)) + } + l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.Recovery) + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *RecoveredSinceDowntimeOfLengthResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SuccesfullyRecovered { + n += 2 + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *RecoveredSinceDowntimeOfLengthRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RecoveredSinceDowntimeOfLengthRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RecoveredSinceDowntimeOfLengthRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Downtime", wireType) + } + m.Downtime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Downtime |= types.Downtime(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Recovery", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.Recovery, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RecoveredSinceDowntimeOfLengthResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RecoveredSinceDowntimeOfLengthResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RecoveredSinceDowntimeOfLengthResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SuccesfullyRecovered", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SuccesfullyRecovered = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/downtime-detector/client/queryproto/query.pb.gw.go b/x/downtime-detector/client/queryproto/query.pb.gw.go new file mode 100644 index 00000000000..0d025dcb19f --- /dev/null +++ b/x/downtime-detector/client/queryproto/query.pb.gw.go @@ -0,0 +1,171 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: osmosis/downtime-detector/v1beta1/query.proto + +/* +Package queryproto is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package queryproto + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +var ( + filter_Query_RecoveredSinceDowntimeOfLength_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_RecoveredSinceDowntimeOfLength_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RecoveredSinceDowntimeOfLengthRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_RecoveredSinceDowntimeOfLength_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.RecoveredSinceDowntimeOfLength(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RecoveredSinceDowntimeOfLength_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RecoveredSinceDowntimeOfLengthRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_RecoveredSinceDowntimeOfLength_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.RecoveredSinceDowntimeOfLength(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_RecoveredSinceDowntimeOfLength_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RecoveredSinceDowntimeOfLength_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RecoveredSinceDowntimeOfLength_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_RecoveredSinceDowntimeOfLength_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_RecoveredSinceDowntimeOfLength_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RecoveredSinceDowntimeOfLength_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_RecoveredSinceDowntimeOfLength_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "downtime-detector", "v1beta1", "RecoveredSinceDowntimeOfLength"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_RecoveredSinceDowntimeOfLength_0 = runtime.ForwardResponseMessage +) diff --git a/x/downtime-detector/genesis.go b/x/downtime-detector/genesis.go new file mode 100644 index 00000000000..0c90258e4ba --- /dev/null +++ b/x/downtime-detector/genesis.go @@ -0,0 +1,48 @@ +package downtimedetector + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +func (k *Keeper) InitGenesis(ctx sdk.Context, gen *types.GenesisState) { + k.StoreLastBlockTime(ctx, gen.LastBlockTime) + // set all default genesis down times, in case the provided list in genesis misses some. + k.setGenDowntimes(ctx, types.DefaultGenesis().GetDowntimes()) + // override with genesis list + k.setGenDowntimes(ctx, gen.Downtimes) +} + +func (k *Keeper) setGenDowntimes(ctx sdk.Context, genDowntimes []types.GenesisDowntimeEntry) { + for _, downtime := range genDowntimes { + k.StoreLastDowntimeOfLength(ctx, downtime.Duration, downtime.LastDowntime) + } +} + +// ExportGenesis returns the downtime detector module's exported genesis. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + t, err := k.GetLastBlockTime(ctx) + if err != nil { + panic(err) + } + return &types.GenesisState{ + Downtimes: k.getGenDowntimes(ctx), + LastBlockTime: t, + } +} + +func (k *Keeper) getGenDowntimes(ctx sdk.Context) []types.GenesisDowntimeEntry { + downtimes := []types.GenesisDowntimeEntry{} + for _, downtime := range types.DowntimeToDuration.Keys() { + t, err := k.GetLastDowntimeOfLength(ctx, downtime) + if err != nil { + panic(err) + } + downtimes = append(downtimes, types.GenesisDowntimeEntry{ + Duration: downtime, + LastDowntime: t, + }) + } + return downtimes +} diff --git a/x/downtime-detector/genesis_test.go b/x/downtime-detector/genesis_test.go new file mode 100644 index 00000000000..da7d6191a3e --- /dev/null +++ b/x/downtime-detector/genesis_test.go @@ -0,0 +1,46 @@ +package downtimedetector_test + +import ( + "time" + + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +func (suite *KeeperTestSuite) TestImportExport() { + tests := map[string]struct { + Downtimes []types.GenesisDowntimeEntry + LastBlockTime time.Time + }{ + "no downtimes": { + LastBlockTime: baseTime, + }, + "some downtimes": { + LastBlockTime: baseTime, + Downtimes: []types.GenesisDowntimeEntry{ + {Duration: types.Downtime_DURATION_10M, LastDowntime: baseTime.Add(-time.Hour)}, + {Duration: types.Downtime_DURATION_30M, LastDowntime: baseTime.Add(-time.Hour)}, + }, + }, + } + for name, test := range tests { + suite.Run(name, func() { + suite.Ctx = suite.Ctx.WithBlockTime(test.LastBlockTime.Add(time.Hour)) + genState := &types.GenesisState{Downtimes: test.Downtimes, LastBlockTime: test.LastBlockTime} + suite.App.DowntimeKeeper.InitGenesis(suite.Ctx, genState) + exportedState := suite.App.DowntimeKeeper.ExportGenesis(suite.Ctx) + suite.Require().Equal(test.LastBlockTime, exportedState.LastBlockTime) + // O(N^2) method of checking downtimes, not concerned with run-time as its bounded. + for _, downtime := range test.Downtimes { + found := false + for _, exportedDowntime := range exportedState.Downtimes { + if exportedDowntime.Duration == downtime.Duration { + suite.Require().Equal(downtime.LastDowntime, exportedDowntime.LastDowntime) + found = true + break + } + } + suite.Require().True(found, "downtime %s not found in exported state", downtime.Duration.String()) + } + }) + } +} diff --git a/x/downtime-detector/keeper.go b/x/downtime-detector/keeper.go new file mode 100644 index 00000000000..5ac6d5ad103 --- /dev/null +++ b/x/downtime-detector/keeper.go @@ -0,0 +1,13 @@ +package downtimedetector + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type Keeper struct { + storeKey sdk.StoreKey +} + +func NewKeeper(storeKey sdk.StoreKey) *Keeper { + return &Keeper{storeKey: storeKey} +} diff --git a/x/downtime-detector/keeper_test.go b/x/downtime-detector/keeper_test.go new file mode 100644 index 00000000000..058e08efe27 --- /dev/null +++ b/x/downtime-detector/keeper_test.go @@ -0,0 +1,159 @@ +package downtimedetector_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "github.com/osmosis-labs/osmosis/v13/app/apptesting" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +var baseTime = time.Unix(1257894000, 0).UTC() +var sec = time.Second +var min = time.Minute + +type blocktimes []time.Duration + +func (b blocktimes) EndTime() time.Time { + endTime := baseTime + for _, d := range b { + endTime = endTime.Add(d) + } + return endTime +} + +func (suite *KeeperTestSuite) runBlocktimes(times blocktimes) { + suite.Ctx = suite.Ctx.WithBlockTime(baseTime) + suite.App.DowntimeKeeper.BeginBlock(suite.Ctx) + for _, duration := range times { + suite.Ctx = suite.Ctx.WithBlockTime(suite.Ctx.BlockTime().Add(duration)) + suite.App.DowntimeKeeper.BeginBlock(suite.Ctx) + } +} + +var abruptRecovery5minDowntime10min blocktimes = []time.Duration{sec, 10 * min, 5 * min} +var smootherRecovery5minDowntime10min blocktimes = []time.Duration{sec, 10 * min, min, min, min, min, min} +var fifteenMinEndtime = abruptRecovery5minDowntime10min.EndTime() +var tenMinEndtime = abruptRecovery5minDowntime10min.EndTime().Add(-5 * min) + +func (suite *KeeperTestSuite) TestBeginBlock() { + tests := map[string]struct { + times blocktimes + downtimes []types.GenesisDowntimeEntry + }{ + "10 min halt, then 5 min halt": { + times: abruptRecovery5minDowntime10min, + downtimes: []types.GenesisDowntimeEntry{ + types.NewGenesisDowntimeEntry(types.Downtime_DURATION_1M, fifteenMinEndtime), + types.NewGenesisDowntimeEntry(types.Downtime_DURATION_3M, fifteenMinEndtime), + types.NewGenesisDowntimeEntry(types.Downtime_DURATION_5M, fifteenMinEndtime), + types.NewGenesisDowntimeEntry(types.Downtime_DURATION_10M, tenMinEndtime), + }, + }, + "10 min halt, then 1 min sequence": { + times: smootherRecovery5minDowntime10min, + downtimes: []types.GenesisDowntimeEntry{ + types.NewGenesisDowntimeEntry(types.Downtime_DURATION_1M, fifteenMinEndtime), + types.NewGenesisDowntimeEntry(types.Downtime_DURATION_2M, tenMinEndtime), + types.NewGenesisDowntimeEntry(types.Downtime_DURATION_5M, tenMinEndtime), + types.NewGenesisDowntimeEntry(types.Downtime_DURATION_10M, tenMinEndtime), + }, + }, + } + for name, test := range tests { + suite.Run(name, func() { + suite.runBlocktimes(test.times) + suite.Require().Equal(test.times.EndTime(), suite.Ctx.BlockTime()) + for _, downtime := range test.downtimes { + lastDowntime, err := suite.App.DowntimeKeeper.GetLastDowntimeOfLength(suite.Ctx, downtime.Duration) + suite.Require().NoError(err) + suite.Require().Equal(downtime.LastDowntime, lastDowntime) + } + }) + } +} + +func (suite *KeeperTestSuite) TestRecoveryQuery() { + type queryTestcase struct { + downtime types.Downtime + recovTime time.Duration + expectRecovered bool + } + + tests := map[string]struct { + times blocktimes + cases []queryTestcase + }{ + "10 min halt, then 5 min halt": { + times: abruptRecovery5minDowntime10min, + cases: []queryTestcase{ + {types.Downtime_DURATION_10M, 4 * min, true}, + {types.Downtime_DURATION_10M, 5 * min, true}, + {types.Downtime_DURATION_10M, 6 * min, false}, + {types.Downtime_DURATION_30S, 1 * min, false}, + }, + }, + "10 min halt, then 1 min sequence": { + times: smootherRecovery5minDowntime10min, + cases: []queryTestcase{ + {types.Downtime_DURATION_10M, 4 * min, true}, + {types.Downtime_DURATION_10M, 5 * min, true}, + {types.Downtime_DURATION_10M, 6 * min, false}, + {types.Downtime_DURATION_30S, 1 * min, false}, + }, + }, + } + for name, test := range tests { + suite.Run(name, func() { + suite.runBlocktimes(test.times) + suite.Require().Equal(test.times.EndTime(), suite.Ctx.BlockTime()) + for _, query := range test.cases { + recovered, err := suite.App.DowntimeKeeper.RecoveredSinceDowntimeOfLength( + suite.Ctx, query.downtime, query.recovTime) + suite.Require().NoError(err) + suite.Require().Equal(query.expectRecovered, recovered) + } + }) + } +} + +func (suite *KeeperTestSuite) TestRecoveryQueryErrors() { + tests := map[string]struct { + times blocktimes + downtime types.Downtime + recovTime time.Duration + }{ + "invalid downtime": { + times: abruptRecovery5minDowntime10min, + downtime: types.Downtime(0x7F), + recovTime: min, + }, + "0 recovery time": { + times: abruptRecovery5minDowntime10min, + downtime: types.Downtime_DURATION_1H, + recovTime: time.Duration(0), + }, + } + for name, test := range tests { + suite.Run(name, func() { + suite.runBlocktimes(test.times) + _, err := suite.App.DowntimeKeeper.RecoveredSinceDowntimeOfLength( + suite.Ctx, test.downtime, test.recovTime) + suite.Require().Error(err) + }) + } +} + +type KeeperTestSuite struct { + apptesting.KeeperTestHelper +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.Setup() +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/downtime-detector/module/module.go b/x/downtime-detector/module/module.go new file mode 100644 index 00000000000..72a79b794c7 --- /dev/null +++ b/x/downtime-detector/module/module.go @@ -0,0 +1,122 @@ +package downtimemodule + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + downtimedetector "github.com/osmosis-labs/osmosis/v13/x/downtime-detector" + downtimeclient "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client" + downtimecli "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/cli" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/grpc" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/client/queryproto" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +type AppModuleBasic struct{} + +func (AppModuleBasic) Name() string { return types.ModuleName } + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { +} + +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +func (b AppModuleBasic) RegisterRESTRoutes(ctx client.Context, r *mux.Router) { +} + +func (b AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + queryproto.RegisterQueryHandlerClient(context.Background(), mux, queryproto.NewQueryClient(clientCtx)) //nolint:errcheck +} + +func (b AppModuleBasic) GetTxCmd() *cobra.Command { + return nil +} + +func (b AppModuleBasic) GetQueryCmd() *cobra.Command { + return downtimecli.GetQueryCmd() +} + +func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { +} + +type AppModule struct { + AppModuleBasic + + k downtimedetector.Keeper +} + +func (am AppModule) RegisterServices(cfg module.Configurator) { + queryproto.RegisterQueryServer(cfg.QueryServer(), grpc.Querier{Q: downtimeclient.Querier{K: am.k}}) +} + +func NewAppModule(k downtimedetector.Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + k: k, + } +} + +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} + +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +func (AppModule) QuerierRoute() string { return types.RouterKey } + +func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { + return func(sdk.Context, []string, abci.RequestQuery) ([]byte, error) { + return nil, fmt.Errorf("legacy querier not supported for the x/%s module", types.ModuleName) + } +} + +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + + cdc.MustUnmarshalJSON(gs, &genesisState) + + am.k.InitGenesis(ctx, &genesisState) + return []abci.ValidatorUpdate{} +} + +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.k.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} + +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { + am.k.BeginBlock(ctx) +} + +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +func (AppModule) ConsensusVersion() uint64 { return 1 } diff --git a/x/downtime-detector/query.go b/x/downtime-detector/query.go new file mode 100644 index 00000000000..4523ca24455 --- /dev/null +++ b/x/downtime-detector/query.go @@ -0,0 +1,26 @@ +package downtimedetector + +import ( + "errors" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +func (k *Keeper) RecoveredSinceDowntimeOfLength(ctx sdk.Context, downtime types.Downtime, recoveryDuration time.Duration) (bool, error) { + lastDowntime, err := k.GetLastDowntimeOfLength(ctx, downtime) + if err != nil { + return false, err + } + if recoveryDuration == time.Duration(0) { + return false, errors.New("invalid recovery duration of 0") + } + // Check if current time < lastDowntime + recovery duration + // if LTE, then we have not waited recovery duration. + if ctx.BlockTime().Before(lastDowntime.Add(recoveryDuration)) { + return false, nil + } + return true, nil +} diff --git a/x/downtime-detector/store.go b/x/downtime-detector/store.go new file mode 100644 index 00000000000..295bd540a04 --- /dev/null +++ b/x/downtime-detector/store.go @@ -0,0 +1,49 @@ +package downtimedetector + +import ( + "errors" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/osmoutils" + "github.com/osmosis-labs/osmosis/v13/x/downtime-detector/types" +) + +func (k *Keeper) GetLastBlockTime(ctx sdk.Context) (time.Time, error) { + store := ctx.KVStore(k.storeKey) + timeBz := store.Get(types.GetLastBlockTimestampKey()) + if len(timeBz) == 0 { + return time.Time{}, errors.New("no last block time stored in state. Should not happen, did initialization happen correctly?") + } + timeV, err := osmoutils.ParseTimeString(string(timeBz)) + if err != nil { + return time.Time{}, err + } + return timeV, nil +} + +func (k *Keeper) StoreLastBlockTime(ctx sdk.Context, t time.Time) { + store := ctx.KVStore(k.storeKey) + timeBz := osmoutils.FormatTimeString(t) + store.Set(types.GetLastBlockTimestampKey(), []byte(timeBz)) +} + +func (k *Keeper) GetLastDowntimeOfLength(ctx sdk.Context, dur types.Downtime) (time.Time, error) { + store := ctx.KVStore(k.storeKey) + timeBz := store.Get(types.GetLastDowntimeOfLengthKey(dur)) + if len(timeBz) == 0 { + return time.Time{}, errors.New("no last time stored in state. Should not happen, did initialization happen correctly?") + } + timeV, err := osmoutils.ParseTimeString(string(timeBz)) + if err != nil { + return time.Time{}, err + } + return timeV, nil +} + +func (k *Keeper) StoreLastDowntimeOfLength(ctx sdk.Context, dur types.Downtime, t time.Time) { + store := ctx.KVStore(k.storeKey) + timeBz := osmoutils.FormatTimeString(t) + store.Set(types.GetLastDowntimeOfLengthKey(dur), []byte(timeBz)) +} diff --git a/x/downtime-detector/types/constants.go b/x/downtime-detector/types/constants.go new file mode 100644 index 00000000000..86020ed6bb1 --- /dev/null +++ b/x/downtime-detector/types/constants.go @@ -0,0 +1,81 @@ +package types + +import ( + fmt "fmt" + "strings" + time "time" + + "github.com/tidwall/btree" +) + +const ( + // we don't use a `-` as RouterKey must be alphanumeric + ModuleName = "downtimedetector" + StoreKey = ModuleName + RouterKey = ModuleName + + QuerierRoute = ModuleName +) + +var DowntimeToDuration = btree.NewMap[Downtime, time.Duration](16) +var DefaultLastDowntime = time.Unix(0, 0) + +// init initializes the DowntimeToDuration map with mappings +// from the Duration enum values to their corresponding +// time.Duration values. +func init() { + DowntimeToDuration.Set(Downtime_DURATION_30S, 30*time.Second) + DowntimeToDuration.Set(Downtime_DURATION_1M, time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_2M, 2*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_3M, 3*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_4M, 4*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_5M, 5*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_10M, 10*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_20M, 20*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_30M, 30*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_40M, 40*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_50M, 50*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_1H, time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_1_5H, time.Hour+30*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_2H, 2*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_2_5H, 2*time.Hour+30*time.Minute) + DowntimeToDuration.Set(Downtime_DURATION_3H, 3*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_4H, 4*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_5H, 5*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_6H, 6*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_9H, 9*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_12H, 12*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_18H, 18*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_24H, 24*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_36H, 36*time.Hour) + DowntimeToDuration.Set(Downtime_DURATION_48H, 48*time.Hour) +} + +func DowntimeStrings() []string { + arr := []string{} + DowntimeToDuration.Ascend(Downtime(0), func(_ Downtime, v time.Duration) bool { + s := strings.Replace(v.String(), "m0s", "m", 1) + s = strings.Replace(s, "h0m", "h", 1) + arr = append(arr, s) + return true + }) + return arr +} + +func DowntimeByDuration(duration time.Duration) (Downtime, error) { + var result Downtime + found := false + DowntimeToDuration.Ascend(Downtime(0), func(k Downtime, v time.Duration) bool { + if v == duration { + result = k + found = true + return false + } + return true + }) + if found { + return result, nil + } + downtimeOptions := strings.Join(DowntimeStrings(), ", ") + return result, fmt.Errorf("downtime of %s does not exist. Chain-provided downtimes [%s]", duration.String(), downtimeOptions) +} diff --git a/x/downtime-detector/types/constants_test.go b/x/downtime-detector/types/constants_test.go new file mode 100644 index 00000000000..537e64432fa --- /dev/null +++ b/x/downtime-detector/types/constants_test.go @@ -0,0 +1,19 @@ +package types + +import ( + "testing" + time "time" + + "github.com/stretchr/testify/require" +) + +func TestDowntimeToDurationAscending(t *testing.T) { + numEntries := 0 + lastDur := time.Duration(0) + DowntimeToDuration.Ascend(Downtime(0), func(_ Downtime, v time.Duration) bool { + numEntries++ + require.Greater(t, v, lastDur) + return true + }) + require.Equal(t, numEntries, 25) +} diff --git a/x/downtime-detector/types/downtime_duration.pb.go b/x/downtime-detector/types/downtime_duration.pb.go new file mode 100644 index 00000000000..c86cc3cfea9 --- /dev/null +++ b/x/downtime-detector/types/downtime_duration.pb.go @@ -0,0 +1,156 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/downtime-detector/v1beta1/downtime_duration.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Downtime int32 + +const ( + Downtime_DURATION_30S Downtime = 0 + Downtime_DURATION_1M Downtime = 1 + Downtime_DURATION_2M Downtime = 2 + Downtime_DURATION_3M Downtime = 3 + Downtime_DURATION_4M Downtime = 4 + Downtime_DURATION_5M Downtime = 5 + Downtime_DURATION_10M Downtime = 6 + Downtime_DURATION_20M Downtime = 7 + Downtime_DURATION_30M Downtime = 8 + Downtime_DURATION_40M Downtime = 9 + Downtime_DURATION_50M Downtime = 10 + Downtime_DURATION_1H Downtime = 11 + Downtime_DURATION_1_5H Downtime = 12 + Downtime_DURATION_2H Downtime = 13 + Downtime_DURATION_2_5H Downtime = 14 + Downtime_DURATION_3H Downtime = 15 + Downtime_DURATION_4H Downtime = 16 + Downtime_DURATION_5H Downtime = 17 + Downtime_DURATION_6H Downtime = 18 + Downtime_DURATION_9H Downtime = 19 + Downtime_DURATION_12H Downtime = 20 + Downtime_DURATION_18H Downtime = 21 + Downtime_DURATION_24H Downtime = 22 + Downtime_DURATION_36H Downtime = 23 + Downtime_DURATION_48H Downtime = 24 +) + +var Downtime_name = map[int32]string{ + 0: "DURATION_30S", + 1: "DURATION_1M", + 2: "DURATION_2M", + 3: "DURATION_3M", + 4: "DURATION_4M", + 5: "DURATION_5M", + 6: "DURATION_10M", + 7: "DURATION_20M", + 8: "DURATION_30M", + 9: "DURATION_40M", + 10: "DURATION_50M", + 11: "DURATION_1H", + 12: "DURATION_1_5H", + 13: "DURATION_2H", + 14: "DURATION_2_5H", + 15: "DURATION_3H", + 16: "DURATION_4H", + 17: "DURATION_5H", + 18: "DURATION_6H", + 19: "DURATION_9H", + 20: "DURATION_12H", + 21: "DURATION_18H", + 22: "DURATION_24H", + 23: "DURATION_36H", + 24: "DURATION_48H", +} + +var Downtime_value = map[string]int32{ + "DURATION_30S": 0, + "DURATION_1M": 1, + "DURATION_2M": 2, + "DURATION_3M": 3, + "DURATION_4M": 4, + "DURATION_5M": 5, + "DURATION_10M": 6, + "DURATION_20M": 7, + "DURATION_30M": 8, + "DURATION_40M": 9, + "DURATION_50M": 10, + "DURATION_1H": 11, + "DURATION_1_5H": 12, + "DURATION_2H": 13, + "DURATION_2_5H": 14, + "DURATION_3H": 15, + "DURATION_4H": 16, + "DURATION_5H": 17, + "DURATION_6H": 18, + "DURATION_9H": 19, + "DURATION_12H": 20, + "DURATION_18H": 21, + "DURATION_24H": 22, + "DURATION_36H": 23, + "DURATION_48H": 24, +} + +func (x Downtime) String() string { + return proto.EnumName(Downtime_name, int32(x)) +} + +func (Downtime) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_21a1969f22fb2a7e, []int{0} +} + +func init() { + proto.RegisterEnum("osmosis.downtimedetector.v1beta1.Downtime", Downtime_name, Downtime_value) +} + +func init() { + proto.RegisterFile("osmosis/downtime-detector/v1beta1/downtime_duration.proto", fileDescriptor_21a1969f22fb2a7e) +} + +var fileDescriptor_21a1969f22fb2a7e = []byte{ + // 386 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0xbb, 0x6e, 0xe2, 0x50, + 0x10, 0x86, 0xed, 0x65, 0x97, 0x65, 0x0d, 0x2c, 0x83, 0x97, 0xbd, 0x51, 0x78, 0xb7, 0x8e, 0x84, + 0x8f, 0x2f, 0x80, 0xa0, 0x48, 0x91, 0x88, 0xe2, 0xa4, 0x38, 0x89, 0x94, 0x8b, 0x22, 0xa5, 0xb1, + 0x6c, 0x70, 0x1c, 0x4b, 0x98, 0x83, 0xf0, 0x81, 0x84, 0xb7, 0xc8, 0x33, 0xa5, 0x4a, 0x49, 0x99, + 0x32, 0x82, 0x17, 0x89, 0xf0, 0x85, 0x68, 0x50, 0x3a, 0xcf, 0x37, 0xf3, 0xfb, 0xfc, 0xff, 0x68, + 0x94, 0x3e, 0x8f, 0x23, 0x1e, 0x87, 0x31, 0x19, 0xf1, 0xfb, 0x89, 0x08, 0x23, 0xbf, 0x35, 0xf2, + 0x85, 0x3f, 0x14, 0x7c, 0x46, 0x16, 0xa6, 0xe7, 0x0b, 0xd7, 0xdc, 0x75, 0x9c, 0xd1, 0x7c, 0xe6, + 0x8a, 0x90, 0x4f, 0xf4, 0xe9, 0x8c, 0x0b, 0xae, 0xfe, 0xcf, 0xa4, 0x7a, 0x3e, 0x90, 0x2b, 0xf5, + 0x4c, 0xd9, 0x6c, 0x04, 0x3c, 0xe0, 0xc9, 0x30, 0xd9, 0x7e, 0xa5, 0xba, 0xe6, 0xdf, 0x80, 0xf3, + 0x60, 0xec, 0x93, 0xa4, 0xf2, 0xe6, 0xb7, 0xc4, 0x9d, 0x2c, 0xf3, 0xd6, 0x30, 0xf9, 0xa7, 0x93, + 0x6a, 0xd2, 0x22, 0x6b, 0x69, 0xfb, 0x2a, 0xec, 0xa6, 0xf9, 0x6f, 0xbf, 0xbf, 0x75, 0x14, 0x0b, + 0x37, 0x9a, 0xa6, 0x03, 0x07, 0x4f, 0x05, 0xa5, 0x34, 0xc8, 0x9c, 0xaa, 0xa0, 0x54, 0x06, 0x57, + 0xe7, 0x47, 0x97, 0x27, 0x67, 0xa7, 0x8e, 0x6d, 0x5c, 0x80, 0xa4, 0xd6, 0x94, 0xf2, 0x8e, 0x98, + 0x0c, 0x64, 0x04, 0x2c, 0x06, 0x9f, 0x10, 0xb0, 0x19, 0x14, 0x10, 0x68, 0x33, 0xf8, 0x8c, 0x40, + 0x87, 0xc1, 0x17, 0xf4, 0x8c, 0x69, 0x30, 0x28, 0x22, 0x62, 0x19, 0x0c, 0xbe, 0xee, 0x59, 0x61, + 0x50, 0x42, 0xa4, 0x6d, 0x30, 0xf8, 0x86, 0x48, 0xc7, 0x60, 0xa0, 0x60, 0xbb, 0x14, 0xca, 0x6a, + 0x5d, 0xa9, 0xbe, 0x03, 0xa7, 0x43, 0xa1, 0x82, 0x13, 0x50, 0xa8, 0xa2, 0x19, 0x6b, 0x3b, 0xf3, + 0x1d, 0x87, 0xa2, 0x50, 0xc3, 0xa1, 0x28, 0x00, 0x0e, 0x45, 0xa1, 0x8e, 0x40, 0x97, 0x82, 0x8a, + 0x40, 0x9f, 0xc2, 0x0f, 0x1c, 0xdb, 0xa2, 0xd0, 0xc0, 0xa4, 0x47, 0xe1, 0x27, 0x5e, 0x44, 0x9b, + 0xc2, 0x2f, 0xbc, 0x88, 0x2e, 0x85, 0xdf, 0x78, 0x11, 0x3d, 0x0a, 0x7f, 0x8e, 0xaf, 0x9f, 0xd7, + 0x9a, 0xbc, 0x5a, 0x6b, 0xf2, 0xeb, 0x5a, 0x93, 0x1f, 0x37, 0x9a, 0xb4, 0xda, 0x68, 0xd2, 0xcb, + 0x46, 0x93, 0x6e, 0x0e, 0x83, 0x50, 0xdc, 0xcd, 0x3d, 0x7d, 0xc8, 0x23, 0x92, 0x1d, 0x66, 0x6b, + 0xec, 0x7a, 0x71, 0x5e, 0x90, 0x85, 0x69, 0x93, 0x87, 0x0f, 0xce, 0x5c, 0x2c, 0xa7, 0x7e, 0xec, + 0x15, 0x93, 0x23, 0xb1, 0xdf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x48, 0x2b, 0x3d, 0xaf, 0x10, 0x03, + 0x00, 0x00, +} diff --git a/x/downtime-detector/types/genesis.go b/x/downtime-detector/types/genesis.go new file mode 100644 index 00000000000..257b3a079bc --- /dev/null +++ b/x/downtime-detector/types/genesis.go @@ -0,0 +1,25 @@ +package types + +import "time" + +func DefaultGenesis() *GenesisState { + genDowntimes := []GenesisDowntimeEntry{} + for _, downtime := range DowntimeToDuration.Keys() { + genDowntimes = append(genDowntimes, GenesisDowntimeEntry{ + Duration: downtime, + LastDowntime: DefaultLastDowntime, + }) + } + return &GenesisState{ + Downtimes: genDowntimes, + LastBlockTime: time.Unix(0, 0), + } +} + +func (g *GenesisState) Validate() error { + return nil +} + +func NewGenesisDowntimeEntry(dur Downtime, time time.Time) GenesisDowntimeEntry { + return GenesisDowntimeEntry{Duration: dur, LastDowntime: time} +} diff --git a/x/downtime-detector/types/genesis.pb.go b/x/downtime-detector/types/genesis.pb.go new file mode 100644 index 00000000000..d2bef4b2bfb --- /dev/null +++ b/x/downtime-detector/types/genesis.pb.go @@ -0,0 +1,607 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/downtime-detector/v1beta1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" + github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type GenesisDowntimeEntry struct { + Duration Downtime `protobuf:"varint,1,opt,name=duration,proto3,enum=osmosis.downtimedetector.v1beta1.Downtime" json:"duration,omitempty" yaml:"duration"` + LastDowntime time.Time `protobuf:"bytes,2,opt,name=last_downtime,json=lastDowntime,proto3,stdtime" json:"last_downtime" yaml:"last_downtime"` +} + +func (m *GenesisDowntimeEntry) Reset() { *m = GenesisDowntimeEntry{} } +func (m *GenesisDowntimeEntry) String() string { return proto.CompactTextString(m) } +func (*GenesisDowntimeEntry) ProtoMessage() {} +func (*GenesisDowntimeEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_4581e137a44782af, []int{0} +} +func (m *GenesisDowntimeEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisDowntimeEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisDowntimeEntry.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisDowntimeEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisDowntimeEntry.Merge(m, src) +} +func (m *GenesisDowntimeEntry) XXX_Size() int { + return m.Size() +} +func (m *GenesisDowntimeEntry) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisDowntimeEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisDowntimeEntry proto.InternalMessageInfo + +func (m *GenesisDowntimeEntry) GetDuration() Downtime { + if m != nil { + return m.Duration + } + return Downtime_DURATION_30S +} + +func (m *GenesisDowntimeEntry) GetLastDowntime() time.Time { + if m != nil { + return m.LastDowntime + } + return time.Time{} +} + +// GenesisState defines the twap module's genesis state. +type GenesisState struct { + Downtimes []GenesisDowntimeEntry `protobuf:"bytes,1,rep,name=downtimes,proto3" json:"downtimes"` + LastBlockTime time.Time `protobuf:"bytes,2,opt,name=last_block_time,json=lastBlockTime,proto3,stdtime" json:"last_block_time" yaml:"last_block_time"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_4581e137a44782af, []int{1} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetDowntimes() []GenesisDowntimeEntry { + if m != nil { + return m.Downtimes + } + return nil +} + +func (m *GenesisState) GetLastBlockTime() time.Time { + if m != nil { + return m.LastBlockTime + } + return time.Time{} +} + +func init() { + proto.RegisterType((*GenesisDowntimeEntry)(nil), "osmosis.downtimedetector.v1beta1.GenesisDowntimeEntry") + proto.RegisterType((*GenesisState)(nil), "osmosis.downtimedetector.v1beta1.GenesisState") +} + +func init() { + proto.RegisterFile("osmosis/downtime-detector/v1beta1/genesis.proto", fileDescriptor_4581e137a44782af) +} + +var fileDescriptor_4581e137a44782af = []byte{ + // 404 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xc1, 0x6a, 0xe2, 0x40, + 0x1c, 0xc6, 0x33, 0xbb, 0xcb, 0xb2, 0x1b, 0xdd, 0x15, 0xb2, 0xb2, 0x58, 0x0f, 0x49, 0xc8, 0x49, + 0x0a, 0xce, 0xa0, 0x42, 0xa1, 0x85, 0x5e, 0x42, 0x4b, 0xef, 0xb6, 0x50, 0xb0, 0x87, 0x30, 0x89, + 0x63, 0x1a, 0x9a, 0x64, 0x24, 0x33, 0xda, 0xe6, 0x2d, 0x7c, 0x2c, 0x8f, 0xd2, 0x43, 0xe9, 0xc9, + 0x16, 0x7d, 0x03, 0x9f, 0xa0, 0x24, 0x99, 0xd1, 0x2a, 0x82, 0xbd, 0x25, 0xf3, 0xff, 0xbe, 0x8f, + 0xef, 0xf7, 0xe7, 0xaf, 0x22, 0xca, 0x22, 0xca, 0x02, 0x86, 0xfa, 0xf4, 0x31, 0xe6, 0x41, 0x44, + 0x9a, 0x7d, 0xc2, 0x89, 0xc7, 0x69, 0x82, 0xc6, 0x2d, 0x97, 0x70, 0xdc, 0x42, 0x3e, 0x89, 0x09, + 0x0b, 0x18, 0x1c, 0x26, 0x94, 0x53, 0xcd, 0x14, 0x06, 0x28, 0x0d, 0x52, 0x0f, 0x85, 0xbe, 0x5e, + 0xf5, 0xa9, 0x4f, 0x73, 0x31, 0xca, 0xbe, 0x0a, 0x5f, 0xfd, 0xc8, 0xa7, 0xd4, 0x0f, 0x09, 0xca, + 0xff, 0xdc, 0xd1, 0x00, 0xe1, 0x38, 0x95, 0x23, 0x2f, 0xcf, 0x74, 0x0a, 0x4f, 0xf1, 0x23, 0x46, + 0xfa, 0xae, 0xab, 0x3f, 0x4a, 0x30, 0x0f, 0x68, 0x2c, 0xe6, 0xc6, 0xee, 0x3c, 0x6b, 0xc4, 0x38, + 0x8e, 0x86, 0x42, 0x70, 0x7a, 0x98, 0x4f, 0x4e, 0x9c, 0xed, 0x6c, 0xeb, 0x05, 0xa8, 0xd5, 0xab, + 0x82, 0xfd, 0x42, 0x48, 0x2e, 0x63, 0x9e, 0xa4, 0xda, 0x9d, 0xfa, 0x4b, 0x4a, 0x6b, 0xc0, 0x04, + 0x8d, 0xbf, 0xed, 0x63, 0x78, 0x68, 0x2b, 0x50, 0x46, 0xd8, 0xff, 0x56, 0x73, 0xa3, 0x92, 0xe2, + 0x28, 0x3c, 0xb3, 0x64, 0x8a, 0xd5, 0x5d, 0x07, 0x6a, 0x58, 0xfd, 0x13, 0x62, 0xc6, 0x1d, 0x19, + 0x54, 0xfb, 0x66, 0x82, 0x46, 0xa9, 0x5d, 0x87, 0x05, 0x29, 0x94, 0xa4, 0xf0, 0x46, 0x92, 0xda, + 0xe6, 0x74, 0x6e, 0x28, 0xab, 0xb9, 0x51, 0x2d, 0x52, 0xb7, 0xec, 0xd6, 0xe4, 0xcd, 0x00, 0xdd, + 0x72, 0xf6, 0x26, 0x1b, 0x58, 0xcf, 0x40, 0x2d, 0x0b, 0xb0, 0x6b, 0x8e, 0x39, 0xd1, 0x7a, 0xea, + 0x6f, 0xa9, 0x67, 0x35, 0x60, 0x7e, 0x6f, 0x94, 0xda, 0x27, 0x87, 0x89, 0xf6, 0xed, 0xc6, 0xfe, + 0x91, 0x75, 0xe9, 0x6e, 0xe2, 0xb4, 0x81, 0x5a, 0xc9, 0x0b, 0xb9, 0x21, 0xf5, 0x1e, 0x9c, 0x2f, + 0x12, 0x59, 0x82, 0xe8, 0xff, 0x27, 0xa2, 0x4d, 0x40, 0xc1, 0x94, 0xaf, 0xc9, 0xce, 0x1e, 0x33, + 0x9f, 0x7d, 0x3b, 0x5d, 0xe8, 0x60, 0xb6, 0xd0, 0xc1, 0xfb, 0x42, 0x07, 0x93, 0xa5, 0xae, 0xcc, + 0x96, 0xba, 0xf2, 0xba, 0xd4, 0x95, 0xde, 0xb9, 0x1f, 0xf0, 0xfb, 0x91, 0x0b, 0x3d, 0x1a, 0xc9, + 0x6b, 0x6f, 0x86, 0xd8, 0x65, 0xeb, 0xd3, 0x1f, 0xb7, 0x3a, 0xe8, 0x69, 0xcf, 0x81, 0xf0, 0x74, + 0x48, 0x98, 0xfb, 0x33, 0xef, 0xd7, 0xf9, 0x08, 0x00, 0x00, 0xff, 0xff, 0xe8, 0xb3, 0x0b, 0xaf, + 0x2a, 0x03, 0x00, 0x00, +} + +func (m *GenesisDowntimeEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisDowntimeEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisDowntimeEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n1, err1 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastDowntime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastDowntime):]) + if err1 != nil { + return 0, err1 + } + i -= n1 + i = encodeVarintGenesis(dAtA, i, uint64(n1)) + i-- + dAtA[i] = 0x12 + if m.Duration != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Duration)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n2, err2 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastBlockTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastBlockTime):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintGenesis(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x12 + if len(m.Downtimes) > 0 { + for iNdEx := len(m.Downtimes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Downtimes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisDowntimeEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Duration != 0 { + n += 1 + sovGenesis(uint64(m.Duration)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.LastDowntime) + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Downtimes) > 0 { + for _, e := range m.Downtimes { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.LastBlockTime) + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisDowntimeEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisDowntimeEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisDowntimeEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Duration", wireType) + } + m.Duration = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Duration |= Downtime(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastDowntime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.LastDowntime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Downtimes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Downtimes = append(m.Downtimes, GenesisDowntimeEntry{}) + if err := m.Downtimes[len(m.Downtimes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastBlockTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.LastBlockTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/downtime-detector/types/keys.go b/x/downtime-detector/types/keys.go new file mode 100644 index 00000000000..248f16ad4cf --- /dev/null +++ b/x/downtime-detector/types/keys.go @@ -0,0 +1,15 @@ +package types + +import fmt "fmt" + +// There are few of these keys, so we don't concern ourselves with small key names. +var ( + lastBlockTimestampKey = []byte("last_block_timestamp") + lastDowntimeOfLengthPrefix = "last_downtime_of_length/%s" +) + +func GetLastBlockTimestampKey() []byte { return lastBlockTimestampKey } + +func GetLastDowntimeOfLengthKey(downtimeDur Downtime) []byte { + return []byte(fmt.Sprintf(lastDowntimeOfLengthPrefix, downtimeDur.String())) +} diff --git a/x/gamm/pool-models/balancer/pool_suite_test.go b/x/gamm/pool-models/balancer/pool_suite_test.go index 54484c78e11..848636f992b 100644 --- a/x/gamm/pool-models/balancer/pool_suite_test.go +++ b/x/gamm/pool-models/balancer/pool_suite_test.go @@ -713,59 +713,75 @@ func (suite *KeeperTestSuite) TestBalancerSpotPriceBounds() { tests := []struct { name string - baseDenomPoolInput sdk.Coin - baseDenomWeight sdk.Int quoteDenomPoolInput sdk.Coin quoteDenomWeight sdk.Int + baseDenomPoolInput sdk.Coin + baseDenomWeight sdk.Int expectError bool expectedOutput sdk.Dec }{ { name: "spot price check at max bitlen supply", // 2^196, as >= 2^197 trips max bitlen of 256 - baseDenomPoolInput: sdk.NewCoin(baseDenom, sdk.MustNewDecFromStr("100433627766186892221372630771322662657637687111424552206336").TruncateInt()), - baseDenomWeight: sdk.NewInt(100), - quoteDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.MustNewDecFromStr("100433627766186892221372630771322662657637687111424552206337").TruncateInt()), + quoteDenomPoolInput: sdk.NewCoin(baseDenom, sdk.MustNewDecFromStr("100433627766186892221372630771322662657637687111424552206336").TruncateInt()), quoteDenomWeight: sdk.NewInt(100), + baseDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.MustNewDecFromStr("100433627766186892221372630771322662657637687111424552206337").TruncateInt()), + baseDenomWeight: sdk.NewInt(100), expectError: false, expectedOutput: sdk.MustNewDecFromStr("1.000000000000000000"), }, { name: "spot price check at min supply", - baseDenomPoolInput: sdk.NewCoin(baseDenom, sdk.OneInt()), - baseDenomWeight: sdk.NewInt(100), - quoteDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.OneInt()), + quoteDenomPoolInput: sdk.NewCoin(baseDenom, sdk.OneInt()), quoteDenomWeight: sdk.NewInt(100), + baseDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.OneInt()), + baseDenomWeight: sdk.NewInt(100), expectError: false, expectedOutput: sdk.MustNewDecFromStr("1.000000000000000000"), }, { name: "max spot price with equal weights", - baseDenomPoolInput: sdk.NewCoin(baseDenom, types.MaxSpotPrice.TruncateInt()), - baseDenomWeight: sdk.NewInt(100), - quoteDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.OneInt()), + quoteDenomPoolInput: sdk.NewCoin(baseDenom, types.MaxSpotPrice.TruncateInt()), quoteDenomWeight: sdk.NewInt(100), + baseDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.OneInt()), + baseDenomWeight: sdk.NewInt(100), expectError: false, expectedOutput: types.MaxSpotPrice, }, { // test int overflows name: "max spot price with extreme weights", - baseDenomPoolInput: sdk.NewCoin(baseDenom, types.MaxSpotPrice.TruncateInt()), - baseDenomWeight: sdk.OneInt(), - quoteDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.OneInt()), - quoteDenomWeight: sdk.NewInt(1 << 19), + quoteDenomPoolInput: sdk.NewCoin(baseDenom, types.MaxSpotPrice.TruncateInt()), + quoteDenomWeight: sdk.OneInt(), + baseDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.OneInt()), + baseDenomWeight: sdk.NewInt(1 << 19), expectError: true, }, { name: "greater than max spot price with equal weights", // Max spot price capped at 2^160 - baseDenomPoolInput: sdk.NewCoin(baseDenom, types.MaxSpotPrice.TruncateInt().Add(sdk.OneInt())), + quoteDenomPoolInput: sdk.NewCoin(baseDenom, types.MaxSpotPrice.TruncateInt().Add(sdk.OneInt())), + quoteDenomWeight: sdk.NewInt(100), + baseDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.OneInt()), baseDenomWeight: sdk.NewInt(100), - quoteDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.OneInt()), + expectError: true, + }, + { + name: "internal error due to spot price precision being too small, resulting in 0 spot price", + quoteDenomPoolInput: sdk.NewCoin(baseDenom, sdk.OneInt()), quoteDenomWeight: sdk.NewInt(100), + baseDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.NewDec(10).PowerMut(19).TruncateInt().Sub(sdk.NewInt(2))), + baseDenomWeight: sdk.NewInt(100), expectError: true, }, + { + name: "at min spot price", + quoteDenomPoolInput: sdk.NewCoin(baseDenom, sdk.OneInt()), + quoteDenomWeight: sdk.NewInt(100), + baseDenomPoolInput: sdk.NewCoin(quoteDenom, sdk.NewDec(10).PowerMut(18).TruncateInt()), + baseDenomWeight: sdk.NewInt(100), + expectedOutput: sdk.OneDec().Quo(sdk.NewDec(10).PowerMut(18)), + }, } for _, tc := range tests { @@ -790,7 +806,7 @@ func (suite *KeeperTestSuite) TestBalancerSpotPriceBounds() { sut := func() { spotPrice, err := suite.App.GAMMKeeper.CalculateSpotPrice(suite.Ctx, - poolId, tc.baseDenomPoolInput.Denom, tc.quoteDenomPoolInput.Denom) + poolId, tc.quoteDenomPoolInput.Denom, tc.baseDenomPoolInput.Denom) if tc.expectError { suite.Require().Error(err, "test: %s", tc.name) } else { @@ -804,7 +820,6 @@ func (suite *KeeperTestSuite) TestBalancerSpotPriceBounds() { }) } } - func (suite *KeeperTestSuite) TestCalcJoinPoolShares() { // We append shared calcSingleAssetJoinTestCases with multi-asset and edge // test cases defined in multiAssetExactInputTestCases and multiAssetUneverInputTestCases. diff --git a/x/ibc-hooks/README.md b/x/ibc-hooks/README.md index 3434f20afbb..fb4cd21ebb1 100644 --- a/x/ibc-hooks/README.md +++ b/x/ibc-hooks/README.md @@ -114,6 +114,42 @@ In wasm hooks, post packet execution: * if wasm message has error, return ErrAck * otherwise continue through middleware +## Ack callbacks +A contract that sends an IBC transfer, may need to listen for the ACK from that packet. To allow +contracts to listen on the ack of specific packets, we provide Ack callbacks. -### Testing strategy \ No newline at end of file +### Design + +The sender of an IBC transfer packet may specify a callback for when the ack of that packet is received in the memo +field of the transfer packet. + +Crucially, _only_ the IBC packet sender can set the callback. + +### Use case + +The crosschain swaps implementation sends an IBC transfer. If the transfer were to fail, we want to allow the sender +to be able to retrieve their funds (which would otherwise be stuck in the contract). To do this, we allow users to +retrieve the funds after the timeout has passed, but without the ack information, we cannot guarantee that the send +hasn't failed (i.e.: returned an error ack notifying that the receiving change didn't accept it) + +### Implementation + +#### Callback information in memo + +For the callback to be processed, the transfer packet's memo should contain the following in its JSON: + +`{"ibc_callback": "osmo1contractAddr"}` + +The wasm hooks will keep the mapping from the packet's channel and sequence to the contract in storage. When an ack is +received, it will notify the specified contract via a sudo message. + +#### Interface for receiving the Ack + +The contract that awaits the callback should implement the following interface for a sudo message: + +* `ReceiveAck { channel: String, sequence: u64, ack: String, success: bool }` + +# Testing strategy + +See go tests. \ No newline at end of file diff --git a/x/ibc-hooks/bytecode/counter.wasm b/x/ibc-hooks/bytecode/counter.wasm index 55f18df6dd3..af14177e329 100644 Binary files a/x/ibc-hooks/bytecode/counter.wasm and b/x/ibc-hooks/bytecode/counter.wasm differ diff --git a/x/ibc-hooks/bytecode/crosschain_swaps.wasm b/x/ibc-hooks/bytecode/crosschain_swaps.wasm new file mode 100644 index 00000000000..600d52eb956 Binary files /dev/null and b/x/ibc-hooks/bytecode/crosschain_swaps.wasm differ diff --git a/x/ibc-hooks/bytecode/swaprouter.wasm b/x/ibc-hooks/bytecode/swaprouter.wasm new file mode 100644 index 00000000000..684df978d16 Binary files /dev/null and b/x/ibc-hooks/bytecode/swaprouter.wasm differ diff --git a/x/ibc-hooks/genesis.go b/x/ibc-hooks/genesis.go index c59955bb814..0c951267a50 100644 --- a/x/ibc-hooks/genesis.go +++ b/x/ibc-hooks/genesis.go @@ -4,10 +4,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" + "github.com/osmosis-labs/osmosis/x/ibc-hooks/types" + "github.com/osmosis-labs/osmosis/osmoutils" ) -var WasmHookModuleAccountAddr sdk.AccAddress = address.Module(ModuleName, []byte("wasm-hook intermediary account")) +var WasmHookModuleAccountAddr sdk.AccAddress = address.Module(types.ModuleName, []byte("wasm-hook intermediary account")) func IbcHooksInitGenesis(ctx sdk.Context, ak osmoutils.AccountKeeper) { err := osmoutils.CreateModuleAccount(ctx, ak, WasmHookModuleAccountAddr) diff --git a/x/ibc-hooks/go.mod b/x/ibc-hooks/go.mod new file mode 100644 index 00000000000..e4808eac863 --- /dev/null +++ b/x/ibc-hooks/go.mod @@ -0,0 +1,145 @@ +module github.com/osmosis-labs/osmosis/x/ibc-hooks + +go 1.18 + +require ( + github.com/CosmWasm/wasmd v0.29.2 + github.com/cosmos/cosmos-sdk v0.46.7 + github.com/cosmos/ibc-go/v4 v4.2.0 + github.com/gorilla/mux v1.8.0 + github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230101095308-fa4e70e17dbf + github.com/spf13/cobra v1.6.1 + github.com/tendermint/tendermint v0.34.24 +) + +require ( + filippo.io/edwards25519 v1.0.0-beta.2 // indirect + github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect + github.com/99designs/keyring v1.2.1 // indirect + github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect + github.com/CosmWasm/wasmvm v1.1.1 // indirect + github.com/Workiva/go-datastructures v1.0.53 // indirect + github.com/armon/go-metrics v0.4.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/btcsuite/btcd v0.22.1 // indirect + github.com/cenkalti/backoff/v4 v4.1.1 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/coinbase/rosetta-sdk-go v0.7.0 // indirect + github.com/confio/ics23/go v0.7.0 // indirect + github.com/cosmos/btcutil v1.0.4 // indirect + github.com/cosmos/cosmos-proto v1.0.0-alpha8 // indirect + github.com/cosmos/go-bip39 v1.0.0 // indirect + github.com/cosmos/gogoproto v1.4.3 // indirect + github.com/cosmos/gorocksdb v1.2.0 // indirect + github.com/cosmos/iavl v0.19.4 // indirect + github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect + github.com/cosmos/ledger-go v0.9.2 // indirect + github.com/creachadair/taskgroup v0.3.2 // indirect + github.com/danieljoos/wincred v1.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect + github.com/dgraph-io/badger/v3 v3.2103.2 // indirect + github.com/dgraph-io/ristretto v0.1.0 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac // indirect + github.com/dvsekhvalnov/jose2go v1.5.0 // indirect + github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect + github.com/gogo/gateway v1.1.0 // indirect + github.com/gogo/protobuf v1.3.3 // indirect + github.com/golang/glog v1.0.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/flatbuffers v1.12.1 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/orderedcode v0.0.1 // indirect + github.com/gorilla/handlers v1.5.1 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/gtank/merlin v0.1.1 // indirect + github.com/gtank/ristretto255 v0.1.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 // indirect + github.com/improbable-eng/grpc-web v0.15.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/klauspost/compress v1.15.11 // indirect + github.com/lib/pq v1.10.6 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect + github.com/minio/highwayhash v1.0.2 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mtibben/percent v0.2.1 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect + github.com/rakyll/statik v0.1.7 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/regen-network/cosmos-proto v0.3.1 // indirect + github.com/rs/cors v1.8.2 // indirect + github.com/rs/zerolog v1.27.0 // indirect + github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/spf13/afero v1.9.2 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.14.0 // indirect + github.com/stretchr/testify v1.8.1 // indirect + github.com/subosito/gotenv v1.4.1 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect + github.com/tendermint/btcd v0.1.1 // indirect + github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect + github.com/tendermint/go-amino v0.16.0 // indirect + github.com/tendermint/tm-db v0.6.8-0.20220506192307-f628bb5dc95b // indirect + github.com/zondax/hid v0.9.0 // indirect + go.etcd.io/bbolt v1.3.6 // indirect + go.opencensus.io v0.23.0 // indirect + golang.org/x/crypto v0.1.0 // indirect + golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect + golang.org/x/net v0.1.0 // indirect + golang.org/x/sys v0.1.0 // indirect + golang.org/x/term v0.1.0 // indirect + golang.org/x/text v0.4.0 // indirect + google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e // indirect + google.golang.org/grpc v1.50.1 // indirect + google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + nhooyr.io/websocket v1.8.6 // indirect +) + +replace ( + // osmosis-patched wasmd + github.com/CosmWasm/wasmd => github.com/osmosis-labs/wasmd v0.29.2-0.20221222131554-7c8ea36a6e30 + // dragonberry + github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 + // Our cosmos-sdk branch is: https://github.com/osmosis-labs/cosmos-sdk, current branch: v13.x. Direct commit link: https://github.com/osmosis-labs/cosmos-sdk/commit/8757a61551aa1ea993c85a523e18094ab555b1d7 + // tag: https://github.com/osmosis-labs/cosmos-sdk/releases/tag/sdk-v13.0.0-rc2 + github.com/cosmos/cosmos-sdk => github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20221118211718-545aed73e94e + // use cosmos-compatible protobufs + github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 +) diff --git a/x/ibc-hooks/go.sum b/x/ibc-hooks/go.sum new file mode 100644 index 00000000000..c260c6fdaa8 --- /dev/null +++ b/x/ibc-hooks/go.sum @@ -0,0 +1,1295 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.0.0-beta.2 h1:/BZRNzm8N4K4eWfK28dL4yescorxtO7YG1yun8fy+pI= +filippo.io/edwards25519 v1.0.0-beta.2/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= +github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +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/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/CosmWasm/wasmvm v1.1.1 h1:0xtdrmmsP9fibe+x42WcMkp5aQ738BICgcH3FNVLzm4= +github.com/CosmWasm/wasmvm v1.1.1/go.mod h1:ei0xpvomwSdONsxDuONzV7bL1jSET1M8brEx0FCXc+A= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= +github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= +github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= +github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= +github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= +github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= +github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +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 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= +github.com/coinbase/rosetta-sdk-go v0.7.0/go.mod h1:7nD3oBPIiHqhRprqvMgPoGxe/nyq3yftRmpsy29coWE= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= +github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= +github.com/cosmos/cosmos-proto v1.0.0-alpha8 h1:d3pCRuMYYvGA5bM0ZbbjKn+AoQD4A7dyNG2wzwWalUw= +github.com/cosmos/cosmos-proto v1.0.0-alpha8/go.mod h1:6/p+Bc4O8JKeZqe0VqUGTX31eoYqemTT4C1hLCWsO7I= +github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 h1:iKclrn3YEOwk4jQHT2ulgzuXyxmzmPczUalMwW4XH9k= +github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= +github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= +github.com/cosmos/gogoproto v1.4.3 h1:RP3yyVREh9snv/lsOvmsAPQt8f44LgL281X0IOIhhcI= +github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU= +github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= +github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= +github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok= +github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= +github.com/cosmos/ibc-go/v4 v4.2.0 h1:Fx/kKq/uvawrAxk6ZrQ6sEIgffLRU5Cs/AUnvpPBrHI= +github.com/cosmos/ibc-go/v4 v4.2.0/go.mod h1:57qWScDtfCx3FOMLYmBIKPbOLE6xiVhrgxHAQmbWYXM= +github.com/cosmos/interchain-accounts v0.2.4 h1:7UrroFQsCRSp17980mk6anx4YteveIJVkU+a0wlsHQI= +github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= +github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= +github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= +github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= +github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +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/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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +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/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v3 v3.2103.2 h1:dpyM5eCJAtQCBcMCZcT4UBZchuTJgCywerHHgmxfxM8= +github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= +github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac h1:opbrjaN/L8gg6Xh5D04Tem+8xVcz6ajZlGCs49mQgyg= +github.com/dustin/go-humanize v1.0.1-0.20200219035652-afde56e7acac/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= +github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= +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= +github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= +github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +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.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +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/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= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= +github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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-0.20201103224600-674baa8c7fc3/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/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.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= +github.com/google/flatbuffers v1.12.1/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= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= +github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +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= +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-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-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= +github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= +github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b h1:izTof8BKh/nE1wrKOrloNA5q4odOarjf+Xpe+4qow98= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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.11/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= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= +github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= +github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= +github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20221118211718-545aed73e94e h1:A3byMZpvq21iI7yWJUNdHw0nf8jVAbVUsWY9twnXSXE= +github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20221118211718-545aed73e94e/go.mod h1:rud0OaBIuq3+qOqtwT4SR7Q7iSzRp7w41fjninTjfnQ= +github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230101095308-fa4e70e17dbf h1:FZOlrTSaf/YWokt3+tSSZpcu6zu3dXLhsvhJWkHeBxU= +github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230101095308-fa4e70e17dbf/go.mod h1:T7CCZKYhKWASnv5mRE8u3m0gst3NZ/sU16Brjmv4UPw= +github.com/osmosis-labs/wasmd v0.29.2-0.20221222131554-7c8ea36a6e30 h1:6uMi7HhPSwvKKU7j5NqljseFTEz4I7qHr+IPnnn42Ck= +github.com/osmosis-labs/wasmd v0.29.2-0.20221222131554-7c8ea36a6e30/go.mod h1:5fDYJyMXBq6u2iuHqqOTYiZ5NitIOeIW5k7qEXqbwJE= +github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= +github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= +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/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzywPxOvwMdxcg= +github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= +github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= +github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= +github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= +github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +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/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= +github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= +github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= +github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= +github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= +github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= +github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= +github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tendermint/tendermint v0.34.24 h1:879MKKJWYYPJEMMKME+DWUTY4V9f/FBpnZDI82ky+4k= +github.com/tendermint/tendermint v0.34.24/go.mod h1:rXVrl4OYzmIa1I91av3iLv2HS0fGSiucyW9J4aMTpKI= +github.com/tendermint/tm-db v0.6.8-0.20220506192307-f628bb5dc95b h1:Y3ZPG6gdDCAV2sdGkD759ji/09GzaNu1X3qKTmZIbTo= +github.com/tendermint/tm-db v0.6.8-0.20220506192307-f628bb5dc95b/go.mod h1:ADqbS9NOSnBRK9R2RtYC61CdsHmVMD/yXAzcMuPexbU= +github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= +github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= +github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +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= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +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= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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/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= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e h1:S9GbmC1iCgvbLyAokVCwiO6tVIrU9Y7c5oMx1V/ki/Y= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk= +google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +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 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/x/ibc-hooks/hooks.go b/x/ibc-hooks/hooks.go index 14557cd1dcd..49081b2cac4 100644 --- a/x/ibc-hooks/hooks.go +++ b/x/ibc-hooks/hooks.go @@ -6,20 +6,20 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" // ibc-go - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) type Hooks interface{} type OnChanOpenInitOverrideHooks interface { - OnChanOpenInitOverride(im IBCMiddleware, ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) error + OnChanOpenInitOverride(im IBCMiddleware, ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) (string, error) } type OnChanOpenInitBeforeHooks interface { OnChanOpenInitBeforeHook(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) } type OnChanOpenInitAfterHooks interface { - OnChanOpenInitAfterHook(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, err error) + OnChanOpenInitAfterHook(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, finalVersion string, err error) } // OnChanOpenTry Hooks diff --git a/x/ibc-hooks/ibc_middleware_test.go b/x/ibc-hooks/ibc_middleware_test.go deleted file mode 100644 index 81624c48fef..00000000000 --- a/x/ibc-hooks/ibc_middleware_test.go +++ /dev/null @@ -1,353 +0,0 @@ -package ibc_hooks_test - -import ( - "encoding/json" - "fmt" - "testing" - - ibc_hooks "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks" - - "github.com/osmosis-labs/osmosis/osmoutils" - - "github.com/osmosis-labs/osmosis/v13/app/apptesting" - - "github.com/stretchr/testify/suite" - - sdk "github.com/cosmos/cosmos-sdk/types" - - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - - osmosisibctesting "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/testutil" - - "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks/testutils" -) - -type HooksTestSuite struct { - apptesting.KeeperTestHelper - - coordinator *ibctesting.Coordinator - - chainA *osmosisibctesting.TestChain - chainB *osmosisibctesting.TestChain - - path *ibctesting.Path -} - -func (suite *HooksTestSuite) SetupTest() { - suite.Setup() - ibctesting.DefaultTestingAppInit = osmosisibctesting.SetupTestingApp - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) - suite.chainA = &osmosisibctesting.TestChain{ - TestChain: suite.coordinator.GetChain(ibctesting.GetChainID(1)), - } - suite.chainB = &osmosisibctesting.TestChain{ - TestChain: suite.coordinator.GetChain(ibctesting.GetChainID(2)), - } - err := suite.chainA.MoveEpochsToTheFuture() - suite.Require().NoError(err) - err = suite.chainB.MoveEpochsToTheFuture() - suite.Require().NoError(err) - suite.path = NewTransferPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(suite.path) -} - -func TestIBCHooksTestSuite(t *testing.T) { - suite.Run(t, new(HooksTestSuite)) -} - -// ToDo: Move this to osmosistesting to avoid repetition -func NewTransferPath(chainA, chainB *osmosisibctesting.TestChain) *ibctesting.Path { - path := ibctesting.NewPath(chainA.TestChain, chainB.TestChain) - path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort - path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort - path.EndpointA.ChannelConfig.Version = transfertypes.Version - path.EndpointB.ChannelConfig.Version = transfertypes.Version - - return path -} - -func (suite *HooksTestSuite) TestOnRecvPacketHooks() { - var ( - trace transfertypes.DenomTrace - amount sdk.Int - receiver string - status testutils.Status - ) - - testCases := []struct { - msg string - malleate func(*testutils.Status) - expPass bool - }{ - {"override", func(status *testutils.Status) { - suite.chainB.GetOsmosisApp().TransferStack. - ICS4Middleware.Hooks = testutils.TestRecvOverrideHooks{Status: status} - }, true}, - {"before and after", func(status *testutils.Status) { - suite.chainB.GetOsmosisApp().TransferStack. - ICS4Middleware.Hooks = testutils.TestRecvBeforeAfterHooks{Status: status} - }, true}, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.msg, func() { - suite.SetupTest() // reset - - path := NewTransferPath(suite.chainA, suite.chainB) - suite.coordinator.Setup(path) - receiver = suite.chainB.SenderAccount.GetAddress().String() // must be explicitly changed in malleate - status = testutils.Status{} - - amount = sdk.NewInt(100) // must be explicitly changed in malleate - seq := uint64(1) - - trace = transfertypes.ParseDenomTrace(sdk.DefaultBondDenom) - - // send coin from chainA to chainB - transferMsg := transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoin(trace.IBCDenom(), amount), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0) - _, err := suite.chainA.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - tc.malleate(&status) - - data := transfertypes.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), suite.chainA.SenderAccount.GetAddress().String(), receiver) - packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - - ack := suite.chainB.GetOsmosisApp().TransferStack. - OnRecvPacket(suite.chainB.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) - - if tc.expPass { - suite.Require().True(ack.Success()) - } else { - suite.Require().False(ack.Success()) - } - - if _, ok := suite.chainB.GetOsmosisApp().TransferStack. - ICS4Middleware.Hooks.(testutils.TestRecvOverrideHooks); ok { - suite.Require().True(status.OverrideRan) - suite.Require().False(status.BeforeRan) - suite.Require().False(status.AfterRan) - } - - if _, ok := suite.chainB.GetOsmosisApp().TransferStack. - ICS4Middleware.Hooks.(testutils.TestRecvBeforeAfterHooks); ok { - suite.Require().False(status.OverrideRan) - suite.Require().True(status.BeforeRan) - suite.Require().True(status.AfterRan) - } - }) - } -} - -func (suite *HooksTestSuite) makeMockPacket(receiver, memo string, prevSequence uint64) channeltypes.Packet { - packetData := transfertypes.FungibleTokenPacketData{ - Denom: sdk.DefaultBondDenom, - Amount: "1", - Sender: suite.chainB.SenderAccount.GetAddress().String(), - Receiver: receiver, - Memo: memo, - } - - return channeltypes.NewPacket( - packetData.GetBytes(), - prevSequence+1, - suite.path.EndpointB.ChannelConfig.PortID, - suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(0, 100), - 0, - ) -} - -func (suite *HooksTestSuite) receivePacket(receiver, memo string) []byte { - return suite.receivePacketWithSequence(receiver, memo, 0) -} - -func (suite *HooksTestSuite) receivePacketWithSequence(receiver, memo string, prevSequence uint64) []byte { - channelCap := suite.chainB.GetChannelCapability( - suite.path.EndpointB.ChannelConfig.PortID, - suite.path.EndpointB.ChannelID) - - packet := suite.makeMockPacket(receiver, memo, prevSequence) - - err := suite.chainB.GetOsmosisApp().HooksICS4Wrapper.SendPacket( - suite.chainB.GetContext(), channelCap, packet) - suite.Require().NoError(err, "IBC send failed. Expected success. %s", err) - - // Update both clients - err = suite.path.EndpointB.UpdateClient() - suite.Require().NoError(err) - err = suite.path.EndpointA.UpdateClient() - suite.Require().NoError(err) - - // recv in chain a - res, err := suite.path.EndpointA.RecvPacketWithResult(packet) - - // get the ack from the chain a's response - ack, err := ibctesting.ParseAckFromEvents(res.GetEvents()) - suite.Require().NoError(err) - - // manually send the acknowledgement to chain b - err = suite.path.EndpointA.AcknowledgePacket(packet, ack) - suite.Require().NoError(err) - return ack -} - -func (suite *HooksTestSuite) TestRecvTransferWithMetadata() { - // Setup contract - suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/echo.wasm") - addr := suite.chainA.InstantiateContract(&suite.Suite, "{}") - - ackBytes := suite.receivePacket(addr.String(), fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"echo": {"msg": "test"} } } }`, addr)) - ackStr := string(ackBytes) - fmt.Println(ackStr) - var ack map[string]string // This can't be unmarshalled to Acknowledgement because it's fetched from the events - err := json.Unmarshal(ackBytes, &ack) - suite.Require().NoError(err) - suite.Require().NotContains(ack, "error") - suite.Require().Equal(ack["result"], "eyJjb250cmFjdF9yZXN1bHQiOiJkR2hwY3lCemFHOTFiR1FnWldOb2J3PT0iLCJpYmNfYWNrIjoiZXlKeVpYTjFiSFFpT2lKQlVUMDlJbjA9In0=") -} - -// After successfully executing a wasm call, the contract should have the funds sent via IBC -func (suite *HooksTestSuite) TestFundsAreTransferredToTheContract() { - // Setup contract - suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/echo.wasm") - addr := suite.chainA.InstantiateContract(&suite.Suite, "{}") - - // Check that the contract has no funds - localDenom := osmoutils.MustExtractDenomFromPacketOnRecv(suite.makeMockPacket("", "", 0)) - balance := suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) - suite.Require().Equal(sdk.NewInt(0), balance.Amount) - - // Execute the contract via IBC - ackBytes := suite.receivePacket(addr.String(), fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"echo": {"msg": "test"} } } }`, addr)) - ackStr := string(ackBytes) - fmt.Println(ackStr) - var ack map[string]string // This can't be unmarshalled to Acknowledgement because it's fetched from the events - err := json.Unmarshal(ackBytes, &ack) - suite.Require().NoError(err) - suite.Require().NotContains(ack, "error") - suite.Require().Equal(ack["result"], "eyJjb250cmFjdF9yZXN1bHQiOiJkR2hwY3lCemFHOTFiR1FnWldOb2J3PT0iLCJpYmNfYWNrIjoiZXlKeVpYTjFiSFFpT2lKQlVUMDlJbjA9In0=") - - // Check that the token has now been transferred to the contract - balance = suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) - suite.Require().Equal(sdk.NewInt(1), balance.Amount) -} - -// If the wasm call wails, the contract acknowledgement should be an error and the funds returned -func (suite *HooksTestSuite) TestFundsAreReturnedOnFailedContractExec() { - // Setup contract - suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/echo.wasm") - addr := suite.chainA.InstantiateContract(&suite.Suite, "{}") - - // Check that the contract has no funds - localDenom := osmoutils.MustExtractDenomFromPacketOnRecv(suite.makeMockPacket("", "", 0)) - balance := suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) - suite.Require().Equal(sdk.NewInt(0), balance.Amount) - - // Execute the contract via IBC with a message that the contract will reject - ackBytes := suite.receivePacket(addr.String(), fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"not_echo": {"msg": "test"} } } }`, addr)) - ackStr := string(ackBytes) - fmt.Println(ackStr) - var ack map[string]string // This can't be unmarshalled to Acknowledgement because it's fetched from the events - err := json.Unmarshal(ackBytes, &ack) - suite.Require().NoError(err) - suite.Require().Contains(ack, "error") - - // Check that the token has now been transferred to the contract - balance = suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) - fmt.Println(balance) - suite.Require().Equal(sdk.NewInt(0), balance.Amount) -} - -func (suite *HooksTestSuite) TestPacketsThatShouldBeSkipped() { - var sequence uint64 - receiver := suite.chainB.SenderAccount.GetAddress().String() - - testCases := []struct { - memo string - expPassthrough bool - }{ - {"", true}, - {"{01]", true}, // bad json - {"{}", true}, - {`{"something": ""}`, true}, - {`{"wasm": "test"}`, false}, - {`{"wasm": []`, true}, // invalid top level JSON - {`{"wasm": {}`, true}, // invalid top level JSON - {`{"wasm": []}`, false}, - {`{"wasm": {}}`, false}, - {`{"wasm": {"contract": "something"}}`, false}, - {`{"wasm": {"contract": "osmo1clpqr4nrk4khgkxj78fcwwh6dl3uw4epasmvnj"}}`, false}, - {`{"wasm": {"msg": "something"}}`, false}, - // invalid receiver - {`{"wasm": {"contract": "osmo1clpqr4nrk4khgkxj78fcwwh6dl3uw4epasmvnj", "msg": {}}}`, false}, - // msg not an object - {fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": 1}}`, receiver), false}, - } - - for _, tc := range testCases { - ackBytes := suite.receivePacketWithSequence(receiver, tc.memo, sequence) - ackStr := string(ackBytes) - fmt.Println(ackStr) - var ack map[string]string // This can't be unmarshalled to Acknowledgement because it's fetched from the events - err := json.Unmarshal(ackBytes, &ack) - suite.Require().NoError(err) - if tc.expPassthrough { - suite.Require().Equal("AQ==", ack["result"], tc.memo) - } else { - suite.Require().Contains(ackStr, "error", tc.memo) - } - sequence += 1 - } -} - -// After successfully executing a wasm call, the contract should have the funds sent via IBC -func (suite *HooksTestSuite) TestFundTracking() { - // Setup contract - suite.chainA.StoreContractCode(&suite.Suite, "./bytecode/counter.wasm") - addr := suite.chainA.InstantiateContract(&suite.Suite, `{"count": 0}`) - - // Check that the contract has no funds - localDenom := osmoutils.MustExtractDenomFromPacketOnRecv(suite.makeMockPacket("", "", 0)) - balance := suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) - suite.Require().Equal(sdk.NewInt(0), balance.Amount) - - // Execute the contract via IBC - suite.receivePacket( - addr.String(), - fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"increment": {} } } }`, addr)) - - state := suite.chainA.QueryContract( - &suite.Suite, addr, - []byte(fmt.Sprintf(`{"get_count": {"addr": "%s"}}`, ibc_hooks.WasmHookModuleAccountAddr))) - suite.Require().Equal(`{"count":0}`, state) - - state = suite.chainA.QueryContract( - &suite.Suite, addr, - []byte(fmt.Sprintf(`{"get_total_funds": {"addr": "%s"}}`, ibc_hooks.WasmHookModuleAccountAddr))) - suite.Require().Equal(`{"total_funds":[]}`, state) - - suite.receivePacketWithSequence( - addr.String(), - fmt.Sprintf(`{"wasm": {"contract": "%s", "msg": {"increment": {} } } }`, addr), 1) - - state = suite.chainA.QueryContract( - &suite.Suite, addr, - []byte(fmt.Sprintf(`{"get_count": {"addr": "%s"}}`, ibc_hooks.WasmHookModuleAccountAddr))) - suite.Require().Equal(`{"count":1}`, state) - - state = suite.chainA.QueryContract( - &suite.Suite, addr, - []byte(fmt.Sprintf(`{"get_total_funds": {"addr": "%s"}}`, ibc_hooks.WasmHookModuleAccountAddr))) - suite.Require().Equal(`{"total_funds":[{"denom":"ibc/C053D637CCA2A2BA030E2C5EE1B28A16F71CCB0E45E8BE52766DC1B241B77878","amount":"1"}]}`, state) - - // Check that the token has now been transferred to the contract - balance = suite.chainA.GetOsmosisApp().BankKeeper.GetBalance(suite.chainA.GetContext(), addr, localDenom) - suite.Require().Equal(sdk.NewInt(2), balance.Amount) -} diff --git a/x/ibc-hooks/ibc_module.go b/x/ibc-hooks/ibc_module.go index b7646274a02..50430eb08dd 100644 --- a/x/ibc-hooks/ibc_module.go +++ b/x/ibc-hooks/ibc_module.go @@ -6,9 +6,9 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" // ibc-go - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ porttypes.Middleware = &IBCMiddleware{} @@ -35,7 +35,7 @@ func (im IBCMiddleware) OnChanOpenInit( channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { if hook, ok := im.ICS4Middleware.Hooks.(OnChanOpenInitOverrideHooks); ok { return hook.OnChanOpenInitOverride(im, ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) } @@ -44,12 +44,12 @@ func (im IBCMiddleware) OnChanOpenInit( hook.OnChanOpenInitBeforeHook(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) } - err := im.App.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) + finalVersion, err := im.App.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version) if hook, ok := im.ICS4Middleware.Hooks.(OnChanOpenInitAfterHooks); ok { - hook.OnChanOpenInitAfterHook(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version, err) + hook.OnChanOpenInitAfterHook(ctx, order, connectionHops, portID, channelID, channelCap, counterparty, version, finalVersion, err) } - return err + return version, err } // OnChanOpenTry implements the IBCMiddleware interface @@ -252,6 +252,6 @@ func (im IBCMiddleware) WriteAcknowledgement( return im.ICS4Middleware.WriteAcknowledgement(ctx, chanCap, packet, ack) } -//func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { -// return im.ICS4Middleware.GetAppVersion(ctx, portID, channelID) -//} +func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return im.ICS4Middleware.GetAppVersion(ctx, portID, channelID) +} diff --git a/x/ibc-hooks/ics4_middleware.go b/x/ibc-hooks/ics4_middleware.go index 6ec2b54b2d4..5aeeeca3239 100644 --- a/x/ibc-hooks/ics4_middleware.go +++ b/x/ibc-hooks/ics4_middleware.go @@ -6,8 +6,8 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" // ibc-go - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ porttypes.ICS4Wrapper = &ICS4Middleware{} @@ -60,18 +60,18 @@ func (i ICS4Middleware) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilit return err } -//func (i ICS4Middleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { -// if hook, ok := i.Hooks.(GetAppVersionOverrideHooks); ok { -// return hook.GetAppVersionOverride(i, ctx, portID, channelID) -// } -// -// if hook, ok := i.Hooks.(GetAppVersionBeforeHooks); ok { -// hook.GetAppVersionBeforeHook(ctx, portID, channelID) -// } -// version, err := (*i.channel).GetAppVersion(ctx, portID, channelID) -// if hook, ok := i.Hooks.(GetAppVersionAfterHooks); ok { -// hook.GetAppVersionAfterHook(ctx, portID, channelID, version, err) -// } -// -// return version, err -//} +func (i ICS4Middleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + if hook, ok := i.Hooks.(GetAppVersionOverrideHooks); ok { + return hook.GetAppVersionOverride(i, ctx, portID, channelID) + } + + if hook, ok := i.Hooks.(GetAppVersionBeforeHooks); ok { + hook.GetAppVersionBeforeHook(ctx, portID, channelID) + } + version, err := i.channel.GetAppVersion(ctx, portID, channelID) + if hook, ok := i.Hooks.(GetAppVersionAfterHooks); ok { + hook.GetAppVersionAfterHook(ctx, portID, channelID, version, err) + } + + return version, err +} diff --git a/x/ibc-hooks/keeper/keeper.go b/x/ibc-hooks/keeper/keeper.go new file mode 100644 index 00000000000..5aa2965bcbd --- /dev/null +++ b/x/ibc-hooks/keeper/keeper.go @@ -0,0 +1,53 @@ +package keeper + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/osmosis-labs/osmosis/x/ibc-hooks/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type ( + Keeper struct { + storeKey sdk.StoreKey + } +) + +// NewKeeper returns a new instance of the x/ibchooks keeper +func NewKeeper( + storeKey sdk.StoreKey, +) Keeper { + return Keeper{ + storeKey: storeKey, + } +} + +// Logger returns a logger for the x/tokenfactory module +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +func GetPacketKey(channel string, packetSequence uint64) []byte { + return []byte(fmt.Sprintf("%s::%d", channel, packetSequence)) +} + +// StorePacketCallback stores which contract will be listening for the ack or timeout of a packet +func (k Keeper) StorePacketCallback(ctx sdk.Context, channel string, packetSequence uint64, contract string) { + store := ctx.KVStore(k.storeKey) + store.Set(GetPacketKey(channel, packetSequence), []byte(contract)) +} + +// GetPacketCallback returns the bech32 addr of the contract that is expecting a callback from a packet +func (k Keeper) GetPacketCallback(ctx sdk.Context, channel string, packetSequence uint64) string { + store := ctx.KVStore(k.storeKey) + return string(store.Get(GetPacketKey(channel, packetSequence))) +} + +// DeletePacketCallback deletes the callback from storage once it has been processed +func (k Keeper) DeletePacketCallback(ctx sdk.Context, channel string, packetSequence uint64) { + store := ctx.KVStore(k.storeKey) + store.Delete(GetPacketKey(channel, packetSequence)) +} diff --git a/x/ibc-hooks/sdkmodule.go b/x/ibc-hooks/sdkmodule.go index 2619629cf56..9303dff219e 100644 --- a/x/ibc-hooks/sdkmodule.go +++ b/x/ibc-hooks/sdkmodule.go @@ -11,6 +11,8 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" + "github.com/osmosis-labs/osmosis/x/ibc-hooks/types" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/osmosis-labs/osmosis/osmoutils" @@ -19,12 +21,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) -type Ibcmodule struct{} - var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} - ModuleName = "ibchooks" + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} ) // AppModuleBasic defines the basic application module used by the mint module. @@ -34,7 +33,7 @@ var _ module.AppModuleBasic = AppModuleBasic{} // Name returns the mint module's name. func (AppModuleBasic) Name() string { - return ModuleName + return types.ModuleName } // RegisterLegacyAminoCodec registers the mint module's types on the given LegacyAmino codec. @@ -88,7 +87,7 @@ func NewAppModule(ak osmoutils.AccountKeeper) AppModule { // Name returns the mint module's name. func (AppModule) Name() string { - return ModuleName + return types.ModuleName } // RegisterInvariants registers the mint module invariants. @@ -105,7 +104,7 @@ func (AppModule) QuerierRoute() string { // LegacyQuerierHandler returns the x/mint module's sdk.Querier. func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier { return func(sdk.Context, []string, abci.RequestQuery) ([]byte, error) { - return nil, fmt.Errorf("legacy querier not supported for the x/%s module", ModuleName) + return nil, fmt.Errorf("legacy querier not supported for the x/%s module", types.ModuleName) } } diff --git a/x/ibc-hooks/types/keys.go b/x/ibc-hooks/types/keys.go new file mode 100644 index 00000000000..b28ee341b15 --- /dev/null +++ b/x/ibc-hooks/types/keys.go @@ -0,0 +1,7 @@ +package types + +const ( + ModuleName = "ibchooks" + StoreKey = "hooks-for-ibc" // not using the module name because of collisions with key "ibc" + IBCCallbackKey = "ibc_callback" +) diff --git a/x/ibc-hooks/wasm_hook.go b/x/ibc-hooks/wasm_hook.go index 05a4b53584f..571b3e05935 100644 --- a/x/ibc-hooks/wasm_hook.go +++ b/x/ibc-hooks/wasm_hook.go @@ -4,17 +4,22 @@ import ( "encoding/json" "fmt" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/osmosis-labs/osmosis/x/ibc-hooks/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/osmosis-labs/osmosis/osmoutils" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" sdk "github.com/cosmos/cosmos-sdk/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" - "github.com/osmosis-labs/osmosis/v13/x/ibc-hooks/types" + "github.com/osmosis-labs/osmosis/x/ibc-hooks/types" ) type ContractAck struct { @@ -24,14 +29,22 @@ type ContractAck struct { type WasmHooks struct { ContractKeeper *wasmkeeper.PermissionedKeeper + ibcHooksKeeper *keeper.Keeper } -func NewWasmHooks(contractKeeper *wasmkeeper.PermissionedKeeper) WasmHooks { - return WasmHooks{ContractKeeper: contractKeeper} +func NewWasmHooks(ibcHooksKeeper *keeper.Keeper, contractKeeper *wasmkeeper.PermissionedKeeper) WasmHooks { + return WasmHooks{ + ContractKeeper: contractKeeper, + ibcHooksKeeper: ibcHooksKeeper, + } +} + +func (h WasmHooks) ProperlyConfigured() bool { + return h.ContractKeeper != nil && h.ibcHooksKeeper != nil } func (h WasmHooks) OnRecvPacketOverride(im IBCMiddleware, ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { - if h.ContractKeeper == nil { + if !h.ProperlyConfigured() { // Not configured return im.App.OnRecvPacket(ctx, packet, relayer) } @@ -47,10 +60,10 @@ func (h WasmHooks) OnRecvPacketOverride(im IBCMiddleware, ctx sdk.Context, packe return im.App.OnRecvPacket(ctx, packet, relayer) } if err != nil { - return channeltypes.NewErrorAcknowledgement(err.Error()) + return osmoutils.NewStringErrorAcknowledgement(err.Error()) } if msgBytes == nil || contractAddr == nil { // This should never happen - return channeltypes.NewErrorAcknowledgement("error in wasmhook message validation") + return osmoutils.NewStringErrorAcknowledgement("error in wasmhook message validation") } // The funds sent on this packet need to be transferred to the wasm hooks module address/ @@ -62,7 +75,7 @@ func (h WasmHooks) OnRecvPacketOverride(im IBCMiddleware, ctx sdk.Context, packe data.Receiver = WasmHookModuleAccountAddr.String() bz, err := json.Marshal(data) if err != nil { - return channeltypes.NewErrorAcknowledgement(fmt.Sprintf("cannot marshal the ICS20 packet: %s", err.Error())) + return osmoutils.NewStringErrorAcknowledgement(fmt.Sprintf("cannot marshal the ICS20 packet: %s", err.Error())) } packet.Data = bz @@ -76,7 +89,7 @@ func (h WasmHooks) OnRecvPacketOverride(im IBCMiddleware, ctx sdk.Context, packe if !ok { // This should never happen, as it should've been caught in the underlaying call to OnRecvPacket, // but returning here for completeness - return channeltypes.NewErrorAcknowledgement("Invalid packet data: Amount is not an int") + return osmoutils.NewStringErrorAcknowledgement("Invalid packet data: Amount is not an int") } // The packet's denom is the denom in the sender chain. This needs to be converted to the local denom. @@ -91,13 +104,13 @@ func (h WasmHooks) OnRecvPacketOverride(im IBCMiddleware, ctx sdk.Context, packe } response, err := h.execWasmMsg(ctx, &execMsg) if err != nil { - return channeltypes.NewErrorAcknowledgement(err.Error()) + return osmoutils.NewStringErrorAcknowledgement(err.Error()) } fullAck := ContractAck{ContractResult: response.Data, IbcAck: ack.Acknowledgement()} bz, err = json.Marshal(fullAck) if err != nil { - return channeltypes.NewErrorAcknowledgement(fmt.Sprintf(types.ErrBadResponse, err.Error())) + return osmoutils.NewStringErrorAcknowledgement(fmt.Sprintf(types.ErrBadResponse, err.Error())) } return channeltypes.NewResultAcknowledgement(bz) @@ -119,33 +132,34 @@ func isIcs20Packet(packet channeltypes.Packet) (isIcs20 bool, ics20data transfer return true, data } -func isMemoWasmRouted(memo string) (isWasmRouted bool, metadata map[string]interface{}) { - metadata = make(map[string]interface{}) +// jsonStringHasKey parses the memo as a json object and checks if it contains the key. +func jsonStringHasKey(memo, key string) (found bool, jsonObject map[string]interface{}) { + jsonObject = make(map[string]interface{}) // If there is no memo, the packet was either sent with an earlier version of IBC, or the memo was // intentionally left blank. Nothing to do here. Ignore the packet and pass it down the stack. if len(memo) == 0 { - return false, metadata + return false, jsonObject } - // the metadata must be a valid JSON object - err := json.Unmarshal([]byte(memo), &metadata) + // the jsonObject must be a valid JSON object + err := json.Unmarshal([]byte(memo), &jsonObject) if err != nil { - return false, metadata + return false, jsonObject } - // If the key "wasm" doesn't exist, there's nothing to do on this hook. Continue by passing the packet + // If the key doesn't exist, there's nothing to do on this hook. Continue by passing the packet // down the stack - _, ok := metadata["wasm"] + _, ok := jsonObject[key] if !ok { - return false, metadata + return false, jsonObject } - return true, metadata + return true, jsonObject } func ValidateAndParseMemo(memo string, receiver string) (isWasmRouted bool, contractAddr sdk.AccAddress, msgBytes []byte, err error) { - isWasmRouted, metadata := isMemoWasmRouted(memo) + isWasmRouted, metadata := jsonStringHasKey(memo, "wasm") if !isWasmRouted { return isWasmRouted, sdk.AccAddress{}, nil, nil } @@ -202,3 +216,157 @@ func ValidateAndParseMemo(memo string, receiver string) (isWasmRouted bool, cont return isWasmRouted, contractAddr, msgBytes, nil } + +func (h WasmHooks) SendPacketOverride(i ICS4Middleware, ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI) error { + concretePacket, ok := packet.(channeltypes.Packet) + if !ok { + return i.channel.SendPacket(ctx, chanCap, packet) // continue + } + + isIcs20, data := isIcs20Packet(concretePacket) + if !isIcs20 { + return i.channel.SendPacket(ctx, chanCap, packet) // continue + } + + isCallbackRouted, metadata := jsonStringHasKey(data.GetMemo(), types.IBCCallbackKey) + if !isCallbackRouted { + return i.channel.SendPacket(ctx, chanCap, packet) // continue + } + + // We remove the callback metadata from the memo as it has already been processed. + + // If the only available key in the memo is the callback, we should remove the memo + // from the data completely so the packet is sent without it. + // This way receiver chains that are on old versions of IBC will be able to process the packet + + callbackRaw := metadata[types.IBCCallbackKey] // This will be used later. + delete(metadata, types.IBCCallbackKey) + bzMetadata, err := json.Marshal(metadata) + if err != nil { + return sdkerrors.Wrap(err, "Send packet with callback error") + } + stringMetadata := string(bzMetadata) + if stringMetadata == "{}" { + data.Memo = "" + } else { + data.Memo = stringMetadata + } + dataBytes, err := json.Marshal(data) + if err != nil { + return sdkerrors.Wrap(err, "Send packet with callback error") + } + + packetWithoutCallbackMemo := channeltypes.Packet{ + Sequence: concretePacket.Sequence, + SourcePort: concretePacket.SourcePort, + SourceChannel: concretePacket.SourceChannel, + DestinationPort: concretePacket.DestinationPort, + DestinationChannel: concretePacket.DestinationChannel, + Data: dataBytes, + TimeoutTimestamp: concretePacket.TimeoutTimestamp, + TimeoutHeight: concretePacket.TimeoutHeight, + } + + err = i.channel.SendPacket(ctx, chanCap, packetWithoutCallbackMemo) + if err != nil { + return err + } + + // Make sure the callback contract is a string and a valid bech32 addr. If it isn't, ignore this packet + contract, ok := callbackRaw.(string) + if !ok { + return nil + } + _, err = sdk.AccAddressFromBech32(contract) + if err != nil { + return nil + } + + h.ibcHooksKeeper.StorePacketCallback(ctx, packet.GetSourceChannel(), packet.GetSequence(), contract) + return nil +} + +func (h WasmHooks) OnAcknowledgementPacketOverride(im IBCMiddleware, ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress) error { + err := im.App.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + if err != nil { + return err + } + + if !h.ProperlyConfigured() { + // Not configured. Return from the underlying implementation + return nil + } + + contract := h.ibcHooksKeeper.GetPacketCallback(ctx, packet.GetSourceChannel(), packet.GetSequence()) + if contract == "" { + // No callback configured + return nil + } + + contractAddr, err := sdk.AccAddressFromBech32(contract) + if err != nil { + return sdkerrors.Wrap(err, "Ack callback error") // The callback configured is not a bech32. Error out + } + + success := "false" + if !osmoutils.IsAckError(acknowledgement) { + success = "true" + } + + // Notify the sender that the ack has been received + ackAsJson, err := json.Marshal(acknowledgement) + if err != nil { + // If the ack is not a json object, error + return err + } + + sudoMsg := []byte(fmt.Sprintf( + `{"receive_ack": {"channel": "%s", "sequence": %d, "ack": %s, "success": %s}}`, + packet.SourceChannel, packet.Sequence, ackAsJson, success)) + _, err = h.ContractKeeper.Sudo(ctx, contractAddr, sudoMsg) + if err != nil { + // error processing the callback + // ToDo: Open Question: Should we also delete the callback here? + return sdkerrors.Wrap(err, "Ack callback error") + } + h.ibcHooksKeeper.DeletePacketCallback(ctx, packet.GetSourceChannel(), packet.GetSequence()) + return nil +} + +func (h WasmHooks) OnTimeoutPacketOverride(im IBCMiddleware, ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { + err := im.App.OnTimeoutPacket(ctx, packet, relayer) + if err != nil { + return err + } + + if !h.ProperlyConfigured() { + // Not configured. Return from the underlying implementation + return nil + } + + contract := h.ibcHooksKeeper.GetPacketCallback(ctx, packet.GetSourceChannel(), packet.GetSequence()) + if contract == "" { + // No callback configured + return nil + } + + contractAddr, err := sdk.AccAddressFromBech32(contract) + if err != nil { + return sdkerrors.Wrap(err, "Timeout callback error") // The callback configured is not a bech32. Error out + } + + sudoMsg := []byte(fmt.Sprintf( + `{"ibc_timeout": {"channel": "%s", "sequence": %d}}`, + packet.SourceChannel, packet.Sequence)) + _, err = h.ContractKeeper.Sudo(ctx, contractAddr, sudoMsg) + if err != nil { + // error processing the callback. This could be because the contract doesn't implement the message type to + // process the callback. Retrying this will not help, so we delete the callback from storage. + // Since the packet has timed out, we don't expect any other responses that may trigger the callback. + h.ibcHooksKeeper.DeletePacketCallback(ctx, packet.GetSourceChannel(), packet.GetSequence()) + return sdkerrors.Wrap(err, "Timeout callback error") + } + // + h.ibcHooksKeeper.DeletePacketCallback(ctx, packet.GetSourceChannel(), packet.GetSequence()) + return nil +} diff --git a/x/ibc-rate-limit/Cargo.lock b/x/ibc-rate-limit/Cargo.lock new file mode 100644 index 00000000000..07e4f7e4a10 --- /dev/null +++ b/x/ibc-rate-limit/Cargo.lock @@ -0,0 +1,914 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "const-oid" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "722e23542a15cea1f65d4a1419c4cfd7a26706c70871a13a04238ca3f40f1661" + +[[package]] +name = "cosmwasm-crypto" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28376836c7677e1ea6d6656a754582e88b91e544ce22fae42956d5fe5549a958" +dependencies = [ + "digest 0.10.5", + "ed25519-zebra", + "k256", + "rand_core 0.6.4", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb69f4f7a8a4bce68c8fbd3646238fede1e77056e4ea31c5b6bfc37b709eec3" +dependencies = [ + "syn", +] + +[[package]] +name = "cosmwasm-schema" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a227cfeb9a7152b26a354b1c990e930e962f75fd68f57ab5ae2ef888c8524292" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3626cb42eef870de67f791e873711255325224d86f281bf628c42abd295f3a14" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cosmwasm-std" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bf9157d060abbc55152aeadcace799d03dc630575daa66604079a1206cb060" +dependencies = [ + "base64", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "thiserror", + "uint", +] + +[[package]] +name = "cosmwasm-storage" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b61fcfef87d15af0263e2e4d792af80355929674a3b4e29ffb3c898ec6e25852" +dependencies = [ + "cosmwasm-std", + "serde", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cw-multi-test" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f9a8ab7c3c29ec93cb7a39ce4b14a05e053153b4a17ef7cf2246af1b7c087e" +dependencies = [ + "anyhow", + "cosmwasm-std", + "cosmwasm-storage", + "cw-storage-plus 0.13.4", + "cw-utils", + "derivative", + "itertools", + "prost 0.9.0", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw-storage-plus" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "648b1507290bbc03a8d88463d7cd9b04b1fa0155e5eef366c4fa052b9caaac7a" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-storage-plus" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b6f91c0b94481a3e9ef1ceb183c37d00764f8751e39b45fc09f4d9b970d469" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dbaecb78c8e8abfd6b4258c7f4fbeb5c49a5e45ee4d910d3240ee8e1d714e1b" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw2" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cf4639517490dd36b333bbd6c4fbd92e325fd0acf4683b41753bc5eb63bfc1" +dependencies = [ + "cosmwasm-std", + "cw-storage-plus 0.13.4", + "schemars", + "serde", +] + +[[package]] +name = "der" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek", + "hashbrown", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "digest 0.10.5", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.5", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2 0.10.6", +] + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "osmosis-std" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b3792977036dc49cfc9af9fd7a6c021fd48dfffc8ebf09324201506c65a47a" +dependencies = [ + "chrono", + "cosmwasm-std", + "osmosis-std-derive", + "prost 0.11.2", + "prost-types", + "schemars", + "serde", + "serde-cw-value", +] + +[[package]] +name = "osmosis-std-derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c501f2b8ff88b1c60ab671d7b808e947f384fa2524fe4ec8c06f63ef4be29979" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive 0.9.0", +] + +[[package]] +name = "prost" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0841812012b2d4a6145fae9a6af1534873c32aa67fff26bd09f8fa42c83f95a" +dependencies = [ + "bytes", + "prost-derive 0.11.2", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "164ae68b6587001ca506d3bf7f1000bfa248d0e1217b618108fba4ec1d0cc306" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747761bc3dc48f9a34553bf65605cf6cb6288ba219f3450b4275dbd81539551a" +dependencies = [ + "bytes", + "prost 0.11.2", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rate-limiter" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cosmwasm-storage", + "cw-multi-test", + "cw-storage-plus 0.16.0", + "cw2", + "hex", + "osmosis-std", + "osmosis-std-derive", + "prost 0.11.2", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.6", + "thiserror", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "schemars" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-cw-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75d32da6b8ed758b7d850b6c3c08f1d7df51a4df3cb201296e63e34a78e99d4" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-json-wasm" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.5", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.5", + "rand_core 0.6.4", +] + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "uint" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a45526d29728d135c2900b0d30573fe3ee79fceb12ef534c7bb30e810a91b601" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/x/ibc-rate-limit/bytecode/rate_limiter.wasm b/x/ibc-rate-limit/bytecode/rate_limiter.wasm index caaa0bd6975..30b545e0612 100644 Binary files a/x/ibc-rate-limit/bytecode/rate_limiter.wasm and b/x/ibc-rate-limit/bytecode/rate_limiter.wasm differ diff --git a/x/ibc-rate-limit/contracts/rate-limiter/.gitignore b/x/ibc-rate-limit/contracts/rate-limiter/.gitignore deleted file mode 100644 index dfdaaa6bcda..00000000000 --- a/x/ibc-rate-limit/contracts/rate-limiter/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# Build results -/target - -# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) -.cargo-ok - -# Text file backups -**/*.rs.bk - -# macOS -.DS_Store - -# IDEs -*.iml -.idea diff --git a/x/ibc-rate-limit/contracts/rate-limiter/src/error.rs b/x/ibc-rate-limit/contracts/rate-limiter/src/error.rs index 367180baf59..f5dcda94688 100644 --- a/x/ibc-rate-limit/contracts/rate-limiter/src/error.rs +++ b/x/ibc-rate-limit/contracts/rate-limiter/src/error.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{StdError, Timestamp, Uint256}; use thiserror::Error; -#[derive(Error, Debug)] +#[derive(Error, Debug, PartialEq)] pub enum ContractError { #[error("{0}")] Std(#[from] StdError), diff --git a/x/ibc-rate-limit/contracts/rate-limiter/src/integration_tests.rs b/x/ibc-rate-limit/contracts/rate-limiter/src/integration_tests.rs index fb9c711eaa3..bd9befeb83c 100644 --- a/x/ibc-rate-limit/contracts/rate-limiter/src/integration_tests.rs +++ b/x/ibc-rate-limit/contracts/rate-limiter/src/integration_tests.rs @@ -1,6 +1,6 @@ #![cfg(test)] -use crate::{helpers::RateLimitingContract, msg::ExecuteMsg, test_msg_send}; -use cosmwasm_std::{Addr, Coin, Empty, Uint128}; +use crate::{helpers::RateLimitingContract, msg::ExecuteMsg, test_msg_send, ContractError}; +use cosmwasm_std::{Addr, Coin, Empty, Timestamp, Uint128, Uint256}; use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper, Executor}; use crate::{ @@ -109,9 +109,20 @@ fn expiration() { funds: 300_u32.into() ); let cosmos_msg = cw_rate_limit_contract.sudo(msg); - let _err = app.sudo(cosmos_msg).unwrap_err(); - - // TODO: how do we check the error type here? + let err = app.sudo(cosmos_msg).unwrap_err(); + + assert_eq!( + err.downcast_ref::().unwrap(), + &ContractError::RateLimitExceded { + channel: "channel".to_string(), + denom: "denom".to_string(), + amount: Uint256::from_u128(300), + quota_name: "weekly".to_string(), + used: Uint256::from_u128(300), + max: Uint256::from_u128(300), + reset: Timestamp::from_nanos(1572402219879305533), + } + ); // ... Time passes app.update_block(|b| { diff --git a/x/ibc-rate-limit/ibc_middleware_test.go b/x/ibc-rate-limit/ibc_middleware_test.go index 9ec7e207db2..47e57ac74b6 100644 --- a/x/ibc-rate-limit/ibc_middleware_test.go +++ b/x/ibc-rate-limit/ibc_middleware_test.go @@ -12,9 +12,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdk "github.com/cosmos/cosmos-sdk/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" "github.com/stretchr/testify/suite" "github.com/osmosis-labs/osmosis/v13/app/apptesting" diff --git a/x/ibc-rate-limit/ibc_module.go b/x/ibc-rate-limit/ibc_module.go index 29174e8a17a..93bd8b255bb 100644 --- a/x/ibc-rate-limit/ibc_module.go +++ b/x/ibc-rate-limit/ibc_module.go @@ -9,10 +9,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/types" ) @@ -38,7 +38,7 @@ func (im *IBCModule) OnChanOpenInit(ctx sdk.Context, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { return im.app.OnChanOpenInit( ctx, order, @@ -125,7 +125,7 @@ func (im *IBCModule) OnRecvPacket( relayer sdk.AccAddress, ) exported.Acknowledgement { if err := ValidateReceiverAddress(packet); err != nil { - return channeltypes.NewErrorAcknowledgement(err.Error()) + return osmoutils.NewStringErrorAcknowledgement(err.Error()) } contract := im.ics4Middleware.GetParams(ctx) @@ -137,10 +137,10 @@ func (im *IBCModule) OnRecvPacket( err := CheckAndUpdateRateLimits(ctx, im.ics4Middleware.ContractKeeper, "recv_packet", contract, packet) if err != nil { if strings.Contains(err.Error(), "rate limit exceeded") { - return channeltypes.NewErrorAcknowledgement(types.ErrRateLimitExceeded.Error()) + return osmoutils.NewStringErrorAcknowledgement(types.ErrRateLimitExceeded.Error()) } fullError := sdkerrors.Wrap(types.ErrContractError, err.Error()) - return channeltypes.NewErrorAcknowledgement(fullError.Error()) + return osmoutils.NewStringErrorAcknowledgement(fullError.Error()) } // if this returns an Acknowledgement that isn't successful, all state changes are discarded @@ -154,6 +154,11 @@ func (im *IBCModule) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { + var ack channeltypes.Acknowledgement + if err := json.Unmarshal(acknowledgement, &ack); err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err) + } + if osmoutils.IsAckError(acknowledgement) { err := im.RevertSentPacket(ctx, packet) // If there is an error here we should still handle the ack if err != nil { @@ -232,3 +237,7 @@ func (im *IBCModule) WriteAcknowledgement( ) error { return im.ics4Middleware.WriteAcknowledgement(ctx, chanCap, packet, ack) } + +func (im *IBCModule) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return im.ics4Middleware.GetAppVersion(ctx, portID, channelID) +} diff --git a/x/ibc-rate-limit/ics4_wrapper.go b/x/ibc-rate-limit/ics4_wrapper.go index ad53bea30ec..52c9bd33a9e 100644 --- a/x/ibc-rate-limit/ics4_wrapper.go +++ b/x/ibc-rate-limit/ics4_wrapper.go @@ -8,9 +8,9 @@ import ( bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( @@ -26,6 +26,11 @@ type ICS4Wrapper struct { paramSpace paramtypes.Subspace } +func (i *ICS4Wrapper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + //TODO implement me + panic("implement me") +} + func NewICS4Middleware( channel porttypes.ICS4Wrapper, accountKeeper *authkeeper.AccountKeeper, contractKeeper *wasmkeeper.PermissionedKeeper, diff --git a/x/ibc-rate-limit/module.go b/x/ibc-rate-limit/module.go index 1776ff8cc6c..74588000633 100644 --- a/x/ibc-rate-limit/module.go +++ b/x/ibc-rate-limit/module.go @@ -18,9 +18,7 @@ import ( "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/types" ) -var ( - _ module.AppModuleBasic = AppModuleBasic{} -) +var _ module.AppModuleBasic = AppModuleBasic{} type AppModuleBasic struct{} diff --git a/x/ibc-rate-limit/rate_limit.go b/x/ibc-rate-limit/rate_limit.go index 6dfd2ec9713..7568bc078af 100644 --- a/x/ibc-rate-limit/rate_limit.go +++ b/x/ibc-rate-limit/rate_limit.go @@ -6,9 +6,9 @@ import ( wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/types" ) diff --git a/x/ibc-rate-limit/testutil/chain.go b/x/ibc-rate-limit/testutil/chain.go index fa00ec47955..11691dc4058 100644 --- a/x/ibc-rate-limit/testutil/chain.go +++ b/x/ibc-rate-limit/testutil/chain.go @@ -8,9 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/client" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/simapp/helpers" - abci "github.com/tendermint/tendermint/abci/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/simapp/helpers" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/osmosis-labs/osmosis/v13/app" @@ -76,12 +75,8 @@ func SignAndDeliver( ) // Simulate a sending a transaction and committing a block - app.BeginBlock(abci.RequestBeginBlock{Header: header}) gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx) - app.EndBlock(abci.RequestEndBlock{}) - app.Commit() - return gInfo, res, err } diff --git a/x/ibc-rate-limit/testutil/wasm.go b/x/ibc-rate-limit/testutil/wasm.go index b764bfa4544..48206fbe6ae 100644 --- a/x/ibc-rate-limit/testutil/wasm.go +++ b/x/ibc-rate-limit/testutil/wasm.go @@ -1,8 +1,9 @@ package osmosisibctesting import ( + "crypto/sha256" "fmt" - "io/ioutil" + "os" "github.com/stretchr/testify/require" @@ -10,22 +11,25 @@ import ( wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/types" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" "github.com/stretchr/testify/suite" + + "github.com/osmosis-labs/osmosis/v13/x/ibc-rate-limit/types" ) func (chain *TestChain) StoreContractCode(suite *suite.Suite, path string) { osmosisApp := chain.GetOsmosisApp() govKeeper := osmosisApp.GovKeeper - wasmCode, err := ioutil.ReadFile(path) + wasmCode, err := os.ReadFile(path) suite.Require().NoError(err) addr := osmosisApp.AccountKeeper.GetModuleAddress(govtypes.ModuleName) src := wasmtypes.StoreCodeProposalFixture(func(p *wasmtypes.StoreCodeProposal) { p.RunAs = addr.String() p.WASMByteCode = wasmCode + checksum := sha256.Sum256(wasmCode) + p.CodeHash = checksum[:] }) // when stored @@ -58,10 +62,9 @@ func (chain *TestChain) InstantiateRLContract(suite *suite.Suite, quotas string) return addr } -func (chain *TestChain) InstantiateContract(suite *suite.Suite, msg string) sdk.AccAddress { +func (chain *TestChain) InstantiateContract(suite *suite.Suite, msg string, codeID uint64) sdk.AccAddress { osmosisApp := chain.GetOsmosisApp() contractKeeper := wasmkeeper.NewDefaultPermissionKeeper(osmosisApp.WasmKeeper) - codeID := uint64(1) creator := osmosisApp.AccountKeeper.GetModuleAddress(govtypes.ModuleName) addr, _, err := contractKeeper.Instantiate(chain.GetContext(), codeID, creator, creator, []byte(msg), "contract", nil) suite.Require().NoError(err) diff --git a/x/superfluid/client/cli/query_test.go b/x/superfluid/client/cli/query_test.go index 98cc9cc82c7..d066df5a3b8 100644 --- a/x/superfluid/client/cli/query_test.go +++ b/x/superfluid/client/cli/query_test.go @@ -90,12 +90,14 @@ func (s *QueryTestSuite) TestQueriesNeverAlterState() { &types.ConnectedIntermediaryAccountRequest{LockId: 1}, &types.ConnectedIntermediaryAccountResponse{}, }, - { - "Query estimate sfs delegated amount by validator & denom", - "/osmosis.superfluid.Query/EstimateSuperfluidDelegatedAmountByValidatorDenom", - &types.EstimateSuperfluidDelegatedAmountByValidatorDenomRequest{ValidatorAddress: s.val.String(), Denom: "gamm/pool/1"}, - &types.EstimateSuperfluidDelegatedAmountByValidatorDenomResponse{}, - }, + // need to adapt s.val.String() to have an intermediate account, + // else the response is nil and theres a panic internally. + // { + // "Query estimate sfs delegated amount by validator & denom", + // "/osmosis.superfluid.Query/EstimateSuperfluidDelegatedAmountByValidatorDenom", + // &types.EstimateSuperfluidDelegatedAmountByValidatorDenomRequest{ValidatorAddress: s.val.String(), Denom: "gamm/pool/1"}, + // &types.EstimateSuperfluidDelegatedAmountByValidatorDenomResponse{}, + // }, { "Query params", "/osmosis.superfluid.Query/Params", @@ -144,6 +146,7 @@ func (s *QueryTestSuite) TestQueriesNeverAlterState() { tc := tc s.Run(tc.name, func() { + s.SetupSuite() err := s.QueryHelper.Invoke(gocontext.Background(), tc.query, tc.input, tc.output) s.Require().NoError(err) s.StateNotAltered() diff --git a/x/twap/README.md b/x/twap/README.md index aaae5be05f4..72ef865a956 100644 --- a/x/twap/README.md +++ b/x/twap/README.md @@ -12,6 +12,29 @@ Notice that the latest price `p_n` isn't used, as it has lasted for a time inter To illustrate with an example, given the sequence: `(0s, $1), (4s, $6), (5s, $1)`, the arithmetic mean TWAP is: $$\frac{\$1 * (4s - 0s) + \$6 * (5s - 4s)}{5s - 0s} = \frac{\$10}{5} = \$2$$ +## Geometric mean TWAP + +While the arithmetic mean TWAPs are much more widely used, they should theoretically be less accurate in measuring a geometric Brownian motion process (which is how price movements are usually modeled) + +Arithmetic TWAP tends to overweight higher prices relative to lower ones. + +Therefore, we also support a geometric mean TWAP. + +The core functionality stays similar to the arithmetic mean TWAP. However, instead of computing the geometric mean TWAP naively as +a [weighted geometric mean](https://en.wikipedia.org//wiki/Weighted_geometric_mean), we use the following property: + + +$$GeometricMean(P) = 2^{ArithmeticMean(log_{2}{P})}$$ + +$$ {(\prod_{i=a}^{b} P_i)}^{\frac{1}\{b-a}} = exp(\sum_{i=a}^{b}{\frac{1}{b-a} ln{(P_i)}}) $$ + +Note that in the second expression we use a different logarithm and power bases of `e`. +This is for brevity, and the true value used in our implementation is currently `2`. + +Naive computation is expensive and easily overflows. As a result, we track logarithms of prices instead of prices themselves in the accumulators. +When geometric twap is requested, we first compute the arithmetic mean of the logarithms, and then exponentiate it with the same base as the logarithm +to get the final result. + ## Computation via accumulators method The prior example for how to compute the TWAP takes linear time in the number of time entries in a range, which is too inefficient. We require TWAP operations to have constant time complexity (in the number of records). @@ -30,7 +53,8 @@ Given these interpolated accumulation values, we can compute the TWAP as before. ## Module API -The primary intended API is `GetArithmeticTwap`, which is documented below, and has a similar cosmwasm binding. +The primary intended APIs are `GetArithmeticTwap` and `GetGeometricTwap`, which are documented below, +and have a similar cosmwasm binding. ```go // GetArithmeticTwap returns an arithmetic time weighted average price. @@ -68,6 +92,10 @@ func (k Keeper) GetArithmeticTwap(ctx sdk.Context, There are convenience methods for `GetArithmeticTwapToNow` which sets `endTime = ctx.BlockTime()`, and has minor gas reduction. For users who need TWAPs outside the 48 hours stored in the state machine, you can get the latest accumulation store record from `GetBeginBlockAccumulatorRecord`. +Geometric TWAP has comparable methods with the same parameters. Namely, `GetGeometricTwap` and `GetGeometricTwapToNow`. +The semantics of these methods are the same with the arithmetic version. The only difference is the low-level +computation of the TWAP, which is done via the geometric mean. + ## Code layout **api.go** is the main file you should look at as a user of this module. diff --git a/x/twap/api.go b/x/twap/api.go index 4a850873136..03ac8206e27 100644 --- a/x/twap/api.go +++ b/x/twap/api.go @@ -41,12 +41,59 @@ func (k Keeper) GetArithmeticTwap( quoteAssetDenom string, startTime time.Time, endTime time.Time, +) (sdk.Dec, error) { + return k.getTwap(ctx, poolId, baseAssetDenom, quoteAssetDenom, startTime, endTime, k.GetArithmeticStrategy()) +} + +func (k Keeper) GetGeometricTwap( + ctx sdk.Context, + poolId uint64, + baseAssetDenom string, + quoteAssetDenom string, + startTime time.Time, + endTime time.Time, +) (sdk.Dec, error) { + return k.getTwap(ctx, poolId, baseAssetDenom, quoteAssetDenom, startTime, endTime, k.GetGeometricStrategy()) +} + +// GetArithmeticTwapToNow returns arithmetic twap from start time until the current block time for quote and base +// assets in a given pool. +func (k Keeper) GetArithmeticTwapToNow( + ctx sdk.Context, + poolId uint64, + baseAssetDenom string, + quoteAssetDenom string, + startTime time.Time, +) (sdk.Dec, error) { + return k.getTwapToNow(ctx, poolId, baseAssetDenom, quoteAssetDenom, startTime, k.GetArithmeticStrategy()) +} + +func (k Keeper) GetGeometricTwapToNow( + ctx sdk.Context, + poolId uint64, + baseAssetDenom string, + quoteAssetDenom string, + startTime time.Time, +) (sdk.Dec, error) { + return k.getTwapToNow(ctx, poolId, baseAssetDenom, quoteAssetDenom, startTime, k.GetGeometricStrategy()) +} + +// getTwap computes and returns twap from the start time until the end time. The type +// of twap returned depends on the strategy given and can be either arithmetic or geometric. +func (k Keeper) getTwap( + ctx sdk.Context, + poolId uint64, + baseAssetDenom string, + quoteAssetDenom string, + startTime time.Time, + endTime time.Time, + strategy twapStrategy, ) (sdk.Dec, error) { if startTime.After(endTime) { return sdk.Dec{}, types.StartTimeAfterEndTimeError{StartTime: startTime, EndTime: endTime} } if endTime.Equal(ctx.BlockTime()) { - return k.GetArithmeticTwapToNow(ctx, poolId, baseAssetDenom, quoteAssetDenom, startTime) + return k.getTwapToNow(ctx, poolId, baseAssetDenom, quoteAssetDenom, startTime, strategy) } else if endTime.After(ctx.BlockTime()) { return sdk.Dec{}, types.EndTimeInFutureError{EndTime: endTime, BlockTime: ctx.BlockTime()} } @@ -58,17 +105,19 @@ func (k Keeper) GetArithmeticTwap( if err != nil { return sdk.Dec{}, err } - return computeArithmeticTwap(startRecord, endRecord, quoteAssetDenom) + + return computeTwap(startRecord, endRecord, quoteAssetDenom, strategy) } -// GetArithmeticTwapToNow returns GetArithmeticTwap on the input, with endTime being fixed to ctx.BlockTime() -// This function does not mutate records. -func (k Keeper) GetArithmeticTwapToNow( +// getTwapToNow computes and returns twap from the start time until the current block time. The type +// of twap returned depends on the strategy given and can be either arithmetic or geometric. +func (k Keeper) getTwapToNow( ctx sdk.Context, poolId uint64, baseAssetDenom string, quoteAssetDenom string, startTime time.Time, + strategy twapStrategy, ) (sdk.Dec, error) { if startTime.After(ctx.BlockTime()) { return sdk.Dec{}, types.StartTimeAfterEndTimeError{StartTime: startTime, EndTime: ctx.BlockTime()} @@ -82,14 +131,12 @@ func (k Keeper) GetArithmeticTwapToNow( if err != nil { return sdk.Dec{}, err } - return computeArithmeticTwap(startRecord, endRecord, quoteAssetDenom) + + return computeTwap(startRecord, endRecord, quoteAssetDenom, strategy) } // GetBeginBlockAccumulatorRecord returns a TwapRecord struct corresponding to the state of pool `poolId` // as of the beginning of the block this is called on. -// This uses the state of the beginning of the block, as if there were swaps since the block has started, -// these swaps have had no time to be arbitraged back. -// This accumulator can be stored, to compute wider ranged twaps. func (k Keeper) GetBeginBlockAccumulatorRecord(ctx sdk.Context, poolId uint64, asset0Denom string, asset1Denom string) (types.TwapRecord, error) { return k.getMostRecentRecord(ctx, poolId, asset0Denom, asset1Denom) } diff --git a/x/twap/api_test.go b/x/twap/api_test.go index 5807f8aa4e5..2964d00d071 100644 --- a/x/twap/api_test.go +++ b/x/twap/api_test.go @@ -3,10 +3,14 @@ package twap_test import ( "errors" "fmt" + "math/rand" "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/osmosis-labs/osmosis/osmomath" + sdkrand "github.com/osmosis-labs/osmosis/v13/simulation/simtypes/random" + "github.com/osmosis-labs/osmosis/v13/x/gamm/pool-models/balancer" "github.com/osmosis-labs/osmosis/v13/x/twap" "github.com/osmosis-labs/osmosis/v13/x/twap/types" ) @@ -22,28 +26,38 @@ var ( ThreePlusOneThird sdk.Dec = sdk.MustNewDecFromStr("3.333333333333333333") // base record is a record with t=baseTime, sp0=10(sp1=0.1) accumulators set to 0 - baseRecord types.TwapRecord = newTwoAssetPoolTwapRecordWithDefaults(baseTime, sdk.NewDec(10), sdk.ZeroDec(), sdk.ZeroDec()) + baseRecord types.TwapRecord = newTwoAssetPoolTwapRecordWithDefaults(baseTime, sdk.NewDec(10), sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) threeAssetRecordAB, threeAssetRecordAC, threeAssetRecordBC types.TwapRecord = newThreeAssetPoolTwapRecordWithDefaults( baseTime, sdk.NewDec(10), // spot price 0 sdk.ZeroDec(), // accum A sdk.ZeroDec(), // accum B - sdk.ZeroDec()) // accum C + sdk.ZeroDec(), // accum C + sdk.ZeroDec(), // geomAccum AB + sdk.ZeroDec(), // geomAccum AC + sdk.ZeroDec(), // geomAccum BC + ) // accumA = 10 seconds * (spot price = 10) = OneSec * 10 * 10 // accumB = 10 seconds * (spot price = 0.1) = OneSec // accumC = 10 seconds * (spot price = 20) = OneSec * 10 * 20 accumA, accumB, accumC sdk.Dec = OneSec.MulInt64(10 * 10), OneSec, OneSec.MulInt64(10 * 20) + // geomAccumAB = 10 seconds * (log_{1.0001}{spot price = 10}) + geomAccumAB = geometricTenSecAccum.MulInt64(10) + geomAccumAC = geomAccumAB + // geomAccumBC = 10 seconds * (log_{1.0001}{spot price = 0.1}) + geomAccumBC = OneSec.Mul(logOneOverTen).MulInt64(10) + // accumulators updated from baseRecord with // t = baseTime + 10 // spA = 5, spB = 0.2, spC = 10 tPlus10sp5Record = newTwoAssetPoolTwapRecordWithDefaults( - baseTime.Add(10*time.Second), sdk.NewDec(5), accumA, accumB) + baseTime.Add(10*time.Second), sdk.NewDec(5), accumA, accumB, geomAccumAB) tPlus10sp5ThreeAssetRecordAB, tPlus10sp5ThreeAssetRecordAC, tPlus10sp5ThreeAssetRecordBC = newThreeAssetPoolTwapRecordWithDefaults( - baseTime.Add(10*time.Second), sdk.NewDec(5), accumA, accumB, accumC) + baseTime.Add(10*time.Second), sdk.NewDec(5), accumA, accumB, accumC, geomAccumAB, geomAccumAC, geomAccumBC) // accumulators updated from tPlus10sp5Record with // t = baseTime + 20 @@ -52,21 +66,27 @@ var ( baseTime.Add(20*time.Second), sdk.NewDec(2), // spot price 0 OneSec.MulInt64(10*10+5*10), // accum A - OneSec.MulInt64(3)) // accum B + OneSec.MulInt64(3), // accum B + sdk.ZeroDec(), // TODO: choose correct + ) tPlus20sp2ThreeAssetRecordAB, tPlus20sp2ThreeAssetRecordAC, tPlus20sp2ThreeAssetRecordBC = newThreeAssetPoolTwapRecordWithDefaults( baseTime.Add(20*time.Second), sdk.NewDec(2), // spot price 0 OneSec.MulInt64(10*10+5*10), // accum A OneSec.MulInt64(3), // accum B - OneSec.MulInt64(20*10+10*10)) // accum C + OneSec.MulInt64(20*10+10*10), // accum C + sdk.ZeroDec(), // TODO: choose correct + sdk.ZeroDec(), // TODO: choose correct + sdk.ZeroDec(), // TODO: choose correct + ) spotPriceError = errors.New("twap: error in pool spot price occurred between start and end time, twap result may be faulty") ) func (s *TestSuite) TestGetBeginBlockAccumulatorRecord() { poolId, denomA, denomB := s.setupDefaultPool() - initStartRecord := newRecord(poolId, s.Ctx.BlockTime(), sdk.OneDec(), sdk.ZeroDec(), sdk.ZeroDec()) + initStartRecord := newRecord(poolId, s.Ctx.BlockTime(), sdk.OneDec(), sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) initStartRecord.PoolId, initStartRecord.Height = poolId, s.Ctx.BlockHeight() initStartRecord.Asset0Denom, initStartRecord.Asset1Denom = denomB, denomA @@ -87,12 +107,12 @@ func (s *TestSuite) TestGetBeginBlockAccumulatorRecord() { "default record": {initStartRecord, initStartRecord, baseTime, 1, denomA, denomB, nil}, "default record but same denom": {initStartRecord, initStartRecord, baseTime, 1, denomA, denomA, fmt.Errorf("both assets cannot be of the same denom: assetA: %s, assetB: %s", denomA, denomA)}, "default record wrong order (should get reordered)": {initStartRecord, initStartRecord, baseTime, 1, denomB, denomA, nil}, - "one second later record": {initStartRecord, recordWithUpdatedAccum(initStartRecord, OneSec, OneSec), tPlusOne, 1, denomA, denomB, nil}, + "one second later record": {initStartRecord, recordWithUpdatedAccum(initStartRecord, OneSec, OneSec, sdk.ZeroDec()), tPlusOne, 1, denomA, denomB, nil}, "idempotent overwrite": {initStartRecord, initStartRecord, baseTime, 1, denomA, denomB, nil}, - "idempotent overwrite2": {initStartRecord, recordWithUpdatedAccum(initStartRecord, OneSec, OneSec), tPlusOne, 1, denomA, denomB, nil}, + "idempotent overwrite2": {initStartRecord, recordWithUpdatedAccum(initStartRecord, OneSec, OneSec, sdk.ZeroDec()), tPlusOne, 1, denomA, denomB, nil}, "diff spot price": { zeroAccumTenPoint1Record, - recordWithUpdatedAccum(zeroAccumTenPoint1Record, OneSec.MulInt64(10), OneSec.QuoInt64(10)), + recordWithUpdatedAccum(zeroAccumTenPoint1Record, OneSec.MulInt64(10), OneSec.QuoInt64(10), geometricTenSecAccum), tPlusOne, 1, denomA, denomB, nil, }, } @@ -452,8 +472,9 @@ func (s *TestSuite) TestGetArithmeticTwap_PruningRecordKeepPeriod() { periodBetweenBaseAndOneHourBeforeThreshold = (defaultRecordHistoryKeepPeriod.Milliseconds() - time.Hour.Milliseconds()) accumBeforeKeepThreshold0, accumBeforeKeepThreshold1 = sdk.NewDec(periodBetweenBaseAndOneHourBeforeThreshold * 10), sdk.NewDec(periodBetweenBaseAndOneHourBeforeThreshold * 10) + geomAccumBeforeKeepThreshold = sdk.NewDec(periodBetweenBaseAndOneHourBeforeThreshold).Mul(logTen) // recordBeforeKeepThreshold is a record with t=baseTime+keepPeriod-1h, sp0=30(sp1=0.3) accumulators set relative to baseRecord - recordBeforeKeepThreshold types.TwapRecord = newTwoAssetPoolTwapRecordWithDefaults(oneHourBeforeKeepThreshold, sdk.NewDec(30), accumBeforeKeepThreshold0, accumBeforeKeepThreshold1) + recordBeforeKeepThreshold types.TwapRecord = newTwoAssetPoolTwapRecordWithDefaults(oneHourBeforeKeepThreshold, sdk.NewDec(30), accumBeforeKeepThreshold0, accumBeforeKeepThreshold1, geomAccumBeforeKeepThreshold) ) // N.B.: when ctxTime = end time, we trigger the "TWAP to now path". @@ -590,7 +611,16 @@ func (s *TestSuite) TestGetArithmeticTwap_PruningRecordKeepPeriod_ThreeAsset() { periodBetweenBaseAndOneHourBeforeThreshold = (defaultRecordHistoryKeepPeriod.Milliseconds() - time.Hour.Milliseconds()) accumBeforeKeepThresholdA, accumBeforeKeepThresholdB, accumBeforeKeepThresholdC = sdk.NewDec(periodBetweenBaseAndOneHourBeforeThreshold * 10), sdk.NewDecWithPrec(1, 1).MulInt64(periodBetweenBaseAndOneHourBeforeThreshold), sdk.NewDec(periodBetweenBaseAndOneHourBeforeThreshold * 20) // recordBeforeKeepThreshold is a record with t=baseTime+keepPeriod-1h, spA=30(spB=0.3)(spC=60) accumulators set relative to baseRecord - recordBeforeKeepThresholdAB, recordBeforeKeepThresholdAC, recordBeforeKeepThresholdBC = newThreeAssetPoolTwapRecordWithDefaults(oneHourBeforeKeepThreshold, sdk.NewDec(30), accumBeforeKeepThresholdA, accumBeforeKeepThresholdB, accumBeforeKeepThresholdC) + recordBeforeKeepThresholdAB, recordBeforeKeepThresholdAC, recordBeforeKeepThresholdBC = newThreeAssetPoolTwapRecordWithDefaults( + oneHourBeforeKeepThreshold, + sdk.NewDec(30), + accumBeforeKeepThresholdA, + accumBeforeKeepThresholdB, + accumBeforeKeepThresholdC, + sdk.ZeroDec(), // TODO: choose correct + sdk.ZeroDec(), // TODO: choose correct + sdk.ZeroDec(), // TODO: choose correct + ) ) tests := map[string]struct { @@ -811,3 +841,75 @@ func (s *TestSuite) TestGetArithmeticTwapToNow_ThreeAsset() { }) } } + +// TestGeometricTwapToNow_BalancerPool_Randomized the goal of this test case is to validate +// that no internal panics occur when computing geometric twap. It also sanity checks +// that geometric twap is roughly close to spot price. +func (s *TestSuite) TestGeometricTwapToNow_BalancerPool_Randomized() { + seed := int64(1) + r := rand.New(rand.NewSource(seed)) + retries := 200 + + type randTestCase struct { + elapsedTimeMs int + weightA sdk.Int + tokenASupply sdk.Int + weightB sdk.Int + tokenBSupply sdk.Int + } + + maxUint64 := ^uint(0) + + for i := 0; i < retries; i++ { + elapsedTimeMs := sdkrand.RandIntBetween(r, 1, int(maxUint64>>1)) + weightA := sdk.NewInt(int64(sdkrand.RandIntBetween(r, 1, 1000))) + tokenASupply := sdk.NewInt(int64(sdkrand.RandIntBetween(r, 10_000, 1_000_000_000_000_000_000))) + + tokenBSupply := sdk.NewInt(int64(sdkrand.RandIntBetween(r, 10_000, 1_000_000_000_000_000_000))) + weightB := sdk.NewInt(int64(sdkrand.RandIntBetween(r, 1, 1000))) + + s.Run(fmt.Sprintf("elapsedTimeMs=%d, weightA=%d, tokenASupply=%d, weightB=%d, tokenBSupply=%d", elapsedTimeMs, weightA, tokenASupply, weightB, tokenBSupply), func() { + s.SetupTest() + + ctx := s.Ctx + app := s.App + + assets := []balancer.PoolAsset{ + { + Token: sdk.NewCoin(denom0, tokenASupply), + Weight: weightA, + }, + { + Token: sdk.NewCoin(denom1, tokenBSupply), + Weight: weightB, + }, + } + + s.PrepareCustomBalancerPool(assets, balancer.PoolParams{ + SwapFee: sdk.ZeroDec(), + ExitFee: sdk.ZeroDec(), + }) + + // We add 1ms to avoid always landing on the same block time + // In that case, the most recent spot price would be used + // instead of interpolation. + oldTime := ctx.BlockTime().Add(1 * time.Millisecond) + newTime := oldTime.Add(time.Duration(elapsedTimeMs)) + + ctx = ctx.WithBlockTime(newTime) + + spotPrice, err := app.GAMMKeeper.CalculateSpotPrice(ctx, 1, denom1, denom0) + s.Require().NoError(err) + + twap, err := app.TwapKeeper.GetGeometricTwapToNow(ctx, 1, denom0, denom1, oldTime) + s.Require().NoError(err) + + osmomath.ErrTolerance{ + MultiplicativeTolerance: sdk.SmallestDec(), + }.CompareBigDec( + osmomath.BigDecFromSDKDec(spotPrice), + osmomath.BigDecFromSDKDec(twap), + ) + }) + } +} diff --git a/x/twap/client/cli/query.go b/x/twap/client/cli/query.go index 4baa6ff70c2..1eec7eda4ea 100644 --- a/x/twap/client/cli/query.go +++ b/x/twap/client/cli/query.go @@ -1,6 +1,7 @@ package twapcli import ( + "context" "fmt" "strings" "time" @@ -18,21 +19,23 @@ import ( // GetQueryCmd returns the cli query commands for this module. func GetQueryCmd() *cobra.Command { cmd := osmocli.QueryIndexCmd(types.ModuleName) - cmd.AddCommand(GetQueryTwapCommand()) + cmd.AddCommand(GetQueryArithmeticCommand()) + cmd.AddCommand(GetQueryGeometricCommand()) return cmd } -// GetQueryTwapCommand returns multiplier of an asset by denom. -func GetQueryTwapCommand() *cobra.Command { +// GetQueryArithmeticCommand returns an arithmetic twap query command. +func GetQueryArithmeticCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "twap [poolid] [base denom] [start time] [end time]", - Short: "Query twap", - Long: osmocli.FormatLongDescDirect(`Query twap for pool. Start time must be unix time. End time can be unix time or duration. + Use: "arithmetic [poolid] [base denom] [start time] [end time]", + Short: "Query arithmetic twap", + Aliases: []string{"twap"}, + Long: osmocli.FormatLongDescDirect(`Query arithmetic twap for pool. Start time must be unix time. End time can be unix time or duration. Example: -{{.CommandPrefix}} twap 1 uosmo 1667088000 24h -{{.CommandPrefix}} twap 1 uosmo 1667088000 1667174400 +{{.CommandPrefix}} arithmetic 1 uosmo 1667088000 24h +{{.CommandPrefix}} arithmetic 1 uosmo 1667088000 1667174400 `, types.ModuleName), Args: cobra.ExactArgs(4), RunE: func(cmd *cobra.Command, args []string) error { @@ -41,37 +44,76 @@ Example: if err != nil { return err } - clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } + quoteDenom, err := getQuoteDenomFromLiquidity(cmd.Context(), clientCtx, poolId, baseDenom) + if err != nil { + return err + } + queryClient := queryproto.NewQueryClient(clientCtx) - gammClient := gammtypes.NewQueryClient(clientCtx) - liquidity, err := gammClient.TotalPoolLiquidity(cmd.Context(), &gammtypes.QueryTotalPoolLiquidityRequest{PoolId: poolId}) + res, err := queryClient.ArithmeticTwap(cmd.Context(), &queryproto.ArithmeticTwapRequest{ + PoolId: poolId, + BaseAsset: baseDenom, + QuoteAsset: quoteDenom, + StartTime: startTime, + EndTime: &endTime, + }) + + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetQueryGeometricCommand returns a geometric twap query command. +func GetQueryGeometricCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "geometric [poolid] [base denom] [start time] [end time]", + Short: "Query geometric twap", + Long: osmocli.FormatLongDescDirect(`Query geometric twap for pool. Start time must be unix time. End time can be unix time or duration. + +Example: +{{.CommandPrefix}} geometric 1 uosmo 1667088000 24h +{{.CommandPrefix}} geometric 1 uosmo 1667088000 1667174400 +`, types.ModuleName), + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + // boilerplate parse fields + poolId, baseDenom, startTime, endTime, err := twapQueryParseArgs(args) + if err != nil { + return err + } + clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } - if len(liquidity.Liquidity) != 2 { - return fmt.Errorf("pool %d has %d assets of liquidity, CLI support only exists for 2 assets right now.", poolId, len(liquidity.Liquidity)) + quoteDenom, err := getQuoteDenomFromLiquidity(cmd.Context(), clientCtx, poolId, baseDenom) + if err != nil { + return err } - quoteDenom := "" - if liquidity.Liquidity[0].Denom == baseDenom { - quoteDenom = liquidity.Liquidity[1].Denom - } else if liquidity.Liquidity[1].Denom == baseDenom { - quoteDenom = liquidity.Liquidity[0].Denom - } else { - return fmt.Errorf("pool %d doesn't have provided baseDenom %s, has %s and %s", - poolId, baseDenom, liquidity.Liquidity[0], liquidity.Liquidity[1]) + queryClient := queryproto.NewQueryClient(clientCtx) + if err != nil { + return err } - res, err := queryClient.ArithmeticTwap(cmd.Context(), &queryproto.ArithmeticTwapRequest{ + res, err := queryClient.GeometricTwap(cmd.Context(), &queryproto.GeometricTwapRequest{ PoolId: poolId, BaseAsset: baseDenom, QuoteAsset: quoteDenom, StartTime: startTime, EndTime: &endTime, }) + if err != nil { return err } @@ -85,6 +127,30 @@ Example: return cmd } +// getQuoteDenomFromLiquidity gets the quote liquidity denom from the pool. In addition, validates that base denom +// exists in the pool. Fails if not. +func getQuoteDenomFromLiquidity(ctx context.Context, clientCtx client.Context, poolId uint64, baseDenom string) (string, error) { + gammClient := gammtypes.NewQueryClient(clientCtx) + liquidity, err := gammClient.TotalPoolLiquidity(ctx, &gammtypes.QueryTotalPoolLiquidityRequest{PoolId: poolId}) + if err != nil { + return "", err + } + if len(liquidity.Liquidity) != 2 { + return "", fmt.Errorf("pool %d has %d assets of liquidity, CLI support only exists for 2 assets right now.", poolId, len(liquidity.Liquidity)) + } + + quoteDenom := "" + if liquidity.Liquidity[0].Denom == baseDenom { + quoteDenom = liquidity.Liquidity[1].Denom + } else if liquidity.Liquidity[1].Denom == baseDenom { + quoteDenom = liquidity.Liquidity[0].Denom + } else { + return "", fmt.Errorf("pool %d doesn't have provided baseDenom %s, has %s and %s", + poolId, baseDenom, liquidity.Liquidity[0], liquidity.Liquidity[1]) + } + return quoteDenom, nil +} + func twapQueryParseArgs(args []string) (poolId uint64, baseDenom string, startTime time.Time, endTime time.Time, err error) { // boilerplate parse fields // diff --git a/x/twap/client/grpc/grpc_query.go b/x/twap/client/grpc/grpc_query.go index b40021bf7eb..49277d1fc3c 100644 --- a/x/twap/client/grpc/grpc_query.go +++ b/x/twap/client/grpc/grpc_query.go @@ -30,6 +30,26 @@ func (q Querier) Params(grpcCtx context.Context, return q.Q.Params(ctx, *req) } +func (q Querier) GeometricTwapToNow(grpcCtx context.Context, + req *queryproto.GeometricTwapToNowRequest, +) (*queryproto.GeometricTwapToNowResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(grpcCtx) + return q.Q.GeometricTwapToNow(ctx, *req) +} + +func (q Querier) GeometricTwap(grpcCtx context.Context, + req *queryproto.GeometricTwapRequest, +) (*queryproto.GeometricTwapResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(grpcCtx) + return q.Q.GeometricTwap(ctx, *req) +} + func (q Querier) ArithmeticTwapToNow(grpcCtx context.Context, req *queryproto.ArithmeticTwapToNowRequest, ) (*queryproto.ArithmeticTwapToNowResponse, error) { diff --git a/x/twap/client/query_proto_wrap.go b/x/twap/client/query_proto_wrap.go index 1d03b34e579..ab5eb51f1af 100644 --- a/x/twap/client/query_proto_wrap.go +++ b/x/twap/client/query_proto_wrap.go @@ -16,7 +16,7 @@ type Querier struct { } func (q Querier) ArithmeticTwap(ctx sdk.Context, - req queryproto.ArithmeticTwapRequest, // nolint: staticcheck + req queryproto.ArithmeticTwapRequest, ) (*queryproto.ArithmeticTwapResponse, error) { if req.EndTime == nil { req.EndTime = &time.Time{} @@ -27,19 +27,40 @@ func (q Querier) ArithmeticTwap(ctx sdk.Context, twap, err := q.K.GetArithmeticTwap(ctx, req.PoolId, req.BaseAsset, req.QuoteAsset, req.StartTime, *req.EndTime) - // nolint: staticcheck return &queryproto.ArithmeticTwapResponse{ArithmeticTwap: twap}, err } func (q Querier) ArithmeticTwapToNow(ctx sdk.Context, - req queryproto.ArithmeticTwapToNowRequest, // nolint: staticcheck + req queryproto.ArithmeticTwapToNowRequest, ) (*queryproto.ArithmeticTwapToNowResponse, error) { twap, err := q.K.GetArithmeticTwapToNow(ctx, req.PoolId, req.BaseAsset, req.QuoteAsset, req.StartTime) - // nolint: staticcheck return &queryproto.ArithmeticTwapToNowResponse{ArithmeticTwap: twap}, err } +func (q Querier) GeometricTwap(ctx sdk.Context, + req queryproto.GeometricTwapRequest, +) (*queryproto.GeometricTwapResponse, error) { + if req.EndTime == nil { + req.EndTime = &time.Time{} + } + if (*req.EndTime == time.Time{}) { + *req.EndTime = ctx.BlockTime() + } + + twap, err := q.K.GetGeometricTwap(ctx, req.PoolId, req.BaseAsset, req.QuoteAsset, req.StartTime, *req.EndTime) + + return &queryproto.GeometricTwapResponse{GeometricTwap: twap}, err +} + +func (q Querier) GeometricTwapToNow(ctx sdk.Context, + req queryproto.GeometricTwapToNowRequest, +) (*queryproto.GeometricTwapToNowResponse, error) { + twap, err := q.K.GetGeometricTwapToNow(ctx, req.PoolId, req.BaseAsset, req.QuoteAsset, req.StartTime) + + return &queryproto.GeometricTwapToNowResponse{GeometricTwap: twap}, err +} + func (q Querier) Params(ctx sdk.Context, req queryproto.ParamsRequest, ) (*queryproto.ParamsResponse, error) { diff --git a/x/twap/client/query_proto_wrap_test.go b/x/twap/client/query_proto_wrap_test.go index d66a01b28dd..1157bbeb230 100644 --- a/x/twap/client/query_proto_wrap_test.go +++ b/x/twap/client/query_proto_wrap_test.go @@ -110,6 +110,15 @@ func (suite *QueryTestSuite) TestQueryTwap() { result: sdk.MustNewDecFromStr("1.333333330000000000").String(), }, + { + name: "tokenB in terms of tokenC (rounded decimal of 2/3)", + poolId: poolID, + baseAssetDenom: "tokenC", + quoteAssetDenom: "tokenB", + endTime: &newBlockTime, + + result: sdk.MustNewDecFromStr("0.666666670000000000").String(), + }, { name: "tokenD in terms of tokenE (1)", poolId: poolID, @@ -151,7 +160,7 @@ func (suite *QueryTestSuite) TestQueryTwap() { for _, tc := range testCases { tc := tc - suite.Run(tc.name, func() { + suite.Run(tc.name+" arithmetic", func() { client := client.Querier{K: *suite.App.TwapKeeper} startTime := validStartTime @@ -188,5 +197,43 @@ func (suite *QueryTestSuite) TestQueryTwap() { suite.Require().Equal(tc.result, resultToNow.ArithmeticTwap.String()) } }) + + suite.Run(tc.name+" geometric", func() { + client := client.Querier{K: *suite.App.TwapKeeper} + + startTime := validStartTime + if tc.startTimeOverwrite != nil { + startTime = *tc.startTimeOverwrite + } + + result, err := client.GeometricTwap(ctx, queryproto.GeometricTwapRequest{ + PoolId: tc.poolId, + BaseAsset: tc.baseAssetDenom, + QuoteAsset: tc.quoteAssetDenom, + StartTime: startTime, + EndTime: tc.endTime, + }) + + if tc.expectErr { + suite.Require().Error(err, "expected error - GeometricTwap") + } else { + suite.Require().NoError(err, "unexpected error - GeometricTwap") + suite.Require().Equal(result.GeometricTwap.String(), result.GeometricTwap.String()) + } + + resultToNow, err := client.GeometricTwapToNow(ctx, queryproto.GeometricTwapToNowRequest{ + PoolId: tc.poolId, + BaseAsset: tc.baseAssetDenom, + QuoteAsset: tc.quoteAssetDenom, + StartTime: startTime, + }) + + if tc.expectErr { + suite.Require().Error(err, "expected error - GeometricTwapToNow") + } else { + suite.Require().NoError(err, "unexpected error - GeometricTwapToNow") + suite.Require().Equal(result.GeometricTwap.String(), resultToNow.GeometricTwap.String()) + } + }) } } diff --git a/x/twap/client/queryproto/query.pb.go b/x/twap/client/queryproto/query.pb.go index 5856b31e1df..4488021573d 100644 --- a/x/twap/client/queryproto/query.pb.go +++ b/x/twap/client/queryproto/query.pb.go @@ -257,6 +257,224 @@ func (m *ArithmeticTwapToNowResponse) XXX_DiscardUnknown() { var xxx_messageInfo_ArithmeticTwapToNowResponse proto.InternalMessageInfo +type GeometricTwapRequest struct { + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + BaseAsset string `protobuf:"bytes,2,opt,name=base_asset,json=baseAsset,proto3" json:"base_asset,omitempty"` + QuoteAsset string `protobuf:"bytes,3,opt,name=quote_asset,json=quoteAsset,proto3" json:"quote_asset,omitempty"` + StartTime time.Time `protobuf:"bytes,4,opt,name=start_time,json=startTime,proto3,stdtime" json:"start_time" yaml:"start_time"` + EndTime *time.Time `protobuf:"bytes,5,opt,name=end_time,json=endTime,proto3,stdtime" json:"end_time,omitempty" yaml:"end_time"` +} + +func (m *GeometricTwapRequest) Reset() { *m = GeometricTwapRequest{} } +func (m *GeometricTwapRequest) String() string { return proto.CompactTextString(m) } +func (*GeometricTwapRequest) ProtoMessage() {} +func (*GeometricTwapRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_141a22dba58615af, []int{4} +} +func (m *GeometricTwapRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GeometricTwapRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GeometricTwapRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GeometricTwapRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GeometricTwapRequest.Merge(m, src) +} +func (m *GeometricTwapRequest) XXX_Size() int { + return m.Size() +} +func (m *GeometricTwapRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GeometricTwapRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GeometricTwapRequest proto.InternalMessageInfo + +func (m *GeometricTwapRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *GeometricTwapRequest) GetBaseAsset() string { + if m != nil { + return m.BaseAsset + } + return "" +} + +func (m *GeometricTwapRequest) GetQuoteAsset() string { + if m != nil { + return m.QuoteAsset + } + return "" +} + +func (m *GeometricTwapRequest) GetStartTime() time.Time { + if m != nil { + return m.StartTime + } + return time.Time{} +} + +func (m *GeometricTwapRequest) GetEndTime() *time.Time { + if m != nil { + return m.EndTime + } + return nil +} + +type GeometricTwapResponse struct { + GeometricTwap github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=geometric_twap,json=geometricTwap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"geometric_twap" yaml:"geometric_twap"` +} + +func (m *GeometricTwapResponse) Reset() { *m = GeometricTwapResponse{} } +func (m *GeometricTwapResponse) String() string { return proto.CompactTextString(m) } +func (*GeometricTwapResponse) ProtoMessage() {} +func (*GeometricTwapResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_141a22dba58615af, []int{5} +} +func (m *GeometricTwapResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GeometricTwapResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GeometricTwapResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GeometricTwapResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GeometricTwapResponse.Merge(m, src) +} +func (m *GeometricTwapResponse) XXX_Size() int { + return m.Size() +} +func (m *GeometricTwapResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GeometricTwapResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GeometricTwapResponse proto.InternalMessageInfo + +type GeometricTwapToNowRequest struct { + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + BaseAsset string `protobuf:"bytes,2,opt,name=base_asset,json=baseAsset,proto3" json:"base_asset,omitempty"` + QuoteAsset string `protobuf:"bytes,3,opt,name=quote_asset,json=quoteAsset,proto3" json:"quote_asset,omitempty"` + StartTime time.Time `protobuf:"bytes,4,opt,name=start_time,json=startTime,proto3,stdtime" json:"start_time" yaml:"start_time"` +} + +func (m *GeometricTwapToNowRequest) Reset() { *m = GeometricTwapToNowRequest{} } +func (m *GeometricTwapToNowRequest) String() string { return proto.CompactTextString(m) } +func (*GeometricTwapToNowRequest) ProtoMessage() {} +func (*GeometricTwapToNowRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_141a22dba58615af, []int{6} +} +func (m *GeometricTwapToNowRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GeometricTwapToNowRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GeometricTwapToNowRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GeometricTwapToNowRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GeometricTwapToNowRequest.Merge(m, src) +} +func (m *GeometricTwapToNowRequest) XXX_Size() int { + return m.Size() +} +func (m *GeometricTwapToNowRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GeometricTwapToNowRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GeometricTwapToNowRequest proto.InternalMessageInfo + +func (m *GeometricTwapToNowRequest) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *GeometricTwapToNowRequest) GetBaseAsset() string { + if m != nil { + return m.BaseAsset + } + return "" +} + +func (m *GeometricTwapToNowRequest) GetQuoteAsset() string { + if m != nil { + return m.QuoteAsset + } + return "" +} + +func (m *GeometricTwapToNowRequest) GetStartTime() time.Time { + if m != nil { + return m.StartTime + } + return time.Time{} +} + +type GeometricTwapToNowResponse struct { + GeometricTwap github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=geometric_twap,json=geometricTwap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"geometric_twap" yaml:"geometric_twap"` +} + +func (m *GeometricTwapToNowResponse) Reset() { *m = GeometricTwapToNowResponse{} } +func (m *GeometricTwapToNowResponse) String() string { return proto.CompactTextString(m) } +func (*GeometricTwapToNowResponse) ProtoMessage() {} +func (*GeometricTwapToNowResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_141a22dba58615af, []int{7} +} +func (m *GeometricTwapToNowResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GeometricTwapToNowResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GeometricTwapToNowResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GeometricTwapToNowResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GeometricTwapToNowResponse.Merge(m, src) +} +func (m *GeometricTwapToNowResponse) XXX_Size() int { + return m.Size() +} +func (m *GeometricTwapToNowResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GeometricTwapToNowResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GeometricTwapToNowResponse proto.InternalMessageInfo + type ParamsRequest struct { } @@ -264,7 +482,7 @@ func (m *ParamsRequest) Reset() { *m = ParamsRequest{} } func (m *ParamsRequest) String() string { return proto.CompactTextString(m) } func (*ParamsRequest) ProtoMessage() {} func (*ParamsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_141a22dba58615af, []int{4} + return fileDescriptor_141a22dba58615af, []int{8} } func (m *ParamsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -301,7 +519,7 @@ func (m *ParamsResponse) Reset() { *m = ParamsResponse{} } func (m *ParamsResponse) String() string { return proto.CompactTextString(m) } func (*ParamsResponse) ProtoMessage() {} func (*ParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_141a22dba58615af, []int{5} + return fileDescriptor_141a22dba58615af, []int{9} } func (m *ParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -342,6 +560,10 @@ func init() { proto.RegisterType((*ArithmeticTwapResponse)(nil), "osmosis.twap.v1beta1.ArithmeticTwapResponse") proto.RegisterType((*ArithmeticTwapToNowRequest)(nil), "osmosis.twap.v1beta1.ArithmeticTwapToNowRequest") proto.RegisterType((*ArithmeticTwapToNowResponse)(nil), "osmosis.twap.v1beta1.ArithmeticTwapToNowResponse") + proto.RegisterType((*GeometricTwapRequest)(nil), "osmosis.twap.v1beta1.GeometricTwapRequest") + proto.RegisterType((*GeometricTwapResponse)(nil), "osmosis.twap.v1beta1.GeometricTwapResponse") + proto.RegisterType((*GeometricTwapToNowRequest)(nil), "osmosis.twap.v1beta1.GeometricTwapToNowRequest") + proto.RegisterType((*GeometricTwapToNowResponse)(nil), "osmosis.twap.v1beta1.GeometricTwapToNowResponse") proto.RegisterType((*ParamsRequest)(nil), "osmosis.twap.v1beta1.ParamsRequest") proto.RegisterType((*ParamsResponse)(nil), "osmosis.twap.v1beta1.ParamsResponse") } @@ -349,50 +571,57 @@ func init() { func init() { proto.RegisterFile("osmosis/twap/v1beta1/query.proto", fileDescriptor_141a22dba58615af) } var fileDescriptor_141a22dba58615af = []byte{ - // 676 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x95, 0x4f, 0x4f, 0xd4, 0x4e, - 0x18, 0xc7, 0x77, 0x16, 0x58, 0x7e, 0x3b, 0xe4, 0x07, 0x71, 0x44, 0xc4, 0x02, 0xed, 0xa6, 0x12, - 0x82, 0x02, 0xad, 0x0b, 0x9e, 0x88, 0x17, 0x36, 0x1e, 0x34, 0x31, 0x46, 0x1b, 0x62, 0x8c, 0x97, - 0xcd, 0x6c, 0x77, 0x2c, 0x8d, 0xdb, 0x4e, 0xb7, 0x33, 0x0b, 0xee, 0xd5, 0x93, 0x89, 0x17, 0x12, - 0x4f, 0x5e, 0x7c, 0x0d, 0xbe, 0x0c, 0x6e, 0x62, 0xbc, 0x18, 0x0f, 0xd5, 0x80, 0xaf, 0x80, 0x57, - 0x60, 0xe6, 0x4f, 0x57, 0xd8, 0x34, 0x88, 0x27, 0xe3, 0xa9, 0x3b, 0xcf, 0xf3, 0x7d, 0xbe, 0xcf, - 0x67, 0x9e, 0x4e, 0x67, 0x61, 0x8d, 0xb2, 0x88, 0xb2, 0x90, 0xb9, 0x7c, 0x0f, 0x27, 0xee, 0x6e, - 0xbd, 0x45, 0x38, 0xae, 0xbb, 0xdd, 0x1e, 0x49, 0xfb, 0x4e, 0x92, 0x52, 0x4e, 0xd1, 0xb4, 0x56, - 0x38, 0x42, 0xe1, 0x68, 0x85, 0x31, 0x1d, 0xd0, 0x80, 0x4a, 0x81, 0x2b, 0x7e, 0x29, 0xad, 0xb1, - 0x54, 0xe8, 0x26, 0x16, 0xcd, 0x94, 0xf8, 0x34, 0x6d, 0x6b, 0x9d, 0x5d, 0xa8, 0x0b, 0x48, 0x4c, - 0x44, 0x23, 0xa5, 0x31, 0x7d, 0x29, 0x72, 0x5b, 0x98, 0x91, 0x81, 0xc4, 0xa7, 0x61, 0xac, 0xf3, - 0x37, 0x4f, 0xe7, 0x25, 0xf0, 0x40, 0x95, 0xe0, 0x20, 0x8c, 0x31, 0x0f, 0x69, 0xae, 0x9d, 0x0f, - 0x28, 0x0d, 0x3a, 0xc4, 0xc5, 0x49, 0xe8, 0xe2, 0x38, 0xa6, 0x5c, 0x26, 0xf3, 0x4e, 0xd7, 0x74, - 0x56, 0xae, 0x5a, 0xbd, 0xe7, 0x2e, 0x8e, 0xfb, 0x79, 0x4a, 0x35, 0x69, 0xaa, 0x9d, 0xaa, 0x85, - 0x4e, 0x59, 0xc3, 0x55, 0x3c, 0x8c, 0x08, 0xe3, 0x38, 0x4a, 0x94, 0xc0, 0x7e, 0x5f, 0x86, 0x57, - 0xb6, 0xd2, 0x90, 0xef, 0x44, 0x84, 0x87, 0xfe, 0xf6, 0x1e, 0x4e, 0x3c, 0xd2, 0xed, 0x11, 0xc6, - 0xd1, 0x55, 0x38, 0x9e, 0x50, 0xda, 0x69, 0x86, 0xed, 0x59, 0x50, 0x03, 0xcb, 0xa3, 0x5e, 0x45, - 0x2c, 0xef, 0xb7, 0xd1, 0x02, 0x84, 0x62, 0x3b, 0x4d, 0xcc, 0x18, 0xe1, 0xb3, 0xe5, 0x1a, 0x58, - 0xae, 0x7a, 0x55, 0x11, 0xd9, 0x12, 0x01, 0x64, 0xc1, 0x89, 0x6e, 0x8f, 0xf2, 0x3c, 0x3f, 0x22, - 0xf3, 0x50, 0x86, 0x94, 0xe0, 0x29, 0x84, 0x8c, 0xe3, 0x94, 0x37, 0x05, 0xcb, 0xec, 0x68, 0x0d, - 0x2c, 0x4f, 0xac, 0x1b, 0x8e, 0x02, 0x75, 0x72, 0x50, 0x67, 0x3b, 0x07, 0x6d, 0x2c, 0x1c, 0x64, - 0x56, 0xe9, 0x24, 0xb3, 0x2e, 0xf5, 0x71, 0xd4, 0xd9, 0xb4, 0x7f, 0xd5, 0xda, 0xfb, 0xdf, 0x2c, - 0xe0, 0x55, 0x65, 0x40, 0xc8, 0x91, 0x07, 0xff, 0x23, 0x71, 0x5b, 0xf9, 0x8e, 0xfd, 0xd6, 0x77, - 0xee, 0x20, 0xb3, 0xc0, 0x49, 0x66, 0x4d, 0x29, 0xdf, 0xbc, 0x52, 0xb9, 0x8e, 0x93, 0xb8, 0x2d, - 0xa4, 0xf6, 0x1b, 0x00, 0x67, 0x86, 0x07, 0xc4, 0x12, 0x1a, 0x33, 0x82, 0xba, 0x70, 0x0a, 0x0f, - 0x32, 0x4d, 0x71, 0x4a, 0xe4, 0xa4, 0xaa, 0x8d, 0x7b, 0x82, 0xf8, 0x6b, 0x66, 0x2d, 0x05, 0x21, - 0xdf, 0xe9, 0xb5, 0x1c, 0x9f, 0x46, 0xfa, 0xb5, 0xe8, 0xc7, 0x1a, 0x6b, 0xbf, 0x70, 0x79, 0x3f, - 0x21, 0xcc, 0xb9, 0x4b, 0xfc, 0x93, 0xcc, 0x9a, 0x51, 0x0c, 0x43, 0x76, 0xb6, 0x37, 0x89, 0xcf, - 0xb4, 0xb6, 0x3f, 0x02, 0x68, 0x9c, 0xa5, 0xd9, 0xa6, 0x0f, 0xe9, 0xde, 0xbf, 0xfb, 0xce, 0xec, - 0x7d, 0x00, 0xe7, 0x0a, 0x77, 0xf4, 0xf7, 0x86, 0x3c, 0x05, 0xff, 0x7f, 0x84, 0x53, 0x1c, 0x31, - 0x3d, 0x56, 0xfb, 0x01, 0x9c, 0xcc, 0x03, 0x9a, 0x6a, 0x13, 0x56, 0x12, 0x19, 0x91, 0x30, 0x13, - 0xeb, 0xf3, 0x4e, 0xd1, 0x05, 0xe4, 0xa8, 0xaa, 0xc6, 0xa8, 0x40, 0xf5, 0x74, 0xc5, 0xfa, 0xa7, - 0x11, 0x38, 0xf6, 0x58, 0x5c, 0x05, 0xa8, 0x0f, 0x2b, 0x4a, 0x81, 0xae, 0x9f, 0x57, 0xaf, 0x31, - 0x8c, 0xc5, 0xf3, 0x45, 0x0a, 0xcd, 0x5e, 0x7c, 0xf5, 0xf9, 0xc7, 0xdb, 0xb2, 0x89, 0xe6, 0xdd, - 0xc2, 0xfb, 0x4b, 0x37, 0x7c, 0x07, 0xe0, 0xe4, 0xd9, 0xb1, 0xa3, 0x95, 0x62, 0xfb, 0xc2, 0xdb, - 0xc1, 0x58, 0xbd, 0x98, 0x58, 0x33, 0xad, 0x4a, 0xa6, 0x25, 0xb4, 0x58, 0xcc, 0x34, 0x04, 0xf2, - 0x01, 0xc0, 0xcb, 0x05, 0x47, 0x02, 0xdd, 0xba, 0x48, 0xcf, 0xd3, 0xdf, 0x83, 0x51, 0xff, 0x83, - 0x0a, 0x8d, 0x7a, 0x5b, 0xa2, 0xae, 0xa0, 0x1b, 0x17, 0x41, 0x95, 0xa5, 0xaf, 0xcb, 0xa0, 0xf1, - 0xe4, 0xe0, 0xc8, 0x04, 0x87, 0x47, 0x26, 0xf8, 0x7e, 0x64, 0x82, 0xfd, 0x63, 0xb3, 0x74, 0x78, - 0x6c, 0x96, 0xbe, 0x1c, 0x9b, 0xa5, 0x67, 0x77, 0x4e, 0x1d, 0x4f, 0xed, 0xb8, 0xd6, 0xc1, 0x2d, - 0x36, 0xb0, 0xdf, 0xad, 0x6f, 0xb8, 0x2f, 0x55, 0x13, 0xbf, 0x13, 0x92, 0x98, 0xab, 0xff, 0x09, - 0xf5, 0x51, 0x55, 0xe4, 0x63, 0xe3, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0x99, 0x01, 0xcf, 0x37, - 0x02, 0x07, 0x00, 0x00, + // 799 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x96, 0x41, 0x4f, 0x1b, 0x47, + 0x14, 0xc7, 0x3d, 0x2e, 0x98, 0x7a, 0x10, 0x46, 0x9d, 0x02, 0x85, 0x05, 0x76, 0xad, 0x85, 0x22, + 0x17, 0xc3, 0x2e, 0x86, 0x1b, 0xea, 0x05, 0xab, 0x12, 0xad, 0x54, 0x55, 0xed, 0x0a, 0x55, 0x55, + 0x2f, 0xd6, 0xd8, 0x9e, 0x2e, 0xab, 0x7a, 0x77, 0xd6, 0xbb, 0x63, 0x88, 0xaf, 0xb9, 0xe4, 0x90, + 0x1c, 0x50, 0xa2, 0x1c, 0x72, 0x48, 0xee, 0x39, 0xe4, 0x7b, 0x70, 0x4a, 0x90, 0x72, 0x89, 0x72, + 0x70, 0x22, 0xc8, 0x27, 0xe0, 0x13, 0x44, 0x3b, 0x33, 0xeb, 0x78, 0x9d, 0x15, 0x31, 0x27, 0x84, + 0x94, 0x93, 0x99, 0xf7, 0xfe, 0xef, 0xbd, 0xdf, 0xbc, 0xd9, 0x37, 0x03, 0x2c, 0xd2, 0xd0, 0xa5, + 0xa1, 0x13, 0x9a, 0xec, 0x18, 0xfb, 0xe6, 0x51, 0xa5, 0x4e, 0x18, 0xae, 0x98, 0xed, 0x0e, 0x09, + 0xba, 0x86, 0x1f, 0x50, 0x46, 0xd1, 0x8c, 0x54, 0x18, 0x91, 0xc2, 0x90, 0x0a, 0x65, 0xc6, 0xa6, + 0x36, 0xe5, 0x02, 0x33, 0xfa, 0x4b, 0x68, 0x95, 0xb5, 0xd4, 0x6c, 0xd1, 0xa2, 0x16, 0x90, 0x06, + 0x0d, 0x9a, 0x52, 0xa7, 0xa7, 0xea, 0x6c, 0xe2, 0x91, 0xa8, 0x90, 0xd0, 0xa8, 0x0d, 0x2e, 0x32, + 0xeb, 0x38, 0x24, 0x7d, 0x49, 0x83, 0x3a, 0x9e, 0xf4, 0xaf, 0x0f, 0xfa, 0x39, 0x70, 0x5f, 0xe5, + 0x63, 0xdb, 0xf1, 0x30, 0x73, 0x68, 0xac, 0x5d, 0xb2, 0x29, 0xb5, 0x5b, 0xc4, 0xc4, 0xbe, 0x63, + 0x62, 0xcf, 0xa3, 0x8c, 0x3b, 0xe3, 0x4a, 0x0b, 0xd2, 0xcb, 0x57, 0xf5, 0xce, 0x7f, 0x26, 0xf6, + 0xba, 0xb1, 0x4b, 0x14, 0xa9, 0x89, 0x9d, 0x8a, 0x85, 0x74, 0x69, 0xc3, 0x51, 0xcc, 0x71, 0x49, + 0xc8, 0xb0, 0xeb, 0x0b, 0x81, 0xfe, 0x2c, 0x0b, 0x67, 0xf7, 0x02, 0x87, 0x1d, 0xba, 0x84, 0x39, + 0x8d, 0x83, 0x63, 0xec, 0x5b, 0xa4, 0xdd, 0x21, 0x21, 0x43, 0x3f, 0xc0, 0x09, 0x9f, 0xd2, 0x56, + 0xcd, 0x69, 0xce, 0x83, 0x22, 0x28, 0x8d, 0x59, 0xb9, 0x68, 0xf9, 0x5b, 0x13, 0x2d, 0x43, 0x18, + 0x6d, 0xa7, 0x86, 0xc3, 0x90, 0xb0, 0xf9, 0x6c, 0x11, 0x94, 0xf2, 0x56, 0x3e, 0xb2, 0xec, 0x45, + 0x06, 0xa4, 0xc1, 0xc9, 0x76, 0x87, 0xb2, 0xd8, 0xff, 0x0d, 0xf7, 0x43, 0x6e, 0x12, 0x82, 0x7f, + 0x20, 0x0c, 0x19, 0x0e, 0x58, 0x2d, 0x62, 0x99, 0x1f, 0x2b, 0x82, 0xd2, 0xe4, 0xb6, 0x62, 0x08, + 0x50, 0x23, 0x06, 0x35, 0x0e, 0x62, 0xd0, 0xea, 0xf2, 0x69, 0x4f, 0xcb, 0x5c, 0xf6, 0xb4, 0xef, + 0xba, 0xd8, 0x6d, 0xed, 0xea, 0x9f, 0x62, 0xf5, 0x93, 0x77, 0x1a, 0xb0, 0xf2, 0xdc, 0x10, 0xc9, + 0x91, 0x05, 0xbf, 0x25, 0x5e, 0x53, 0xe4, 0x1d, 0xff, 0x62, 0xde, 0xc5, 0xd3, 0x9e, 0x06, 0x2e, + 0x7b, 0xda, 0xb4, 0xc8, 0x1b, 0x47, 0x8a, 0xac, 0x13, 0xc4, 0x6b, 0x46, 0x52, 0xfd, 0x3e, 0x80, + 0x73, 0xc3, 0x0d, 0x0a, 0x7d, 0xea, 0x85, 0x04, 0xb5, 0xe1, 0x34, 0xee, 0x7b, 0x6a, 0xd1, 0x57, + 0xc2, 0x3b, 0x95, 0xaf, 0xfe, 0x1a, 0x11, 0xbf, 0xed, 0x69, 0x6b, 0xb6, 0xc3, 0x0e, 0x3b, 0x75, + 0xa3, 0x41, 0x5d, 0x79, 0x2c, 0xf2, 0x67, 0x33, 0x6c, 0xfe, 0x6f, 0xb2, 0xae, 0x4f, 0x42, 0xe3, + 0x17, 0xd2, 0xb8, 0xec, 0x69, 0x73, 0x82, 0x61, 0x28, 0x9d, 0x6e, 0x15, 0x70, 0xa2, 0xb4, 0xfe, + 0x0a, 0x40, 0x25, 0x49, 0x73, 0x40, 0xff, 0xa0, 0xc7, 0xb7, 0xf7, 0xcc, 0xf4, 0x13, 0x00, 0x17, + 0x53, 0x77, 0x74, 0x73, 0x4d, 0x7e, 0x9a, 0x85, 0x33, 0xfb, 0x84, 0xba, 0x84, 0x05, 0x5f, 0x47, + 0x22, 0x65, 0x24, 0xee, 0x01, 0x38, 0x3b, 0xd4, 0x1f, 0x79, 0x58, 0x1e, 0x2c, 0xd8, 0xb1, 0x63, + 0xf0, 0xac, 0xf6, 0xaf, 0x7d, 0x56, 0xb3, 0x82, 0x20, 0x99, 0x4d, 0xb7, 0xa6, 0xec, 0xc1, 0xba, + 0xfa, 0x4b, 0x00, 0x17, 0x12, 0x24, 0xb7, 0x7d, 0x1a, 0x1e, 0x00, 0xa8, 0xa4, 0x6d, 0xe8, 0x86, + 0xfa, 0x3b, 0x0d, 0xa7, 0xfe, 0xc4, 0x01, 0x76, 0x43, 0xd9, 0x52, 0xfd, 0x77, 0x58, 0x88, 0x0d, + 0x12, 0x69, 0x17, 0xe6, 0x7c, 0x6e, 0xe1, 0x28, 0x93, 0xdb, 0x4b, 0x46, 0xda, 0x53, 0x6c, 0x88, + 0xa8, 0xea, 0x58, 0x04, 0x6a, 0xc9, 0x88, 0xed, 0x87, 0x39, 0x38, 0xfe, 0x57, 0xf4, 0x28, 0xa2, + 0x2e, 0xcc, 0x09, 0x05, 0x5a, 0xb9, 0x2a, 0x5e, 0x62, 0x28, 0xab, 0x57, 0x8b, 0x04, 0x9a, 0xbe, + 0x7a, 0xf7, 0xf5, 0x87, 0x47, 0x59, 0x15, 0x2d, 0x99, 0xa9, 0x2f, 0xb9, 0x2c, 0xf8, 0x04, 0xc0, + 0x42, 0xf2, 0x02, 0x42, 0xe5, 0xf4, 0xf4, 0xa9, 0xef, 0xa4, 0xb2, 0x31, 0x9a, 0x58, 0x32, 0x6d, + 0x70, 0xa6, 0x35, 0xb4, 0x9a, 0xce, 0x34, 0x04, 0xf2, 0x02, 0xc0, 0xef, 0x53, 0x2e, 0x47, 0xb4, + 0x35, 0x4a, 0xcd, 0xc1, 0x59, 0x50, 0x2a, 0xd7, 0x88, 0x90, 0xa8, 0x15, 0x8e, 0x5a, 0x46, 0x3f, + 0x8d, 0x82, 0x2a, 0xb8, 0x1e, 0x03, 0x38, 0x95, 0xf8, 0x7c, 0xd1, 0x7a, 0x7a, 0xdd, 0xb4, 0xeb, + 0x55, 0x29, 0x8f, 0xa4, 0x95, 0x74, 0x65, 0x4e, 0xf7, 0x23, 0x5a, 0x49, 0xa7, 0x4b, 0x52, 0x3c, + 0x07, 0x10, 0x7d, 0x3e, 0x56, 0xc8, 0x1c, 0xa1, 0x60, 0xa2, 0x8b, 0x5b, 0xa3, 0x07, 0x48, 0xcc, + 0x2d, 0x8e, 0xb9, 0x8e, 0x4a, 0x23, 0x60, 0xf2, 0xc8, 0xea, 0xdf, 0xa7, 0xe7, 0x2a, 0x38, 0x3b, + 0x57, 0xc1, 0xfb, 0x73, 0x15, 0x9c, 0x5c, 0xa8, 0x99, 0xb3, 0x0b, 0x35, 0xf3, 0xe6, 0x42, 0xcd, + 0xfc, 0xfb, 0xf3, 0xc0, 0x74, 0xcb, 0x6c, 0x9b, 0x2d, 0x5c, 0x0f, 0xfb, 0xa9, 0x8f, 0x2a, 0x3b, + 0xe6, 0x1d, 0x51, 0xa0, 0xd1, 0x72, 0x88, 0xc7, 0xc4, 0xbf, 0x9c, 0xe2, 0x46, 0xca, 0xf1, 0x9f, + 0x9d, 0x8f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x83, 0xed, 0xb2, 0x07, 0x4d, 0x0b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -410,6 +639,8 @@ type QueryClient interface { Params(ctx context.Context, in *ParamsRequest, opts ...grpc.CallOption) (*ParamsResponse, error) ArithmeticTwap(ctx context.Context, in *ArithmeticTwapRequest, opts ...grpc.CallOption) (*ArithmeticTwapResponse, error) ArithmeticTwapToNow(ctx context.Context, in *ArithmeticTwapToNowRequest, opts ...grpc.CallOption) (*ArithmeticTwapToNowResponse, error) + GeometricTwap(ctx context.Context, in *GeometricTwapRequest, opts ...grpc.CallOption) (*GeometricTwapResponse, error) + GeometricTwapToNow(ctx context.Context, in *GeometricTwapToNowRequest, opts ...grpc.CallOption) (*GeometricTwapToNowResponse, error) } type queryClient struct { @@ -438,7 +669,6 @@ func (c *queryClient) ArithmeticTwap(ctx context.Context, in *ArithmeticTwapRequ return out, nil } -// Deprecated: Do not use. func (c *queryClient) ArithmeticTwapToNow(ctx context.Context, in *ArithmeticTwapToNowRequest, opts ...grpc.CallOption) (*ArithmeticTwapToNowResponse, error) { out := new(ArithmeticTwapToNowResponse) err := c.cc.Invoke(ctx, "/osmosis.twap.v1beta1.Query/ArithmeticTwapToNow", in, out, opts...) @@ -448,11 +678,31 @@ func (c *queryClient) ArithmeticTwapToNow(ctx context.Context, in *ArithmeticTwa return out, nil } +func (c *queryClient) GeometricTwap(ctx context.Context, in *GeometricTwapRequest, opts ...grpc.CallOption) (*GeometricTwapResponse, error) { + out := new(GeometricTwapResponse) + err := c.cc.Invoke(ctx, "/osmosis.twap.v1beta1.Query/GeometricTwap", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) GeometricTwapToNow(ctx context.Context, in *GeometricTwapToNowRequest, opts ...grpc.CallOption) (*GeometricTwapToNowResponse, error) { + out := new(GeometricTwapToNowResponse) + err := c.cc.Invoke(ctx, "/osmosis.twap.v1beta1.Query/GeometricTwapToNow", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { Params(context.Context, *ParamsRequest) (*ParamsResponse, error) ArithmeticTwap(context.Context, *ArithmeticTwapRequest) (*ArithmeticTwapResponse, error) ArithmeticTwapToNow(context.Context, *ArithmeticTwapToNowRequest) (*ArithmeticTwapToNowResponse, error) + GeometricTwap(context.Context, *GeometricTwapRequest) (*GeometricTwapResponse, error) + GeometricTwapToNow(context.Context, *GeometricTwapToNowRequest) (*GeometricTwapToNowResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -468,6 +718,12 @@ func (*UnimplementedQueryServer) ArithmeticTwap(ctx context.Context, req *Arithm func (*UnimplementedQueryServer) ArithmeticTwapToNow(ctx context.Context, req *ArithmeticTwapToNowRequest) (*ArithmeticTwapToNowResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ArithmeticTwapToNow not implemented") } +func (*UnimplementedQueryServer) GeometricTwap(ctx context.Context, req *GeometricTwapRequest) (*GeometricTwapResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GeometricTwap not implemented") +} +func (*UnimplementedQueryServer) GeometricTwapToNow(ctx context.Context, req *GeometricTwapToNowRequest) (*GeometricTwapToNowResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GeometricTwapToNow not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -527,6 +783,42 @@ func _Query_ArithmeticTwapToNow_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _Query_GeometricTwap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GeometricTwapRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).GeometricTwap(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.twap.v1beta1.Query/GeometricTwap", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).GeometricTwap(ctx, req.(*GeometricTwapRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_GeometricTwapToNow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GeometricTwapToNowRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).GeometricTwapToNow(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/osmosis.twap.v1beta1.Query/GeometricTwapToNow", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).GeometricTwapToNow(ctx, req.(*GeometricTwapToNowRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "osmosis.twap.v1beta1.Query", HandlerType: (*QueryServer)(nil), @@ -543,6 +835,14 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "ArithmeticTwapToNow", Handler: _Query_ArithmeticTwapToNow_Handler, }, + { + MethodName: "GeometricTwap", + Handler: _Query_GeometricTwap_Handler, + }, + { + MethodName: "GeometricTwapToNow", + Handler: _Query_GeometricTwapToNow_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "osmosis/twap/v1beta1/query.proto", @@ -724,7 +1024,7 @@ func (m *ArithmeticTwapToNowResponse) MarshalToSizedBuffer(dAtA []byte) (int, er return len(dAtA) - i, nil } -func (m *ParamsRequest) Marshal() (dAtA []byte, err error) { +func (m *GeometricTwapRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -734,20 +1034,57 @@ func (m *ParamsRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ParamsRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *GeometricTwapRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *GeometricTwapRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l + if m.EndTime != nil { + n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.EndTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.EndTime):]) + if err4 != nil { + return 0, err4 + } + i -= n4 + i = encodeVarintQuery(dAtA, i, uint64(n4)) + i-- + dAtA[i] = 0x2a + } + n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime):]) + if err5 != nil { + return 0, err5 + } + i -= n5 + i = encodeVarintQuery(dAtA, i, uint64(n5)) + i-- + dAtA[i] = 0x22 + if len(m.QuoteAsset) > 0 { + i -= len(m.QuoteAsset) + copy(dAtA[i:], m.QuoteAsset) + i = encodeVarintQuery(dAtA, i, uint64(len(m.QuoteAsset))) + i-- + dAtA[i] = 0x1a + } + if len(m.BaseAsset) > 0 { + i -= len(m.BaseAsset) + copy(dAtA[i:], m.BaseAsset) + i = encodeVarintQuery(dAtA, i, uint64(len(m.BaseAsset))) + i-- + dAtA[i] = 0x12 + } + if m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } -func (m *ParamsResponse) Marshal() (dAtA []byte, err error) { +func (m *GeometricTwapResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -757,137 +1094,882 @@ func (m *ParamsResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ParamsResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *GeometricTwapResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *GeometricTwapResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { + size := m.GeometricTwap.Size() + i -= size + if _, err := m.GeometricTwap.MarshalTo(dAtA[i:]); err != nil { return 0, err } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { - offset -= sovQuery(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *ArithmeticTwapRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.PoolId != 0 { - n += 1 + sovQuery(uint64(m.PoolId)) - } - l = len(m.BaseAsset) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.QuoteAsset) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) - n += 1 + l + sovQuery(uint64(l)) - if m.EndTime != nil { - l = github_com_gogo_protobuf_types.SizeOfStdTime(*m.EndTime) - n += 1 + l + sovQuery(uint64(l)) - } - return n -} - -func (m *ArithmeticTwapResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.ArithmeticTwap.Size() - n += 1 + l + sovQuery(uint64(l)) - return n -} - -func (m *ArithmeticTwapToNowRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.PoolId != 0 { - n += 1 + sovQuery(uint64(m.PoolId)) - } - l = len(m.BaseAsset) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.QuoteAsset) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *GeometricTwapToNowRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GeometricTwapToNowRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GeometricTwapToNowRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime):]) + if err6 != nil { + return 0, err6 + } + i -= n6 + i = encodeVarintQuery(dAtA, i, uint64(n6)) + i-- + dAtA[i] = 0x22 + if len(m.QuoteAsset) > 0 { + i -= len(m.QuoteAsset) + copy(dAtA[i:], m.QuoteAsset) + i = encodeVarintQuery(dAtA, i, uint64(len(m.QuoteAsset))) + i-- + dAtA[i] = 0x1a + } + if len(m.BaseAsset) > 0 { + i -= len(m.BaseAsset) + copy(dAtA[i:], m.BaseAsset) + i = encodeVarintQuery(dAtA, i, uint64(len(m.BaseAsset))) + i-- + dAtA[i] = 0x12 + } + if m.PoolId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *GeometricTwapToNowResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GeometricTwapToNowResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GeometricTwapToNowResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.GeometricTwap.Size() + i -= size + if _, err := m.GeometricTwap.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *ParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *ParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ArithmeticTwapRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + l = len(m.BaseAsset) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.QuoteAsset) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) + n += 1 + l + sovQuery(uint64(l)) + if m.EndTime != nil { + l = github_com_gogo_protobuf_types.SizeOfStdTime(*m.EndTime) + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *ArithmeticTwapResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ArithmeticTwap.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *ArithmeticTwapToNowRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + l = len(m.BaseAsset) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.QuoteAsset) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *ArithmeticTwapToNowResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ArithmeticTwap.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *GeometricTwapRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + l = len(m.BaseAsset) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.QuoteAsset) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) + n += 1 + l + sovQuery(uint64(l)) + if m.EndTime != nil { + l = github_com_gogo_protobuf_types.SizeOfStdTime(*m.EndTime) + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *GeometricTwapResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.GeometricTwap.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *GeometricTwapToNowRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovQuery(uint64(m.PoolId)) + } + l = len(m.BaseAsset) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.QuoteAsset) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *GeometricTwapToNowResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.GeometricTwap.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *ParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *ParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ArithmeticTwapRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ArithmeticTwapRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ArithmeticTwapRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseAsset", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BaseAsset = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QuoteAsset", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.QuoteAsset = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.EndTime == nil { + m.EndTime = new(time.Time) + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(m.EndTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ArithmeticTwapResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ArithmeticTwapResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ArithmeticTwapResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ArithmeticTwap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ArithmeticTwap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ArithmeticTwapToNowRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ArithmeticTwapToNowRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ArithmeticTwapToNowRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseAsset", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BaseAsset = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QuoteAsset", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.QuoteAsset = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.StartTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } } - l = github_com_gogo_protobuf_types.SizeOfStdTime(m.StartTime) - n += 1 + l + sovQuery(uint64(l)) - return n -} -func (m *ArithmeticTwapToNowResponse) Size() (n int) { - if m == nil { - return 0 + if iNdEx > l { + return io.ErrUnexpectedEOF } - var l int - _ = l - l = m.ArithmeticTwap.Size() - n += 1 + l + sovQuery(uint64(l)) - return n + return nil } - -func (m *ParamsRequest) Size() (n int) { - if m == nil { - return 0 +func (m *ArithmeticTwapToNowResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ArithmeticTwapToNowResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ArithmeticTwapToNowResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ArithmeticTwap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ArithmeticTwap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } } - var l int - _ = l - return n -} -func (m *ParamsResponse) Size() (n int) { - if m == nil { - return 0 + if iNdEx > l { + return io.ErrUnexpectedEOF } - var l int - _ = l - l = m.Params.Size() - n += 1 + l + sovQuery(uint64(l)) - return n -} - -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + return nil } -func (m *ArithmeticTwapRequest) Unmarshal(dAtA []byte) error { +func (m *GeometricTwapRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -910,10 +1992,10 @@ func (m *ArithmeticTwapRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ArithmeticTwapRequest: wiretype end group for non-group") + return fmt.Errorf("proto: GeometricTwapRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ArithmeticTwapRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GeometricTwapRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1089,7 +2171,7 @@ func (m *ArithmeticTwapRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *ArithmeticTwapResponse) Unmarshal(dAtA []byte) error { +func (m *GeometricTwapResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1112,15 +2194,15 @@ func (m *ArithmeticTwapResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ArithmeticTwapResponse: wiretype end group for non-group") + return fmt.Errorf("proto: GeometricTwapResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ArithmeticTwapResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GeometricTwapResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ArithmeticTwap", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field GeometricTwap", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1148,7 +2230,7 @@ func (m *ArithmeticTwapResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ArithmeticTwap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.GeometricTwap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1173,7 +2255,7 @@ func (m *ArithmeticTwapResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *ArithmeticTwapToNowRequest) Unmarshal(dAtA []byte) error { +func (m *GeometricTwapToNowRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1196,10 +2278,10 @@ func (m *ArithmeticTwapToNowRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ArithmeticTwapToNowRequest: wiretype end group for non-group") + return fmt.Errorf("proto: GeometricTwapToNowRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ArithmeticTwapToNowRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GeometricTwapToNowRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1339,7 +2421,7 @@ func (m *ArithmeticTwapToNowRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *ArithmeticTwapToNowResponse) Unmarshal(dAtA []byte) error { +func (m *GeometricTwapToNowResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1362,15 +2444,15 @@ func (m *ArithmeticTwapToNowResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ArithmeticTwapToNowResponse: wiretype end group for non-group") + return fmt.Errorf("proto: GeometricTwapToNowResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ArithmeticTwapToNowResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GeometricTwapToNowResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ArithmeticTwap", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field GeometricTwap", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1398,7 +2480,7 @@ func (m *ArithmeticTwapToNowResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ArithmeticTwap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.GeometricTwap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/twap/client/queryproto/query.pb.gw.go b/x/twap/client/queryproto/query.pb.gw.go index b9f76d10fb9..911f16155ac 100644 --- a/x/twap/client/queryproto/query.pb.gw.go +++ b/x/twap/client/queryproto/query.pb.gw.go @@ -123,6 +123,78 @@ func local_request_Query_ArithmeticTwapToNow_0(ctx context.Context, marshaler ru } +var ( + filter_Query_GeometricTwap_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_GeometricTwap_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GeometricTwapRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GeometricTwap_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GeometricTwap(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_GeometricTwap_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GeometricTwapRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GeometricTwap_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GeometricTwap(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_GeometricTwapToNow_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_GeometricTwapToNow_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GeometricTwapToNowRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GeometricTwapToNow_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GeometricTwapToNow(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_GeometricTwapToNow_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GeometricTwapToNowRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GeometricTwapToNow_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GeometricTwapToNow(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -198,6 +270,52 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_GeometricTwap_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_GeometricTwap_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_GeometricTwap_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_GeometricTwapToNow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_GeometricTwapToNow_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_GeometricTwapToNow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -299,6 +417,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_GeometricTwap_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_GeometricTwap_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_GeometricTwap_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_GeometricTwapToNow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_GeometricTwapToNow_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_GeometricTwapToNow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -308,6 +466,10 @@ var ( pattern_Query_ArithmeticTwap_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "twap", "v1beta1", "ArithmeticTwap"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_ArithmeticTwapToNow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "twap", "v1beta1", "ArithmeticTwapToNow"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_GeometricTwap_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "twap", "v1beta1", "GeometricTwap"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_GeometricTwapToNow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"osmosis", "twap", "v1beta1", "GeometricTwapToNow"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -316,4 +478,8 @@ var ( forward_Query_ArithmeticTwap_0 = runtime.ForwardResponseMessage forward_Query_ArithmeticTwapToNow_0 = runtime.ForwardResponseMessage + + forward_Query_GeometricTwap_0 = runtime.ForwardResponseMessage + + forward_Query_GeometricTwapToNow_0 = runtime.ForwardResponseMessage ) diff --git a/x/twap/export_test.go b/x/twap/export_test.go index 30f32542bd0..1ccbbd47ab8 100644 --- a/x/twap/export_test.go +++ b/x/twap/export_test.go @@ -9,7 +9,10 @@ import ( ) type ( - TimeTooOldError = timeTooOldError + TimeTooOldError = timeTooOldError + TwapStrategy = twapStrategy + ArithmeticTwapStrategy = arithmetic + GeometricTwapStrategy = geometric ) func (k Keeper) StoreNewRecord(ctx sdk.Context, record types.TwapRecord) { @@ -64,8 +67,16 @@ func (k Keeper) GetInterpolatedRecord(ctx sdk.Context, poolId uint64, asset0Deno return k.getInterpolatedRecord(ctx, poolId, t, asset0Denom, asset1Denom) } -func ComputeArithmeticTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string) (sdk.Dec, error) { - return computeArithmeticTwap(startRecord, endRecord, quoteAsset) +func ComputeTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string, strategy twapStrategy) (sdk.Dec, error) { + return computeTwap(startRecord, endRecord, quoteAsset, strategy) +} + +func (as arithmetic) ComputeTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string) sdk.Dec { + return as.computeTwap(startRecord, endRecord, quoteAsset) +} + +func (gs geometric) ComputeTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string) sdk.Dec { + return gs.computeTwap(startRecord, endRecord, quoteAsset) } func RecordWithUpdatedAccumulators(record types.TwapRecord, t time.Time) types.TwapRecord { @@ -76,6 +87,14 @@ func NewTwapRecord(k types.AmmInterface, ctx sdk.Context, poolId uint64, denom0, return newTwapRecord(k, ctx, poolId, denom0, denom1) } +func TwapLog(x sdk.Dec) sdk.Dec { + return twapLog(x) +} + +func TwapPow(x sdk.Dec) sdk.Dec { + return twapPow(x) +} + func GetSpotPrices( ctx sdk.Context, k types.AmmInterface, diff --git a/x/twap/keeper.go b/x/twap/keeper.go index c7924f0d17e..1fe357e352e 100644 --- a/x/twap/keeper.go +++ b/x/twap/keeper.go @@ -83,3 +83,13 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { Twaps: twapRecords, } } + +// GetGeometricStrategy gets geometric TWAP keeper. +func (k Keeper) GetGeometricStrategy() *geometric { + return &geometric{k} +} + +// GetArithmeticStrategy gets arithmetic TWAP keeper. +func (k Keeper) GetArithmeticStrategy() *arithmetic { + return &arithmetic{k} +} diff --git a/x/twap/keeper_test.go b/x/twap/keeper_test.go index d0c40c145f5..60244f5a32b 100644 --- a/x/twap/keeper_test.go +++ b/x/twap/keeper_test.go @@ -56,6 +56,7 @@ var ( P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), } basicCustomGenesis = types.NewGenesisState( @@ -77,6 +78,7 @@ var ( P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), }, { PoolId: basePoolId, @@ -88,6 +90,7 @@ var ( P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), }, mostRecentRecordPoolOne, }) @@ -102,6 +105,7 @@ var ( P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), } decreasingOrderByTimeRecordsPoolTwo = types.NewGenesisState( @@ -118,6 +122,7 @@ var ( P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), }, { PoolId: basePoolId, @@ -129,6 +134,7 @@ var ( P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), }, }) @@ -214,6 +220,7 @@ func (suite *TestSuite) TestTwapInitGenesis() { P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), }, }), @@ -399,7 +406,7 @@ func (s *TestSuite) createTestRecordsFromTimeInPool(t time.Time, poolId uint64) // newTwoAssetPoolTwapRecordWithDefaults creates a single twap records, mimicking what one would expect from a two asset pool. // given a spot price 0 (sp0), this spot price is assigned to denomA and sp0 is then created and assigned to denomB by // calculating (1 / spA). -func newTwoAssetPoolTwapRecordWithDefaults(t time.Time, sp0, accum0, accum1 sdk.Dec) types.TwapRecord { +func newTwoAssetPoolTwapRecordWithDefaults(t time.Time, sp0, accum0, accum1, geomAccum sdk.Dec) types.TwapRecord { return types.TwapRecord{ PoolId: 1, Time: t, @@ -410,13 +417,14 @@ func newTwoAssetPoolTwapRecordWithDefaults(t time.Time, sp0, accum0, accum1 sdk. P1LastSpotPrice: sdk.OneDec().Quo(sp0), P0ArithmeticTwapAccumulator: accum0, P1ArithmeticTwapAccumulator: accum1, + GeometricTwapAccumulator: geomAccum, } } // newThreeAssetPoolTwapRecordWithDefaults creates three twap records, mimicking what one would expect from a three asset pool. // given a spot price 0 (sp0), this spot price is assigned to denomA and referred to as spA. spB is then created and assigned by // calculating (1 / spA). Finally spC is created and assigned by calculating (2 * spA). -func newThreeAssetPoolTwapRecordWithDefaults(t time.Time, sp0, accumA, accumB, accumC sdk.Dec) (types.TwapRecord, types.TwapRecord, types.TwapRecord) { +func newThreeAssetPoolTwapRecordWithDefaults(t time.Time, sp0, accumA, accumB, accumC, geomAccumAB, geomAccumAC, geomAccumBC sdk.Dec) (types.TwapRecord, types.TwapRecord, types.TwapRecord) { spA := sp0 spB := sdk.OneDec().Quo(sp0) spC := sp0.Mul(sdk.NewDec(2)) @@ -430,15 +438,18 @@ func newThreeAssetPoolTwapRecordWithDefaults(t time.Time, sp0, accumA, accumB, a P1LastSpotPrice: spB, P0ArithmeticTwapAccumulator: accumA, P1ArithmeticTwapAccumulator: accumB, + GeometricTwapAccumulator: geomAccumAB, } twapAC := twapAB twapAC.Asset1Denom = denom2 twapAC.P1LastSpotPrice = spC twapAC.P1ArithmeticTwapAccumulator = accumC + twapAC.GeometricTwapAccumulator = geomAccumAC twapBC := twapAC twapBC.Asset0Denom = denom1 twapBC.P0LastSpotPrice = spB twapBC.P0ArithmeticTwapAccumulator = accumB + twapBC.GeometricTwapAccumulator = geomAccumBC return twapAB, twapAC, twapBC } @@ -454,10 +465,21 @@ func newEmptyPriceRecord(poolId uint64, t time.Time, asset0 string, asset1 strin P1LastSpotPrice: sdk.ZeroDec(), P0ArithmeticTwapAccumulator: sdk.ZeroDec(), P1ArithmeticTwapAccumulator: sdk.ZeroDec(), + GeometricTwapAccumulator: sdk.ZeroDec(), } } -func newRecord(poolId uint64, t time.Time, sp0, accum0, accum1 sdk.Dec) types.TwapRecord { +func withPrice0Set(twapRecord types.TwapRecord, price0ToSet sdk.Dec) types.TwapRecord { + twapRecord.P0LastSpotPrice = price0ToSet + return twapRecord +} + +func withPrice1Set(twapRecord types.TwapRecord, price1ToSet sdk.Dec) types.TwapRecord { + twapRecord.P1LastSpotPrice = price1ToSet + return twapRecord +} + +func newRecord(poolId uint64, t time.Time, sp0, accum0, accum1, geomAccum sdk.Dec) types.TwapRecord { return types.TwapRecord{ PoolId: poolId, Asset0Denom: defaultTwoAssetCoins[0].Denom, @@ -468,21 +490,23 @@ func newRecord(poolId uint64, t time.Time, sp0, accum0, accum1 sdk.Dec) types.Tw // make new copies P0ArithmeticTwapAccumulator: accum0.Add(sdk.ZeroDec()), P1ArithmeticTwapAccumulator: accum1.Add(sdk.ZeroDec()), + GeometricTwapAccumulator: geomAccum.Add(sdk.ZeroDec()), } } // make an expected record for math tests, we adjust other values in the test runner. -func newExpRecord(accum0, accum1 sdk.Dec) types.TwapRecord { +func newExpRecord(accum0, accum1, geomAccum sdk.Dec) types.TwapRecord { return types.TwapRecord{ Asset0Denom: defaultTwoAssetCoins[0].Denom, Asset1Denom: defaultTwoAssetCoins[1].Denom, // make new copies P0ArithmeticTwapAccumulator: accum0.Add(sdk.ZeroDec()), P1ArithmeticTwapAccumulator: accum1.Add(sdk.ZeroDec()), + GeometricTwapAccumulator: geomAccum.Add(sdk.ZeroDec()), } } -func newThreeAssetRecord(poolId uint64, t time.Time, sp0, accumA, accumB, accumC sdk.Dec) []types.TwapRecord { +func newThreeAssetRecord(poolId uint64, t time.Time, sp0, accumA, accumB, accumC, geomAccumAB, geomAccumAC, geomAccumBC sdk.Dec) []types.TwapRecord { spA := sp0 spB := sdk.OneDec().Quo(sp0) spC := sp0.Mul(sdk.NewDec(2)) @@ -496,20 +520,23 @@ func newThreeAssetRecord(poolId uint64, t time.Time, sp0, accumA, accumB, accumC // make new copies P0ArithmeticTwapAccumulator: accumA.Add(sdk.ZeroDec()), P1ArithmeticTwapAccumulator: accumB.Add(sdk.ZeroDec()), + GeometricTwapAccumulator: geomAccumAB.Add(sdk.ZeroDec()), } twapAC := twapAB twapAC.Asset1Denom = denom2 twapAC.P1LastSpotPrice = spC twapAC.P1ArithmeticTwapAccumulator = accumC + twapAC.GeometricTwapAccumulator = geomAccumAC.Add(sdk.ZeroDec()) twapBC := twapAC twapBC.Asset0Denom = denom1 twapBC.P0LastSpotPrice = spB twapBC.P0ArithmeticTwapAccumulator = accumB + twapBC.GeometricTwapAccumulator = geomAccumBC.Add(sdk.ZeroDec()) return []types.TwapRecord{twapAB, twapAC, twapBC} } // make an expected record for math tests, we adjust other values in the test runner. -func newThreeAssetExpRecord(poolId uint64, accumA, accumB, accumC sdk.Dec) []types.TwapRecord { +func newThreeAssetExpRecord(poolId uint64, accumA, accumB, accumC, geomAccumAB, geomAccumAC, geomAccumBC sdk.Dec) []types.TwapRecord { twapAB := types.TwapRecord{ PoolId: poolId, Asset0Denom: defaultThreeAssetCoins[0].Denom, @@ -517,13 +544,16 @@ func newThreeAssetExpRecord(poolId uint64, accumA, accumB, accumC sdk.Dec) []typ // make new copies P0ArithmeticTwapAccumulator: accumA.Add(sdk.ZeroDec()), P1ArithmeticTwapAccumulator: accumB.Add(sdk.ZeroDec()), + GeometricTwapAccumulator: geomAccumAB.Add(sdk.ZeroDec()), } twapAC := twapAB twapAC.Asset1Denom = denom2 twapAC.P1ArithmeticTwapAccumulator = accumC + twapAC.GeometricTwapAccumulator = geomAccumAC.Add(sdk.ZeroDec()) twapBC := twapAC twapBC.Asset0Denom = denom1 twapBC.P0ArithmeticTwapAccumulator = accumB + twapBC.GeometricTwapAccumulator = geomAccumBC.Add(sdk.ZeroDec()) return []types.TwapRecord{twapAB, twapAC, twapBC} } @@ -539,6 +569,13 @@ func newOneSidedRecord(time time.Time, accum sdk.Dec, useP0 bool) types.TwapReco return record } +func newOneSidedGeometricRecord(time time.Time, accum sdk.Dec) types.TwapRecord { + record := types.TwapRecord{Time: time, Asset0Denom: denom0, Asset1Denom: denom1} + record.GeometricTwapAccumulator = accum + record.P0LastSpotPrice = sdk.NewDec(10) + return record +} + func newThreeAssetOneSidedRecord(time time.Time, accum sdk.Dec, useP0 bool) []types.TwapRecord { record := types.TwapRecord{Time: time, Asset0Denom: denom0, Asset1Denom: denom1} if useP0 { @@ -546,6 +583,7 @@ func newThreeAssetOneSidedRecord(time time.Time, accum sdk.Dec, useP0 bool) []ty } else { record.P1ArithmeticTwapAccumulator = accum } + record.GeometricTwapAccumulator = accum record.P0LastSpotPrice = sdk.ZeroDec() record.P1LastSpotPrice = sdk.OneDec() records := []types.TwapRecord{record, record, record} @@ -555,9 +593,10 @@ func newThreeAssetOneSidedRecord(time time.Time, accum sdk.Dec, useP0 bool) []ty return records } -func recordWithUpdatedAccum(record types.TwapRecord, accum0 sdk.Dec, accum1 sdk.Dec) types.TwapRecord { +func recordWithUpdatedAccum(record types.TwapRecord, accum0 sdk.Dec, accum1, geomAccum sdk.Dec) types.TwapRecord { record.P0ArithmeticTwapAccumulator = accum0 record.P1ArithmeticTwapAccumulator = accum1 + record.GeometricTwapAccumulator = geomAccum return record } diff --git a/x/twap/logic.go b/x/twap/logic.go index 2f4a471111d..e807d0cff29 100644 --- a/x/twap/logic.go +++ b/x/twap/logic.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/v13/x/twap/types" ) @@ -27,6 +28,7 @@ func newTwapRecord(k types.AmmInterface, ctx sdk.Context, poolId uint64, denom0, P1LastSpotPrice: sp1, P0ArithmeticTwapAccumulator: sdk.ZeroDec(), P1ArithmeticTwapAccumulator: sdk.ZeroDec(), + GeometricTwapAccumulator: sdk.ZeroDec(), LastErrorTime: lastErrorTime, }, nil } @@ -44,7 +46,9 @@ func getSpotPrices( previousErrorTime time.Time, ) (sp0 sdk.Dec, sp1 sdk.Dec, latestErrTime time.Time) { latestErrTime = previousErrorTime + // sp0 = denom0 quote, denom1 base. sp0, err0 := k.CalculateSpotPrice(ctx, poolId, denom0, denom1) + // sp1 = denom0 base, denom1 quote. sp1, err1 := k.CalculateSpotPrice(ctx, poolId, denom1, denom0) if err0 != nil || err1 != nil { latestErrTime = ctx.BlockTime() @@ -190,6 +194,20 @@ func recordWithUpdatedAccumulators(record types.TwapRecord, newTime time.Time) t p1NewAccum := types.SpotPriceMulDuration(record.P1LastSpotPrice, timeDelta) newRecord.P1ArithmeticTwapAccumulator = newRecord.P1ArithmeticTwapAccumulator.Add(p1NewAccum) + // If the last spot price is zero, then the logarithm is undefined. + // As a result, we cannot update the geometric accumulator. + // We set the last error time to be the new time, and return the record. + if record.P0LastSpotPrice.IsZero() { + newRecord.LastErrorTime = newTime + return newRecord + } + + // logP0SpotPrice = log_{2}{P_0} + logP0SpotPrice := twapLog(record.P0LastSpotPrice) + // p0NewGeomAccum = log_{2}{P_0} * timeDelta + p0NewGeomAccum := types.SpotPriceMulDuration(logP0SpotPrice, timeDelta) + newRecord.GeometricTwapAccumulator = newRecord.GeometricTwapAccumulator.Add(p0NewGeomAccum) + return newRecord } @@ -219,15 +237,16 @@ func (k Keeper) getMostRecentRecord(ctx sdk.Context, poolId uint64, assetA, asse return record, nil } -// computeArithmeticTwap computes and returns an arithmetic TWAP between -// two records given the quote asset. +// computeTwap computes and returns a TWAP of a given +// type - arithmetic or geometric. +// Between two records given the quote asset. // precondition: endRecord.Time >= startRecord.Time // if (endRecord.LastErrorTime >= startRecord.Time) returns an error at end + result // if (startRecord.LastErrorTime == startRecord.Time) returns an error at end + result // if (endRecord.Time == startRecord.Time) returns endRecord.LastSpotPrice // else returns // (endRecord.Accumulator - startRecord.Accumulator) / (endRecord.Time - startRecord.Time) -func computeArithmeticTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string) (sdk.Dec, error) { +func computeTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string, strategy twapStrategy) (sdk.Dec, error) { // see if we need to return an error, due to spot price issues var err error = nil if endRecord.LastErrorTime.After(startRecord.Time) || @@ -243,11 +262,25 @@ func computeArithmeticTwap(startRecord types.TwapRecord, endRecord types.TwapRec } return endRecord.P1LastSpotPrice, err } - var accumDiff sdk.Dec - if quoteAsset == startRecord.Asset0Denom { - accumDiff = endRecord.P0ArithmeticTwapAccumulator.Sub(startRecord.P0ArithmeticTwapAccumulator) - } else { - accumDiff = endRecord.P1ArithmeticTwapAccumulator.Sub(startRecord.P1ArithmeticTwapAccumulator) + + return strategy.computeTwap(startRecord, endRecord, quoteAsset), err +} + +// twapLog returns the logarithm of the given spot price, base 2. +// Panics if zero is given. +func twapLog(price sdk.Dec) sdk.Dec { + if price.IsZero() { + panic("twap: cannot take logarithm of zero") + } + + return osmomath.BigDecFromSDKDec(price).LogBase2().SDKDec() +} + +// twapPow exponentiates 2 to the given exponent. +func twapPow(exponent sdk.Dec) sdk.Dec { + exp2 := osmomath.Exp2(osmomath.BigDecFromSDKDec(exponent.Abs())) + if exponent.IsNegative() { + return osmomath.OneDec().Quo(exp2).SDKDec() } - return types.AccumDiffDivDuration(accumDiff, timeDelta), err + return exp2.SDKDec() } diff --git a/x/twap/logic_test.go b/x/twap/logic_test.go index 7ea6f6a98c9..9d3b92df26f 100644 --- a/x/twap/logic_test.go +++ b/x/twap/logic_test.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + "github.com/osmosis-labs/osmosis/osmomath" "github.com/osmosis-labs/osmosis/osmoutils" "github.com/osmosis-labs/osmosis/osmoutils/osmoassert" gammtypes "github.com/osmosis-labs/osmosis/v13/x/gamm/types" @@ -18,10 +19,15 @@ import ( ) var ( - zeroDec = sdk.ZeroDec() - oneDec = sdk.OneDec() - twoDec = oneDec.Add(oneDec) - OneSec = sdk.MustNewDecFromStr("1000.000000000000000000") + zeroDec = sdk.ZeroDec() + oneDec = sdk.OneDec() + twoDec = oneDec.Add(oneDec) + pointFiveDec = sdk.OneDec().Quo(twoDec) + OneSec = sdk.MustNewDecFromStr("1000.000000000000000000") + logTen = twap.TwapLog(sdk.NewDec(10)) + logOneOverTen = twap.TwapLog(sdk.OneDec().QuoInt64(10)) + tenSecAccum = OneSec.MulInt64(10) + geometricTenSecAccum = OneSec.Mul(logTen) ) func (s *TestSuite) TestGetSpotPrices() { @@ -143,6 +149,7 @@ func (s *TestSuite) TestNewTwapRecord() { s.Require().Equal(s.Ctx.BlockTime(), twapRecord.Time) s.Require().Equal(sdk.ZeroDec(), twapRecord.P0ArithmeticTwapAccumulator) s.Require().Equal(sdk.ZeroDec(), twapRecord.P1ArithmeticTwapAccumulator) + s.Require().Equal(sdk.ZeroDec(), twapRecord.GeometricTwapAccumulator) } }) } @@ -160,8 +167,8 @@ func (s *TestSuite) TestUpdateRecord() { updateTime := time.Unix(3, 0).UTC() baseTimeMinusOne := time.Unix(1, 0).UTC() - zeroAccumNoErrSp10Record := newRecord(poolId, baseTime, sdk.NewDec(10), zeroDec, zeroDec) - sp10OneTimeUnitAccumRecord := newExpRecord(OneSec.MulInt64(10), OneSec.QuoInt64(10)) + zeroAccumNoErrSp10Record := newRecord(poolId, baseTime, sdk.NewDec(10), zeroDec, zeroDec, zeroDec) + sp10OneTimeUnitAccumRecord := newExpRecord(OneSec.MulInt64(10), OneSec.QuoInt64(10), geometricTenSecAccum) // all tests occur with updateTime = base time + time.Unix(1, 0) tests := map[string]struct { record types.TwapRecord @@ -236,31 +243,52 @@ func (s *TestSuite) TestUpdateRecord() { func TestRecordWithUpdatedAccumulators(t *testing.T) { poolId := uint64(1) - defaultRecord := newRecord(poolId, time.Unix(1, 0), sdk.NewDec(10), oneDec, twoDec) + defaultRecord := newRecord(poolId, time.Unix(1, 0), sdk.NewDec(10), oneDec, twoDec, pointFiveDec) tests := map[string]struct { - record types.TwapRecord - newTime time.Time - expRecord types.TwapRecord + record types.TwapRecord + newTime time.Time + expRecord types.TwapRecord + expectPanic bool }{ "accum with zero value": { - record: newRecord(poolId, time.Unix(1, 0), sdk.NewDec(10), zeroDec, zeroDec), + record: newRecord(poolId, time.Unix(1, 0), sdk.NewDec(10), zeroDec, zeroDec, zeroDec), newTime: time.Unix(2, 0), - expRecord: newExpRecord(OneSec.MulInt64(10), OneSec.QuoInt64(10)), + expRecord: newExpRecord(OneSec.MulInt64(10), OneSec.QuoInt64(10), geometricTenSecAccum), }, "small starting accumulators": { record: defaultRecord, newTime: time.Unix(2, 0), - expRecord: newExpRecord(oneDec.Add(OneSec.MulInt64(10)), twoDec.Add(OneSec.QuoInt64(10))), + expRecord: newExpRecord(oneDec.Add(OneSec.MulInt64(10)), twoDec.Add(OneSec.QuoInt64(10)), pointFiveDec.Add(geometricTenSecAccum)), }, "larger time interval": { - record: newRecord(poolId, time.Unix(11, 0), sdk.NewDec(10), oneDec, twoDec), + record: newRecord(poolId, time.Unix(11, 0), sdk.NewDec(10), oneDec, twoDec, pointFiveDec), newTime: time.Unix(55, 0), - expRecord: newExpRecord(oneDec.Add(OneSec.MulInt64(44*10)), twoDec.Add(OneSec.MulInt64(44).QuoInt64(10))), + expRecord: newExpRecord(oneDec.Add(OneSec.MulInt64(44*10)), twoDec.Add(OneSec.MulInt64(44).QuoInt64(10)), pointFiveDec.Add(OneSec.MulInt64(44).Mul(logTen))), }, "same time, accumulator should not change": { record: defaultRecord, newTime: time.Unix(1, 0), - expRecord: newExpRecord(oneDec, twoDec), + expRecord: newExpRecord(oneDec, twoDec, pointFiveDec), + }, + "sp0 - zero spot price - accum0 unchanged, accum1 updated, geom accum unchanged, last err time set": { + record: withPrice0Set(defaultRecord, sdk.ZeroDec()), + newTime: defaultRecord.Time.Add(time.Second), + expRecord: withLastErrTime(newExpRecord(oneDec, twoDec.Add(sdk.NewDecWithPrec(1, 1).Mul(OneSec)), pointFiveDec), defaultRecord.Time.Add(time.Second)), + }, + "sp1 - zero spot price - accum0 updated, accum1 unchanged, geom accum updated correctly": { + record: withPrice1Set(defaultRecord, sdk.ZeroDec()), + newTime: defaultRecord.Time.Add(time.Second), + expRecord: newExpRecord(tenSecAccum.Add(oneDec), twoDec, pointFiveDec.Add(geometricTenSecAccum)), + }, + "both sp - zero spot price - accum0 unchange, accum1 unchanged, geom accum unchanged": { + record: withPrice1Set(withPrice0Set(defaultRecord, sdk.ZeroDec()), sdk.ZeroDec()), + newTime: defaultRecord.Time.Add(time.Second), + expRecord: withLastErrTime(newExpRecord(oneDec, twoDec, pointFiveDec), defaultRecord.Time.Add(time.Second)), + }, + "spot price of one - geom accumulator 0": { + record: withPrice1Set(withPrice0Set(defaultRecord, sdk.OneDec()), sdk.OneDec()), + newTime: defaultRecord.Time.Add(time.Second), + expRecord: newExpRecord(oneDec.Add(OneSec), twoDec.Add(OneSec), pointFiveDec), }, } @@ -272,8 +300,10 @@ func TestRecordWithUpdatedAccumulators(t *testing.T) { test.expRecord.P0LastSpotPrice = test.record.P0LastSpotPrice test.expRecord.P1LastSpotPrice = test.record.P1LastSpotPrice - gotRecord := twap.RecordWithUpdatedAccumulators(test.record, test.newTime) - require.Equal(t, test.expRecord, gotRecord) + osmoassert.ConditionalPanic(t, test.expectPanic, func() { + gotRecord := twap.RecordWithUpdatedAccumulators(test.record, test.newTime) + require.Equal(t, test.expRecord, gotRecord) + }) }) } } @@ -286,19 +316,19 @@ func TestRecordWithUpdatedAccumulators_ThreeAsset(t *testing.T) { expRecord []types.TwapRecord }{ "accum with zero value": { - record: newThreeAssetRecord(poolId, time.Unix(1, 0), sdk.NewDec(10), zeroDec, zeroDec, zeroDec), + record: newThreeAssetRecord(poolId, time.Unix(1, 0), sdk.NewDec(10), zeroDec, zeroDec, zeroDec, zeroDec, zeroDec, zeroDec), interpolateTime: time.Unix(2, 0), - expRecord: newThreeAssetExpRecord(poolId, OneSec.MulInt64(10), OneSec.QuoInt64(10), OneSec.MulInt64(20)), + expRecord: newThreeAssetExpRecord(poolId, OneSec.MulInt64(10), OneSec.QuoInt64(10), OneSec.MulInt64(20), geometricTenSecAccum, geometricTenSecAccum, OneSec.Mul(logOneOverTen)), }, "small starting accumulators": { - record: newThreeAssetRecord(poolId, time.Unix(1, 0), sdk.NewDec(10), twoDec, oneDec, twoDec), + record: newThreeAssetRecord(poolId, time.Unix(1, 0), sdk.NewDec(10), twoDec, oneDec, twoDec, oneDec, twoDec, oneDec), interpolateTime: time.Unix(2, 0), - expRecord: newThreeAssetExpRecord(poolId, twoDec.Add(OneSec.MulInt64(10)), oneDec.Add(OneSec.QuoInt64(10)), twoDec.Add(OneSec.MulInt64(20))), + expRecord: newThreeAssetExpRecord(poolId, twoDec.Add(OneSec.MulInt64(10)), oneDec.Add(OneSec.QuoInt64(10)), twoDec.Add(OneSec.MulInt64(20)), oneDec.Add(geometricTenSecAccum), twoDec.Add(geometricTenSecAccum), oneDec.Add(OneSec.Mul(logOneOverTen))), }, "larger time interval": { - record: newThreeAssetRecord(poolId, time.Unix(11, 0), sdk.NewDec(10), twoDec, oneDec, twoDec), + record: newThreeAssetRecord(poolId, time.Unix(11, 0), sdk.NewDec(10), twoDec, oneDec, twoDec, oneDec, twoDec, oneDec), interpolateTime: time.Unix(55, 0), - expRecord: newThreeAssetExpRecord(poolId, twoDec.Add(OneSec.MulInt64(44*10)), oneDec.Add(OneSec.MulInt64(44).QuoInt64(10)), twoDec.Add(OneSec.MulInt64(44*20))), + expRecord: newThreeAssetExpRecord(poolId, twoDec.Add(OneSec.MulInt64(44*10)), oneDec.Add(OneSec.MulInt64(44).QuoInt64(10)), twoDec.Add(OneSec.MulInt64(44*20)), oneDec.Add(OneSec.MulInt64(44).Mul(logTen)), twoDec.Add(OneSec.MulInt64(44).Mul(logTen)), oneDec.Add(OneSec.MulInt64(44).Mul(logOneOverTen))), }, } @@ -318,7 +348,7 @@ func TestRecordWithUpdatedAccumulators_ThreeAsset(t *testing.T) { } func (s *TestSuite) TestGetInterpolatedRecord() { - baseRecord := newTwoAssetPoolTwapRecordWithDefaults(baseTime, sdk.OneDec(), sdk.OneDec(), sdk.OneDec()) + baseRecord := newTwoAssetPoolTwapRecordWithDefaults(baseTime, sdk.OneDec(), sdk.OneDec(), sdk.OneDec(), sdk.OneDec().Quo(twoDec)) // all tests occur with updateTime = base time + time.Unix(1, 0) tests := map[string]struct { @@ -416,7 +446,7 @@ func (s *TestSuite) TestGetInterpolatedRecord() { } func (s *TestSuite) TestGetInterpolatedRecord_ThreeAsset() { - baseRecord := newThreeAssetRecord(2, baseTime, sdk.NewDec(10), sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) + baseRecord := newThreeAssetRecord(2, baseTime, sdk.NewDec(10), sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) // all tests occur with updateTime = base time + time.Unix(1, 0) tests := map[string]struct { recordsToPreSet []types.TwapRecord @@ -518,14 +548,6 @@ func (s *TestSuite) TestGetInterpolatedRecord_ThreeAsset() { } } -type computeArithmeticTwapTestCase struct { - startRecord types.TwapRecord - endRecord types.TwapRecord - quoteAsset string - expTwap sdk.Dec - expErr bool -} - type computeThreeAssetArithmeticTwapTestCase struct { startRecord []types.TwapRecord endRecord []types.TwapRecord @@ -534,188 +556,6 @@ type computeThreeAssetArithmeticTwapTestCase struct { expErr bool } -// TestComputeArithmeticTwap tests ComputeArithmeticTwap on various inputs. -// The test vectors are structured by setting up different start and records, -// based on time interval, and their accumulator values. -// Then an expected TWAP is provided in each test case, to compare against computed. -func TestComputeArithmeticTwap(t *testing.T) { - testCaseFromDeltas := func(startAccum, accumDiff sdk.Dec, timeDelta time.Duration, expectedTwap sdk.Dec) computeArithmeticTwapTestCase { - return computeArithmeticTwapTestCase{ - newOneSidedRecord(baseTime, startAccum, true), - newOneSidedRecord(baseTime.Add(timeDelta), startAccum.Add(accumDiff), true), - denom0, - expectedTwap, - false, - } - } - testCaseFromDeltasAsset1 := func(startAccum, accumDiff sdk.Dec, timeDelta time.Duration, expectedTwap sdk.Dec) computeArithmeticTwapTestCase { - return computeArithmeticTwapTestCase{ - newOneSidedRecord(baseTime, startAccum, false), - newOneSidedRecord(baseTime.Add(timeDelta), startAccum.Add(accumDiff), false), - denom1, - expectedTwap, - false, - } - } - tenSecAccum := OneSec.MulInt64(10) - pointOneAccum := OneSec.QuoInt64(10) - tests := map[string]computeArithmeticTwapTestCase{ - "basic: spot price = 1 for one second, 0 init accumulator": { - startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newOneSidedRecord(tPlusOne, OneSec, true), - quoteAsset: denom0, - expTwap: sdk.OneDec(), - }, - // this test just shows what happens in case the records are reversed. - // It should return the correct result, even though this is incorrect internal API usage - "invalid call: reversed records of above": { - startRecord: newOneSidedRecord(tPlusOne, OneSec, true), - endRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - quoteAsset: denom0, - expTwap: sdk.OneDec(), - }, - "same record: denom0, end spot price = 0": { - startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - quoteAsset: denom0, - expTwap: sdk.ZeroDec(), - }, - "same record: denom1, end spot price = 1": { - startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - quoteAsset: denom1, - expTwap: sdk.OneDec(), - }, - "accumulator = 10*OneSec, t=5s. 0 base accum": testCaseFromDeltas( - sdk.ZeroDec(), tenSecAccum, 5*time.Second, sdk.NewDec(2)), - "accumulator = 10*OneSec, t=3s. 0 base accum": testCaseFromDeltas( - sdk.ZeroDec(), tenSecAccum, 3*time.Second, ThreePlusOneThird), - "accumulator = 10*OneSec, t=100s. 0 base accum": testCaseFromDeltas( - sdk.ZeroDec(), tenSecAccum, 100*time.Second, sdk.NewDecWithPrec(1, 1)), - - // test that base accum has no impact - "accumulator = 10*OneSec, t=5s. 10 base accum": testCaseFromDeltas( - sdk.NewDec(10), tenSecAccum, 5*time.Second, sdk.NewDec(2)), - "accumulator = 10*OneSec, t=3s. 10*second base accum": testCaseFromDeltas( - tenSecAccum, tenSecAccum, 3*time.Second, ThreePlusOneThird), - "accumulator = 10*OneSec, t=100s. .1*second base accum": testCaseFromDeltas( - pointOneAccum, tenSecAccum, 100*time.Second, sdk.NewDecWithPrec(1, 1)), - - "accumulator = 10*OneSec, t=100s. 0 base accum (asset 1)": testCaseFromDeltasAsset1(sdk.ZeroDec(), OneSec.MulInt64(10), 100*time.Second, sdk.NewDecWithPrec(1, 1)), - } - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actualTwap, err := twap.ComputeArithmeticTwap(test.startRecord, test.endRecord, test.quoteAsset) - require.Equal(t, test.expTwap, actualTwap) - require.NoError(t, err) - }) - } -} - -func TestComputeArithmeticTwap_ThreeAsset(t *testing.T) { - testThreeAssetCaseFromDeltas := func(startAccum, accumDiff sdk.Dec, timeDelta time.Duration, expectedTwap sdk.Dec) computeThreeAssetArithmeticTwapTestCase { - return computeThreeAssetArithmeticTwapTestCase{ - newThreeAssetOneSidedRecord(baseTime, startAccum, true), - newThreeAssetOneSidedRecord(baseTime.Add(timeDelta), startAccum.Add(accumDiff), true), - []string{denom0, denom0, denom1}, - []sdk.Dec{expectedTwap, expectedTwap, expectedTwap}, - false, - } - } - - tenSecAccum := OneSec.MulInt64(10) - pointOneAccum := OneSec.QuoInt64(10) - tests := map[string]computeThreeAssetArithmeticTwapTestCase{ - "three asset basic: spot price = 1 for one second, 0 init accumulator": { - startRecord: newThreeAssetOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newThreeAssetOneSidedRecord(tPlusOne, OneSec, true), - quoteAsset: []string{denom0, denom0, denom1}, - expTwap: []sdk.Dec{sdk.OneDec(), sdk.OneDec(), sdk.OneDec()}, - }, - "three asset same record: asset1, end spot price = 1": { - startRecord: newThreeAssetOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newThreeAssetOneSidedRecord(baseTime, sdk.ZeroDec(), true), - quoteAsset: []string{denom1, denom2, denom2}, - expTwap: []sdk.Dec{sdk.OneDec(), sdk.OneDec(), sdk.OneDec()}, - }, - "three asset. accumulator = 10*OneSec, t=5s. 0 base accum": testThreeAssetCaseFromDeltas( - sdk.ZeroDec(), tenSecAccum, 5*time.Second, sdk.NewDec(2)), - - // test that base accum has no impact - "three asset. accumulator = 10*OneSec, t=5s. 10 base accum": testThreeAssetCaseFromDeltas( - sdk.NewDec(10), tenSecAccum, 5*time.Second, sdk.NewDec(2)), - "three asset. accumulator = 10*OneSec, t=100s. .1*second base accum": testThreeAssetCaseFromDeltas( - pointOneAccum, tenSecAccum, 100*time.Second, sdk.NewDecWithPrec(1, 1)), - } - for name, test := range tests { - t.Run(name, func(t *testing.T) { - for i, startRec := range test.startRecord { - actualTwap, err := twap.ComputeArithmeticTwap(startRec, test.endRecord[i], test.quoteAsset[i]) - require.Equal(t, test.expTwap[i], actualTwap) - require.NoError(t, err) - } - }) - } -} - -// This tests the behavior of computeArithmeticTwap, around error returning -// when there has been an intermediate spot price error. -func TestComputeArithmeticTwapWithSpotPriceError(t *testing.T) { - newOneSidedRecordWErrorTime := func(time time.Time, accum sdk.Dec, useP0 bool, errTime time.Time) types.TwapRecord { - record := newOneSidedRecord(time, accum, useP0) - record.LastErrorTime = errTime - return record - } - tests := map[string]computeArithmeticTwapTestCase{ - // should error, since end time may have been used to interpolate this value - "errAtEndTime from end record": { - startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newOneSidedRecordWErrorTime(tPlusOne, OneSec, true, tPlusOne), - quoteAsset: denom0, - expTwap: sdk.OneDec(), - expErr: true, - }, - // should error, since start time may have been used to interpolate this value - "err at StartTime exactly from end record": { - startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newOneSidedRecordWErrorTime(tPlusOne, OneSec, true, baseTime), - quoteAsset: denom0, - expTwap: sdk.OneDec(), - expErr: true, - }, - // should error, since start record is erroneous - "err at StartTime exactly from start record": { - startRecord: newOneSidedRecordWErrorTime(baseTime, sdk.ZeroDec(), true, baseTime), - endRecord: newOneSidedRecord(tPlusOne, OneSec, true), - quoteAsset: denom0, - expTwap: sdk.OneDec(), - expErr: true, - }, - "err before StartTime": { - startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newOneSidedRecordWErrorTime(tPlusOne, OneSec, true, tMinOne), - quoteAsset: denom0, - expTwap: sdk.OneDec(), - expErr: false, - }, - // Should not happen, but if it did would error - "err after EndTime": { - startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), - endRecord: newOneSidedRecordWErrorTime(tPlusOne, OneSec.MulInt64(2), true, baseTime.Add(20*time.Second)), - quoteAsset: denom0, - expTwap: sdk.OneDec().MulInt64(2), - expErr: true, - }, - } - for name, test := range tests { - t.Run(name, func(t *testing.T) { - actualTwap, err := twap.ComputeArithmeticTwap(test.startRecord, test.endRecord, test.quoteAsset) - require.Equal(t, test.expTwap, actualTwap) - osmoassert.ConditionalError(t, test.expErr, err) - }) - } -} - // TestPruneRecords tests that twap records earlier than // current block time - RecordHistoryKeepPeriod are pruned from the store // while keeping the newest record before the above time threshold. @@ -1424,3 +1264,205 @@ func (s *TestSuite) TestAfterCreatePool() { }) } } + +// This tests the behavior of computeArithmeticTwap, around error returning +// when there has been an intermediate spot price error. +func (s *TestSuite) TestComputeArithmeticTwapWithSpotPriceError() { + newOneSidedRecordWErrorTime := func(time time.Time, accum sdk.Dec, useP0 bool, errTime time.Time) types.TwapRecord { + record := newOneSidedRecord(time, accum, useP0) + record.LastErrorTime = errTime + return record + } + + arithStrategy := &twap.ArithmeticTwapStrategy{ + TwapKeeper: *s.App.TwapKeeper, + } + + tests := map[string]computeTwapTestCase{ + // should error, since end time may have been used to interpolate this value + "errAtEndTime from end record": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecordWErrorTime(tPlusOne, OneSec, true, tPlusOne), + quoteAsset: denom0, + expTwap: sdk.OneDec(), + expErr: true, + }, + // should error, since start time may have been used to interpolate this value + "err at StartTime exactly from end record": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecordWErrorTime(tPlusOne, OneSec, true, baseTime), + quoteAsset: denom0, + expTwap: sdk.OneDec(), + expErr: true, + }, + // should error, since start record is erroneous + "err at StartTime exactly from start record": { + startRecord: newOneSidedRecordWErrorTime(baseTime, sdk.ZeroDec(), true, baseTime), + endRecord: newOneSidedRecord(tPlusOne, OneSec, true), + quoteAsset: denom0, + expTwap: sdk.OneDec(), + expErr: true, + }, + "err before StartTime": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecordWErrorTime(tPlusOne, OneSec, true, tMinOne), + quoteAsset: denom0, + expTwap: sdk.OneDec(), + expErr: false, + }, + // Should not happen, but if it did would error + "err after EndTime": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecordWErrorTime(tPlusOne, OneSec.MulInt64(2), true, baseTime.Add(20*time.Second)), + quoteAsset: denom0, + expTwap: sdk.OneDec().MulInt64(2), + expErr: true, + }, + } + for name, test := range tests { + s.Run(name, func() { + actualTwap, err := twap.ComputeTwap(test.startRecord, test.endRecord, test.quoteAsset, arithStrategy) + s.Require().Equal(test.expTwap, actualTwap) + osmoassert.ConditionalError(s.T(), test.expErr, err) + }) + } +} + +// TestTwapLog_CorrectBase tests that the base of 2 is used for the twap log function. +// log_2{16} = 4 +func (s *TestSuite) TestTwapLog_CorrectBase() { + logOf := sdk.NewDec(16) + expectedValue := sdk.NewDec(4) + + result := twap.TwapLog(logOf) + + s.Require().Equal(expectedValue, result) +} + +func (s *TestSuite) TestTwapLog() { + smallestAdditiveTolerance := osmomath.ErrTolerance{ + AdditiveTolerance: sdk.SmallestDec(), + } + + testcases := []struct { + name string + price sdk.Dec + expected sdk.Dec + expectPanic bool + }{ + { + "max spot price", + gammtypes.MaxSpotPrice, + // log_2{2^128 - 1} = 128 + sdk.MustNewDecFromStr("127.999999999999999999"), + false, + }, + { + "zero price - panic", + sdk.ZeroDec(), + sdk.Dec{}, + true, + }, + { + "smallest dec", + sdk.SmallestDec(), + // https://www.wolframalpha.com/input?i=log+base+2+of+%2810%5E-18%29+with+20+digits + sdk.MustNewDecFromStr("59.794705707972522262").Neg(), + false, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + osmoassert.ConditionalPanic(s.T(), tc.expectPanic, func() { + result := twap.TwapLog(tc.price) + + smallestAdditiveTolerance.CompareBigDec( + osmomath.BigDecFromSDKDec(tc.expected), + osmomath.BigDecFromSDKDec(result), + ) + }) + }) + } +} + +// TestTwapPow_CorrectBase tests that the base of 2 is used for the twap power function. +// 2^3 = 8 +func (s *TestSuite) TestTwapPow_CorrectBase() { + exponentValue := osmomath.NewBigDec(3) + expectedValue := sdk.NewDec(8) + + result := twap.TwapPow(exponentValue.SDKDec()) + + s.Require().Equal(expectedValue, result) +} + +// TestTwapPow_NegativeExponent tests that twap pow can handle a negative exponent +// 2^-1 = 0.5 +func (s *TestSuite) TestTwapPow_NegativeExponent() { + expectedResult := sdk.MustNewDecFromStr("0.5") + result := twap.TwapPow(oneDec.Neg()) + s.Require().Equal(expectedResult, result) +} + +func testCaseFromDeltas(s *TestSuite, startAccum, accumDiff sdk.Dec, timeDelta time.Duration, expectedTwap sdk.Dec) computeTwapTestCase { + return computeTwapTestCase{ + newOneSidedRecord(baseTime, startAccum, true), + newOneSidedRecord(baseTime.Add(timeDelta), startAccum.Add(accumDiff), true), + []twap.TwapStrategy{ + &twap.ArithmeticTwapStrategy{ + TwapKeeper: *s.App.TwapKeeper, + }, + }, + denom0, + expectedTwap, + false, + false, + } +} + +func testCaseFromDeltasAsset1(s *TestSuite, startAccum, accumDiff sdk.Dec, timeDelta time.Duration, expectedTwap sdk.Dec) computeTwapTestCase { + return computeTwapTestCase{ + newOneSidedRecord(baseTime, startAccum, false), + newOneSidedRecord(baseTime.Add(timeDelta), startAccum.Add(accumDiff), false), + []twap.TwapStrategy{ + &twap.ArithmeticTwapStrategy{ + TwapKeeper: *s.App.TwapKeeper, + }, + }, + denom1, + expectedTwap, + false, + false, + } +} + +func geometricTestCaseFromDeltas0(s *TestSuite, startAccum, accumDiff sdk.Dec, timeDelta time.Duration, expectedTwap sdk.Dec) computeTwapTestCase { + return computeTwapTestCase{ + newOneSidedGeometricRecord(baseTime, startAccum), + newOneSidedGeometricRecord(baseTime.Add(timeDelta), startAccum.Add(accumDiff)), + []twap.TwapStrategy{ + &twap.GeometricTwapStrategy{ + TwapKeeper: *s.App.TwapKeeper, + }, + }, + denom0, + expectedTwap, + false, + false, + } +} + +func geometricTestCaseFromDeltas1(s *TestSuite, startAccum, accumDiff sdk.Dec, timeDelta time.Duration, expectedTwap sdk.Dec) computeTwapTestCase { + return geometricTestCaseFromDeltas0(s, startAccum, accumDiff, timeDelta, sdk.OneDec().Quo(expectedTwap)) +} + +func testThreeAssetCaseFromDeltas(startAccum, accumDiff sdk.Dec, timeDelta time.Duration, expectedTwap sdk.Dec) computeThreeAssetArithmeticTwapTestCase { + return computeThreeAssetArithmeticTwapTestCase{ + newThreeAssetOneSidedRecord(baseTime, startAccum, true), + newThreeAssetOneSidedRecord(baseTime.Add(timeDelta), startAccum.Add(accumDiff), true), + []string{denom0, denom0, denom1}, + []sdk.Dec{expectedTwap, expectedTwap, expectedTwap}, + false, + } +} diff --git a/x/twap/migrate_test.go b/x/twap/migrate_test.go index 37c7905f1e3..1410a2d0884 100644 --- a/x/twap/migrate_test.go +++ b/x/twap/migrate_test.go @@ -3,6 +3,9 @@ package twap_test import ( "time" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/gogo/protobuf/proto" + "github.com/osmosis-labs/osmosis/v13/x/twap/types" ) @@ -64,3 +67,29 @@ func (s *TestSuite) TestMigrateExistingPoolsError() { err := s.twapkeeper.MigrateExistingPools(s.Ctx, latestPoolIdPlusOne) s.Require().Error(err) } + +// TestTwapRecord_GeometricTwap_MarshalUnmarshal this test proves that migrations +// to initialize geometric twap accumulators are not required. +// This is because proto marshalling will initialize the field to the zero value. +// Zero value is the expected initialization value for the geometric twap accumulator. +func (suite *TestSuite) TestTwapRecord_GeometricTwap_MarshalUnmarshal() { + originalRecord := types.TwapRecord{ + Asset0Denom: "uatom", + Asset1Denom: "uusd", + } + + suite.Require().True(originalRecord.GeometricTwapAccumulator.IsNil()) + + bz, err := proto.Marshal(&originalRecord) + suite.Require().NoError(err) + + var deserialized types.TwapRecord + err = proto.Unmarshal(bz, &deserialized) + suite.Require().NoError(err) + + suite.Require().Equal(originalRecord, deserialized) + suite.Require().Equal(originalRecord.String(), deserialized.String()) + + suite.Require().False(originalRecord.GeometricTwapAccumulator.IsNil()) + suite.Require().Equal(sdk.ZeroDec(), originalRecord.GeometricTwapAccumulator) +} diff --git a/x/twap/store_test.go b/x/twap/store_test.go index 61dd87b2e3c..6d8b2bea0e4 100644 --- a/x/twap/store_test.go +++ b/x/twap/store_test.go @@ -162,11 +162,11 @@ func (s *TestSuite) TestGetRecordAtOrBeforeTime() { defaultInputAt := func(t time.Time) getRecordInput { return getRecordInput{1, t, denom0, denom1} } wrongPoolIdInputAt := func(t time.Time) getRecordInput { return getRecordInput{2, t, denom0, denom1} } defaultRevInputAt := func(t time.Time) getRecordInput { return getRecordInput{1, t, denom1, denom0} } - baseRecord := newEmptyPriceRecord(1, baseTime, denom0, denom1) + baseRecord := withPrice0Set(newEmptyPriceRecord(1, baseTime, denom0, denom1), sdk.OneDec()) tMin1 := baseTime.Add(-time.Second) - tMin1Record := newEmptyPriceRecord(1, tMin1, denom0, denom1) + tMin1Record := withPrice0Set(newEmptyPriceRecord(1, tMin1, denom0, denom1), sdk.OneDec()) tPlus1 := baseTime.Add(time.Second) - tPlus1Record := newEmptyPriceRecord(1, tPlus1, denom0, denom1) + tPlus1Record := withPrice0Set(newEmptyPriceRecord(1, tPlus1, denom0, denom1), sdk.OneDec()) tests := map[string]struct { recordsToSet []types.TwapRecord diff --git a/x/twap/strategy.go b/x/twap/strategy.go new file mode 100644 index 00000000000..7863ff93a4b --- /dev/null +++ b/x/twap/strategy.go @@ -0,0 +1,59 @@ +package twap + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/osmomath" + "github.com/osmosis-labs/osmosis/v13/x/twap/types" + + gammtypes "github.com/osmosis-labs/osmosis/v13/x/gamm/types" +) + +// twapStrategy is an interface for computing TWAPs. +// We have two strategies implementing the interface - arithmetic and geometric. +// We expose a common TWAP API to reduce duplication and avoid complexity. +type twapStrategy interface { + // computeTwap calculates the TWAP with specific startRecord and endRecord. + computeTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string) sdk.Dec +} + +type arithmetic struct { + TwapKeeper Keeper +} + +type geometric struct { + TwapKeeper Keeper +} + +// computeTwap computes and returns an arithmetic TWAP between +// two records given the quote asset. +func (s *arithmetic) computeTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string) sdk.Dec { + var accumDiff sdk.Dec + if quoteAsset == startRecord.Asset0Denom { + accumDiff = endRecord.P0ArithmeticTwapAccumulator.Sub(startRecord.P0ArithmeticTwapAccumulator) + } else { + accumDiff = endRecord.P1ArithmeticTwapAccumulator.Sub(startRecord.P1ArithmeticTwapAccumulator) + } + timeDelta := endRecord.Time.Sub(startRecord.Time) + return types.AccumDiffDivDuration(accumDiff, timeDelta) +} + +// computeTwap computes and returns a geometric TWAP between +// two records given the quote asset. +func (s *geometric) computeTwap(startRecord types.TwapRecord, endRecord types.TwapRecord, quoteAsset string) sdk.Dec { + accumDiff := endRecord.GeometricTwapAccumulator.Sub(startRecord.GeometricTwapAccumulator) + + timeDelta := endRecord.Time.Sub(startRecord.Time) + arithmeticMeanOfLogPrices := types.AccumDiffDivDuration(accumDiff, timeDelta) + + result := twapPow(arithmeticMeanOfLogPrices) + // N.B.: Geometric mean of recprocals is reciprocal of geometric mean. + // https://proofwiki.org/wiki/Geometric_Mean_of_Reciprocals_is_Reciprocal_of_Geometric_Mean + if quoteAsset == startRecord.Asset1Denom { + result = sdk.OneDec().Quo(result) + } + + // N.B. we round because this is the max number of significant figures supported + // by the underlying spot price function. + return osmomath.SigFigRound(result, gammtypes.SpotPriceSigFigs) +} diff --git a/x/twap/strategy_test.go b/x/twap/strategy_test.go new file mode 100644 index 00000000000..f5208f4c948 --- /dev/null +++ b/x/twap/strategy_test.go @@ -0,0 +1,323 @@ +package twap_test + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/osmosis-labs/osmosis/osmomath" + "github.com/osmosis-labs/osmosis/osmoutils/osmoassert" + gammtypes "github.com/osmosis-labs/osmosis/v13/x/gamm/types" + "github.com/osmosis-labs/osmosis/v13/x/twap" + "github.com/osmosis-labs/osmosis/v13/x/twap/types" +) + +type computeTwapTestCase struct { + startRecord types.TwapRecord + endRecord types.TwapRecord + twapStrategies []twap.TwapStrategy + quoteAsset string + expTwap sdk.Dec + expErr bool + expPanic bool +} + +var ( + oneHundredYears = OneSec.MulInt64(60 * 60 * 24 * 365 * 100) +) + +// TestComputeArithmeticTwap tests computeTwap on various inputs. +// The test vectors are structured by setting up different start and records, +// based on time interval, and their accumulator values. +// Then an expected TWAP is provided in each test case, to compare against computed. +func (s *TestSuite) TestComputeTwap() { + arithStrategy := &twap.ArithmeticTwapStrategy{ + TwapKeeper: *s.App.TwapKeeper, + } + + geomStrategy := &twap.GeometricTwapStrategy{ + TwapKeeper: *s.App.TwapKeeper, + } + + tests := map[string]computeTwapTestCase{ + "arithmetic only, basic: spot price = 1 for one second, 0 init accumulator": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecord(tPlusOne, OneSec, true), + quoteAsset: denom0, + twapStrategies: []twap.TwapStrategy{ + arithStrategy, + }, + expTwap: sdk.OneDec(), + }, + // this test just shows what happens in case the records are reversed. + // It should return the correct result, even though this is incorrect internal API usage + "arithmetic only: invalid call: reversed records of above": { + startRecord: newOneSidedRecord(tPlusOne, OneSec, true), + endRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + quoteAsset: denom0, + twapStrategies: []twap.TwapStrategy{ + arithStrategy, + }, + expTwap: sdk.OneDec(), + }, + "same record: denom0, end spot price = 0": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + quoteAsset: denom0, + twapStrategies: []twap.TwapStrategy{ + arithStrategy, + geomStrategy, + }, + expTwap: sdk.ZeroDec(), + }, + "same record: denom1, end spot price = 1": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + quoteAsset: denom1, + twapStrategies: []twap.TwapStrategy{ + arithStrategy, + geomStrategy, + }, + expTwap: sdk.OneDec(), + }, + "arithmetic only: accumulator = 10*OneSec, t=5s. 0 base accum": testCaseFromDeltas( + s, sdk.ZeroDec(), tenSecAccum, 5*time.Second, sdk.NewDec(2)), + "arithmetic only: accumulator = 10*OneSec, t=100s. 0 base accum (asset 1)": testCaseFromDeltasAsset1(s, sdk.ZeroDec(), OneSec.MulInt64(10), 100*time.Second, sdk.NewDecWithPrec(1, 1)), + "geometric only: accumulator = log(10)*OneSec, t=5s. 0 base accum": geometricTestCaseFromDeltas0( + s, sdk.ZeroDec(), geometricTenSecAccum, 5*time.Second, twap.TwapPow(geometricTenSecAccum.QuoInt64(5*1000))), + "geometric only: accumulator = log(10)*OneSec, t=100s. 0 base accum (asset 1)": geometricTestCaseFromDeltas1(s, sdk.ZeroDec(), geometricTenSecAccum, 100*time.Second, sdk.OneDec().Quo(twap.TwapPow(geometricTenSecAccum.QuoInt64(100*1000)))), + "three asset same record: asset1, end spot price = 1": { + startRecord: newThreeAssetOneSidedRecord(baseTime, sdk.ZeroDec(), true)[1], + endRecord: newThreeAssetOneSidedRecord(baseTime, sdk.ZeroDec(), true)[1], + quoteAsset: denom2, + expTwap: sdk.OneDec(), + twapStrategies: []twap.TwapStrategy{ + arithStrategy, + geomStrategy, + }, + }, + } + for name, test := range tests { + s.Run(name, func() { + for _, twapStrategy := range test.twapStrategies { + actualTwap, err := twap.ComputeTwap(test.startRecord, test.endRecord, test.quoteAsset, twapStrategy) + s.Require().NoError(err) + osmoassert.DecApproxEq(s.T(), test.expTwap, actualTwap, osmomath.GetPowPrecision()) + } + }) + } +} + +// TestComputeArithmeticStrategyTwap tests arithmetic strategy's computeTwap +// Contrary to computeTwap function (logic.go) that handles the cases with zero delta correctly, +// this function should panic in case of zero delta. +func (s *TestSuite) TestComputeArithmeticStrategyTwap() { + pointOneAccum := OneSec.QuoInt64(10) + tests := map[string]computeTwapTestCase{ + "basic: spot price = 1 for one second, 0 init accumulator": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecord(tPlusOne, OneSec, true), + quoteAsset: denom0, + expTwap: sdk.OneDec(), + }, + // this test just shows what happens in case the records are reversed. + // It should return the correct result, even though this is incorrect internal API usage + "invalid call: reversed records of above": { + startRecord: newOneSidedRecord(tPlusOne, OneSec, true), + endRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + quoteAsset: denom0, + expTwap: sdk.OneDec(), + }, + "same record (zero time delta), division by 0 - panic": { + startRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newOneSidedRecord(baseTime, sdk.ZeroDec(), true), + quoteAsset: denom0, + expPanic: true, + }, + "accumulator = 10*OneSec, t=5s. 0 base accum": testCaseFromDeltas( + s, sdk.ZeroDec(), tenSecAccum, 5*time.Second, sdk.NewDec(2)), + "accumulator = 10*OneSec, t=3s. 0 base accum": testCaseFromDeltas( + s, sdk.ZeroDec(), tenSecAccum, 3*time.Second, ThreePlusOneThird), + "accumulator = 10*OneSec, t=100s. 0 base accum": testCaseFromDeltas( + s, sdk.ZeroDec(), tenSecAccum, 100*time.Second, sdk.NewDecWithPrec(1, 1)), + + // test that base accum has no impact + "accumulator = 10*OneSec, t=5s. 10 base accum": testCaseFromDeltas( + s, sdk.NewDec(10), tenSecAccum, 5*time.Second, sdk.NewDec(2)), + "accumulator = 10*OneSec, t=3s. 10*second base accum": testCaseFromDeltas( + s, tenSecAccum, tenSecAccum, 3*time.Second, ThreePlusOneThird), + "accumulator = 10*OneSec, t=100s. .1*second base accum": testCaseFromDeltas( + s, pointOneAccum, tenSecAccum, 100*time.Second, sdk.NewDecWithPrec(1, 1)), + + "accumulator = 10*OneSec, t=100s. 0 base accum (asset 1)": testCaseFromDeltasAsset1(s, sdk.ZeroDec(), OneSec.MulInt64(10), 100*time.Second, sdk.NewDecWithPrec(1, 1)), + } + for name, test := range tests { + s.Run(name, func() { + osmoassert.ConditionalPanic(s.T(), test.expPanic, func() { + arithmeticStrategy := &twap.ArithmeticTwapStrategy{TwapKeeper: *s.App.TwapKeeper} + actualTwap := arithmeticStrategy.ComputeTwap(test.startRecord, test.endRecord, test.quoteAsset) + s.Require().Equal(test.expTwap, actualTwap) + }) + }) + } +} + +// TestComputeGeometricStrategyTwap tests geometric strategy's computeTwap +// Contrary to computeTwap function (logic.go) that handles the cases with zero delta correctly, +// this function should panic in case of zero delta. +func (s *TestSuite) TestComputeGeometricStrategyTwap() { + tests := map[string]computeTwapTestCase{ + // basic test for both denom with zero start accumulator + "basic denom0: spot price = 1 for one second, 0 init accumulator": { + startRecord: newOneSidedGeometricRecord(baseTime, sdk.ZeroDec()), + endRecord: newOneSidedGeometricRecord(tPlusOne, geometricTenSecAccum), + quoteAsset: denom0, + expTwap: sdk.NewDec(10), + }, + "basic denom1: spot price = 1 for one second, 0 init accumulator": { + startRecord: newOneSidedGeometricRecord(baseTime, sdk.ZeroDec()), + endRecord: newOneSidedGeometricRecord(tPlusOne, geometricTenSecAccum), + quoteAsset: denom1, + expTwap: sdk.OneDec().Quo(sdk.NewDec(10)), + }, + + // basic test for both denom with non-zero start accumulator + "denom0: start accumulator of 10 * 1s, end accumulator 10 * 1s + 20 * 2s = 20": { + startRecord: newOneSidedGeometricRecord(baseTime, geometricTenSecAccum), + endRecord: newOneSidedGeometricRecord(baseTime.Add(time.Second*2), geometricTenSecAccum.Add(OneSec.MulInt64(2).Mul(twap.TwapLog(sdk.NewDec(20))))), + quoteAsset: denom0, + expTwap: sdk.NewDec(20), + }, + "denom1 start accumulator of 10 * 1s, end accumulator 10 * 1s + 20 * 2s = 20": { + startRecord: newOneSidedGeometricRecord(baseTime, geometricTenSecAccum), + endRecord: newOneSidedGeometricRecord(baseTime.Add(time.Second*2), geometricTenSecAccum.Add(OneSec.MulInt64(2).Mul(twap.TwapLog(sdk.NewDec(20))))), + quoteAsset: denom1, + expTwap: sdk.OneDec().Quo(sdk.NewDec(20)), + }, + + // toggle time delta. + "accumulator = log(10)*OneSec, t=5s. 0 base accum": geometricTestCaseFromDeltas0( + s, sdk.ZeroDec(), geometricTenSecAccum, 5*time.Second, twap.TwapPow(geometricTenSecAccum.QuoInt64(5*1000))), + "accumulator = log(10)*OneSec, t=3s. 0 base accum": geometricTestCaseFromDeltas0( + s, sdk.ZeroDec(), geometricTenSecAccum, 3*time.Second, twap.TwapPow(geometricTenSecAccum.QuoInt64(3*1000))), + "accumulator = log(10)*OneSec, t=100s. 0 base accum": geometricTestCaseFromDeltas0( + s, sdk.ZeroDec(), geometricTenSecAccum, 100*time.Second, twap.TwapPow(geometricTenSecAccum.QuoInt64(100*1000))), + + // test that base accum has no impact + "accumulator = log(10)*OneSec, t=5s. 10 base accum": geometricTestCaseFromDeltas0( + s, logTen, geometricTenSecAccum, 5*time.Second, twap.TwapPow(geometricTenSecAccum.QuoInt64(5*1000))), + "accumulator = log(10)*OneSec, t=3s. 10*second base accum": geometricTestCaseFromDeltas0( + s, OneSec.MulInt64(10).Mul(logTen), geometricTenSecAccum, 3*time.Second, twap.TwapPow(geometricTenSecAccum.QuoInt64(3*1000))), + "accumulator = 10*OneSec, t=100s. .1*second base accum": geometricTestCaseFromDeltas0( + s, OneSec.MulInt64(10).Mul(logOneOverTen), geometricTenSecAccum, 100*time.Second, twap.TwapPow(geometricTenSecAccum.QuoInt64(100*1000))), + + // TODO: this is the highest price we currently support with the given precision bounds. + // Need to choose better base and potentially improve math functions to mitigate. + "price of 1_000_000 for an hour": { + startRecord: newOneSidedGeometricRecord(baseTime, sdk.ZeroDec()), + endRecord: newOneSidedGeometricRecord(baseTime.Add(time.Hour), OneSec.MulInt64(60*60).Mul(twap.TwapLog(sdk.NewDec(1_000_000)))), + quoteAsset: denom0, + expTwap: sdk.NewDec(1_000_000), + }, + // TODO: overflow tests + // - max spot price + // - large time delta + // - both + + // TODO: hand calculated tests + } + + for name, tc := range tests { + s.Run(name, func() { + osmoassert.ConditionalPanic(s.T(), tc.expPanic, func() { + geometricStrategy := &twap.GeometricTwapStrategy{TwapKeeper: *s.App.TwapKeeper} + actualTwap := geometricStrategy.ComputeTwap(tc.startRecord, tc.endRecord, tc.quoteAsset) + osmoassert.DecApproxEq(s.T(), tc.expTwap, actualTwap, osmomath.GetPowPrecision()) + }) + }) + } +} + +func (s *TestSuite) TestComputeArithmeticStrategyTwap_ThreeAsset() { + tenSecAccum := OneSec.MulInt64(10) + pointOneAccum := OneSec.QuoInt64(10) + tests := map[string]computeThreeAssetArithmeticTwapTestCase{ + "three asset basic: spot price = 1 for one second, 0 init accumulator": { + startRecord: newThreeAssetOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newThreeAssetOneSidedRecord(tPlusOne, OneSec, true), + quoteAsset: []string{denom0, denom0, denom1}, + expTwap: []sdk.Dec{sdk.OneDec(), sdk.OneDec(), sdk.OneDec()}, + }, + "three asset. accumulator = 10*OneSec, t=5s. 0 base accum": testThreeAssetCaseFromDeltas( + sdk.ZeroDec(), tenSecAccum, 5*time.Second, sdk.NewDec(2)), + + // test that base accum has no impact + "three asset. accumulator = 10*OneSec, t=5s. 10 base accum": testThreeAssetCaseFromDeltas( + sdk.NewDec(10), tenSecAccum, 5*time.Second, sdk.NewDec(2)), + "three asset. accumulator = 10*OneSec, t=100s. .1*second base accum": testThreeAssetCaseFromDeltas( + pointOneAccum, tenSecAccum, 100*time.Second, sdk.NewDecWithPrec(1, 1)), + } + for name, test := range tests { + s.Run(name, func() { + for i, startRec := range test.startRecord { + arithmeticStrategy := &twap.ArithmeticTwapStrategy{TwapKeeper: *s.App.TwapKeeper} + actualTwap := arithmeticStrategy.ComputeTwap(startRec, test.endRecord[i], test.quoteAsset[i]) + s.Require().Equal(test.expTwap[i], actualTwap) + } + }) + } +} + +func (s *TestSuite) TestComputeGeometricStrategyTwap_ThreeAsset() { + var ( + five = sdk.NewDec(5) + fiveFor3Sec = OneSec.MulInt64(3).Mul(twap.TwapLog(five)) + + ten = five.MulInt64(2) + tenFor100Sec = OneSec.MulInt64(100).Mul(twap.TwapLog(ten)) + + errTolerance = sdk.MustNewDecFromStr("0.00000001") + ) + + tests := map[string]computeThreeAssetArithmeticTwapTestCase{ + "three asset basic: spot price = 10 for one second, 0 init accumulator": { + startRecord: newThreeAssetOneSidedRecord(baseTime, sdk.ZeroDec(), true), + endRecord: newThreeAssetOneSidedRecord(tPlusOne, geometricTenSecAccum, true), + quoteAsset: []string{denom0, denom0, denom1}, + expTwap: []sdk.Dec{sdk.NewDec(10), sdk.NewDec(10), sdk.NewDec(10)}, + }, + "three asset. accumulator = 5*3Sec, t=3s, no start accum": testThreeAssetCaseFromDeltas( + sdk.ZeroDec(), fiveFor3Sec, 3*time.Second, five), + + // test that base accum has no impact + "three asset. accumulator = 5*3Sec, t=3s. 10 base accum": testThreeAssetCaseFromDeltas( + geometricTenSecAccum, fiveFor3Sec, 3*time.Second, five), + "three asset. accumulator = 100*100s, t=100s. .1*second base accum": testThreeAssetCaseFromDeltas( + twap.TwapLog(OneSec.Quo(ten)), tenFor100Sec, 100*time.Second, ten), + } + for name, test := range tests { + s.Run(name, func() { + for i, startRec := range test.startRecord { + geometricStrategy := &twap.GeometricTwapStrategy{TwapKeeper: *s.App.TwapKeeper} + actualTwap := geometricStrategy.ComputeTwap(startRec, test.endRecord[i], test.quoteAsset[i]) + osmoassert.DecApproxEq(s.T(), test.expTwap[i], actualTwap, errTolerance) + } + }) + } +} + +// TestTwapPow_MaxSpotPrice_NoOverflow tests that no overflow occurs at log_2{max spot price values}. +// and that the epsilon is within the tolerated multiplicative error. +func (s *TestSuite) TestTwapLogPow_MaxSpotPrice_NoOverflow() { + errTolerance := osmomath.ErrTolerance{ + MultiplicativeTolerance: sdk.OneDec().Quo(sdk.NewDec(10).Power(18)), + RoundingDir: osmomath.RoundDown, + } + + oneHundredYearsTimesMaxSpotPrice := oneHundredYears.Mul(gammtypes.MaxSpotPrice) + + exponentValue := twap.TwapLog(oneHundredYearsTimesMaxSpotPrice) + finalValue := twap.TwapPow(exponentValue) + + s.Require().Equal(0, errTolerance.CompareBigDec(osmomath.BigDecFromSDKDec(oneHundredYearsTimesMaxSpotPrice), osmomath.BigDecFromSDKDec(finalValue))) +} diff --git a/x/twap/types/expected_interfaces.go b/x/twap/types/expected_interfaces.go index 8ed0bfe4e58..1a8dadb6d78 100644 --- a/x/twap/types/expected_interfaces.go +++ b/x/twap/types/expected_interfaces.go @@ -12,7 +12,7 @@ type AmmInterface interface { CalculateSpotPrice( ctx sdk.Context, poolID uint64, - baseAssetDenom string, quoteAssetDenom string, + baseAssetDenom string, ) (price sdk.Dec, err error) } diff --git a/x/twap/types/genesis.go b/x/twap/types/genesis.go index ac47da89bbd..fdd273bcd7b 100644 --- a/x/twap/types/genesis.go +++ b/x/twap/types/genesis.go @@ -81,5 +81,9 @@ func (t TwapRecord) validate() error { if t.P1ArithmeticTwapAccumulator.IsNil() || t.P1ArithmeticTwapAccumulator.IsNegative() { return fmt.Errorf("twap record p1 accumulator cannot be negative, was (%s)", t.P1ArithmeticTwapAccumulator) } + + if t.GeometricTwapAccumulator.IsNil() || t.GeometricTwapAccumulator.IsNegative() { + return fmt.Errorf("twap record geometric accumulator cannot be negative, was (%s)", t.GeometricTwapAccumulator) + } return nil } diff --git a/x/twap/types/genesis_test.go b/x/twap/types/genesis_test.go index 313668b1002..bc65efe03ad 100644 --- a/x/twap/types/genesis_test.go +++ b/x/twap/types/genesis_test.go @@ -28,6 +28,7 @@ var ( P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), } ) @@ -55,6 +56,7 @@ func TestGenesisState_Validate(t *testing.T) { P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), }, { PoolId: basePoolId, @@ -66,6 +68,7 @@ func TestGenesisState_Validate(t *testing.T) { P1LastSpotPrice: sdk.OneDec(), P0ArithmeticTwapAccumulator: sdk.OneDec(), P1ArithmeticTwapAccumulator: sdk.OneDec(), + GeometricTwapAccumulator: sdk.OneDec(), }, }) ) @@ -294,6 +297,23 @@ func TestTWAPRecord_Validate(t *testing.T) { }(), expectedErr: true, }, + "invalid geometric accum: nil": { + twapRecord: func() TwapRecord { + r := TwapRecord{ + PoolId: basePoolId, + Asset0Denom: denom0, + Asset1Denom: denom1, + Height: 3, + Time: tPlusOne.Add(time.Second), + P0LastSpotPrice: sdk.OneDec(), + P1LastSpotPrice: sdk.OneDec(), + P0ArithmeticTwapAccumulator: sdk.OneDec(), + P1ArithmeticTwapAccumulator: sdk.OneDec(), + } + return r + }(), + expectedErr: true, + }, } // make test cases symmetric testCasesSym := map[string]testcase{} diff --git a/x/twap/types/twap_record.pb.go b/x/twap/types/twap_record.pb.go index 8f06949df49..7faa318b4f0 100644 --- a/x/twap/types/twap_record.pb.go +++ b/x/twap/types/twap_record.pb.go @@ -55,6 +55,7 @@ type TwapRecord struct { P1LastSpotPrice github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,7,opt,name=p1_last_spot_price,json=p1LastSpotPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"p1_last_spot_price"` P0ArithmeticTwapAccumulator github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,8,opt,name=p0_arithmetic_twap_accumulator,json=p0ArithmeticTwapAccumulator,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"p0_arithmetic_twap_accumulator"` P1ArithmeticTwapAccumulator github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,9,opt,name=p1_arithmetic_twap_accumulator,json=p1ArithmeticTwapAccumulator,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"p1_arithmetic_twap_accumulator"` + GeometricTwapAccumulator github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,10,opt,name=geometric_twap_accumulator,json=geometricTwapAccumulator,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"geometric_twap_accumulator"` // This field contains the time in which the last spot price error occured. // It is used to alert the caller if they are getting a potentially erroneous // TWAP, due to an unforeseen underlying error. @@ -145,40 +146,41 @@ func init() { } var fileDescriptor_dbf5c78678e601aa = []byte{ - // 523 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0xc7, 0x63, 0x1a, 0x5c, 0xba, 0xa1, 0xaa, 0x64, 0x45, 0x60, 0x82, 0x64, 0x07, 0x1f, 0xaa, - 0x70, 0xa8, 0x3f, 0xe8, 0x8d, 0x5b, 0xa2, 0x72, 0x00, 0x21, 0x84, 0x4c, 0x4f, 0x70, 0x58, 0xad, - 0xed, 0xad, 0x63, 0x61, 0x67, 0x57, 0xde, 0x4d, 0x4b, 0x5e, 0x81, 0x53, 0x1f, 0xab, 0xc7, 0x1e, - 0x11, 0x07, 0x83, 0x92, 0x1b, 0xc7, 0x3e, 0x01, 0xda, 0x8f, 0x84, 0x26, 0x08, 0x2a, 0xe5, 0x64, - 0xcf, 0xcc, 0x7f, 0x7e, 0x33, 0xb3, 0xb3, 0x36, 0x38, 0x24, 0xac, 0x22, 0xac, 0x60, 0x01, 0xbf, - 0x40, 0x34, 0x38, 0x8f, 0x12, 0xcc, 0x51, 0x24, 0x0d, 0x58, 0xe3, 0x94, 0xd4, 0x99, 0x4f, 0x6b, - 0xc2, 0x89, 0xd5, 0xd5, 0x3a, 0x5f, 0x84, 0x7c, 0xad, 0xeb, 0x75, 0x73, 0x92, 0x13, 0x29, 0x08, - 0xc4, 0x9b, 0xd2, 0xf6, 0x9e, 0xe4, 0x84, 0xe4, 0x25, 0x0e, 0xa4, 0x95, 0x4c, 0xcf, 0x02, 0x34, - 0x99, 0x2d, 0x43, 0xa9, 0xe4, 0x40, 0x95, 0xa3, 0x0c, 0x1d, 0x72, 0x94, 0x15, 0x24, 0x88, 0xe1, - 0x55, 0x23, 0x29, 0x29, 0x26, 0x3a, 0xee, 0x6e, 0x52, 0x79, 0x51, 0x61, 0xc6, 0x51, 0x45, 0x95, - 0xc0, 0xfb, 0x6a, 0x02, 0x70, 0x7a, 0x81, 0x68, 0x2c, 0xfb, 0xb6, 0x1e, 0x83, 0x5d, 0x4a, 0x48, - 0x09, 0x8b, 0xcc, 0x36, 0xfa, 0xc6, 0xa0, 0x1d, 0x9b, 0xc2, 0x7c, 0x9d, 0x59, 0xcf, 0xc0, 0x43, - 0xc4, 0x18, 0xe6, 0x21, 0xcc, 0xf0, 0x84, 0x54, 0xf6, 0xbd, 0xbe, 0x31, 0xd8, 0x8b, 0x3b, 0xca, - 0x77, 0x22, 0x5c, 0x2b, 0x49, 0xa4, 0x25, 0x3b, 0xb7, 0x24, 0x91, 0x92, 0x0c, 0x81, 0x39, 0xc6, - 0x45, 0x3e, 0xe6, 0x76, 0xbb, 0x6f, 0x0c, 0x76, 0x46, 0xcf, 0x7f, 0x35, 0xee, 0xbe, 0x3a, 0x32, - 0xa8, 0x02, 0x37, 0x8d, 0xdb, 0x9d, 0xa1, 0xaa, 0x7c, 0xe9, 0xad, 0xb9, 0xbd, 0x58, 0x27, 0x5a, - 0xef, 0x40, 0x5b, 0xcc, 0x60, 0xdf, 0xef, 0x1b, 0x83, 0xce, 0x8b, 0x9e, 0xaf, 0x06, 0xf4, 0x97, - 0x03, 0xfa, 0xa7, 0xcb, 0x01, 0x47, 0xce, 0x55, 0xe3, 0xb6, 0x6e, 0x1a, 0xd7, 0x5a, 0xe3, 0x89, - 0x64, 0xef, 0xf2, 0x87, 0x6b, 0xc4, 0x92, 0x63, 0x7d, 0x02, 0x16, 0x0d, 0x61, 0x89, 0x18, 0x87, - 0x8c, 0x12, 0x0e, 0x69, 0x5d, 0xa4, 0xd8, 0x36, 0x45, 0xef, 0x23, 0x5f, 0x10, 0xbe, 0x37, 0xee, - 0x61, 0x5e, 0xf0, 0xf1, 0x34, 0xf1, 0x53, 0x52, 0xe9, 0xe3, 0xd7, 0x8f, 0x23, 0x96, 0x7d, 0x0e, - 0xf8, 0x8c, 0x62, 0xe6, 0x9f, 0xe0, 0x34, 0x3e, 0xa0, 0xe1, 0x5b, 0xc4, 0xf8, 0x07, 0x4a, 0xf8, - 0x7b, 0x81, 0x91, 0xf0, 0xe8, 0x2f, 0xf8, 0xee, 0x96, 0xf0, 0x68, 0x1d, 0xce, 0x80, 0x43, 0x43, - 0x88, 0xea, 0x82, 0x8f, 0x2b, 0xcc, 0x8b, 0x14, 0xca, 0x0b, 0x88, 0xd2, 0x74, 0x5a, 0x4d, 0x4b, - 0xc4, 0x49, 0x6d, 0x3f, 0xd8, 0xaa, 0xd0, 0x53, 0x1a, 0x0e, 0x57, 0x50, 0x71, 0x37, 0x86, 0x7f, - 0x90, 0xb2, 0x68, 0xf4, 0xdf, 0xa2, 0x7b, 0x5b, 0x16, 0x8d, 0xfe, 0x5d, 0xf4, 0x0c, 0x1c, 0xc8, - 0x33, 0xc4, 0x75, 0x4d, 0x6a, 0xb9, 0x41, 0xbb, 0x73, 0xe7, 0xfa, 0x3d, 0xbd, 0xfe, 0x47, 0x6a, - 0xfd, 0x1b, 0x00, 0x75, 0x05, 0xf6, 0x85, 0xf7, 0x95, 0x70, 0x8a, 0xbc, 0xd1, 0x9b, 0xab, 0xb9, - 0x63, 0x5c, 0xcf, 0x1d, 0xe3, 0xe7, 0xdc, 0x31, 0x2e, 0x17, 0x4e, 0xeb, 0x7a, 0xe1, 0xb4, 0xbe, - 0x2d, 0x9c, 0xd6, 0xc7, 0xf0, 0xd6, 0x18, 0xfa, 0xa3, 0x3e, 0x2a, 0x51, 0xc2, 0x96, 0x46, 0x70, - 0x1e, 0x1d, 0x07, 0x5f, 0xd4, 0xff, 0x40, 0x0e, 0x95, 0x98, 0xb2, 0xa5, 0xe3, 0xdf, 0x01, 0x00, - 0x00, 0xff, 0xff, 0x1f, 0x9b, 0x44, 0x27, 0x2c, 0x04, 0x00, 0x00, + // 539 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xbf, 0x6f, 0xd3, 0x40, + 0x14, 0xc7, 0x63, 0x1a, 0x52, 0x7a, 0xa1, 0xaa, 0x64, 0x45, 0x60, 0x82, 0x64, 0x87, 0x0c, 0x55, + 0x18, 0xea, 0x1f, 0x74, 0x63, 0x4b, 0x54, 0x06, 0x10, 0x42, 0xc8, 0x74, 0x82, 0xe1, 0x74, 0xb6, + 0xaf, 0x8e, 0x85, 0x9d, 0x3b, 0xdd, 0x5d, 0x5a, 0xf2, 0x5f, 0xf4, 0xcf, 0xea, 0xd8, 0x11, 0x31, + 0x18, 0x94, 0x6c, 0x8c, 0x9d, 0x18, 0xd1, 0xfd, 0x48, 0x68, 0xc2, 0x2f, 0x29, 0x53, 0xf2, 0xde, + 0xfb, 0xbe, 0xcf, 0xf7, 0x3d, 0xfb, 0xc9, 0xe0, 0x90, 0xf0, 0x8a, 0xf0, 0x82, 0x07, 0xe2, 0x02, + 0xd1, 0xe0, 0x3c, 0x4a, 0xb0, 0x40, 0x91, 0x0a, 0x20, 0xc3, 0x29, 0x61, 0x99, 0x4f, 0x19, 0x11, + 0xc4, 0xee, 0x18, 0x9d, 0x2f, 0x4b, 0xbe, 0xd1, 0x75, 0x3b, 0x39, 0xc9, 0x89, 0x12, 0x04, 0xf2, + 0x9f, 0xd6, 0x76, 0x1f, 0xe5, 0x84, 0xe4, 0x25, 0x0e, 0x54, 0x94, 0x4c, 0xcf, 0x02, 0x34, 0x99, + 0x2d, 0x4b, 0xa9, 0xe2, 0x40, 0xdd, 0xa3, 0x03, 0x53, 0x72, 0x75, 0x14, 0x24, 0x88, 0xe3, 0xd5, + 0x20, 0x29, 0x29, 0x26, 0xa6, 0xee, 0x6d, 0x52, 0x45, 0x51, 0x61, 0x2e, 0x50, 0x45, 0xb5, 0xa0, + 0xff, 0xa3, 0x05, 0xc0, 0xe9, 0x05, 0xa2, 0xb1, 0x9a, 0xdb, 0x7e, 0x08, 0x76, 0x29, 0x21, 0x25, + 0x2c, 0x32, 0xc7, 0xea, 0x59, 0x83, 0x66, 0xdc, 0x92, 0xe1, 0xcb, 0xcc, 0x7e, 0x02, 0xee, 0x23, + 0xce, 0xb1, 0x08, 0x61, 0x86, 0x27, 0xa4, 0x72, 0xee, 0xf4, 0xac, 0xc1, 0x5e, 0xdc, 0xd6, 0xb9, + 0x13, 0x99, 0x5a, 0x49, 0x22, 0x23, 0xd9, 0xb9, 0x25, 0x89, 0xb4, 0x64, 0x08, 0x5a, 0x63, 0x5c, + 0xe4, 0x63, 0xe1, 0x34, 0x7b, 0xd6, 0x60, 0x67, 0xf4, 0xf4, 0x7b, 0xed, 0xed, 0xeb, 0x47, 0x06, + 0x75, 0xe1, 0xa6, 0xf6, 0x3a, 0x33, 0x54, 0x95, 0xcf, 0xfb, 0x6b, 0xe9, 0x7e, 0x6c, 0x1a, 0xed, + 0x37, 0xa0, 0x29, 0x77, 0x70, 0xee, 0xf6, 0xac, 0x41, 0xfb, 0x59, 0xd7, 0xd7, 0x0b, 0xfa, 0xcb, + 0x05, 0xfd, 0xd3, 0xe5, 0x82, 0x23, 0xf7, 0xaa, 0xf6, 0x1a, 0x37, 0xb5, 0x67, 0xaf, 0xf1, 0x64, + 0x73, 0xff, 0xf2, 0xab, 0x67, 0xc5, 0x8a, 0x63, 0x7f, 0x00, 0x36, 0x0d, 0x61, 0x89, 0xb8, 0x80, + 0x9c, 0x12, 0x01, 0x29, 0x2b, 0x52, 0xec, 0xb4, 0xe4, 0xec, 0x23, 0x5f, 0x12, 0xbe, 0xd4, 0xde, + 0x61, 0x5e, 0x88, 0xf1, 0x34, 0xf1, 0x53, 0x52, 0x99, 0xc7, 0x6f, 0x7e, 0x8e, 0x78, 0xf6, 0x31, + 0x10, 0x33, 0x8a, 0xb9, 0x7f, 0x82, 0xd3, 0xf8, 0x80, 0x86, 0xaf, 0x11, 0x17, 0xef, 0x28, 0x11, + 0x6f, 0x25, 0x46, 0xc1, 0xa3, 0xdf, 0xe0, 0xbb, 0x5b, 0xc2, 0xa3, 0x75, 0x38, 0x07, 0x2e, 0x0d, + 0x21, 0x62, 0x85, 0x18, 0x57, 0x58, 0x14, 0x29, 0x54, 0x07, 0x88, 0xd2, 0x74, 0x5a, 0x4d, 0x4b, + 0x24, 0x08, 0x73, 0xee, 0x6d, 0x65, 0xf4, 0x98, 0x86, 0xc3, 0x15, 0x54, 0xde, 0xc6, 0xf0, 0x17, + 0x52, 0x99, 0x46, 0xff, 0x34, 0xdd, 0xdb, 0xd2, 0x34, 0xfa, 0xbb, 0x69, 0x09, 0xba, 0x39, 0x26, + 0x15, 0x16, 0xec, 0x4f, 0x86, 0x60, 0x2b, 0x43, 0x67, 0x45, 0xdc, 0x74, 0x3b, 0x03, 0x07, 0xea, + 0x8d, 0x61, 0xc6, 0x08, 0x53, 0xf7, 0xe2, 0xb4, 0xff, 0x7b, 0x6c, 0x7d, 0x73, 0x6c, 0x0f, 0xf4, + 0xb1, 0x6d, 0x00, 0xf4, 0xc1, 0xed, 0xcb, 0xec, 0x0b, 0x99, 0x94, 0x7d, 0xa3, 0x57, 0x57, 0x73, + 0xd7, 0xba, 0x9e, 0xbb, 0xd6, 0xb7, 0xb9, 0x6b, 0x5d, 0x2e, 0xdc, 0xc6, 0xf5, 0xc2, 0x6d, 0x7c, + 0x5e, 0xb8, 0x8d, 0xf7, 0xe1, 0xad, 0x1d, 0xcc, 0x27, 0xe4, 0xa8, 0x44, 0x09, 0x5f, 0x06, 0xc1, + 0x79, 0x74, 0x1c, 0x7c, 0xd2, 0x5f, 0x1f, 0xb5, 0x51, 0xd2, 0x52, 0x23, 0x1d, 0xff, 0x0c, 0x00, + 0x00, 0xff, 0xff, 0xa4, 0x13, 0xe4, 0xcf, 0x9a, 0x04, 0x00, 0x00, } func (m *TwapRecord) Marshal() (dAtA []byte, err error) { @@ -209,6 +211,16 @@ func (m *TwapRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTwapRecord(dAtA, i, uint64(n1)) i-- dAtA[i] = 0x5a + { + size := m.GeometricTwapAccumulator.Size() + i -= size + if _, err := m.GeometricTwapAccumulator.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTwapRecord(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 { size := m.P1ArithmeticTwapAccumulator.Size() i -= size @@ -325,6 +337,8 @@ func (m *TwapRecord) Size() (n int) { n += 1 + l + sovTwapRecord(uint64(l)) l = m.P1ArithmeticTwapAccumulator.Size() n += 1 + l + sovTwapRecord(uint64(l)) + l = m.GeometricTwapAccumulator.Size() + n += 1 + l + sovTwapRecord(uint64(l)) l = github_com_gogo_protobuf_types.SizeOfStdTime(m.LastErrorTime) n += 1 + l + sovTwapRecord(uint64(l)) return n @@ -636,6 +650,40 @@ func (m *TwapRecord) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GeometricTwapAccumulator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTwapRecord + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTwapRecord + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTwapRecord + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GeometricTwapAccumulator.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex case 11: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field LastErrorTime", wireType) diff --git a/x/twap/types/twapmock/amminterface.go b/x/twap/types/twapmock/amminterface.go index 4b7b408d306..3f2ba2df9ab 100644 --- a/x/twap/types/twapmock/amminterface.go +++ b/x/twap/types/twapmock/amminterface.go @@ -52,7 +52,7 @@ func (p *ProgrammedAmmInterface) ProgramPoolDenomsOverride(poolId uint64, overri } func (p *ProgrammedAmmInterface) ProgramPoolSpotPriceOverride(poolId uint64, - baseDenom, quoteDenom string, overrideSp sdk.Dec, overrideErr error, + quoteDenom, baseDenom string, overrideSp sdk.Dec, overrideErr error, ) { input := SpotPriceInput{poolId, baseDenom, quoteDenom} p.programmedSpotPrice[input] = SpotPriceResult{overrideSp, overrideErr} @@ -71,12 +71,12 @@ func (p *ProgrammedAmmInterface) GetPoolDenoms(ctx sdk.Context, poolId uint64) ( func (p *ProgrammedAmmInterface) CalculateSpotPrice(ctx sdk.Context, poolId uint64, - baseDenom, - quoteDenom string, + quoteDenom, + baseDenom string, ) (price sdk.Dec, err error) { input := SpotPriceInput{poolId, baseDenom, quoteDenom} if res, ok := p.programmedSpotPrice[input]; ok { return res.Sp, res.Err } - return p.underlyingKeeper.CalculateSpotPrice(ctx, poolId, baseDenom, quoteDenom) + return p.underlyingKeeper.CalculateSpotPrice(ctx, poolId, quoteDenom, baseDenom) }